commit 8c648aa559e35bdb83263181246cb8be79074450 Author: Martin Dimitrov Date: Sat Mar 28 12:38:39 2026 +0200 Initial commit with stock files diff --git a/.assetsignore.template b/.assetsignore.template new file mode 100644 index 0000000..648eb55 --- /dev/null +++ b/.assetsignore.template @@ -0,0 +1,40 @@ +# Cloudflare Workers Assets Ignore File +# This file is copied to dist/.assetsignore during build +# See: https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/ + +# Dependencies (shouldn't be in dist, but exclude for safety) +**/node_modules +**/.pnpm-store + +# OS files +**/.DS_Store +**/Thumbs.db +**/ehthumbs.db + +# Git files (shouldn't be in dist, but exclude for safety) +**/.git +**/.gitignore + +# Environment files +**/.env +**/.env.local +**/.env.production + +# Editor files +**/.vscode +**/.idea +**/*.suo +**/*.ntvs* +**/*.njsproj +**/*.sln +**/*.sw? + +# Temporary files +**/*.tmp +**/*.temp +**/.temp + +# Logs +**/*.log +**/*.log.* + diff --git a/.config/astro/config.json b/.config/astro/config.json new file mode 100644 index 0000000..913a888 --- /dev/null +++ b/.config/astro/config.json @@ -0,0 +1,7 @@ +{ + "telemetry": { + "enabled": true, + "notifiedAt": "1756406630228", + "anonymousId": "82b7175d26b171e9f07d9a80e388260f202e2356cbfbe75a95e2377580689494" + } +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5f19f7e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +cli/ export-ignore +.github/ export-ignore +AGENTS.md export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abea441 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Dependencies +node_modules/ +.pnpm-store/ +cli/node_modules/ + +# Build +dist/ +.astro/ + +# Environment variables +.env +.env.local +.env.production + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Temporary files +*.tmp +*.temp +.temp/ +.ref/ + +# OS generated files +Thumbs.db +ehthumbs.db +.DS_Store + +# Obsidian workspace files +src/content/.obsidian/workspace.json +src/content/.obsidian/workspace-mobile.json +obsidian_askpass.sh + +# Generated deployment platform files (GitHub Pages + Cloudflare Workers only) +public/_redirects +public/_headers diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cb9408a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 David V. Kimball + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b1335e5 --- /dev/null +++ b/README.md @@ -0,0 +1,176 @@ +# Astro Modular + +A flexible [Astro](https://astro.build) blog theme designed for [Obsidian](https://obsidian.md) users. + +[![Alt](https://github.com/user-attachments/assets/612b2171-d141-412b-a891-5b1caa1447b8 "Astro Modular theme shown off in 3 screenshots, with the left screenshot showing the homepage, the top right showing the bottom of a post, and the bottom right showing a minimal homepage")](https://astro.build/themes/details/astro-modular/) + +## Made with Vault CMS + +Use Obsidian as a CMS with [Vault CMS](https://github.com/davidvkimball/vault-cms). + +![Alt](https://github.com/user-attachments/assets/3db459e6-6b9a-4c37-b86d-0f661e88e204 "Astro Modular Obsidian vault") + +## Stats + +![Alt](https://repobeats.axiom.co/api/embed/66fe41c94d95b32b92c1a2fd8d6dc83d386bc10a.svg "Repobeats analytics image") + +![Alt](https://github.com/user-attachments/assets/e09c8ee1-6f91-46d6-84a5-e2d8a35c1e14 "Pagespeed scores") + + +### Status +[![Netlify Status](https://api.netlify.com/api/v1/badges/3f849f7a-71e6-463b-84af-01c523012348/deploy-status)](https://app.netlify.com/sites/astro-modular/deploys) +[![GitHub last commit](https://img.shields.io/github/last-commit/davidvkimball/astro-modular/master)](https://github.com/davidvkimball/astro-modular) +[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/davidvkimball/astro-modular)](https://github.com/davidvkimball/astro-modular) + +### Tech Stack +[![Astro](https://img.shields.io/badge/Astro-6.0.0--beta.1-FF5D01?logo=astro&logoColor=white)](https://astro.build/) +[![TypeScript](https://img.shields.io/badge/TypeScript-5.9.2-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/) +[![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-3.4.17-38B2AC?logo=tailwind-css&logoColor=white)](https://tailwindcss.com/) +[![Node.js](https://img.shields.io/badge/Node.js-24.13.0-339933?logo=node.js&logoColor=white)](https://nodejs.org/) +[![pnpm](https://img.shields.io/badge/pnpm-10.29.3-F69220?logo=pnpm&logoColor=white)](https://pnpm.io/) +[![Obsidian](https://img.shields.io/badge/Obsidian-1.12.2-7C3AED?logo=obsidian&logoColor=white)](https://obsidian.md/) + +## Why Astro Modular? + +- **Obsidian As A CMS**: Works with Obsidian out of the box (built upon [Vault CMS](https://github.com/davidvkimball/vault-cms)), write and publish instantly +- **Highly Customizable**: Every feature can be enabled/disabled independently +- **Performance-Focused**: Assets are highly optimized for lightning-fast loading +- **SEO-Ready**: Automatic sitemap, RSS feed, and Open Graph image generation + +## Features + +- [x] **Custom Themes** +- [x] **Feature Toggle Control** +- [x] **Dark/Light Mode** +- [x] **Search & Command Palette** +- [x] **Wikilinks & Linked Mentions** +- [x] **Obsidian-Style Callouts** +- [x] **Obsidian Embeds Files** +- [x] **Folder-Based Posts** +- [x] **Multiple Content Types** +- [x] **Image Optimization** +- [x] **Automatic Feed Generation** +- [x] **Table of Contents** +- [x] **Smooth Scroll & Page Transitions** +- [x] **Image Gallery & Lightbox** +- [x] **Reading Time & Word Count** +- [x] **Tagging** +- [x] **Graph View** +- [x] **Mermaid Diagrams** +- [x] **LaTeX & Math Rendering** +- [x] **Custom Typography** +- [x] **Profile Picture** +- [x] **Comments** + +## Quick Start + +[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/davidvkimball/astro-modular) +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/davidvkimball/astro-modular) +[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/davidvkimball/astro-modular) + +### Get the Code + +Choose one of the following methods to get started: + +#### Option 1: CLI (Recommended) + +```bash +pnpm create astro-modular my-blog +cd my-blog +``` + +[![npm version](https://img.shields.io/npm/v/create-astro-modular)](https://www.npmjs.com/package/create-astro-modular) + +This downloads the latest template, removes dev-only files, and installs dependencies automatically. Also works with `npm create astro-modular my-blog`. + +#### Option 2: Use GitHub Template + +1. Click the **"Use this template"** button on the [repository page](https://github.com/davidvkimball/astro-modular) +2. Select **"Create a new repository"** +3. Choose your repository name and settings +4. Click **"Create repository from template"** +5. Clone your new repository: + ```bash + git clone https://github.com/your-username/your-repo-name.git + cd your-repo-name + ``` + + + +### Prerequisites +- Node.js 24.13.0+ +- pnpm 10.29.3+ or npm 9.6.5+ + +> [!NOTE] +> While this theme works great with any markdown editor, it's specifically optimized for Obsidian use. See the [Astro Suite Vault Guide](src/content/posts/vault-cms-guide.md) for Obsidian-specific features. + +### Setup + +1. **Install pnpm (if you don't have it):** + ```bash + npm install -g pnpm + ``` + +2. **Install dependencies:** + ```bash + pnpm install + ``` + +3. **Preview:** + ```bash + pnpm dev + ``` + Your blog will be available at `http://localhost:5000` + +4. **Build for production:** + ```bash + pnpm build + ``` + +### Updating the theme + +To pull the latest theme release (framework files, Astro, config) while keeping your content and assets: + +```bash +pnpm run update +``` + +This downloads the latest release from GitHub, replaces framework files, restores your `src/content` and profile/favicon assets, then runs `pnpm install`. After updating, open Obsidian and use **Astro Modular Settings → Apply all settings** so your saved settings are written to the new `config.ts` if needed. + +### Configuration + +Edit `src/config.ts` to customize your site - change the theme, enable/disable features, and configure all settings. + +## Deployment + +Set your deployment platform once in `src/config.ts` under `deployment.platform` ("netlify", "vercel", "github-pages", or "cloudflare-workers"). The build process automatically generates the correct configuration files for your chosen platform - no environment variables needed! + +## Documentation + +For detailed guides, see the included blog posts: +- **[Getting Started](src/content/posts/getting-started.md)** - complete setup and workflow guide +- **[Formatting Reference](src/content/posts/formatting-reference.md)** - comprehensive formatting reference +- **[Vault CMS Guide](src/content/posts/vault-cms-guide.md)** - Obsidian vault walkthrough +- **[Obsidian Embeds Demo](src/content/posts/obsidian-embeds-demo.md)** - Obsidian embed examples + +**For AI Agents & Developers:** See [AGENTS.md](AGENTS.md) for comprehensive technical documentation. + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=davidvkimball/astro-modular&type=date&legend=top-left)](https://www.star-history.com/#davidvkimball/astro-modular&type=date&legend=top-left) + +## Acknowledgments + +[Spaceship Astro theme](https://github.com/aitorllj93/astro-theme-spaceship) for the graph view functionality upon which this theme's is based. + +[ogImage.click](https://ogimage.click/) to generate the open graph image used for this theme. + +## Contributing + +This is an open-source project. Feel free to submit feature requests, report bugs, or contribute improvements. + +If you are contributing code back to the theme itself, please fork the repository and submit a Pull Request. **Do not fork the repository if you are just building your own site from this template.** + +## License + +[MIT License](https://github.com/davidvkimball/astro-modular?tab=MIT-1-ov-file) diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..7fc2521 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.8.6 diff --git a/astro.config.mjs b/astro.config.mjs new file mode 100644 index 0000000..ee1aa10 --- /dev/null +++ b/astro.config.mjs @@ -0,0 +1,225 @@ +import { defineConfig } from 'astro/config'; +import tailwind from '@astrojs/tailwind'; +import sitemap from '@astrojs/sitemap'; +import mdx from '@astrojs/mdx'; +import { remarkInternalLinks, remarkFolderImages, remarkImageCaptions } from './src/utils/internallinks.ts'; +import remarkCallouts from './src/utils/remark-callouts.ts'; +import remarkImageGrids from './src/utils/remark-image-grids.ts'; +import remarkMermaid from './src/utils/remark-mermaid.ts'; +import { remarkObsidianEmbeds } from './src/utils/remark-obsidian-embeds.ts'; +import remarkBases from './src/utils/remark-bases.ts'; +import remarkInlineTags from './src/utils/remark-inline-tags.ts'; +import { remarkObsidianComments } from './src/utils/remark-obsidian-comments.ts'; +import remarkObsidianImageSize from './src/utils/remark-obsidian-image-size.ts'; +import remarkMath from 'remark-math'; +import remarkReadingTime from 'remark-reading-time'; +import remarkToc from 'remark-toc'; +import remarkBreaks from 'remark-breaks'; +import rehypeKatex from 'rehype-katex'; +import rehypeMark from './src/utils/rehype-mark.ts'; +import rehypeImageAttributes from './src/utils/rehype-image-attributes.ts'; +import { rehypeNormalizeAnchors } from './src/utils/rehype-normalize-anchors.ts'; +import rehypeSlug from 'rehype-slug'; +import rehypeAutolinkHeadings from 'rehype-autolink-headings'; +import { siteConfig } from './src/config.ts'; +import swup from '@swup/astro'; +import refreshContentOnChange from './src/integrations/refresh-content-on-change.ts'; +import { fileURLToPath } from 'node:url'; + +// Deployment platform configuration +const DEPLOYMENT_PLATFORM = process.env.DEPLOYMENT_PLATFORM || 'netlify'; + +export default defineConfig({ + site: siteConfig.site, + deployment: { + platform: DEPLOYMENT_PLATFORM + }, + csp: { + scriptDirective: { + resources: [ + "'self'", + "'unsafe-inline'", + "https://unpkg.com", + "https://cdnjs.cloudflare.com", + "https://cdn.jsdelivr.net", + "https://giscus.app", + "https://platform.twitter.com" + ] + }, + styleDirective: { + resources: [ + "'self'", + "'unsafe-inline'", + "https://fonts.googleapis.com", + "https://cdnjs.cloudflare.com" + ] + }, + fontDirective: { + resources: [ + "'self'", + "data:", + "https://fonts.gstatic.com", + "https://cdnjs.cloudflare.com" + ] + }, + imgDirective: { + resources: ["'self'", "data:", "https:"] + }, + connectDirective: { + resources: ["'self'", "https://giscus.app"] + }, + frameDirective: { + resources: [ + "'self'", + "https://www.youtube.com", + "https://giscus.app", + "https://platform.twitter.com" + ] + } + }, + devToolbar: { + enabled: true + }, + redirects: (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'build') ? { + '/about-me': '/about', + '/about-us': '/about', + '/contact-me': '/contact', + '/contact-us': '/contact', + '/privacy': '/privacy-policy', + '/posts/mermaid-test': '/posts/obsidian-embeds-demo', + '/posts/mermaid-diagram-test': '/posts/obsidian-embeds-demo', + '/posts/mermaid-diagrams': '/posts/obsidian-embeds-demo', + '/posts/astro-suite-vault-modular-guide': '/posts/vault-cms-guide', + '/posts/astro-suite-obsidian-vault-guide-astro-modular': '/posts/vault-cms-guide', + '/posts/obsidian-vault-guide': '/posts/vault-cms-guide', + '/projects/obsidian-astro-composer': '/projects/astro-composer', + '/projects/obsidian-astro-suite': '/projects/vault-cms', + '/docs/api-reference': '/docs/api', + '/docs/astro-modular-configuration': '/docs/configuration', + '/docs/sourcetree-and-git': '/docs/sourcetree-and-git-setup' +} : {}, +image: { + service: { + entrypoint: 'astro/assets/services/sharp', + config: { + limitInputPixels: false, + } + }, + remotePatterns: [{ + protocol: 'https' + }] + }, + integrations: [ + refreshContentOnChange(), + tailwind(), + sitemap(), + mdx(), + swup({ + theme: false, + animationClass: 'transition-swup-', + containers: ['#swup-container'], + smoothScrolling: false, + cache: process.env.NODE_ENV === 'production', // off in dev so post edits show immediately + preload: true, + accessibility: false, + updateHead: true, + updateBodyClass: false, + globalInstance: true, + plugins: [], // Disable all plugins including scroll + skipPopStateHandling: (event) => { + // ALWAYS skip Swup handling for back/forward navigation + // Let the browser handle it naturally + return true; + }, + // Simplified link selector for better compatibility + linkSelector: 'a[href]:not([data-no-swup]):not([href^="mailto:"]):not([href^="tel:"])' + }) + ], + markdown: { + remarkPlugins: [ + remarkObsidianImageSize, // Parse Obsidian image size syntax first + remarkInternalLinks, + remarkInlineTags, + remarkObsidianComments, // Remove Obsidian comments (%%...%%) early in processing + remarkFolderImages, + remarkObsidianEmbeds, + // Bases directive (table-only v1) + remarkBases, + remarkImageCaptions, + remarkMath, + remarkCallouts, + remarkBreaks, + remarkImageGrids, + remarkMermaid, + [remarkReadingTime, {}], + [remarkToc, { + tight: true, + ordered: false, + maxDepth: 3, + heading: 'contents|table[ -]of[ -]contents?|toc' + }], + ], + rehypePlugins: [ + rehypeKatex, + rehypeMark, + rehypeImageAttributes, + [rehypeSlug, { + test: (node) => node.tagName !== 'h1' + }], + [rehypeAutolinkHeadings, { + behavior: 'wrap', + test: (node) => node.tagName !== 'h1', + properties: { + className: ['anchor-link'], + ariaLabel: 'Link to this section' + } + }], + rehypeNormalizeAnchors, // Run LAST to ensure className and href fixes aren't overridden + ], + shikiConfig: { + theme: 'github-dark', + wrap: true + } + }, + vite: { + assetsInclude: ['**/*.base', '**/*.home', '**/*.base'], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + '@/components': fileURLToPath(new URL('./src/components', import.meta.url)), + '@/layouts': fileURLToPath(new URL('./src/layouts', import.meta.url)), + '@/utils': fileURLToPath(new URL('./src/utils', import.meta.url)), + '@/types': fileURLToPath(new URL('./src/types.ts', import.meta.url)), + '@/config': fileURLToPath(new URL('./src/config.ts', import.meta.url)) + } + }, + server: { + host: 'localhost', + port: 5000, + strictPort: false, // Allow fallback to 5001 if 5000 is occupied (e.g., AirPlay on macOS) + allowedHosts: [], + middlewareMode: false, + hmr: true, + watch: { + ignored: ['**/.obsidian/**', '**/_bases/**', '**/bases/**'], + usePolling: process.platform === 'win32', + interval: 1000 + }, + headers: { + 'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0' + // CSP headers are handled by src/middleware.ts for all routes + } + }, + define: { + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), + 'process.env.ASTRO_CONTENT_COLLECTION_CACHE': 'false' + }, + optimizeDeps: { + exclude: ['astro:content'] + }, + exclude: ['**/_redirects'] + }, + build: { + assets: '_assets' + } +}); diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..45740ee --- /dev/null +++ b/netlify.toml @@ -0,0 +1,247 @@ +[build] + publish = "dist" + command = "pnpm run build" + +[build.environment] + NODE_VERSION = "22" + PNPM_VERSION = "8" + +# Enable compression for all text-based files +# Note: Netlify automatically handles gzip/brotli compression based on client support +[[headers]] + for = "/*.html" + [headers.values] + Cache-Control = "public, max-age=3600, s-maxage=86400" + +[[headers]] + for = "/*.css" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/*.js" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/*.json" + [headers.values] + Cache-Control = "public, max-age=3600" + +[[headers]] + for = "/*.xml" + [headers.values] + Cache-Control = "public, max-age=3600" + +[[headers]] + for = "/*.txt" + [headers.values] + Cache-Control = "public, max-age=3600" + +# Handle pre-compressed files +[[headers]] + for = "/*.gz" + [headers.values] + Content-Encoding = "gzip" + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/*.br" + [headers.values] + Content-Encoding = "br" + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "/*" + [headers.values] + X-Frame-Options = "DENY" + X-XSS-Protection = "1; mode=block" + X-Content-Type-Options = "nosniff" + Referrer-Policy = "strict-origin-when-cross-origin" + Permissions-Policy = "camera=(), microphone=(), geolocation=()" + Cross-Origin-Embedder-Policy = "unsafe-none" + Cross-Origin-Opener-Policy = "same-origin" + Content-Security-Policy = "default-src 'self'; script-src 'self' 'unsafe-inline' https://unpkg.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://giscus.app https://platform.twitter.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; img-src 'self' data: https:; connect-src 'self' https://giscus.app; frame-src 'self' https://www.youtube.com https://giscus.app https://platform.twitter.com; object-src 'none'; base-uri 'self';" + +# Static assets with long-term caching +[[headers]] + for = "/_assets/*" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.webp" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.woff2" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.woff" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.ttf" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.eot" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +# Images with long-term caching +[[headers]] + for = "*.jpg" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.jpeg" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.png" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.gif" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.svg" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[[headers]] + for = "*.ico" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +# PDF files - allow iframe embedding +[[headers]] + for = "*.pdf" + [headers.values] + Cache-Control = "public, max-age=3600" + X-Frame-Options = "SAMEORIGIN" + +# Favicon files +[[headers]] + for = "/favicon*" + [headers.values] + Cache-Control = "public, max-age=31536000, immutable" + +[dev] + command = "pnpm run dev" + port = 5000 + publish = "dist" + +# Generated redirects from content aliases + +[[redirects]] + from = "/about-me" + to = "/about" + status = 301 + force = true + +[[redirects]] + from = "/about-us" + to = "/about" + status = 301 + force = true + +[[redirects]] + from = "/contact-me" + to = "/contact" + status = 301 + force = true + +[[redirects]] + from = "/contact-us" + to = "/contact" + status = 301 + force = true + +[[redirects]] + from = "/privacy" + to = "/privacy-policy" + status = 301 + force = true + +[[redirects]] + from = "/posts/mermaid-test" + to = "/posts/obsidian-embeds-demo" + status = 301 + force = true + +[[redirects]] + from = "/posts/mermaid-diagram-test" + to = "/posts/obsidian-embeds-demo" + status = 301 + force = true + +[[redirects]] + from = "/posts/mermaid-diagrams" + to = "/posts/obsidian-embeds-demo" + status = 301 + force = true + +[[redirects]] + from = "/posts/astro-suite-vault-modular-guide" + to = "/posts/vault-cms-guide" + status = 301 + force = true + +[[redirects]] + from = "/posts/astro-suite-obsidian-vault-guide-astro-modular" + to = "/posts/vault-cms-guide" + status = 301 + force = true + +[[redirects]] + from = "/posts/obsidian-vault-guide" + to = "/posts/vault-cms-guide" + status = 301 + force = true + +[[redirects]] + from = "/projects/obsidian-astro-composer" + to = "/projects/astro-composer" + status = 301 + force = true + +[[redirects]] + from = "/projects/obsidian-astro-suite" + to = "/projects/vault-cms" + status = 301 + force = true + +[[redirects]] + from = "/docs/api-reference" + to = "/docs/api" + status = 301 + force = true + +[[redirects]] + from = "/docs/astro-modular-configuration" + to = "/docs/configuration" + status = 301 + force = true + +[[redirects]] + from = "/docs/sourcetree-and-git" + to = "/docs/sourcetree-and-git-setup" + status = 301 + force = true + +[[redirects]] + from = "/*" + to = "/404" + status = 404 \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..5bfd3d8 --- /dev/null +++ b/package.json @@ -0,0 +1,71 @@ +{ + "name": "astro-modular", + "version": "0.8.6", + "type": "module", + "description": "A flexible blog theme designed for Obsidian users.", + "main": "index.js", + "scripts": { + "dev": "cross-env ASTRO_CONTENT_COLLECTION_CACHE=false node scripts/setup-dev.mjs && node scripts/sync-images.js && node scripts/process-aliases.js && node scripts/generate-deployment-config.js && node scripts/generate-graph-data.js && node scripts/dev-with-port.js", + "build": "node scripts/sync-images.js && node scripts/process-aliases.js && node scripts/generate-deployment-config.js && node scripts/generate-graph-data.js --production && astro build", + "preview": "pnpm run build && node scripts/dev-with-port.js preview", + "sync-images": "node scripts/sync-images.js", + "process-aliases": "node scripts/process-aliases.js", + "generate-deployment-config": "node scripts/generate-deployment-config.js", + "generate-deployment-config:dry-run": "node scripts/generate-deployment-config.js --dry-run", + "generate-deployment-config:validate": "node scripts/generate-deployment-config.js --validate", + "generate-graph-data": "node scripts/generate-graph-data.js", + "check-images": "node scripts/check-missing-images.js", + "update": "node scripts/update.mjs", + "version": "node scripts/get-version.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "astro", + "blog", + "theme", + "obsidian" + ], + "author": "David V. Kimball", + "license": "MIT", + "dependencies": { + "@astrojs/check": "0.9.8", + "@astrojs/mdx": "5.0.2", + "@astrojs/rss": "4.0.17", + "@astrojs/sitemap": "3.7.1", + "@astrojs/tailwind": "^6.0.2", + "@fontsource/inter": "^5.2.8", + "@fontsource/jetbrains-mono": "^5.2.8", + "@fortawesome/fontawesome-svg-core": "^7.2.0", + "@fortawesome/free-brands-svg-icons": "^7.2.0", + "@swup/astro": "^1.8.0", + "@tailwindcss/typography": "^0.5.19", + "@types/d3": "^7.4.3", + "astro": "6.0.8", + "astro-redirect-from": "^1.3.5", + "d3": "^7.9.0", + "fuse.js": "^7.1.0", + "katex": "^0.16.38", + "lucide": "^0.542.0", + "mermaid": "^11.13.0", + "rehype-autolink-headings": "^7.1.0", + "rehype-katex": "^7.0.1", + "rehype-slug": "^6.0.0", + "remark-breaks": "^4.0.0", + "remark-math": "^6.0.0", + "remark-reading-time": "^2.1.0", + "remark-toc": "^9.0.0", + "sharp": "^0.34.5", + "swup": "^4.8.3", + "tailwindcss": "^3.4.19", + "typescript": "^5.9.3", + "unified": "^11.0.5", + "unist-util-visit": "^5.1.0" + }, + "devDependencies": { + "@types/hast": "^3.0.4", + "@types/unist": "^3.0.3", + "cross-env": "^10.1.0", + "vite": "^7.3.1", + "wrangler": "^4.71.0" + } +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..3822695 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,10997 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@astrojs/check': + specifier: 0.9.8 + version: 0.9.8(prettier@3.8.1)(typescript@5.9.3) + '@astrojs/mdx': + specifier: 5.0.2 + version: 5.0.2(astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) + '@astrojs/rss': + specifier: 4.0.17 + version: 4.0.17 + '@astrojs/sitemap': + specifier: 3.7.1 + version: 3.7.1 + '@astrojs/tailwind': + specifier: ^6.0.2 + version: 6.0.2(astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))(tailwindcss@3.4.19(yaml@2.8.2)) + '@fontsource/inter': + specifier: ^5.2.8 + version: 5.2.8 + '@fontsource/jetbrains-mono': + specifier: ^5.2.8 + version: 5.2.8 + '@fortawesome/fontawesome-svg-core': + specifier: ^7.2.0 + version: 7.2.0 + '@fortawesome/free-brands-svg-icons': + specifier: ^7.2.0 + version: 7.2.0 + '@swup/astro': + specifier: ^1.8.0 + version: 1.8.0 + '@tailwindcss/typography': + specifier: ^0.5.19 + version: 0.5.19(tailwindcss@3.4.19(yaml@2.8.2)) + '@types/d3': + specifier: ^7.4.3 + version: 7.4.3 + astro: + specifier: 6.0.8 + version: 6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + astro-redirect-from: + specifier: ^1.3.5 + version: 1.3.5(astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) + d3: + specifier: ^7.9.0 + version: 7.9.0 + fuse.js: + specifier: ^7.1.0 + version: 7.1.0 + katex: + specifier: ^0.16.38 + version: 0.16.38 + lucide: + specifier: ^0.542.0 + version: 0.542.0 + mermaid: + specifier: ^11.13.0 + version: 11.13.0 + rehype-autolink-headings: + specifier: ^7.1.0 + version: 7.1.0 + rehype-katex: + specifier: ^7.0.1 + version: 7.0.1 + rehype-slug: + specifier: ^6.0.0 + version: 6.0.0 + remark-breaks: + specifier: ^4.0.0 + version: 4.0.0 + remark-math: + specifier: ^6.0.0 + version: 6.0.0 + remark-reading-time: + specifier: ^2.1.0 + version: 2.1.0 + remark-toc: + specifier: ^9.0.0 + version: 9.0.0 + sharp: + specifier: ^0.34.5 + version: 0.34.5 + swup: + specifier: ^4.8.3 + version: 4.8.3 + tailwindcss: + specifier: ^3.4.19 + version: 3.4.19(yaml@2.8.2) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + unified: + specifier: ^11.0.5 + version: 11.0.5 + unist-util-visit: + specifier: ^5.1.0 + version: 5.1.0 + devDependencies: + '@types/hast': + specifier: ^3.0.4 + version: 3.0.4 + '@types/unist': + specifier: ^3.0.3 + version: 3.0.3 + cross-env: + specifier: ^10.1.0 + version: 10.1.0 + vite: + specifier: ^7.3.1 + version: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.46.0)(yaml@2.8.2) + wrangler: + specifier: ^4.71.0 + version: 4.71.0 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@antfu/install-pkg@1.1.0': + resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} + + '@astrojs/check@0.9.8': + resolution: {integrity: sha512-LDng8446QLS5ToKjRHd3bgUdirvemVVExV7nRyJfW2wV36xuv7vDxwy5NWN9zqeSEDgg0Tv84sP+T3yEq+Zlkw==} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + + '@astrojs/compiler@2.13.1': + resolution: {integrity: sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg==} + + '@astrojs/compiler@3.0.0': + resolution: {integrity: sha512-MwAbDE5mawZ1SS+D8qWiHdprdME5Tlj2e0YjxnEICvcOpbSukNS7Sa7hA5PK+6RrmUr/t6Gi5YgrdZKjbO/WPQ==} + + '@astrojs/internal-helpers@0.8.0': + resolution: {integrity: sha512-J56GrhEiV+4dmrGLPNOl2pZjpHXAndWVyiVDYGDuw6MWKpBSEMLdFxHzeM/6sqaknw9M+HFfHZAcvi3OfT3D/w==} + + '@astrojs/language-server@2.16.6': + resolution: {integrity: sha512-N990lu+HSFiG57owR0XBkr02BYMgiLCshLf+4QG4v6jjSWkBeQGnzqi+E1L08xFPPJ7eEeXnxPXGLaVv5pa4Ug==} + hasBin: true + peerDependencies: + prettier: ^3.0.0 + prettier-plugin-astro: '>=0.11.0' + peerDependenciesMeta: + prettier: + optional: true + prettier-plugin-astro: + optional: true + + '@astrojs/markdown-remark@7.0.1': + resolution: {integrity: sha512-zAfLJmn07u9SlDNNHTpjv0RT4F8D4k54NR7ReRas8CO4OeGoqSvOuKwqCFg2/cqN3wHwdWlK/7Yv/lMXlhVIaw==} + + '@astrojs/mdx@5.0.2': + resolution: {integrity: sha512-0as6odPH9ZQhS3pdH9dWmVOwgXuDtytJiE4VvYgR0lSFBvF4PSTyE0HdODHm/d7dBghvWTPc2bQaBm4y4nTBNw==} + engines: {node: '>=22.12.0'} + peerDependencies: + astro: ^6.0.0 + + '@astrojs/prism@4.0.1': + resolution: {integrity: sha512-nksZQVjlferuWzhPsBpQ1JE5XuKAf1id1/9Hj4a9KG4+ofrlzxUUwX4YGQF/SuDiuiGKEnzopGOt38F3AnVWsQ==} + engines: {node: '>=22.12.0'} + + '@astrojs/rss@4.0.17': + resolution: {integrity: sha512-eV+wdMbeVKC9+sPaV0LN8JL1LGo9YAh3GKl4Ou4nzMNLmXM/aswYpSGxVEAuHilgBZ6/++/Pv08ICmuOqX107w==} + + '@astrojs/sitemap@3.7.1': + resolution: {integrity: sha512-IzQqdTeskaMX+QDZCzMuJIp8A8C1vgzMBp/NmHNnadepHYNHcxQdGLQZYfkbd2EbRXUfOS+UDIKx8sKg0oWVdw==} + + '@astrojs/tailwind@6.0.2': + resolution: {integrity: sha512-j3mhLNeugZq6A8dMNXVarUa8K6X9AW+QHU9u3lKNrPLMHhOQ0S7VeWhHwEeJFpEK1BTKEUY1U78VQv2gN6hNGg==} + peerDependencies: + astro: ^3.0.0 || ^4.0.0 || ^5.0.0 + tailwindcss: ^3.0.24 + + '@astrojs/telemetry@3.3.0': + resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} + engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + + '@astrojs/yaml2ts@0.2.3': + resolution: {integrity: sha512-PJzRmgQzUxI2uwpdX2lXSHtP4G8ocp24/t+bZyf5Fy0SZLSF9f9KXZoMlFM/XCGue+B0nH/2IZ7FpBYQATBsCg==} + + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-define-polyfill-provider@0.6.7': + resolution: {integrity: sha512-6Fqi8MtQ/PweQ9xvux65emkLQ83uB+qAVtfHkC9UodyHMIZdxNI01HjLCLUtybElp2KY2XNE0nOgyP1E1vXw9w==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + + '@babel/helper-remap-async-to-generator@7.27.1': + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.6': + resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.0': + resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.13.0 + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-proposal-class-properties@7.12.1': + resolution: {integrity: sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==} + deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': + resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-flow@7.28.6': + resolution: {integrity: sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': + resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoped-functions@7.27.1': + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.12.0 + + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-keys@7.27.1': + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.27.1': + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-export-namespace-from@7.27.1': + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-flow-strip-types@7.27.1': + resolution: {integrity: sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-for-of@7.27.1': + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-function-name@7.27.1': + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-literals@7.27.1': + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-member-expression-literals@7.27.1': + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-amd@7.27.1': + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.27.1': + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-new-target@7.27.1': + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-object-super@7.27.1': + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-parameters@7.27.7': + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-property-literals@7.27.1': + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-display-name@7.28.0': + resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-development@7.27.1': + resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-pure-annotations@7.27.1': + resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-reserved-words@7.27.1': + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-shorthand-properties@7.27.1': + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-sticky-regex@7.27.1': + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typeof-symbol@7.27.1': + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-escapes@7.27.1': + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-regex@7.27.1': + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/preset-env@7.29.0': + resolution: {integrity: sha512-fNEdfc0yi16lt6IZo2Qxk3knHVdfMYX33czNb4v8yWhemoBhibCpQK/uYHtSKIiO+p/zd3+8fYVXhQdOVV608w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-flow@7.27.1': + resolution: {integrity: sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-modules@0.1.6-no-external-plugins': + resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} + peerDependencies: + '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + + '@babel/preset-react@7.28.5': + resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + + '@capsizecss/unpack@4.0.0': + resolution: {integrity: sha512-VERIM64vtTP1C4mxQ5thVT9fK0apjPFobqybMtA1UdUujWka24ERHbRHFGmpbbhp73MhV+KSsHQH9C6uOTdEQA==} + engines: {node: '>=18'} + + '@chevrotain/cst-dts-gen@11.1.2': + resolution: {integrity: sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==} + + '@chevrotain/gast@11.1.2': + resolution: {integrity: sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==} + + '@chevrotain/regexp-to-ast@11.1.2': + resolution: {integrity: sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==} + + '@chevrotain/types@11.1.2': + resolution: {integrity: sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==} + + '@chevrotain/utils@11.1.2': + resolution: {integrity: sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==} + + '@clack/core@1.1.0': + resolution: {integrity: sha512-SVcm4Dqm2ukn64/8Gub2wnlA5nS2iWJyCkdNHcvNHPIeBTGojpdJ+9cZKwLfmqy7irD4N5qLteSilJlE0WLAtA==} + + '@clack/prompts@1.1.0': + resolution: {integrity: sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g==} + + '@cloudflare/kv-asset-handler@0.4.2': + resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} + engines: {node: '>=18.0.0'} + + '@cloudflare/unenv-preset@2.15.0': + resolution: {integrity: sha512-EGYmJaGZKWl+X8tXxcnx4v2bOZSjQeNI5dWFeXivgX9+YCT69AkzHHwlNbVpqtEUTbew8eQurpyOpeN8fg00nw==} + peerDependencies: + unenv: 2.0.0-rc.24 + workerd: 1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0 + peerDependenciesMeta: + workerd: + optional: true + + '@cloudflare/workerd-darwin-64@1.20260301.1': + resolution: {integrity: sha512-+kJvwociLrvy1JV9BAvoSVsMEIYD982CpFmo/yMEvBwxDIjltYsLTE8DLi0mCkGsQ8Ygidv2fD9wavzXeiY7OQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + + '@cloudflare/workerd-darwin-arm64@1.20260301.1': + resolution: {integrity: sha512-PPIetY3e67YBr9O4UhILK8nbm5TqUDl14qx4rwFNrRSBOvlzuczzbd4BqgpAtbGVFxKp1PWpjAnBvGU/OI/tLQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + + '@cloudflare/workerd-linux-64@1.20260301.1': + resolution: {integrity: sha512-Gu5vaVTZuYl3cHa+u5CDzSVDBvSkfNyuAHi6Mdfut7TTUdcb3V5CIcR/mXRSyMXzEy9YxEWIfdKMxOMBjupvYQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + + '@cloudflare/workerd-linux-arm64@1.20260301.1': + resolution: {integrity: sha512-igL1pkyCXW6GiGpjdOAvqMi87UW0LMc/+yIQe/CSzuZJm5GzXoAMrwVTkCFnikk6JVGELrM5x0tGYlxa0sk5Iw==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + + '@cloudflare/workerd-windows-64@1.20260301.1': + resolution: {integrity: sha512-Q0wMJ4kcujXILwQKQFc1jaYamVsNvjuECzvRrTI8OxGFMx2yq9aOsswViE4X1gaS2YQQ5u0JGwuGi5WdT1Lt7A==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@emmetio/abbreviation@2.3.3': + resolution: {integrity: sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA==} + + '@emmetio/css-abbreviation@2.1.8': + resolution: {integrity: sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw==} + + '@emmetio/css-parser@0.4.1': + resolution: {integrity: sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ==} + + '@emmetio/html-matcher@1.3.0': + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + + '@emmetio/scanner@1.0.4': + resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} + + '@emmetio/stream-reader-utils@0.1.0': + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + + '@emmetio/stream-reader@2.2.0': + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} + + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@fontsource/inter@5.2.8': + resolution: {integrity: sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==} + + '@fontsource/jetbrains-mono@5.2.8': + resolution: {integrity: sha512-6w8/SG4kqvIMu7xd7wt6x3idn1Qux3p9N62s6G3rfldOUYHpWcc2FKrqf+Vo44jRvqWj2oAtTHrZXEP23oSKwQ==} + + '@fortawesome/fontawesome-common-types@7.2.0': + resolution: {integrity: sha512-IpR0bER9FY25p+e7BmFH25MZKEwFHTfRAfhOyJubgiDnoJNsSvJ7nigLraHtp4VOG/cy8D7uiV0dLkHOne5Fhw==} + engines: {node: '>=6'} + + '@fortawesome/fontawesome-svg-core@7.2.0': + resolution: {integrity: sha512-6639htZMjEkwskf3J+e6/iar+4cTNM9qhoWuRfj9F3eJD6r7iCzV1SWnQr2Mdv0QT0suuqU8BoJCZUyCtP9R4Q==} + engines: {node: '>=6'} + + '@fortawesome/free-brands-svg-icons@7.2.0': + resolution: {integrity: sha512-VNG8xqOip1JuJcC3zsVsKRQ60oXG9+oYNDCosjoU/H9pgYmLTEwWw8pE0jhPz/JWdHeUuK6+NQ3qsM4gIbdbYQ==} + engines: {node: '>=6'} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@iconify/utils@3.1.0': + resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@mdx-js/mdx@3.1.1': + resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} + + '@mermaid-js/parser@1.0.1': + resolution: {integrity: sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ==} + + '@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'} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} + + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@rollup/plugin-alias@3.1.9': + resolution: {integrity: sha512-QI5fsEvm9bDzt32k39wpOwZhVzRcL5ydcffUHMyLVaVaLeC70I8TJZ17F1z1eMoLu4E/UOcH9BWVkKpIKdrfiw==} + engines: {node: '>=8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/plugin-babel@5.3.1': + resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} + engines: {node: '>= 10.0.0'} + peerDependencies: + '@babel/core': ^7.0.0 + '@types/babel__core': ^7.1.9 + rollup: ^1.20.0||^2.0.0 + peerDependenciesMeta: + '@types/babel__core': + optional: true + + '@rollup/plugin-commonjs@17.1.0': + resolution: {integrity: sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^2.30.0 + + '@rollup/plugin-json@4.1.0': + resolution: {integrity: sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==} + peerDependencies: + rollup: ^1.20.0 || ^2.0.0 + + '@rollup/plugin-node-resolve@11.2.1': + resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==} + engines: {node: '>= 10.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/pluginutils@3.1.0': + resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} + engines: {node: '>= 8.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0 + + '@rollup/pluginutils@4.2.1': + resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} + engines: {node: '>= 8.0.0'} + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.59.0': + resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.59.0': + resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.59.0': + resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.59.0': + resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.59.0': + resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.59.0': + resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.59.0': + resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.59.0': + resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.59.0': + resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.59.0': + resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.59.0': + resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.59.0': + resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.59.0': + resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.59.0': + resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.59.0': + resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} + cpu: [x64] + os: [win32] + + '@shikijs/core@4.0.2': + resolution: {integrity: sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@4.0.2': + resolution: {integrity: sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@4.0.2': + resolution: {integrity: sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==} + engines: {node: '>=20'} + + '@shikijs/langs@4.0.2': + resolution: {integrity: sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.0.2': + resolution: {integrity: sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==} + engines: {node: '>=20'} + + '@shikijs/themes@4.0.2': + resolution: {integrity: sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==} + engines: {node: '>=20'} + + '@shikijs/types@4.0.2': + resolution: {integrity: sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} + engines: {node: '>=18'} + + '@sindresorhus/merge-streams@4.0.0': + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + + '@speed-highlight/core@1.2.14': + resolution: {integrity: sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==} + + '@surma/rollup-plugin-off-main-thread@2.2.3': + resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} + + '@swup/a11y-plugin@5.0.0': + resolution: {integrity: sha512-t0pVWAVea+Imjj05n9QMPfqZhw9i5rx7BV/l3Ejeic+X3Qs0VZwVvEJIcdqireCVJgAJGZAPlmgbiuaj5UHJaQ==} + peerDependencies: + swup: ^4.0.0 + + '@swup/astro@1.8.0': + resolution: {integrity: sha512-FI8/jNXgyUoWpnOgdB3MOUobRtRzedKBE8+qbBH5c8CE4q9Ni/GHPGrXK/0xG+g1ZiIQuTF3OXRvTLNVouiBig==} + + '@swup/body-class-plugin@3.3.0': + resolution: {integrity: sha512-4h/6mAgDd0+ml8Gc2kX8tikIR0HZZLF+WTnfm0JTVrGDw74bgEBenbsaWFfIS+gn4RWKZdWBUOfaZ+Im5J7Gvw==} + peerDependencies: + swup: ^4.6.0 + + '@swup/browserslist-config@1.0.1': + resolution: {integrity: sha512-/3nBqG7LqmK1uqaCSTA6s2NwQBDQXNyLAFBzlX6uaxqjIQcAZyq6K+sgcQ40oj02Vn/2mLSkeL9DOfP7BPOwVA==} + + '@swup/debug-plugin@4.1.0': + resolution: {integrity: sha512-R+RP4hjoeXrO+wowSswaTM4P05lu6iDg6UwdbQn0wfJ082KiUpH+DDwHYNOatxusKVExFuhLec+X9IbyAyiv8w==} + peerDependencies: + swup: ^4.0.0 + + '@swup/fade-theme@2.0.2': + resolution: {integrity: sha512-x2XLIzAk8akrmVkozrlv0cU8wWnzt8MC164F1801qdffzY7mOi1v2mHl5Db9pqrP3BZ4UqC+5683/hQJ4obYEA==} + peerDependencies: + swup: ^4.0.0 + + '@swup/forms-plugin@3.6.0': + resolution: {integrity: sha512-pRN6OR5wR27LvJqQOlCgu1fP9Z0ZsGauxWOE6nRCtjP1+98wlGTMiMsQ+jGvvs+IOK9IDTJQ7jvprnJAZaw9zw==} + peerDependencies: + swup: ^4.6.0 + + '@swup/fragment-plugin@1.3.0': + resolution: {integrity: sha512-wz1aaLrvdWfucjO5fs7DgtptYKj3DpfIUNsEyzlt46iOxy9bV74VGDcBOEmnR8blmKBytNBRqDNPT0fhcVCr9w==} + peerDependencies: + swup: ^4.6.0 + + '@swup/head-plugin@2.3.1': + resolution: {integrity: sha512-kdv60fO9c0/3+K40f7Fj/uV34nSuuPeCsld83J5uVVFizOmoovA737C5M1Iqac5Spf2GLU7q+mhN6AbohSIBjA==} + peerDependencies: + swup: ^4.6.0 + + '@swup/overlay-theme@2.0.2': + resolution: {integrity: sha512-nfk5jrEru0lbFzlOzkT/f77sUwVHM/iUzlPMAT/KkWecn4/YuT4Y+lgIY3Se9VtD8TbSFrXYoHJea4GMZPJRAg==} + peerDependencies: + swup: ^4.0.0 + + '@swup/parallel-plugin@0.4.0': + resolution: {integrity: sha512-un37RpdFz2vuJV1r9Hr0nCl5qgloN/Z3SczC3wi1XfkiHtzZ8kFTcm5pIW5rUkDVwtCTil44mlAA/STouBEgDw==} + peerDependencies: + swup: ^4.6.0 + + '@swup/plugin@3.0.1': + resolution: {integrity: sha512-A9yiJeKTmQ9kac2Eo3MbMWW+Tiw23W5OSzAHVTCfW6n5zze6dexY3FLEUSDTcvRgciknvXfMZ9JTnebbvCKKWw==} + hasBin: true + + '@swup/plugin@4.0.0': + resolution: {integrity: sha512-3Kq31BJxnzoPg643YxGoWQggoU6VPKZpdE5CqqmP7wwkpCYTzkRmrfcQ29mGhsSS7xfS7D33iZoBiwY+wPoo2A==} + + '@swup/preload-plugin@3.2.11': + resolution: {integrity: sha512-dq50u+d8L+63/pU6dUDnypuBoF49ubjRzRJqitGem2K7wRn7xccxRSvdyeGKdA2vNvzGDAmLfwVTZdSotvvDrw==} + peerDependencies: + swup: ^4.0.0 + + '@swup/prettier-config@1.1.0': + resolution: {integrity: sha512-EF4DMdIGieEsuY2XK0PuLf7Uw7yUQOMbA6IdCMvvRvKXj03WLLpnNIFfFp+6hmMtXRSUE88VBpRyp6Giiu1Pbg==} + + '@swup/progress-plugin@3.2.0': + resolution: {integrity: sha512-Ur+D4+aee9swR6pn7JbEyGMwVP1BTcN5ygjlno7IaSQ/vMZbuJ73po1RkKlIi86p+/PZ+1kynkH4K4eMZuHKKg==} + peerDependencies: + swup: ^4.0.0 + + '@swup/route-name-plugin@4.1.0': + resolution: {integrity: sha512-1tw3WeExEKwI3pVMXTptCGxFUDOSEpc63D741eeUCjjGW/f9q7ekuqEaPQd5YJ6POpzDjdt1jjuC9yv54CbeXA==} + peerDependencies: + swup: ^4.0.0 + + '@swup/scripts-plugin@2.1.0': + resolution: {integrity: sha512-JSMFsFCN9gn4q3m1Ccv0gq3gwRoZl6UGALOQO3OeQ8wOIq9vPC5dcUD3CMBuaPanksjR4GC8ZoukIjHrlT52fg==} + peerDependencies: + swup: ^4.2.0 + + '@swup/scroll-plugin@3.3.2': + resolution: {integrity: sha512-jwngTz8LZza8p7ZWqaqQIzkH8x4hwyPh8RbrJSwTKussx24YUQuV9sgjDCzvJ16k/aYk9NCCvqLbb+4TcT3jqA==} + peerDependencies: + swup: ^4.2.0 + + '@swup/slide-theme@2.0.2': + resolution: {integrity: sha512-CLFD+Nd/wIDLMOfg7D7sOX2d1AyhZsoLXT+G6xB4ARELaP1j+nQGDjyuRvgAESMW+GA1EL43y/BcXOAKTjzrsg==} + peerDependencies: + swup: ^4.0.0 + + '@swup/theme@2.1.0': + resolution: {integrity: sha512-nwAzx+GYySIYs6uSCFYGNdpLWv2z/mEryRD1gvmIqsaSP2N7sVd4mKAboraJAzIzbasRhTsTQzyN1LfLeti3AA==} + peerDependencies: + swup: ^4.0.0 + + '@tailwindcss/typography@0.5.19': + resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + + '@types/d3-array@3.2.2': + resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} + + '@types/d3-axis@3.0.6': + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + + '@types/d3-brush@3.0.6': + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + + '@types/d3-chord@3.0.6': + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-contour@3.0.6': + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + + '@types/d3-delaunay@6.0.4': + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + + '@types/d3-dispatch@3.0.7': + resolution: {integrity: sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-dsv@3.0.7': + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + + '@types/d3-ease@3.0.2': + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + + '@types/d3-fetch@3.0.7': + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + + '@types/d3-force@3.0.10': + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + + '@types/d3-format@3.0.4': + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + + '@types/d3-geo@3.1.0': + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + + '@types/d3-hierarchy@3.1.7': + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-path@3.1.1': + resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==} + + '@types/d3-polygon@3.0.2': + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + + '@types/d3-quadtree@3.0.6': + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + + '@types/d3-random@3.0.3': + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + + '@types/d3-scale-chromatic@3.1.0': + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + + '@types/d3-scale@4.0.9': + resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} + + '@types/d3-time-format@4.0.3': + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + + '@types/d3-time@3.0.4': + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + + '@types/d3-timer@3.0.2': + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/d3@7.4.3': + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@0.0.39': + resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/geojson@7946.0.16': + resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdx@2.0.13': + resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/nlcst@2.0.3': + resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + + '@types/node@24.12.0': + resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==} + + '@types/node@25.4.0': + resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/resolve@1.17.1': + resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} + + '@types/sax@1.2.7': + resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==} + + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + + '@types/ungap__structured-clone@1.2.0': + resolution: {integrity: sha512-ZoaihZNLeZSxESbk9PUAPZOlSpcKx81I1+4emtULDVmBLkYutTcMlCj2K9VNlf9EWODxdO6gkAqEaLorXwZQVA==} + + '@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.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + + '@volar/kit@2.4.28': + resolution: {integrity: sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg==} + peerDependencies: + typescript: '*' + + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/language-server@2.4.28': + resolution: {integrity: sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw==} + + '@volar/language-service@2.4.28': + resolution: {integrity: sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + + '@vscode/emmet-helper@2.11.0': + resolution: {integrity: sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw==} + + '@vscode/l10n@0.0.18': + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@2.2.1: + resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} + engines: {node: '>=0.10.0'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + 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==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + astring@1.9.0: + resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} + hasBin: true + + astro-redirect-from@1.3.5: + resolution: {integrity: sha512-4TYtOKT/X2H3IzzgwZc9YKN8MUoOjqNHgXd7qt5jbf5LiCi9a1sOg6LhIYSDl242PPTou4CdaKS5XDc7u5EAkg==} + engines: {astro: '>=3.0.0', node: '>=22.0.0'} + peerDependencies: + astro: '>=3.0.0' + + astro@6.0.8: + resolution: {integrity: sha512-DCPeb8GKOoFWh+8whB7Qi/kKWD/6NcQ9nd1QVNzJFxgHkea3WYrNroQRq4whmBdjhkYPTLS/1gmUAl2iA2Es2g==} + engines: {node: '>=22.12.0', npm: '>=9.6.5', pnpm: '>=7.1.0'} + hasBin: true + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asyncro@3.0.0: + resolution: {integrity: sha512-nEnWYfrBmA3taTiuiOoZYmgJ/CNrSoQLeLs29SeLcPu60yaw/mHDBHV0iOZ051fTvsTHxpCY+gXibqT9wbQYfg==} + + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + babel-plugin-polyfill-corejs2@0.4.16: + resolution: {integrity: sha512-xaVwwSfebXf0ooE11BJovZYKhFjIvQo7TsyVpETuIeH2JHv0k/T6Y5j22pPTvqYqmpkxdlPAJlyJ0tfOJAoMxw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.14.1: + resolution: {integrity: sha512-ENp89vM9Pw4kv/koBb5N2f9bDZsR0hpf3BdPMOg/pkS3pwO4dzNnQZVXtBbeyAadgm865DmQG2jMMLqmZXvuCw==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.7: + resolution: {integrity: sha512-OTYbUlSwXhNgr4g6efMZgsO8//jA61P7ZbRX3iTT53VON8l+WQS8IAUEVo4a4cWknrg2W8Cj4gQhRYNCJ8GkAA==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-transform-async-to-promises@0.8.18: + resolution: {integrity: sha512-WpOrF76nUHijnNn10eBGOHZmXQC8JYRME9rOLxStOga7Av2VO53ehVFvVNImMksVtQuL2/7ZNxEgxnx7oo/3Hw==} + + babel-plugin-transform-replace-expressions@0.2.0: + resolution: {integrity: sha512-Eh1rRd9hWEYgkgoA3D0kGp7xJ/wgVshgsqmq60iC4HVWD+Lux+fNHSHBa2v1Hsv+dHflShC71qKhiH40OiPtDA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + baseline-browser-mapping@2.10.0: + resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} + engines: {node: '>=6.0.0'} + hasBin: true + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brotli-size@4.0.0: + resolution: {integrity: sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==} + engines: {node: '>= 10.16.0'} + + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001777: + resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@1.1.3: + resolution: {integrity: sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==} + engines: {node: '>=0.10.0'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + 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==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + chevrotain-allstar@0.3.1: + resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + peerDependencies: + chevrotain: ^11.0.0 + + chevrotain@11.1.2: + resolution: {integrity: sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + collapse-white-space@2.1.0: + resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} + + 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==} + + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + common-ancestor-path@2.0.0: + resolution: {integrity: sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==} + engines: {node: '>= 18'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-with-sourcemaps@1.1.0: + resolution: {integrity: sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + core-js-compat@3.48.0: + resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} + + cose-base@1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + + cose-base@2.2.0: + resolution: {integrity: sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + cross-env@10.1.0: + resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} + engines: {node: '>=20'} + hasBin: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + + css-declaration-sorter@6.4.1: + resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==} + engines: {node: ^10 || ^12 || >=14} + peerDependencies: + postcss: ^8.0.9 + + css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + + css-tree@2.2.1: + resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-preset-default@5.2.14: + resolution: {integrity: sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + cssnano-utils@3.1.0: + resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + cssnano@5.1.15: + resolution: {integrity: sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + csso@4.2.0: + resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} + engines: {node: '>=8.0.0'} + + csso@5.0.5: + resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + + cytoscape-cose-bilkent@4.1.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape-fcose@2.2.0: + resolution: {integrity: sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==} + peerDependencies: + cytoscape: ^3.2.0 + + cytoscape@3.33.1: + resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + engines: {node: '>=0.10'} + + d3-array@2.12.1: + resolution: {integrity: sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==} + + d3-array@3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + + d3-axis@3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + + d3-brush@3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + + d3-chord@3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-contour@4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + + d3-delaunay@6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-dsv@3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-fetch@3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + + d3-force@3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} + engines: {node: '>=12'} + + d3-geo@3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + + d3-hierarchy@3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-path@1.0.9: + resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} + + d3-path@3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + + d3-polygon@3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + + d3-quadtree@3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + + d3-random@3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + + d3-sankey@0.12.3: + resolution: {integrity: sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==} + + d3-scale-chromatic@3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + + d3-scale@4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-shape@1.3.7: + resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} + + d3-shape@3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + + d3-time-format@4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + + d3-time@3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + d3@7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + dayjs@1.11.19: + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + delaunator@5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + + delegate-it@6.3.0: + resolution: {integrity: sha512-WAa6cA61M5mfDR31PBgMNQQ3LY1q++TxnZzcm7E9XV8ODBPxDutxH0toTR/BXqIkLaVuU7ntFe1uOqDllhA22A==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devalue@5.6.3: + resolution: {integrity: sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} + + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + dompurify@3.3.2: + resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==} + engines: {node: '>=20'} + + domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer@0.1.1: + resolution: {integrity: sha512-sxNZ+ljy+RA1maXoUReeqBBpBC6RLKmg5ewzV+x+mSETmWNoKdZN6vcQjpFROemza23hGFskJtFNoUWUaQ+R4Q==} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.307: + resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} + + emmet@2.4.11: + resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + error-stack-parser-es@1.0.5: + resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} + + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esast-util-from-estree@2.0.0: + resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} + + esast-util-from-js@2.0.1: + resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} + + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estree-util-attach-comments@3.0.0: + resolution: {integrity: sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==} + + estree-util-build-jsx@3.0.1: + resolution: {integrity: sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-util-scope@1.0.0: + resolution: {integrity: sha512-2CAASclonf+JFWBNJPndcOpA8EMJwa0Q8LUFJEKqXLW6+qBvbFZuF5gItbQOs/umBUkjviCSDCbBwU2cXbmrhQ==} + + estree-util-to-js@2.0.0: + resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} + + estree-util-value-to-estree@3.5.0: + resolution: {integrity: sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==} + + estree-util-visit@2.0.0: + resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} + + estree-walker@0.6.1: + resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} + + estree-walker@1.0.1: + resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fast-xml-builder@1.0.0: + resolution: {integrity: sha512-fpZuDogrAgnyt9oDDz+5DBz0zgPdPZz6D4IR7iESxRXElrlGTRkHJ9eEt+SACRJwT0FNFrt71DFQIUFBJfX/uQ==} + + fast-xml-parser@5.4.1: + resolution: {integrity: sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==} + hasBin: true + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + figures@1.7.0: + resolution: {integrity: sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==} + engines: {node: '>=0.10.0'} + + filelist@1.0.6: + resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} + + filesize@6.4.0: + resolution: {integrity: sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==} + engines: {node: '>= 0.4.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + flattie@1.1.1: + resolution: {integrity: sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ==} + engines: {node: '>=8'} + + focus-options-polyfill@1.6.0: + resolution: {integrity: sha512-uyrAmLZrPnUItQY5wTdg31TO9GGZRGsh/jmohUg9oLmLi/sw5y7LlTV/mwyd6rvbxIOGwmRiv6LcTS8w7Bk9NQ==} + + fontace@0.4.1: + resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} + + fontkitten@1.0.3: + resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} + engines: {node: '>=20'} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + 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==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + fuse.js@7.1.0: + resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} + engines: {node: '>=10'} + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + generic-names@4.0.0: + resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + 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@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globalyzer@0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + + globby@16.1.1: + resolution: {integrity: sha512-dW7vl+yiAJSp6aCekaVnVJxurRv7DCOLyXqEG3RYMYUg7AuJ2jCqPkZTA8ooqC2vtnkaMcV5WfFBMuEnTu1OQg==} + engines: {node: '>=20'} + + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + gray-matter@4.0.3: + resolution: {integrity: sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==} + engines: {node: '>=6.0'} + + gzip-size@3.0.0: + resolution: {integrity: sha512-6s8trQiK+OMzSaCSVXX+iqIcLV9tC+E73jrJrJTyS4h/AJhlxHvzFKqM1YLDJWRGgHX8uLkBeXkA0njNj39L4w==} + engines: {node: '>=0.12.0'} + + gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + + h3@1.15.6: + resolution: {integrity: sha512-oi15ESLW5LRthZ+qPCi5GNasY/gvynSKUQxgiovrY63bPAtG59wtM+LSrlcwvOHAXzGrXVLnI97brbkdPF9WoQ==} + + hachure-fill@0.5.2: + resolution: {integrity: sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==} + + has-ansi@2.0.0: + resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} + engines: {node: '>=0.10.0'} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-from-dom@5.0.1: + resolution: {integrity: sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==} + + hast-util-from-html-isomorphic@2.0.0: + resolution: {integrity: sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==} + + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + + hast-util-from-parse5@8.0.3: + resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} + + hast-util-heading-rank@3.0.0: + resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} + + 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-raw@9.1.0: + resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} + + hast-util-to-estree@3.1.3: + resolution: {integrity: sha512-48+B/rJWAp0jamNbAAf9M7Uf//UVqAoMmgXhBdxTDJLGKY+LRnZ99qcG+Qjl5HfMpYNzS5v4EAwVEF34LeAj7w==} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-to-parse5@8.0.1: + resolution: {integrity: sha512-MlWT6Pjt4CG9lFCjiz4BH7l9wmrMkfkJYCxFwKQic8+RTZgWPuWxwAfjJElsXkex7DJjfSJsQIt931ilUgmwdA==} + + hast-util-to-string@3.0.1: + resolution: {integrity: sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==} + + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hastscript@9.0.1: + resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} + + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + icss-replace-symbols@1.1.0: + resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==} + + icss-utils@5.1.0: + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-cwd@3.0.0: + resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} + engines: {node: '>=8'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-from@3.0.0: + resolution: {integrity: sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ==} + engines: {node: '>=8'} + + 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==} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + internmap@1.0.1: + resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} + + internmap@2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + + interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-reference@1.2.1: + resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jake@10.9.4: + resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} + engines: {node: '>=10'} + hasBin: true + + jest-worker@26.6.2: + resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} + engines: {node: '>= 10.13.0'} + + jiti@1.21.7: + resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@2.3.1: + resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + katex@0.16.38: + resolution: {integrity: sha512-cjHooZUmIAUmDsHBN+1n8LaZdpmbj03LtYeYPyuYB7OuloiaeaV6N4LcfjcnHVzGWjVQmKrxxTrpDcmSzEZQwQ==} + hasBin: true + + khroma@2.1.0: + resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + langium@4.2.1: + resolution: {integrity: sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} + + layout-base@1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + + layout-base@2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + + lightningcss-darwin-arm64@1.29.3: + resolution: {integrity: sha512-fb7raKO3pXtlNbQbiMeEu8RbBVHnpyqAoxTyTRMEWFQWmscGC2wZxoHzZ+YKAepUuKT9uIW5vL2QbFivTgprZg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.29.3: + resolution: {integrity: sha512-KF2XZ4ZdmDGGtEYmx5wpzn6u8vg7AdBHaEOvDKu8GOs7xDL/vcU2vMKtTeNe1d4dogkDdi3B9zC77jkatWBwEQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.29.3: + resolution: {integrity: sha512-VUWeVf+V1UM54jv9M4wen9vMlIAyT69Krl9XjI8SsRxz4tdNV/7QEPlW6JASev/pYdiynUCW0pwaFquDRYdxMw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.29.3: + resolution: {integrity: sha512-UhgZ/XVNfXQVEJrMIWeK1Laj8KbhjbIz7F4znUk7G4zeGw7TRoJxhb66uWrEsonn1+O45w//0i0Fu0wIovYdYg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.29.3: + resolution: {integrity: sha512-Pqau7jtgJNmQ/esugfmAT1aCFy/Gxc92FOxI+3n+LbMHBheBnk41xHDhc0HeYlx9G0xP5tK4t0Koy3QGGNqypw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.29.3: + resolution: {integrity: sha512-dxakOk66pf7KLS7VRYFO7B8WOJLecE5OPL2YOk52eriFd/yeyxt2Km5H0BjLfElokIaR+qWi33gB8MQLrdAY3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.29.3: + resolution: {integrity: sha512-ySZTNCpbfbK8rqpKJeJR2S0g/8UqqV3QnzcuWvpI60LWxnFN91nxpSSwCbzfOXkzKfar9j5eOuOplf+klKtINg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.29.3: + resolution: {integrity: sha512-3pVZhIzW09nzi10usAXfIGTTSTYQ141dk88vGFNCgawIzayiIzZQxEcxVtIkdvlEq2YuFsL9Wcj/h61JHHzuFQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.29.3: + resolution: {integrity: sha512-VRnkAvtIkeWuoBJeGOTrZxsNp4HogXtcaaLm8agmbYtLDOhQdpgxW6NjZZjDXbvGF+eOehGulXZ3C1TiwHY4QQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.29.3: + resolution: {integrity: sha512-IszwRPu2cPnDQsZpd7/EAr0x2W7jkaWqQ1SwCVIZ/tSbZVXPLt6k8s6FkcyBjViCzvB5CW0We0QbbP7zp2aBjQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.29.3: + resolution: {integrity: sha512-GlOJwTIP6TMIlrTFsxTerwC0W6OpQpCGuX1ECRLBUVRh6fpJH3xTqjCjRgQHTb4ZXexH9rtHou1Lf03GKzmhhQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} + engines: {node: '>= 12.13.0'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash-es@4.17.23: + resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + lru-cache@11.2.6: + resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide@0.542.0: + resolution: {integrity: sha512-+EtDSHjqg/nONgCfnjHCNd84OzbDjxR8ShnOf+oImlU+A8gqlptZ6pGrMCnhEDw8pVNQv3zu/L0eDvMzcc7nWA==} + + magic-string@0.25.9: + resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + markdown-extensions@2.0.0: + resolution: {integrity: sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==} + engines: {node: '>=16'} + + markdown-table@3.0.4: + resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + + marked@16.4.2: + resolution: {integrity: sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==} + engines: {node: '>= 20'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + maxmin@2.1.0: + resolution: {integrity: sha512-NWlApBjW9az9qRPaeg7CX4sQBWwytqz32bIEo1PW9pRW+kBP9KLRfJO3UC+TV31EcQZEUq7eMzikC7zt3zPJcw==} + engines: {node: '>=0.12'} + + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + + mdast-util-find-and-replace@3.0.2: + resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdx@3.0.0: + resolution: {integrity: sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-newline-to-break@2.0.0: + resolution: {integrity: sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdast-util-toc@7.1.0: + resolution: {integrity: sha512-2TVKotOQzqdY7THOdn2gGzS9d1Sdd66bvxUyw3aNpWfcPXCLYSJCCgfPy30sEtuzkDraJgqF35dzgmz6xlvH/w==} + + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + + mdn-data@2.0.28: + resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + mermaid@11.13.0: + resolution: {integrity: sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw==} + + microbundle@0.15.1: + resolution: {integrity: sha512-aAF+nwFbkSIJGfrJk+HyzmJOq3KFaimH6OIFBU6J2DPjQeg1jXIYlIyEv81Gyisb9moUkudn+wj7zLNYMOv75Q==} + hasBin: true + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-extension-math@3.1.0: + resolution: {integrity: sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==} + + micromark-extension-mdx-expression@3.0.1: + resolution: {integrity: sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==} + + micromark-extension-mdx-jsx@3.0.2: + resolution: {integrity: sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==} + + micromark-extension-mdx-md@2.0.0: + resolution: {integrity: sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==} + + micromark-extension-mdxjs-esm@3.0.0: + resolution: {integrity: sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==} + + micromark-extension-mdxjs@3.0.0: + resolution: {integrity: sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-mdx-expression@2.0.3: + resolution: {integrity: sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-events-to-acorn@2.0.3: + resolution: {integrity: sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + miniflare@4.20260301.1: + resolution: {integrity: sha512-fqkHx0QMKswRH9uqQQQOU/RoaS3Wjckxy3CUX3YGJr0ZIMu7ObvI+NovdYi6RIsSPthNtq+3TPmRNxjeRiasog==} + engines: {node: '>=18.0.0'} + hasBin: true + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + mlly@1.8.1: + resolution: {integrity: sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==} + + morphdom@2.7.8: + resolution: {integrity: sha512-D/fR4xgGUyVRbdMGU6Nejea1RFzYxYtyurG4Fbv2Fi/daKlWKuXGLOdXtl+3eIwL110cI2hz1ZojGICjjFLgTg==} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + neotraverse@0.6.18: + resolution: {integrity: sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==} + engines: {node: '>= 10'} + + nlcst-to-string@4.0.0: + resolution: {integrity: sha512-YKLBCcUYKAg0FNlOBT6aI91qFmSiFKiluk655WzPF+DDMA02qIyy8uiRqI8QXtcFpEvll12LpL5MXqEmAZ+dcA==} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-mock-http@1.0.4: + resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} + + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + + 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'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.4: + resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + opencollective-postinstall@2.0.3: + resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==} + hasBin: true + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@7.3.0: + resolution: {integrity: sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==} + engines: {node: '>=20'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-queue@6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + + p-queue@9.1.0: + resolution: {integrity: sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==} + engines: {node: '>=20'} + + p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + + p-timeout@7.0.1: + resolution: {integrity: sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==} + engines: {node: '>=20'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-data-parser@0.1.0: + resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + 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-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + piccolore@0.1.3: + resolution: {integrity: sha512-o8bTeDWjE086iwKrROaDf31K0qC/BENdm15/uH9usSC/uZjJOKb2YGiVHfLY4GhwsERiPI1jmwI2XrA7ACOxVw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + points-on-curve@0.2.0: + resolution: {integrity: sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==} + + points-on-path@0.2.1: + resolution: {integrity: sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-calc@8.2.4: + resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} + peerDependencies: + postcss: ^8.2.2 + + postcss-colormin@5.3.1: + resolution: {integrity: sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-convert-values@5.1.3: + resolution: {integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-comments@5.1.2: + resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-duplicates@5.1.0: + resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-empty@5.1.1: + resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-overridden@5.1.0: + resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + 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.1.0: + resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + + postcss-load-config@3.1.4: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + + 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@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-merge-longhand@5.1.7: + resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-merge-rules@5.1.4: + resolution: {integrity: sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-font-values@5.1.0: + resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-gradients@5.1.1: + resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-params@5.1.4: + resolution: {integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-selectors@5.2.1: + resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-local-by-default@4.2.0: + resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-scope@3.2.1: + resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-values@4.0.0: + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules@4.3.1: + resolution: {integrity: sha512-ItUhSUxBBdNamkT3KzIZwYNNRFKmkJrofvC2nWab3CPKhYBQ1f27XXh1PAPE27Psx58jeelPsxWB/+og+KEH0Q==} + peerDependencies: + postcss: ^8.0.0 + + postcss-nested@6.2.0: + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-normalize-charset@5.1.0: + resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-display-values@5.1.0: + resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-positions@5.1.1: + resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-repeat-style@5.1.1: + resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-string@5.1.0: + resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-timing-functions@5.1.0: + resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-unicode@5.1.1: + resolution: {integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-url@5.1.0: + resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-whitespace@5.1.1: + resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-ordered-values@5.1.3: + resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-reduce-initial@5.1.2: + resolution: {integrity: sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-reduce-transforms@5.1.0: + resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + 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-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-svgo@5.1.0: + resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-unique-selectors@5.1.1: + resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.8: + resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} + engines: {node: ^10 || ^12 || >=14} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + pretty-bytes@3.0.1: + resolution: {integrity: sha512-eb7ZAeUTgfh294cElcu51w+OTRp/6ItW758LjwJSK72LDevcuJn0P4eD71PLMDGPwwatXmAmYHTkzvpKlJE3ow==} + engines: {node: '>=0.10.0'} + + pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + promise.series@0.2.0: + resolution: {integrity: sha512-VWQJyU2bcDTgZw8kpfBpB/ejZASlCrzwz5f2hjb/zlujOEB4oeiAhHygAWq8ubsX2GVkD4kCU5V2dwOTaCY5EQ==} + engines: {node: '>=0.12'} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + 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'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} + + reading-time@1.5.0: + resolution: {integrity: sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==} + + rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + + recma-build-jsx@1.0.0: + resolution: {integrity: sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew==} + + recma-jsx@1.0.1: + resolution: {integrity: sha512-huSIy7VU2Z5OLv6oFLosQGGDqPqdO1iq6bWNAdhzMxSJP7RAso4fCZ1cKu8j9YHCZf3TPrq4dw3okhrylgcd7w==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + recma-parse@1.0.0: + resolution: {integrity: sha512-OYLsIGBB5Y5wjnSnQW6t3Xg7q3fQ7FWbw/vcXtORTnyaSFscOtABg+7Pnz6YZ6c27fG1/aN8CjfwoUEUIdwqWQ==} + + recma-stringify@1.0.0: + resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + + rehype-autolink-headings@7.1.0: + resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} + + rehype-katex@7.0.1: + resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} + + rehype-parse@9.0.1: + resolution: {integrity: sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + rehype-recma@1.0.0: + resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} + + 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@13.0.2: + resolution: {integrity: sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==} + + remark-breaks@4.0.0: + resolution: {integrity: sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-math@6.0.0: + resolution: {integrity: sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==} + + remark-mdx@3.1.1: + resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-reading-time@2.1.0: + resolution: {integrity: sha512-gBsJbQv87TUq4dRMSOgIX6P60Tk9ke8c29KsL7bccmsv2m9AycDfVu3ghRtrNpHLZU3TE5P/vImGOMSPzYU8rA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.2: + resolution: {integrity: sha512-ILTWeOriIluwEvPjv67v7Blgrcx+LZOkAUVtKI3putuhlZm84FnqDORNXPPm+HY3NdZOMhyDwZ1E+eZB/Df5dA==} + engines: {node: '>=16.0.0'} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + remark-toc@9.0.0: + resolution: {integrity: sha512-KJ9txbo33GjDAV1baHFze7ij4G8c7SGYoY8Kzsm2gzFpbhL/bSoVpMMzGa3vrNDSWASNd/3ppAqL7cP2zD6JIA==} + + request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + + retext-smartypants@6.2.0: + resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + robust-predicates@3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + + rollup-plugin-bundle-size@1.0.3: + resolution: {integrity: sha512-aWj0Pvzq90fqbI5vN1IvUrlf4utOqy+AERYxwWjegH1G8PzheMnrRIgQ5tkwKVtQMDP0bHZEACW/zLDF+XgfXQ==} + + rollup-plugin-postcss@4.0.2: + resolution: {integrity: sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==} + engines: {node: '>=10'} + peerDependencies: + postcss: 8.x + + rollup-plugin-terser@7.0.2: + resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} + deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser + peerDependencies: + rollup: ^2.0.0 + + rollup-plugin-typescript2@0.32.1: + resolution: {integrity: sha512-RanO8bp1WbeMv0bVlgcbsFNCn+Y3rX7wF97SQLDxf0fMLsg0B/QFF005t4AsGUcDgF3aKJHoqt4JF2xVaABeKw==} + peerDependencies: + rollup: '>=1.26.3' + typescript: '>=2.4.0' + + rollup-plugin-visualizer@5.14.0: + resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + rolldown: 1.x + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rolldown: + optional: true + rollup: + optional: true + + rollup-pluginutils@2.8.2: + resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} + + rollup@2.80.0: + resolution: {integrity: sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==} + engines: {node: '>=10.0.0'} + hasBin: true + + rollup@4.59.0: + resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + roughjs@4.6.6: + resolution: {integrity: sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rw@1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-identifier@0.4.2: + resolution: {integrity: sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sax@1.5.0: + resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} + engines: {node: '>=11.0.0'} + + scrl@2.0.0: + resolution: {integrity: sha512-BbbVXxrOn58Ge4wjOORIRVZamssQu08ISLL/AC2z9aATIsKqZLESwZVW5YR0Yz0C7qqDRHb4yNXJlQ8yW0SGHw==} + + section-matter@1.0.0: + resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} + engines: {node: '>=4'} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@4.0.0: + resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + 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'} + + shelljs-live@0.0.5: + resolution: {integrity: sha512-IR5+gA7f+v/V8ao7ZKE4TQpbG6ABeGxQhwL0seIbOXvHdoFAHw3MEiUICrhUfuroRREKL0n7HDA5b/R5it8KHg==} + peerDependencies: + shelljs: ^0.8.4 + + shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + + shiki@4.0.2: + resolution: {integrity: sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==} + engines: {node: '>=20'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + sitemap@9.0.1: + resolution: {integrity: sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==} + engines: {node: '>=20.19.5', npm: '>=10.8.2'} + hasBin: true + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + smol-toml@1.6.0: + resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} + engines: {node: '>= 18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + sourcemap-codec@1.4.8: + resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stable@0.1.8: + resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} + deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + stream-replace-string@2.0.0: + resolution: {integrity: sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==} + + string-hash@1.1.3: + resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom-string@1.0.0: + resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} + engines: {node: '>=0.10.0'} + + strnum@2.2.0: + resolution: {integrity: sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==} + + style-inject@0.3.0: + resolution: {integrity: sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + stylehacks@5.1.1: + resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-color@2.0.0: + resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} + engines: {node: '>=0.8.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svgo@2.8.2: + resolution: {integrity: sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA==} + engines: {node: '>=10.13.0'} + hasBin: true + + svgo@4.0.1: + resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} + engines: {node: '>=16'} + hasBin: true + + swup-morph-plugin@1.3.0: + resolution: {integrity: sha512-vTqWYA5ZFkWMo54K8jlol5OCvboqRsELLfM1PUkS2IiL+1dDDChzMHa4ZBI5+yfl7bZUCWgd8EmuhMd/i/o+Qg==} + peerDependencies: + swup: ^4.6.0 + + swup@4.8.3: + resolution: {integrity: sha512-2U+mE7SnU4Jm+H82C2FChML04v5kb+fnf+2aYP2e0MX7vWOnmd6SHvjSBF8MH3HOrwalaXnynQVImgCaxGZxtA==} + + tailwindcss@3.4.19: + resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} + engines: {node: '>=14.0.0'} + hasBin: true + + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + engines: {node: '>=10'} + 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==} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyclip@0.1.12: + resolution: {integrity: sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==} + engines: {node: ^16.14.0 || >= 17.3.0} + + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + 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-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typed-query-selector@2.12.1: + resolution: {integrity: sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA==} + + typesafe-path@0.2.2: + resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} + + typescript-auto-import-cache@0.3.6: + resolution: {integrity: sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ==} + + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + + ultrahtml@1.6.0: + resolution: {integrity: sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici@7.18.2: + resolution: {integrity: sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==} + engines: {node: '>=20.18.1'} + + unenv@2.0.0-rc.24: + resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + + unicorn-magic@0.4.0: + resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} + engines: {node: '>=20'} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unifont@0.7.4: + resolution: {integrity: sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + + unist-util-position-from-estree@2.0.0: + resolution: {integrity: sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-remove-position@5.0.0: + resolution: {integrity: sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unstorage@1.17.4: + resolution: {integrity: sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==} + peerDependencies: + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6 || ^7 || ^8 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/functions': ^2.2.12 || ^3.0.0 + '@vercel/kv': ^1 || ^2 || ^3 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@deno/kv': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/blob': + optional: true + '@vercel/functions': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: + optional: true + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitefu@1.1.2: + resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + volar-service-css@0.0.70: + resolution: {integrity: sha512-K1qyOvBpE3rzdAv3e4/6Rv5yizrYPy5R/ne3IWCAzLBuMO4qBMV3kSqWzj6KUVe6S0AnN6wxF7cRkiaKfYMYJw==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-emmet@0.0.70: + resolution: {integrity: sha512-xi5bC4m/VyE3zy/n2CXspKeDZs3qA41tHLTw275/7dNWM/RqE2z3BnDICQybHIVp/6G1iOQj5c1qXMgQC08TNg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-html@0.0.70: + resolution: {integrity: sha512-eR6vCgMdmYAo4n+gcT7DSyBQbwB8S3HZZvSagTf0sxNaD4WppMCFfpqWnkrlGStPKMZvMiejRRVmqsX9dYcTvQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-prettier@0.0.70: + resolution: {integrity: sha512-Z6BCFSpGVCd8BPAsZ785Kce1BGlWd5ODqmqZGVuB14MJvrR4+CYz6cDy4F+igmE1gMifqfvMhdgT8Aud4M5ngg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + prettier: ^2.2 || ^3.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + prettier: + optional: true + + volar-service-typescript-twoslash-queries@0.0.70: + resolution: {integrity: sha512-IdD13Z9N2Bu8EM6CM0fDV1E69olEYGHDU25X51YXmq8Y0CmJ2LNj6gOiBJgpS5JGUqFzECVhMNBW7R0sPdRTMQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-typescript@0.0.70: + resolution: {integrity: sha512-l46Bx4cokkUedTd74ojO5H/zqHZJ8SUuyZ0IB8JN4jfRqUM3bQFBHoOwlZCyZmOeO0A3RQNkMnFclxO4c++gsg==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + volar-service-yaml@0.0.70: + resolution: {integrity: sha512-0c8bXDBeoATF9F6iPIlOuYTuZAC4c+yi0siQo920u7eiBJk8oQmUmg9cDUbR4+Gl++bvGP4plj3fErbJuPqdcQ==} + peerDependencies: + '@volar/language-service': ~2.4.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-css-languageservice@6.3.10: + resolution: {integrity: sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA==} + + vscode-html-languageservice@5.6.2: + resolution: {integrity: sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg==} + + vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.12: + resolution: {integrity: sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-pm-runs@1.1.0: + resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} + engines: {node: '>=4'} + + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + workerd@1.20260301.1: + resolution: {integrity: sha512-oterQ1IFd3h7PjCfT4znSFOkJCvNQ6YMOyZ40YsnO3nrSpgB4TbJVYWFOnyJAw71/RQuupfVqZZWKvsy8GO3fw==} + engines: {node: '>=16'} + hasBin: true + + wrangler@4.71.0: + resolution: {integrity: sha512-j6pSGAncOLNQDRzqtp0EqzYj52CldDP7uz/C9cxVrIgqa5p+cc0b4pIwnapZZAGv9E1Loa3tmPD0aXonH7KTkw==} + engines: {node: '>=20.0.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20260226.1 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xxhash-wasm@1.1.0: + resolution: {integrity: sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml-language-server@1.20.0: + resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==} + hasBin: true + + yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} + hasBin: true + + yaml@2.8.2: + resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + youch-core@0.3.3: + resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} + + youch@4.1.0-beta.10: + resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@antfu/install-pkg@1.1.0': + dependencies: + package-manager-detector: 1.6.0 + tinyexec: 1.0.2 + + '@astrojs/check@0.9.8(prettier@3.8.1)(typescript@5.9.3)': + dependencies: + '@astrojs/language-server': 2.16.6(prettier@3.8.1)(typescript@5.9.3) + chokidar: 4.0.3 + kleur: 4.1.5 + typescript: 5.9.3 + yargs: 17.7.2 + transitivePeerDependencies: + - prettier + - prettier-plugin-astro + + '@astrojs/compiler@2.13.1': {} + + '@astrojs/compiler@3.0.0': {} + + '@astrojs/internal-helpers@0.8.0': + dependencies: + picomatch: 4.0.3 + + '@astrojs/language-server@2.16.6(prettier@3.8.1)(typescript@5.9.3)': + dependencies: + '@astrojs/compiler': 2.13.1 + '@astrojs/yaml2ts': 0.2.3 + '@jridgewell/sourcemap-codec': 1.5.5 + '@volar/kit': 2.4.28(typescript@5.9.3) + '@volar/language-core': 2.4.28 + '@volar/language-server': 2.4.28 + '@volar/language-service': 2.4.28 + muggle-string: 0.4.1 + tinyglobby: 0.2.15 + volar-service-css: 0.0.70(@volar/language-service@2.4.28) + volar-service-emmet: 0.0.70(@volar/language-service@2.4.28) + volar-service-html: 0.0.70(@volar/language-service@2.4.28) + volar-service-prettier: 0.0.70(@volar/language-service@2.4.28)(prettier@3.8.1) + volar-service-typescript: 0.0.70(@volar/language-service@2.4.28) + volar-service-typescript-twoslash-queries: 0.0.70(@volar/language-service@2.4.28) + volar-service-yaml: 0.0.70(@volar/language-service@2.4.28) + vscode-html-languageservice: 5.6.2 + vscode-uri: 3.1.0 + optionalDependencies: + prettier: 3.8.1 + transitivePeerDependencies: + - typescript + + '@astrojs/markdown-remark@7.0.1': + dependencies: + '@astrojs/internal-helpers': 0.8.0 + '@astrojs/prism': 4.0.1 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + js-yaml: 4.1.1 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + remark-smartypants: 3.0.2 + shiki: 4.0.2 + smol-toml: 1.6.0 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/mdx@5.0.2(astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))': + dependencies: + '@astrojs/markdown-remark': 7.0.1 + '@mdx-js/mdx': 3.1.1 + acorn: 8.16.0 + astro: 6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + es-module-lexer: 2.0.0 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1 + remark-smartypants: 3.0.2 + source-map: 0.7.6 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@astrojs/prism@4.0.1': + dependencies: + prismjs: 1.30.0 + + '@astrojs/rss@4.0.17': + dependencies: + fast-xml-parser: 5.4.1 + piccolore: 0.1.3 + zod: 4.3.6 + + '@astrojs/sitemap@3.7.1': + dependencies: + sitemap: 9.0.1 + stream-replace-string: 2.0.0 + zod: 4.3.6 + + '@astrojs/tailwind@6.0.2(astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))(tailwindcss@3.4.19(yaml@2.8.2))': + dependencies: + astro: 6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + autoprefixer: 10.4.27(postcss@8.5.8) + postcss: 8.5.8 + postcss-load-config: 4.0.2(postcss@8.5.8) + tailwindcss: 3.4.19(yaml@2.8.2) + transitivePeerDependencies: + - ts-node + + '@astrojs/telemetry@3.3.0': + dependencies: + ci-info: 4.4.0 + debug: 4.4.3 + dlv: 1.1.3 + dset: 3.1.4 + is-docker: 3.0.0 + is-wsl: 3.1.1 + which-pm-runs: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@astrojs/yaml2ts@0.2.3': + dependencies: + yaml: 2.8.2 + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.28.6 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.6.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + debug: 4.4.3 + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helper-wrap-function@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/parser@7.29.0': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-class-properties@7.12.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + + '@babel/plugin-syntax-flow@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/preset-env@7.29.0(@babel/core@7.29.0)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.0) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.29.0) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.29.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.0) + babel-plugin-polyfill-corejs2: 0.4.16(@babel/core@7.29.0) + babel-plugin-polyfill-corejs3: 0.14.1(@babel/core@7.29.0) + babel-plugin-polyfill-regenerator: 0.6.7(@babel/core@7.29.0) + core-js-compat: 3.48.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-flow@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 + esutils: 2.0.3 + + '@babel/preset-react@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.28.6': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@braintree/sanitize-url@7.1.2': {} + + '@capsizecss/unpack@4.0.0': + dependencies: + fontkitten: 1.0.3 + + '@chevrotain/cst-dts-gen@11.1.2': + dependencies: + '@chevrotain/gast': 11.1.2 + '@chevrotain/types': 11.1.2 + lodash-es: 4.17.23 + + '@chevrotain/gast@11.1.2': + dependencies: + '@chevrotain/types': 11.1.2 + lodash-es: 4.17.23 + + '@chevrotain/regexp-to-ast@11.1.2': {} + + '@chevrotain/types@11.1.2': {} + + '@chevrotain/utils@11.1.2': {} + + '@clack/core@1.1.0': + dependencies: + sisteransi: 1.0.5 + + '@clack/prompts@1.1.0': + dependencies: + '@clack/core': 1.1.0 + sisteransi: 1.0.5 + + '@cloudflare/kv-asset-handler@0.4.2': {} + + '@cloudflare/unenv-preset@2.15.0(unenv@2.0.0-rc.24)(workerd@1.20260301.1)': + dependencies: + unenv: 2.0.0-rc.24 + optionalDependencies: + workerd: 1.20260301.1 + + '@cloudflare/workerd-darwin-64@1.20260301.1': + optional: true + + '@cloudflare/workerd-darwin-arm64@1.20260301.1': + optional: true + + '@cloudflare/workerd-linux-64@1.20260301.1': + optional: true + + '@cloudflare/workerd-linux-arm64@1.20260301.1': + optional: true + + '@cloudflare/workerd-windows-64@1.20260301.1': + optional: true + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emmetio/abbreviation@2.3.3': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-abbreviation@2.1.8': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/css-parser@0.4.1': + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + + '@emmetio/html-matcher@1.3.0': + dependencies: + '@emmetio/scanner': 1.0.4 + + '@emmetio/scanner@1.0.4': {} + + '@emmetio/stream-reader-utils@0.1.0': {} + + '@emmetio/stream-reader@2.2.0': {} + + '@emnapi/runtime@1.8.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@epic-web/invariant@1.0.0': {} + + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.3': + optional: true + + '@fontsource/inter@5.2.8': {} + + '@fontsource/jetbrains-mono@5.2.8': {} + + '@fortawesome/fontawesome-common-types@7.2.0': {} + + '@fortawesome/fontawesome-svg-core@7.2.0': + dependencies: + '@fortawesome/fontawesome-common-types': 7.2.0 + + '@fortawesome/free-brands-svg-icons@7.2.0': + dependencies: + '@fortawesome/fontawesome-common-types': 7.2.0 + + '@iconify/types@2.0.0': {} + + '@iconify/utils@3.1.0': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@iconify/types': 2.0.0 + mlly: 1.8.1 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.8.1 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@mdx-js/mdx@3.1.1': + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdx': 2.0.13 + acorn: 8.16.0 + collapse-white-space: 2.1.0 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-util-scope: 1.0.0 + estree-walker: 3.0.3 + hast-util-to-jsx-runtime: 2.3.6 + markdown-extensions: 2.0.0 + recma-build-jsx: 1.0.0 + recma-jsx: 1.0.1(acorn@8.16.0) + recma-stringify: 1.0.0 + rehype-recma: 1.0.0 + remark-mdx: 3.1.1 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + source-map: 0.7.6 + unified: 11.0.5 + unist-util-position-from-estree: 2.0.0 + unist-util-stringify-position: 4.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@mermaid-js/parser@1.0.1': + dependencies: + langium: 4.2.1 + + '@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.20.1 + + '@oslojs/encoding@1.1.0': {} + + '@poppinss/colors@4.1.6': + dependencies: + kleur: 4.1.5 + + '@poppinss/dumper@0.6.5': + dependencies: + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 + supports-color: 10.2.2 + + '@poppinss/exception@1.2.3': {} + + '@rollup/plugin-alias@3.1.9(rollup@2.80.0)': + dependencies: + rollup: 2.80.0 + slash: 3.0.0 + + '@rollup/plugin-babel@5.3.1(@babel/core@7.29.0)(rollup@2.80.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@rollup/pluginutils': 3.1.0(rollup@2.80.0) + rollup: 2.80.0 + transitivePeerDependencies: + - supports-color + + '@rollup/plugin-commonjs@17.1.0(rollup@2.80.0)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.80.0) + commondir: 1.0.1 + estree-walker: 2.0.2 + glob: 7.2.3 + is-reference: 1.2.1 + magic-string: 0.25.9 + resolve: 1.22.11 + rollup: 2.80.0 + + '@rollup/plugin-json@4.1.0(rollup@2.80.0)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.80.0) + rollup: 2.80.0 + + '@rollup/plugin-node-resolve@11.2.1(rollup@2.80.0)': + dependencies: + '@rollup/pluginutils': 3.1.0(rollup@2.80.0) + '@types/resolve': 1.17.1 + builtin-modules: 3.3.0 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + rollup: 2.80.0 + + '@rollup/pluginutils@3.1.0(rollup@2.80.0)': + dependencies: + '@types/estree': 0.0.39 + estree-walker: 1.0.1 + picomatch: 2.3.1 + rollup: 2.80.0 + + '@rollup/pluginutils@4.2.1': + dependencies: + estree-walker: 2.0.2 + picomatch: 2.3.1 + + '@rollup/pluginutils@5.3.0(rollup@2.80.0)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 2.80.0 + + '@rollup/rollup-android-arm-eabi@4.59.0': + optional: true + + '@rollup/rollup-android-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-arm64@4.59.0': + optional: true + + '@rollup/rollup-darwin-x64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-arm64@4.59.0': + optional: true + + '@rollup/rollup-freebsd-x64@4.59.0': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.59.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.59.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.59.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.59.0': + optional: true + + '@rollup/rollup-openbsd-x64@4.59.0': + optional: true + + '@rollup/rollup-openharmony-arm64@4.59.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.59.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.59.0': + optional: true + + '@shikijs/core@4.0.2': + dependencies: + '@shikijs/primitive': 4.0.2 + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.4 + + '@shikijs/engine-oniguruma@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + + '@shikijs/primitive@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/themes@4.0.2': + dependencies: + '@shikijs/types': 4.0.2 + + '@shikijs/types@4.0.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sindresorhus/is@7.2.0': {} + + '@sindresorhus/merge-streams@4.0.0': {} + + '@speed-highlight/core@1.2.14': {} + + '@surma/rollup-plugin-off-main-thread@2.2.3': + dependencies: + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.25.9 + string.prototype.matchall: 4.0.12 + + '@swup/a11y-plugin@5.0.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + focus-options-polyfill: 1.6.0 + swup: 4.8.3 + + '@swup/astro@1.8.0': + dependencies: + '@swup/a11y-plugin': 5.0.0(swup@4.8.3) + '@swup/body-class-plugin': 3.3.0(swup@4.8.3) + '@swup/debug-plugin': 4.1.0(swup@4.8.3) + '@swup/fade-theme': 2.0.2(swup@4.8.3) + '@swup/forms-plugin': 3.6.0(swup@4.8.3) + '@swup/fragment-plugin': 1.3.0(swup@4.8.3) + '@swup/head-plugin': 2.3.1(swup@4.8.3) + '@swup/overlay-theme': 2.0.2(swup@4.8.3) + '@swup/parallel-plugin': 0.4.0(swup@4.8.3) + '@swup/preload-plugin': 3.2.11(swup@4.8.3) + '@swup/progress-plugin': 3.2.0(swup@4.8.3) + '@swup/route-name-plugin': 4.1.0(swup@4.8.3) + '@swup/scripts-plugin': 2.1.0(swup@4.8.3) + '@swup/scroll-plugin': 3.3.2(swup@4.8.3) + '@swup/slide-theme': 2.0.2(swup@4.8.3) + swup: 4.8.3 + swup-morph-plugin: 1.3.0(swup@4.8.3) + transitivePeerDependencies: + - '@types/babel__core' + - rolldown + - supports-color + - ts-node + + '@swup/body-class-plugin@3.3.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/browserslist-config@1.0.1': {} + + '@swup/debug-plugin@4.1.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/fade-theme@2.0.2(swup@4.8.3)': + dependencies: + '@swup/theme': 2.1.0(swup@4.8.3) + swup: 4.8.3 + + '@swup/forms-plugin@3.6.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/fragment-plugin@1.3.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/head-plugin@2.3.1(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/overlay-theme@2.0.2(swup@4.8.3)': + dependencies: + '@swup/theme': 2.1.0(swup@4.8.3) + swup: 4.8.3 + + '@swup/parallel-plugin@0.4.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 3.0.1 + swup: 4.8.3 + transitivePeerDependencies: + - '@types/babel__core' + - rolldown + - supports-color + - ts-node + + '@swup/plugin@3.0.1': + dependencies: + '@swup/browserslist-config': 1.0.1 + '@swup/prettier-config': 1.1.0 + chalk: 5.6.2 + microbundle: 0.15.1 + prettier: 2.8.8 + shelljs: 0.8.5 + shelljs-live: 0.0.5(shelljs@0.8.5) + swup: 4.8.3 + transitivePeerDependencies: + - '@types/babel__core' + - rolldown + - supports-color + - ts-node + + '@swup/plugin@4.0.0': + dependencies: + swup: 4.8.3 + + '@swup/preload-plugin@3.2.11(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/prettier-config@1.1.0': {} + + '@swup/progress-plugin@3.2.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/route-name-plugin@4.1.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 3.0.1 + swup: 4.8.3 + transitivePeerDependencies: + - '@types/babel__core' + - rolldown + - supports-color + - ts-node + + '@swup/scripts-plugin@2.1.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@swup/scroll-plugin@3.3.2(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + scrl: 2.0.0 + swup: 4.8.3 + + '@swup/slide-theme@2.0.2(swup@4.8.3)': + dependencies: + '@swup/theme': 2.1.0(swup@4.8.3) + swup: 4.8.3 + + '@swup/theme@2.1.0(swup@4.8.3)': + dependencies: + '@swup/plugin': 4.0.0 + swup: 4.8.3 + + '@tailwindcss/typography@0.5.19(tailwindcss@3.4.19(yaml@2.8.2))': + dependencies: + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.19(yaml@2.8.2) + + '@types/d3-array@3.2.2': {} + + '@types/d3-axis@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-brush@3.0.6': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-chord@3.0.6': {} + + '@types/d3-color@3.1.3': {} + + '@types/d3-contour@3.0.6': + dependencies: + '@types/d3-array': 3.2.2 + '@types/geojson': 7946.0.16 + + '@types/d3-delaunay@6.0.4': {} + + '@types/d3-dispatch@3.0.7': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-dsv@3.0.7': {} + + '@types/d3-ease@3.0.2': {} + + '@types/d3-fetch@3.0.7': + dependencies: + '@types/d3-dsv': 3.0.7 + + '@types/d3-force@3.0.10': {} + + '@types/d3-format@3.0.4': {} + + '@types/d3-geo@3.1.0': + dependencies: + '@types/geojson': 7946.0.16 + + '@types/d3-hierarchy@3.1.7': {} + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-path@3.1.1': {} + + '@types/d3-polygon@3.0.2': {} + + '@types/d3-quadtree@3.0.6': {} + + '@types/d3-random@3.0.3': {} + + '@types/d3-scale-chromatic@3.1.0': {} + + '@types/d3-scale@4.0.9': + dependencies: + '@types/d3-time': 3.0.4 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-shape@3.1.8': + dependencies: + '@types/d3-path': 3.1.1 + + '@types/d3-time-format@4.0.3': {} + + '@types/d3-time@3.0.4': {} + + '@types/d3-timer@3.0.2': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/d3@7.4.3': + dependencies: + '@types/d3-array': 3.2.2 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.7 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.1 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.9 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.8 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@0.0.39': {} + + '@types/estree@1.0.8': {} + + '@types/geojson@7946.0.16': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/katex@0.16.8': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdx@2.0.13': {} + + '@types/ms@2.1.0': {} + + '@types/nlcst@2.0.3': + dependencies: + '@types/unist': 3.0.3 + + '@types/node@24.12.0': + dependencies: + undici-types: 7.16.0 + + '@types/node@25.4.0': + dependencies: + undici-types: 7.18.2 + + '@types/parse-json@4.0.2': {} + + '@types/resolve@1.17.1': + dependencies: + '@types/node': 25.4.0 + + '@types/sax@1.2.7': + dependencies: + '@types/node': 25.4.0 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/ungap__structured-clone@1.2.0': {} + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.0': {} + + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + '@volar/kit@2.4.28(typescript@5.9.3)': + dependencies: + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + typesafe-path: 0.2.2 + typescript: 5.9.3 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/language-server@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + '@volar/language-service': 2.4.28 + '@volar/typescript': 2.4.28 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/language-service@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vscode/emmet-helper@2.11.0': + dependencies: + emmet: 2.4.11 + jsonc-parser: 2.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + '@vscode/l10n@0.0.18': {} + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + ajv-draft-04@1.0.0(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@2.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-styles@2.2.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@5.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-iterate@2.0.1: {} + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + astring@1.9.0: {} + + astro-redirect-from@1.3.5(astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)): + dependencies: + astro: 6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + globby: 16.1.1 + gray-matter: 4.0.3 + + astro@6.0.8(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(rollup@2.80.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2): + dependencies: + '@astrojs/compiler': 3.0.0 + '@astrojs/internal-helpers': 0.8.0 + '@astrojs/markdown-remark': 7.0.1 + '@astrojs/telemetry': 3.3.0 + '@capsizecss/unpack': 4.0.0 + '@clack/prompts': 1.1.0 + '@oslojs/encoding': 1.1.0 + '@rollup/pluginutils': 5.3.0(rollup@2.80.0) + aria-query: 5.3.2 + axobject-query: 4.1.0 + ci-info: 4.4.0 + clsx: 2.1.1 + common-ancestor-path: 2.0.0 + cookie: 1.1.1 + devalue: 5.6.3 + diff: 8.0.3 + dlv: 1.1.3 + dset: 3.1.4 + es-module-lexer: 2.0.0 + esbuild: 0.27.3 + flattie: 1.1.1 + fontace: 0.4.1 + github-slugger: 2.0.0 + html-escaper: 3.0.3 + http-cache-semantics: 4.2.0 + js-yaml: 4.1.1 + magic-string: 0.30.21 + magicast: 0.5.2 + mrmime: 2.0.1 + neotraverse: 0.6.18 + obug: 2.1.1 + p-limit: 7.3.0 + p-queue: 9.1.0 + package-manager-detector: 1.6.0 + piccolore: 0.1.3 + picomatch: 4.0.3 + rehype: 13.0.2 + semver: 7.7.4 + shiki: 4.0.2 + smol-toml: 1.6.0 + svgo: 4.0.1 + tinyclip: 0.1.12 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tsconfck: 3.1.6(typescript@5.9.3) + ultrahtml: 1.6.0 + unifont: 0.7.4 + unist-util-visit: 5.1.0 + unstorage: 1.17.4 + vfile: 6.0.3 + vite: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.46.0)(yaml@2.8.2) + vitefu: 1.1.2(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.46.0)(yaml@2.8.2)) + xxhash-wasm: 1.1.0 + yargs-parser: 22.0.0 + zod: 4.3.6 + optionalDependencies: + sharp: 0.34.5 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@types/node' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - idb-keyval + - ioredis + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - typescript + - uploadthing + - yaml + + async-function@1.0.0: {} + + async@3.2.6: {} + + asyncro@3.0.0: {} + + autoprefixer@10.4.27(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001777 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axobject-query@4.1.0: {} + + babel-plugin-macros@3.1.0: + dependencies: + '@babel/runtime': 7.28.6 + cosmiconfig: 7.1.0 + resolve: 1.22.11 + + babel-plugin-polyfill-corejs2@0.4.16(@babel/core@7.29.0): + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-corejs3@0.14.1(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + core-js-compat: 3.48.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-polyfill-regenerator@0.6.7(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-define-polyfill-provider': 0.6.7(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + babel-plugin-transform-async-to-promises@0.8.18: {} + + babel-plugin-transform-replace-expressions@0.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.0 + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + baseline-browser-mapping@2.10.0: {} + + binary-extensions@2.3.0: {} + + blake3-wasm@2.1.5: {} + + boolbase@1.0.0: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + brotli-size@4.0.0: + dependencies: + duplexer: 0.1.1 + + browserslist@4.28.1: + dependencies: + baseline-browser-mapping: 2.10.0 + caniuse-lite: 1.0.30001777 + electron-to-chromium: 1.5.307 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) + + buffer-from@1.1.2: {} + + builtin-modules@3.3.0: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase-css@2.0.1: {} + + camelcase@6.3.0: {} + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.28.1 + caniuse-lite: 1.0.30001777 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001777: {} + + ccount@2.0.1: {} + + chalk@1.1.3: + dependencies: + ansi-styles: 2.2.1 + escape-string-regexp: 1.0.5 + has-ansi: 2.0.0 + strip-ansi: 3.0.1 + supports-color: 2.0.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + chevrotain-allstar@0.3.1(chevrotain@11.1.2): + dependencies: + chevrotain: 11.1.2 + lodash-es: 4.17.23 + + chevrotain@11.1.2: + dependencies: + '@chevrotain/cst-dts-gen': 11.1.2 + '@chevrotain/gast': 11.1.2 + '@chevrotain/regexp-to-ast': 11.1.2 + '@chevrotain/types': 11.1.2 + '@chevrotain/utils': 11.1.2 + lodash-es: 4.17.23 + + 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 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chokidar@5.0.0: + dependencies: + readdirp: 5.0.0 + + ci-info@4.4.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + collapse-white-space@2.1.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colord@2.9.3: {} + + comma-separated-tokens@2.0.3: {} + + commander@11.1.0: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + commander@7.2.0: {} + + commander@8.3.0: {} + + common-ancestor-path@2.0.0: {} + + commondir@1.0.1: {} + + concat-map@0.0.1: {} + + concat-with-sourcemaps@1.1.0: + dependencies: + source-map: 0.6.1 + + confbox@0.1.8: {} + + convert-source-map@2.0.0: {} + + cookie-es@1.2.2: {} + + cookie@1.1.1: {} + + core-js-compat@3.48.0: + dependencies: + browserslist: 4.28.1 + + cose-base@1.0.3: + dependencies: + layout-base: 1.0.2 + + cose-base@2.2.0: + dependencies: + layout-base: 2.0.1 + + cosmiconfig@7.1.0: + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.1 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crossws@0.3.5: + dependencies: + uncrypto: 0.1.3 + + css-declaration-sorter@6.4.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + css-select@4.3.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + + css-select@5.2.2: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + + css-tree@1.1.3: + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + + css-tree@2.2.1: + dependencies: + mdn-data: 2.0.28 + source-map-js: 1.2.1 + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css-what@6.2.2: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@5.2.14(postcss@8.5.8): + dependencies: + css-declaration-sorter: 6.4.1(postcss@8.5.8) + cssnano-utils: 3.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-calc: 8.2.4(postcss@8.5.8) + postcss-colormin: 5.3.1(postcss@8.5.8) + postcss-convert-values: 5.1.3(postcss@8.5.8) + postcss-discard-comments: 5.1.2(postcss@8.5.8) + postcss-discard-duplicates: 5.1.0(postcss@8.5.8) + postcss-discard-empty: 5.1.1(postcss@8.5.8) + postcss-discard-overridden: 5.1.0(postcss@8.5.8) + postcss-merge-longhand: 5.1.7(postcss@8.5.8) + postcss-merge-rules: 5.1.4(postcss@8.5.8) + postcss-minify-font-values: 5.1.0(postcss@8.5.8) + postcss-minify-gradients: 5.1.1(postcss@8.5.8) + postcss-minify-params: 5.1.4(postcss@8.5.8) + postcss-minify-selectors: 5.2.1(postcss@8.5.8) + postcss-normalize-charset: 5.1.0(postcss@8.5.8) + postcss-normalize-display-values: 5.1.0(postcss@8.5.8) + postcss-normalize-positions: 5.1.1(postcss@8.5.8) + postcss-normalize-repeat-style: 5.1.1(postcss@8.5.8) + postcss-normalize-string: 5.1.0(postcss@8.5.8) + postcss-normalize-timing-functions: 5.1.0(postcss@8.5.8) + postcss-normalize-unicode: 5.1.1(postcss@8.5.8) + postcss-normalize-url: 5.1.0(postcss@8.5.8) + postcss-normalize-whitespace: 5.1.1(postcss@8.5.8) + postcss-ordered-values: 5.1.3(postcss@8.5.8) + postcss-reduce-initial: 5.1.2(postcss@8.5.8) + postcss-reduce-transforms: 5.1.0(postcss@8.5.8) + postcss-svgo: 5.1.0(postcss@8.5.8) + postcss-unique-selectors: 5.1.1(postcss@8.5.8) + + cssnano-utils@3.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + cssnano@5.1.15(postcss@8.5.8): + dependencies: + cssnano-preset-default: 5.2.14(postcss@8.5.8) + lilconfig: 2.1.0 + postcss: 8.5.8 + yaml: 1.10.2 + + csso@4.2.0: + dependencies: + css-tree: 1.1.3 + + csso@5.0.5: + dependencies: + css-tree: 2.2.1 + + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + dependencies: + cose-base: 1.0.3 + cytoscape: 3.33.1 + + cytoscape-fcose@2.2.0(cytoscape@3.33.1): + dependencies: + cose-base: 2.2.0 + cytoscape: 3.33.1 + + cytoscape@3.33.1: {} + + d3-array@2.12.1: + dependencies: + internmap: 1.0.1 + + d3-array@3.2.4: + dependencies: + internmap: 2.0.3 + + d3-axis@3.0.0: {} + + d3-brush@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3-chord@3.0.1: + dependencies: + d3-path: 3.1.0 + + d3-color@3.1.0: {} + + d3-contour@4.0.2: + dependencies: + d3-array: 3.2.4 + + d3-delaunay@6.0.4: + dependencies: + delaunator: 5.0.1 + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-dsv@3.0.1: + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + + d3-ease@3.0.1: {} + + d3-fetch@3.0.1: + dependencies: + d3-dsv: 3.0.1 + + d3-force@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + + d3-format@3.1.2: {} + + d3-geo@3.1.1: + dependencies: + d3-array: 3.2.4 + + d3-hierarchy@3.1.2: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-path@1.0.9: {} + + d3-path@3.1.0: {} + + d3-polygon@3.0.1: {} + + d3-quadtree@3.0.1: {} + + d3-random@3.0.1: {} + + d3-sankey@0.12.3: + dependencies: + d3-array: 2.12.1 + d3-shape: 1.3.7 + + d3-scale-chromatic@3.1.0: + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + + d3-scale@4.0.2: + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.2 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + + d3-selection@3.0.0: {} + + d3-shape@1.3.7: + dependencies: + d3-path: 1.0.9 + + d3-shape@3.2.0: + dependencies: + d3-path: 3.1.0 + + d3-time-format@4.1.0: + dependencies: + d3-time: 3.1.0 + + d3-time@3.1.0: + dependencies: + d3-array: 3.2.4 + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + d3@7.9.0: + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.2 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1(d3-selection@3.0.0) + d3-zoom: 3.0.0 + + dagre-d3-es@7.0.14: + dependencies: + d3: 7.9.0 + lodash-es: 4.17.23 + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + dayjs@1.11.19: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-lazy-prop@2.0.0: {} + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + defu@6.1.4: {} + + delaunator@5.0.1: + dependencies: + robust-predicates: 3.0.2 + + delegate-it@6.3.0: + dependencies: + typed-query-selector: 2.12.1 + + dequal@2.0.3: {} + + destr@2.0.5: {} + + detect-libc@2.1.2: {} + + devalue@5.6.3: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + didyoumean@1.2.2: {} + + diff@8.0.3: {} + + dlv@1.1.3: {} + + dom-serializer@1.4.1: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + + dom-serializer@2.0.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + + domelementtype@2.3.0: {} + + domhandler@4.3.1: + dependencies: + domelementtype: 2.3.0 + + domhandler@5.0.3: + dependencies: + domelementtype: 2.3.0 + + dompurify@3.3.2: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + domutils@2.8.0: + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + + domutils@3.2.2: + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + + dset@3.1.4: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer@0.1.1: {} + + duplexer@0.1.2: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.4 + + electron-to-chromium@1.5.307: {} + + emmet@2.4.11: + dependencies: + '@emmetio/abbreviation': 2.3.3 + '@emmetio/css-abbreviation': 2.1.8 + + emoji-regex@8.0.0: {} + + entities@2.2.0: {} + + entities@4.5.0: {} + + entities@6.0.1: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser-es@1.0.5: {} + + es-abstract@1.24.1: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.20 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.0.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esast-util-from-estree@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + unist-util-position-from-estree: 2.0.0 + + esast-util-from-js@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + acorn: 8.16.0 + esast-util-from-estree: 2.0.0 + vfile-message: 4.0.3 + + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + esprima@4.0.1: {} + + estree-util-attach-comments@3.0.0: + dependencies: + '@types/estree': 1.0.8 + + estree-util-build-jsx@3.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + estree-walker: 3.0.3 + + estree-util-is-identifier-name@3.0.0: {} + + estree-util-scope@1.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + + estree-util-to-js@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + astring: 1.9.0 + source-map: 0.7.6 + + estree-util-value-to-estree@3.5.0: + dependencies: + '@types/estree': 1.0.8 + + estree-util-visit@2.0.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/unist': 3.0.3 + + estree-walker@0.6.1: {} + + estree-walker@1.0.1: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + eventemitter3@4.0.7: {} + + eventemitter3@5.0.4: {} + + extend-shallow@2.0.1: + dependencies: + is-extendable: 0.1.1 + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + 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 + + fast-uri@3.1.0: {} + + fast-xml-builder@1.0.0: {} + + fast-xml-parser@5.4.1: + dependencies: + fast-xml-builder: 1.0.0 + strnum: 2.2.0 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + figures@1.7.0: + dependencies: + escape-string-regexp: 1.0.5 + object-assign: 4.1.1 + + filelist@1.0.6: + dependencies: + minimatch: 5.1.9 + + filesize@6.4.0: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-cache-dir@3.3.2: + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + flattie@1.1.1: {} + + focus-options-polyfill@1.6.0: {} + + fontace@0.4.1: + dependencies: + fontkitten: 1.0.3 + + fontkitten@1.0.3: + dependencies: + tiny-inflate: 1.0.3 + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + fraction.js@5.3.4: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + fuse.js@7.1.0: {} + + generator-function@2.0.1: {} + + generic-names@4.0.0: + dependencies: + loader-utils: 3.3.1 + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + 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@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + globalyzer@0.1.0: {} + + globby@16.1.1: + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + is-path-inside: 4.0.0 + slash: 5.1.0 + unicorn-magic: 0.4.0 + + globrex@0.1.2: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + gray-matter@4.0.3: + dependencies: + js-yaml: 3.14.2 + kind-of: 6.0.3 + section-matter: 1.0.0 + strip-bom-string: 1.0.0 + + gzip-size@3.0.0: + dependencies: + duplexer: 0.1.2 + + gzip-size@6.0.0: + dependencies: + duplexer: 0.1.2 + + h3@1.15.6: + dependencies: + cookie-es: 1.2.2 + crossws: 0.3.5 + defu: 6.1.4 + destr: 2.0.5 + iron-webcrypto: 1.2.1 + node-mock-http: 1.0.4 + radix3: 1.1.2 + ufo: 1.6.3 + uncrypto: 0.1.3 + + hachure-fill@0.5.2: {} + + has-ansi@2.0.0: + dependencies: + ansi-regex: 2.1.1 + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-from-dom@5.0.1: + dependencies: + '@types/hast': 3.0.4 + hastscript: 9.0.1 + web-namespaces: 2.0.1 + + hast-util-from-html-isomorphic@2.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-dom: 5.0.1 + hast-util-from-html: 2.0.3 + unist-util-remove-position: 5.0.0 + + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.3 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.3 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-heading-rank@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + 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-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.1 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-estree@3.1.3: + dependencies: + '@types/estree': 1.0.8 + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-attach-comments: 3.0.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + zwitch: 2.0.4 + transitivePeerDependencies: + - supports-color + + hast-util-to-html@9.0.5: + 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.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-string@3.0.1: + dependencies: + '@types/hast': 3.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + html-escaper@3.0.3: {} + + html-void-elements@3.0.0: {} + + http-cache-semantics@4.2.0: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + icss-replace-symbols@1.1.0: {} + + icss-utils@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + ignore@7.0.5: {} + + import-cwd@3.0.0: + dependencies: + import-from: 3.0.0 + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-from@3.0.0: + dependencies: + resolve-from: 5.0.0 + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + inline-style-parser@0.2.7: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + internmap@1.0.1: {} + + internmap@2.0.3: {} + + interpret@1.4.0: {} + + iron-webcrypto@1.2.1: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-decimal@2.0.1: {} + + is-docker@2.2.1: {} + + is-docker@3.0.0: {} + + is-extendable@0.1.1: {} + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-map@2.0.3: {} + + is-module@1.0.0: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-path-inside@4.0.0: {} + + is-plain-obj@4.1.0: {} + + is-reference@1.2.1: + dependencies: + '@types/estree': 1.0.8 + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + jake@10.9.4: + dependencies: + async: 3.2.6 + filelist: 1.0.6 + picocolors: 1.1.1 + + jest-worker@26.6.2: + dependencies: + '@types/node': 25.4.0 + merge-stream: 2.0.0 + supports-color: 7.2.0 + + jiti@1.21.7: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@1.0.0: {} + + json5@2.2.3: {} + + jsonc-parser@2.3.1: {} + + jsonc-parser@3.3.1: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + katex@0.16.38: + dependencies: + commander: 8.3.0 + + khroma@2.1.0: {} + + kind-of@6.0.3: {} + + kleur@4.1.5: {} + + langium@4.2.1: + dependencies: + chevrotain: 11.1.2 + chevrotain-allstar: 0.3.1(chevrotain@11.1.2) + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + + layout-base@1.0.2: {} + + layout-base@2.0.1: {} + + lightningcss-darwin-arm64@1.29.3: + optional: true + + lightningcss-darwin-x64@1.29.3: + optional: true + + lightningcss-freebsd-x64@1.29.3: + optional: true + + lightningcss-linux-arm-gnueabihf@1.29.3: + optional: true + + lightningcss-linux-arm64-gnu@1.29.3: + optional: true + + lightningcss-linux-arm64-musl@1.29.3: + optional: true + + lightningcss-linux-x64-gnu@1.29.3: + optional: true + + lightningcss-linux-x64-musl@1.29.3: + optional: true + + lightningcss-win32-arm64-msvc@1.29.3: + optional: true + + lightningcss-win32-x64-msvc@1.29.3: + optional: true + + lightningcss@1.29.3: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.3 + lightningcss-darwin-x64: 1.29.3 + lightningcss-freebsd-x64: 1.29.3 + lightningcss-linux-arm-gnueabihf: 1.29.3 + lightningcss-linux-arm64-gnu: 1.29.3 + lightningcss-linux-arm64-musl: 1.29.3 + lightningcss-linux-x64-gnu: 1.29.3 + lightningcss-linux-x64-musl: 1.29.3 + lightningcss-win32-arm64-msvc: 1.29.3 + lightningcss-win32-x64-msvc: 1.29.3 + optional: true + + lilconfig@2.1.0: {} + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + loader-utils@3.3.1: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash-es@4.17.23: {} + + lodash.camelcase@4.3.0: {} + + lodash.debounce@4.0.8: {} + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.uniq@4.5.0: {} + + longest-streak@3.1.0: {} + + lru-cache@11.2.6: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide@0.542.0: {} + + magic-string@0.25.9: + dependencies: + sourcemap-codec: 1.4.8 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + + make-dir@3.1.0: + dependencies: + semver: 6.3.1 + + markdown-extensions@2.0.0: {} + + markdown-table@3.0.4: {} + + marked@16.4.2: {} + + math-intrinsics@1.1.0: {} + + maxmin@2.1.0: + dependencies: + chalk: 1.1.3 + figures: 1.7.0 + gzip-size: 3.0.0 + pretty-bytes: 3.0.1 + + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-autolink-literal@2.0.1: + dependencies: + '@types/mdast': 4.0.4 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-find-and-replace: 3.0.2 + micromark-util-character: 2.1.1 + + mdast-util-gfm-footnote@2.1.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + micromark-util-normalize-identifier: 2.0.1 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-strikethrough@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-table@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + markdown-table: 3.0.4 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm-task-list-item@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-gfm@3.1.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-gfm-autolink-literal: 2.0.1 + mdast-util-gfm-footnote: 2.1.0 + mdast-util-gfm-strikethrough: 2.0.0 + mdast-util-gfm-table: 2.0.0 + mdast-util-gfm-task-list-item: 2.0.0 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-math@3.0.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx@3.0.0: + dependencies: + mdast-util-from-markdown: 2.0.3 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-newline-to-break@2.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-find-and-replace: 3.0.2 + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.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.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdast-util-toc@7.1.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/ungap__structured-clone': 1.2.0 + '@ungap/structured-clone': 1.3.0 + github-slugger: 2.0.0 + mdast-util-to-string: 4.0.0 + unist-util-is: 6.0.1 + unist-util-visit: 5.1.0 + + mdn-data@2.0.14: {} + + mdn-data@2.0.28: {} + + mdn-data@2.27.1: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + mermaid@11.13.0: + dependencies: + '@braintree/sanitize-url': 7.1.2 + '@iconify/utils': 3.1.0 + '@mermaid-js/parser': 1.0.1 + '@types/d3': 7.4.3 + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.1 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) + cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + d3: 7.9.0 + d3-sankey: 0.12.3 + dagre-d3-es: 7.0.14 + dayjs: 1.11.19 + dompurify: 3.3.2 + katex: 0.16.38 + khroma: 2.1.0 + lodash-es: 4.17.23 + marked: 16.4.2 + roughjs: 4.6.6 + stylis: 4.3.6 + ts-dedent: 2.2.0 + uuid: 11.1.0 + + microbundle@0.15.1: + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-proposal-class-properties': 7.12.1(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.29.0) + '@babel/preset-env': 7.29.0(@babel/core@7.29.0) + '@babel/preset-flow': 7.27.1(@babel/core@7.29.0) + '@babel/preset-react': 7.28.5(@babel/core@7.29.0) + '@rollup/plugin-alias': 3.1.9(rollup@2.80.0) + '@rollup/plugin-babel': 5.3.1(@babel/core@7.29.0)(rollup@2.80.0) + '@rollup/plugin-commonjs': 17.1.0(rollup@2.80.0) + '@rollup/plugin-json': 4.1.0(rollup@2.80.0) + '@rollup/plugin-node-resolve': 11.2.1(rollup@2.80.0) + '@surma/rollup-plugin-off-main-thread': 2.2.3 + asyncro: 3.0.0 + autoprefixer: 10.4.27(postcss@8.5.8) + babel-plugin-macros: 3.1.0 + babel-plugin-transform-async-to-promises: 0.8.18 + babel-plugin-transform-replace-expressions: 0.2.0(@babel/core@7.29.0) + brotli-size: 4.0.0 + builtin-modules: 3.3.0 + camelcase: 6.3.0 + escape-string-regexp: 4.0.0 + filesize: 6.4.0 + gzip-size: 6.0.0 + kleur: 4.1.5 + lodash.merge: 4.6.2 + postcss: 8.5.8 + pretty-bytes: 5.6.0 + rollup: 2.80.0 + rollup-plugin-bundle-size: 1.0.3 + rollup-plugin-postcss: 4.0.2(postcss@8.5.8) + rollup-plugin-terser: 7.0.2(rollup@2.80.0) + rollup-plugin-typescript2: 0.32.1(rollup@2.80.0)(typescript@4.9.5) + rollup-plugin-visualizer: 5.14.0(rollup@2.80.0) + sade: 1.8.1 + terser: 5.46.0 + tiny-glob: 0.2.9 + tslib: 2.8.1 + typescript: 4.9.5 + transitivePeerDependencies: + - '@types/babel__core' + - rolldown + - supports-color + - ts-node + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-autolink-literal@2.1.0: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-footnote@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-strikethrough@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-table@2.1.1: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm-tagfilter@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-gfm-task-list-item@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-gfm@3.0.0: + dependencies: + micromark-extension-gfm-autolink-literal: 2.1.0 + micromark-extension-gfm-footnote: 2.1.0 + micromark-extension-gfm-strikethrough: 2.1.0 + micromark-extension-gfm-table: 2.1.1 + micromark-extension-gfm-tagfilter: 2.0.0 + micromark-extension-gfm-task-list-item: 2.1.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-math@3.1.0: + dependencies: + '@types/katex': 0.16.8 + devlop: 1.1.0 + katex: 0.16.38 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-expression@3.0.1: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-extension-mdx-jsx@3.0.2: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + micromark-factory-mdx-expression: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-extension-mdx-md@2.0.0: + dependencies: + micromark-util-types: 2.0.2 + + micromark-extension-mdxjs-esm@3.0.0: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-extension-mdxjs@3.0.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + micromark-extension-mdx-expression: 3.0.1 + micromark-extension-mdx-jsx: 3.0.2 + micromark-extension-mdx-md: 2.0.0 + micromark-extension-mdxjs-esm: 3.0.0 + micromark-util-combine-extensions: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-mdx-expression@2.0.3: + dependencies: + '@types/estree': 1.0.8 + devlop: 1.1.0 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-events-to-acorn: 2.0.3 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-position-from-estree: 2.0.0 + vfile-message: 4.0.3 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-events-to-acorn@2.0.3: + dependencies: + '@types/estree': 1.0.8 + '@types/unist': 3.0.3 + devlop: 1.1.0 + estree-util-visit: 2.0.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + vfile-message: 4.0.3 + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + 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-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + miniflare@4.20260301.1: + dependencies: + '@cspotcode/source-map-support': 0.8.1 + sharp: 0.34.5 + undici: 7.18.2 + workerd: 1.20260301.1 + ws: 8.18.0 + youch: 4.1.0-beta.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.2 + + mlly@1.8.1: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + + morphdom@2.7.8: {} + + mri@1.2.0: {} + + mrmime@2.0.1: {} + + ms@2.1.3: {} + + muggle-string@0.4.1: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + neotraverse@0.6.18: {} + + nlcst-to-string@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + + node-fetch-native@1.6.7: {} + + node-mock-http@1.0.4: {} + + node-releases@2.0.36: {} + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + number-is-nan@1.0.1: {} + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + obug@2.1.1: {} + + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.3 + + ohash@2.0.11: {} + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.4: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.1.0 + regex-recursion: 6.0.2 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + + opencollective-postinstall@2.0.3: {} + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-finally@1.0.0: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@7.3.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-queue@6.6.2: + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + + p-queue@9.1.0: + dependencies: + eventemitter3: 5.0.4 + p-timeout: 7.0.1 + + p-timeout@3.2.0: + dependencies: + p-finally: 1.0.0 + + p-timeout@7.0.1: {} + + p-try@2.2.0: {} + + package-manager-detector@1.6.0: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + + path-browserify@1.0.1: {} + + path-data-parser@0.1.0: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-to-regexp@6.3.0: {} + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + piccolore@0.1.3: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pify@2.3.0: {} + + pify@5.0.0: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.1 + pathe: 2.0.3 + + points-on-curve@0.2.0: {} + + points-on-path@0.2.1: + dependencies: + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + + possible-typed-array-names@1.1.0: {} + + postcss-calc@8.2.4(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + postcss-value-parser: 4.2.0 + + postcss-colormin@5.3.1(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-convert-values@5.1.3(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-discard-comments@5.1.2(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-discard-duplicates@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-discard-empty@5.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-discard-overridden@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-import@15.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.11 + + postcss-js@4.1.0(postcss@8.5.8): + dependencies: + camelcase-css: 2.0.1 + postcss: 8.5.8 + + postcss-load-config@3.1.4(postcss@8.5.8): + dependencies: + lilconfig: 2.1.0 + yaml: 1.10.2 + optionalDependencies: + postcss: 8.5.8 + + postcss-load-config@4.0.2(postcss@8.5.8): + dependencies: + lilconfig: 3.1.3 + yaml: 2.8.2 + optionalDependencies: + postcss: 8.5.8 + + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.8)(yaml@2.8.2): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 1.21.7 + postcss: 8.5.8 + yaml: 2.8.2 + + postcss-merge-longhand@5.1.7(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + stylehacks: 5.1.1(postcss@8.5.8) + + postcss-merge-rules@5.1.4(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + cssnano-utils: 3.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + postcss-minify-font-values@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-minify-gradients@5.1.1(postcss@8.5.8): + dependencies: + colord: 2.9.3 + cssnano-utils: 3.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-minify-params@5.1.4(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + cssnano-utils: 3.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-minify-selectors@5.2.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + postcss-modules-extract-imports@3.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-modules-local-by-default@4.2.0(postcss@8.5.8): + dependencies: + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@3.2.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 7.1.1 + + postcss-modules-values@4.0.0(postcss@8.5.8): + dependencies: + icss-utils: 5.1.0(postcss@8.5.8) + postcss: 8.5.8 + + postcss-modules@4.3.1(postcss@8.5.8): + dependencies: + generic-names: 4.0.0 + icss-replace-symbols: 1.1.0 + lodash.camelcase: 4.3.0 + postcss: 8.5.8 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.8) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.8) + postcss-modules-scope: 3.2.1(postcss@8.5.8) + postcss-modules-values: 4.0.0(postcss@8.5.8) + string-hash: 1.1.3 + + postcss-nested@6.2.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + postcss-normalize-charset@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + + postcss-normalize-display-values@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-positions@5.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-repeat-style@5.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-string@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-unicode@5.1.1(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-url@5.1.0(postcss@8.5.8): + dependencies: + normalize-url: 6.1.0 + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-normalize-whitespace@5.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-ordered-values@5.1.3(postcss@8.5.8): + dependencies: + cssnano-utils: 3.1.0(postcss@8.5.8) + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + postcss-reduce-initial@5.1.2(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + caniuse-api: 3.0.0 + postcss: 8.5.8 + + postcss-reduce-transforms@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + + 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-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-svgo@5.1.0(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-value-parser: 4.2.0 + svgo: 2.8.2 + + postcss-unique-selectors@5.1.1(postcss@8.5.8): + dependencies: + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.8: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@2.8.8: {} + + prettier@3.8.1: {} + + pretty-bytes@3.0.1: + dependencies: + number-is-nan: 1.0.1 + + pretty-bytes@5.6.0: {} + + prismjs@1.30.0: {} + + promise.series@0.2.0: {} + + property-information@7.1.0: {} + + queue-microtask@1.2.3: {} + + radix3@1.1.2: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + read-cache@1.0.0: + dependencies: + pify: 2.3.0 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.1.2: {} + + readdirp@5.0.0: {} + + reading-time@1.5.0: {} + + rechoir@0.6.2: + dependencies: + resolve: 1.22.11 + + recma-build-jsx@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-build-jsx: 3.0.1 + vfile: 6.0.3 + + recma-jsx@1.0.1(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + estree-util-to-js: 2.0.0 + recma-parse: 1.0.0 + recma-stringify: 1.0.0 + unified: 11.0.5 + + recma-parse@1.0.0: + dependencies: + '@types/estree': 1.0.8 + esast-util-from-js: 2.0.1 + unified: 11.0.5 + vfile: 6.0.3 + + recma-stringify@1.0.0: + dependencies: + '@types/estree': 1.0.8 + estree-util-to-js: 2.0.0 + unified: 11.0.5 + vfile: 6.0.3 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regenerate-unicode-properties@10.2.2: + dependencies: + regenerate: 1.4.2 + + regenerate@1.4.2: {} + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + regexpu-core@6.4.0: + dependencies: + regenerate: 1.4.2 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 + unicode-match-property-ecmascript: 2.0.0 + unicode-match-property-value-ecmascript: 2.2.1 + + regjsgen@0.8.0: {} + + regjsparser@0.13.0: + dependencies: + jsesc: 3.1.0 + + rehype-autolink-headings@7.1.0: + dependencies: + '@types/hast': 3.0.4 + '@ungap/structured-clone': 1.3.0 + hast-util-heading-rank: 3.0.0 + hast-util-is-element: 3.0.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + rehype-katex@7.0.1: + dependencies: + '@types/hast': 3.0.4 + '@types/katex': 0.16.8 + hast-util-from-html-isomorphic: 2.0.0 + hast-util-to-text: 4.0.2 + katex: 0.16.38 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + + rehype-parse@9.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-from-html: 2.0.3 + unified: 11.0.5 + + rehype-raw@7.0.0: + dependencies: + '@types/hast': 3.0.4 + hast-util-raw: 9.1.0 + vfile: 6.0.3 + + rehype-recma@1.0.0: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + hast-util-to-estree: 3.1.3 + transitivePeerDependencies: + - supports-color + + 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.1.0 + + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + + rehype@13.0.2: + dependencies: + '@types/hast': 3.0.4 + rehype-parse: 9.0.1 + rehype-stringify: 10.0.1 + unified: 11.0.5 + + remark-breaks@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-newline-to-break: 2.0.0 + unified: 11.0.5 + + remark-gfm@4.0.1: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-gfm: 3.1.0 + micromark-extension-gfm: 3.0.0 + remark-parse: 11.0.0 + remark-stringify: 11.0.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-math@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-math: 3.0.0 + micromark-extension-math: 3.1.0 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-mdx@3.1.1: + dependencies: + mdast-util-mdx: 3.0.0 + micromark-extension-mdxjs: 3.0.0 + transitivePeerDependencies: + - supports-color + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-reading-time@2.1.0: + dependencies: + estree-util-is-identifier-name: 3.0.0 + estree-util-value-to-estree: 3.5.0 + reading-time: 1.5.0 + unist-util-visit: 5.1.0 + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.2: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + + remark-stringify@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-to-markdown: 2.1.2 + unified: 11.0.5 + + remark-toc@9.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-toc: 7.1.0 + + request-light@0.5.8: {} + + request-light@0.7.0: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + + retext-smartypants@6.2.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unist-util-visit: 5.1.0 + + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + + reusify@1.1.0: {} + + robust-predicates@3.0.2: {} + + rollup-plugin-bundle-size@1.0.3: + dependencies: + chalk: 1.1.3 + maxmin: 2.1.0 + + rollup-plugin-postcss@4.0.2(postcss@8.5.8): + dependencies: + chalk: 4.1.2 + concat-with-sourcemaps: 1.1.0 + cssnano: 5.1.15(postcss@8.5.8) + import-cwd: 3.0.0 + p-queue: 6.6.2 + pify: 5.0.0 + postcss: 8.5.8 + postcss-load-config: 3.1.4(postcss@8.5.8) + postcss-modules: 4.3.1(postcss@8.5.8) + promise.series: 0.2.0 + resolve: 1.22.11 + rollup-pluginutils: 2.8.2 + safe-identifier: 0.4.2 + style-inject: 0.3.0 + transitivePeerDependencies: + - ts-node + + rollup-plugin-terser@7.0.2(rollup@2.80.0): + dependencies: + '@babel/code-frame': 7.29.0 + jest-worker: 26.6.2 + rollup: 2.80.0 + serialize-javascript: 4.0.0 + terser: 5.46.0 + + rollup-plugin-typescript2@0.32.1(rollup@2.80.0)(typescript@4.9.5): + dependencies: + '@rollup/pluginutils': 4.2.1 + find-cache-dir: 3.3.2 + fs-extra: 10.1.0 + resolve: 1.22.11 + rollup: 2.80.0 + tslib: 2.8.1 + typescript: 4.9.5 + + rollup-plugin-visualizer@5.14.0(rollup@2.80.0): + dependencies: + open: 8.4.2 + picomatch: 4.0.3 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 2.80.0 + + rollup-pluginutils@2.8.2: + dependencies: + estree-walker: 0.6.1 + + rollup@2.80.0: + optionalDependencies: + fsevents: 2.3.3 + + rollup@4.59.0: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.59.0 + '@rollup/rollup-android-arm64': 4.59.0 + '@rollup/rollup-darwin-arm64': 4.59.0 + '@rollup/rollup-darwin-x64': 4.59.0 + '@rollup/rollup-freebsd-arm64': 4.59.0 + '@rollup/rollup-freebsd-x64': 4.59.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 + '@rollup/rollup-linux-arm-musleabihf': 4.59.0 + '@rollup/rollup-linux-arm64-gnu': 4.59.0 + '@rollup/rollup-linux-arm64-musl': 4.59.0 + '@rollup/rollup-linux-loong64-gnu': 4.59.0 + '@rollup/rollup-linux-loong64-musl': 4.59.0 + '@rollup/rollup-linux-ppc64-gnu': 4.59.0 + '@rollup/rollup-linux-ppc64-musl': 4.59.0 + '@rollup/rollup-linux-riscv64-gnu': 4.59.0 + '@rollup/rollup-linux-riscv64-musl': 4.59.0 + '@rollup/rollup-linux-s390x-gnu': 4.59.0 + '@rollup/rollup-linux-x64-gnu': 4.59.0 + '@rollup/rollup-linux-x64-musl': 4.59.0 + '@rollup/rollup-openbsd-x64': 4.59.0 + '@rollup/rollup-openharmony-arm64': 4.59.0 + '@rollup/rollup-win32-arm64-msvc': 4.59.0 + '@rollup/rollup-win32-ia32-msvc': 4.59.0 + '@rollup/rollup-win32-x64-gnu': 4.59.0 + '@rollup/rollup-win32-x64-msvc': 4.59.0 + fsevents: 2.3.3 + + roughjs@4.6.6: + dependencies: + hachure-fill: 0.5.2 + path-data-parser: 0.1.0 + points-on-curve: 0.2.0 + points-on-path: 0.2.1 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rw@1.3.3: {} + + sade@1.8.1: + dependencies: + mri: 1.2.0 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-identifier@0.4.2: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + sax@1.5.0: {} + + scrl@2.0.0: {} + + section-matter@1.0.0: + dependencies: + extend-shallow: 2.0.1 + kind-of: 6.0.3 + + semver@6.3.1: {} + + semver@7.7.4: {} + + serialize-javascript@4.0.0: + dependencies: + randombytes: 2.1.0 + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.7.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shelljs-live@0.0.5(shelljs@0.8.5): + dependencies: + cross-spawn: 7.0.6 + shelljs: 0.8.5 + + shelljs@0.8.5: + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + + shiki@4.0.2: + dependencies: + '@shikijs/core': 4.0.2 + '@shikijs/engine-javascript': 4.0.2 + '@shikijs/engine-oniguruma': 4.0.2 + '@shikijs/langs': 4.0.2 + '@shikijs/themes': 4.0.2 + '@shikijs/types': 4.0.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sisteransi@1.0.5: {} + + sitemap@9.0.1: + dependencies: + '@types/node': 24.12.0 + '@types/sax': 1.2.7 + arg: 5.0.2 + sax: 1.5.0 + + slash@3.0.0: {} + + slash@5.1.0: {} + + smol-toml@1.6.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + sourcemap-codec@1.4.8: {} + + space-separated-tokens@2.0.2: {} + + sprintf-js@1.0.3: {} + + stable@0.1.8: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + stream-replace-string@2.0.0: {} + + string-hash@1.1.3: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@3.0.1: + dependencies: + ansi-regex: 2.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom-string@1.0.0: {} + + strnum@2.2.0: {} + + style-inject@0.3.0: {} + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + stylehacks@5.1.1(postcss@8.5.8): + dependencies: + browserslist: 4.28.1 + postcss: 8.5.8 + postcss-selector-parser: 6.1.2 + + stylis@4.3.6: {} + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.15 + ts-interface-checker: 0.1.13 + + supports-color@10.2.2: {} + + supports-color@2.0.0: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svgo@2.8.2: + dependencies: + commander: 7.2.0 + css-select: 4.3.0 + css-tree: 1.1.3 + csso: 4.2.0 + picocolors: 1.1.1 + sax: 1.5.0 + stable: 0.1.8 + + svgo@4.0.1: + dependencies: + commander: 11.1.0 + css-select: 5.2.2 + css-tree: 3.2.1 + css-what: 6.2.2 + csso: 5.0.5 + picocolors: 1.1.1 + sax: 1.5.0 + + swup-morph-plugin@1.3.0(swup@4.8.3): + dependencies: + '@swup/plugin': 4.0.0 + morphdom: 2.7.8 + swup: 4.8.3 + + swup@4.8.3: + dependencies: + delegate-it: 6.3.0 + opencollective-postinstall: 2.0.3 + path-to-regexp: 6.3.0 + + tailwindcss@3.4.19(yaml@2.8.2): + 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.3 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.7 + lilconfig: 3.1.3 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.1 + postcss: 8.5.8 + postcss-import: 15.1.0(postcss@8.5.8) + postcss-js: 4.1.0(postcss@8.5.8) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.8)(yaml@2.8.2) + postcss-nested: 6.2.0(postcss@8.5.8) + postcss-selector-parser: 6.1.2 + resolve: 1.22.11 + sucrase: 3.35.1 + transitivePeerDependencies: + - tsx + - yaml + + terser@5.46.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + 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 + + tiny-inflate@1.0.3: {} + + tinyclip@0.1.12: {} + + tinyexec@1.0.2: {} + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + ts-dedent@2.2.0: {} + + ts-interface-checker@0.1.13: {} + + tsconfck@3.1.6(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 + + tslib@2.8.1: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typed-query-selector@2.12.1: {} + + typesafe-path@0.2.2: {} + + typescript-auto-import-cache@0.3.6: + dependencies: + semver: 7.7.4 + + typescript@4.9.5: {} + + typescript@5.9.3: {} + + ufo@1.6.3: {} + + ultrahtml@1.6.0: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + uncrypto@0.1.3: {} + + undici-types@7.16.0: {} + + undici-types@7.18.2: {} + + undici@7.18.2: {} + + unenv@2.0.0-rc.24: + dependencies: + pathe: 2.0.3 + + unicode-canonical-property-names-ecmascript@2.0.1: {} + + unicode-match-property-ecmascript@2.0.0: + dependencies: + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 + + unicode-match-property-value-ecmascript@2.2.1: {} + + unicode-property-aliases-ecmascript@2.2.0: {} + + unicorn-magic@0.4.0: {} + + 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 + + unifont@0.7.4: + dependencies: + css-tree: 3.2.1 + ofetch: 1.5.1 + ohash: 2.0.11 + + unist-util-find-after@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + + unist-util-position-from-estree@2.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-remove-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + universalify@2.0.1: {} + + unstorage@1.17.4: + dependencies: + anymatch: 3.1.3 + chokidar: 5.0.0 + destr: 2.0.5 + h3: 1.15.6 + lru-cache: 11.2.6 + node-fetch-native: 1.6.7 + ofetch: 1.5.1 + ufo: 1.6.3 + + update-browserslist-db@1.2.3(browserslist@4.28.1): + dependencies: + browserslist: 4.28.1 + escalade: 3.2.0 + picocolors: 1.1.1 + + util-deprecate@1.0.2: {} + + uuid@11.1.0: {} + + vfile-location@5.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile: 6.0.3 + + vfile-message@4.0.3: + 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.3 + + vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.46.0)(yaml@2.8.2): + dependencies: + esbuild: 0.27.3 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.8 + rollup: 4.59.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 25.4.0 + fsevents: 2.3.3 + jiti: 1.21.7 + lightningcss: 1.29.3 + terser: 5.46.0 + yaml: 2.8.2 + + vitefu@1.1.2(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.46.0)(yaml@2.8.2)): + optionalDependencies: + vite: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(lightningcss@1.29.3)(terser@5.46.0)(yaml@2.8.2) + + volar-service-css@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-css-languageservice: 6.3.10 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-emmet@0.0.70(@volar/language-service@2.4.28): + dependencies: + '@emmetio/css-parser': 0.4.1 + '@emmetio/html-matcher': 1.3.0 + '@vscode/emmet-helper': 2.11.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-html@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-html-languageservice: 5.6.2 + vscode-languageserver-textdocument: 1.0.12 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-prettier@0.0.70(@volar/language-service@2.4.28)(prettier@3.8.1): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + prettier: 3.8.1 + + volar-service-typescript-twoslash-queries@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-typescript@0.0.70(@volar/language-service@2.4.28): + dependencies: + path-browserify: 1.0.1 + semver: 7.7.4 + typescript-auto-import-cache: 0.3.6 + vscode-languageserver-textdocument: 1.0.12 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + volar-service-yaml@0.0.70(@volar/language-service@2.4.28): + dependencies: + vscode-uri: 3.1.0 + yaml-language-server: 1.20.0 + optionalDependencies: + '@volar/language-service': 2.4.28 + + vscode-css-languageservice@6.3.10: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-html-languageservice@5.6.2: + dependencies: + '@vscode/l10n': 0.0.18 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + + vscode-json-languageservice@4.1.8: + dependencies: + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.1.0 + + vscode-jsonrpc@8.2.0: {} + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.12: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + + vscode-uri@3.1.0: {} + + web-namespaces@2.0.1: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.20 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-pm-runs@1.1.0: {} + + which-typed-array@1.1.20: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + workerd@1.20260301.1: + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20260301.1 + '@cloudflare/workerd-darwin-arm64': 1.20260301.1 + '@cloudflare/workerd-linux-64': 1.20260301.1 + '@cloudflare/workerd-linux-arm64': 1.20260301.1 + '@cloudflare/workerd-windows-64': 1.20260301.1 + + wrangler@4.71.0: + dependencies: + '@cloudflare/kv-asset-handler': 0.4.2 + '@cloudflare/unenv-preset': 2.15.0(unenv@2.0.0-rc.24)(workerd@1.20260301.1) + blake3-wasm: 2.1.5 + esbuild: 0.27.3 + miniflare: 4.20260301.1 + path-to-regexp: 6.3.0 + unenv: 2.0.0-rc.24 + workerd: 1.20260301.1 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + ws@8.18.0: {} + + xxhash-wasm@1.1.0: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml-language-server@1.20.0: + dependencies: + '@vscode/l10n': 0.0.18 + ajv: 8.18.0 + ajv-draft-04: 1.0.0(ajv@8.18.0) + prettier: 3.8.1 + request-light: 0.5.8 + vscode-json-languageservice: 4.1.8 + vscode-languageserver: 9.0.1 + vscode-languageserver-textdocument: 1.0.12 + vscode-languageserver-types: 3.17.5 + vscode-uri: 3.1.0 + yaml: 2.7.1 + + yaml@1.10.2: {} + + yaml@2.7.1: {} + + yaml@2.8.2: {} + + yargs-parser@21.1.1: {} + + yargs-parser@22.0.0: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@1.2.2: {} + + youch-core@0.3.3: + dependencies: + '@poppinss/exception': 1.2.3 + error-stack-parser-es: 1.0.5 + + youch@4.1.0-beta.10: + dependencies: + '@poppinss/colors': 4.1.6 + '@poppinss/dumper': 0.6.5 + '@speed-highlight/core': 1.2.14 + cookie: 1.1.1 + youch-core: 0.3.3 + + zod@4.3.6: {} + + zwitch@2.0.4: {} diff --git a/public/docs/api-reference/code.png b/public/docs/api-reference/code.png new file mode 100644 index 0000000..1b80654 Binary files /dev/null and b/public/docs/api-reference/code.png differ diff --git a/public/docs/attachments/astro-modular-configuration.png b/public/docs/attachments/astro-modular-configuration.png new file mode 100644 index 0000000..227aa6d Binary files /dev/null and b/public/docs/attachments/astro-modular-configuration.png differ diff --git a/public/docs/attachments/astro-modular-configuration.webp b/public/docs/attachments/astro-modular-configuration.webp new file mode 100644 index 0000000..983ab69 Binary files /dev/null and b/public/docs/attachments/astro-modular-configuration.webp differ diff --git a/public/docs/attachments/obsidian-cover.png b/public/docs/attachments/obsidian-cover.png new file mode 100644 index 0000000..9e6287f Binary files /dev/null and b/public/docs/attachments/obsidian-cover.png differ diff --git a/public/docs/attachments/obsidian-cover.webp b/public/docs/attachments/obsidian-cover.webp new file mode 100644 index 0000000..8874d43 Binary files /dev/null and b/public/docs/attachments/obsidian-cover.webp differ diff --git a/public/docs/configuration/astro-modular-configuration.webp b/public/docs/configuration/astro-modular-configuration.webp new file mode 100644 index 0000000..405fb06 Binary files /dev/null and b/public/docs/configuration/astro-modular-configuration.webp differ diff --git a/public/docs/sourcetree-and-git-setup/sourcetree.png b/public/docs/sourcetree-and-git-setup/sourcetree.png new file mode 100644 index 0000000..befc8db Binary files /dev/null and b/public/docs/sourcetree-and-git-setup/sourcetree.png differ diff --git a/public/docs/sourcetree-and-git-setup/sourcetree.webp b/public/docs/sourcetree-and-git-setup/sourcetree.webp new file mode 100644 index 0000000..5addfcf Binary files /dev/null and b/public/docs/sourcetree-and-git-setup/sourcetree.webp differ diff --git a/public/docs/sourcetree-and-git/sourcetree.png b/public/docs/sourcetree-and-git/sourcetree.png new file mode 100644 index 0000000..befc8db Binary files /dev/null and b/public/docs/sourcetree-and-git/sourcetree.png differ diff --git a/public/favicon-dark.png b/public/favicon-dark.png new file mode 100644 index 0000000..77b25dd Binary files /dev/null and b/public/favicon-dark.png differ diff --git a/public/favicon-light.png b/public/favicon-light.png new file mode 100644 index 0000000..e7858be Binary files /dev/null and b/public/favicon-light.png differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..5b93ac3 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/graph/graph-data.json b/public/graph/graph-data.json new file mode 100644 index 0000000..77ed79f --- /dev/null +++ b/public/graph/graph-data.json @@ -0,0 +1,127 @@ +{ + "nodes": [ + { + "id": "formatting-reference", + "type": "post", + "title": "Formatting Reference", + "slug": "formatting-reference", + "connections": 13 + }, + { + "id": "getting-started", + "type": "post", + "title": "Getting Started", + "slug": "getting-started", + "connections": 6 + }, + { + "id": "obsidian-embeds-demo", + "type": "post", + "title": "Obsidian Embeds Demo", + "slug": "obsidian-embeds-demo", + "connections": 0 + }, + { + "id": "sample-folder-based-post", + "type": "post", + "title": "Sample Folder-Based Post", + "slug": "sample-folder-based-post", + "connections": 0 + }, + { + "id": "vault-cms-guide", + "type": "post", + "title": "Vault CMS Guide", + "slug": "vault-cms-guide", + "connections": 0 + } + ], + "connections": [ + { + "source": "formatting-reference", + "target": "getting-started", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "getting-started", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "sample-folder-based-post", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "vault-cms-guide", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "obsidian-embeds-demo", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "getting-started", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "getting-started", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "getting-started", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "obsidian-embeds-demo", + "type": "link" + }, + { + "source": "formatting-reference", + "target": "obsidian-embeds-demo", + "type": "link" + }, + { + "source": "getting-started", + "target": "vault-cms-guide", + "type": "link" + }, + { + "source": "getting-started", + "target": "formatting-reference", + "type": "link" + }, + { + "source": "getting-started", + "target": "vault-cms-guide", + "type": "link" + }, + { + "source": "getting-started", + "target": "formatting-reference", + "type": "link" + }, + { + "source": "getting-started", + "target": "vault-cms-guide", + "type": "link" + }, + { + "source": "getting-started", + "target": "formatting-reference", + "type": "link" + } + ], + "metadata": { + "totalPosts": 5, + "totalConnections": 16, + "maxNodesApplied": false, + "originalNodeCount": 5 + } +} \ No newline at end of file diff --git a/public/open-graph.png b/public/open-graph.png new file mode 100644 index 0000000..6190bb0 Binary files /dev/null and b/public/open-graph.png differ diff --git a/public/pages/attachments/water.png b/public/pages/attachments/water.png new file mode 100644 index 0000000..c9867f6 Binary files /dev/null and b/public/pages/attachments/water.png differ diff --git a/public/pages/attachments/water.webp b/public/pages/attachments/water.webp new file mode 100644 index 0000000..2ece9a6 Binary files /dev/null and b/public/pages/attachments/water.webp differ diff --git a/public/posts/advanced-folder-example/gallery-1.jpg b/public/posts/advanced-folder-example/gallery-1.jpg new file mode 100644 index 0000000..28a975f Binary files /dev/null and b/public/posts/advanced-folder-example/gallery-1.jpg differ diff --git a/public/posts/advanced-folder-example/gallery-2.jpg b/public/posts/advanced-folder-example/gallery-2.jpg new file mode 100644 index 0000000..e2cb559 Binary files /dev/null and b/public/posts/advanced-folder-example/gallery-2.jpg differ diff --git a/public/posts/advanced-folder-example/hero-image.jpg b/public/posts/advanced-folder-example/hero-image.jpg new file mode 100644 index 0000000..3386450 Binary files /dev/null and b/public/posts/advanced-folder-example/hero-image.jpg differ diff --git a/public/posts/another-folder-based-test/cover.png b/public/posts/another-folder-based-test/cover.png new file mode 100644 index 0000000..9822333 Binary files /dev/null and b/public/posts/another-folder-based-test/cover.png differ diff --git a/public/posts/another-folder-based-test/cover.webp b/public/posts/another-folder-based-test/cover.webp new file mode 100644 index 0000000..b07d591 Binary files /dev/null and b/public/posts/another-folder-based-test/cover.webp differ diff --git a/public/posts/attachments/autumn-leaves.webp b/public/posts/attachments/autumn-leaves.webp new file mode 100644 index 0000000..c536e6b Binary files /dev/null and b/public/posts/attachments/autumn-leaves.webp differ diff --git a/public/posts/attachments/city-skyline.webp b/public/posts/attachments/city-skyline.webp new file mode 100644 index 0000000..a356031 Binary files /dev/null and b/public/posts/attachments/city-skyline.webp differ diff --git a/public/posts/attachments/desert-sunset.webp b/public/posts/attachments/desert-sunset.webp new file mode 100644 index 0000000..7b68d43 Binary files /dev/null and b/public/posts/attachments/desert-sunset.webp differ diff --git a/public/posts/attachments/document.pdf b/public/posts/attachments/document.pdf new file mode 100644 index 0000000..f49b156 Binary files /dev/null and b/public/posts/attachments/document.pdf differ diff --git a/public/posts/attachments/forest-path.webp b/public/posts/attachments/forest-path.webp new file mode 100644 index 0000000..0a56336 Binary files /dev/null and b/public/posts/attachments/forest-path.webp differ diff --git a/public/posts/attachments/galaxy.png b/public/posts/attachments/galaxy.png new file mode 100644 index 0000000..97aabaa Binary files /dev/null and b/public/posts/attachments/galaxy.png differ diff --git a/public/posts/attachments/galaxy.webp b/public/posts/attachments/galaxy.webp new file mode 100644 index 0000000..2429cdb Binary files /dev/null and b/public/posts/attachments/galaxy.webp differ diff --git a/public/posts/attachments/mountain-landscape.webp b/public/posts/attachments/mountain-landscape.webp new file mode 100644 index 0000000..7b68d43 Binary files /dev/null and b/public/posts/attachments/mountain-landscape.webp differ diff --git a/public/posts/attachments/mountains-clouds.png b/public/posts/attachments/mountains-clouds.png new file mode 100644 index 0000000..23cb75b Binary files /dev/null and b/public/posts/attachments/mountains-clouds.png differ diff --git a/public/posts/attachments/mountains-clouds.webp b/public/posts/attachments/mountains-clouds.webp new file mode 100644 index 0000000..fea26f3 Binary files /dev/null and b/public/posts/attachments/mountains-clouds.webp differ diff --git a/public/posts/attachments/mountains.png b/public/posts/attachments/mountains.png new file mode 100644 index 0000000..15b0e93 Binary files /dev/null and b/public/posts/attachments/mountains.png differ diff --git a/public/posts/attachments/mountains.webp b/public/posts/attachments/mountains.webp new file mode 100644 index 0000000..6f76877 Binary files /dev/null and b/public/posts/attachments/mountains.webp differ diff --git a/public/posts/attachments/ocean-view.webp b/public/posts/attachments/ocean-view.webp new file mode 100644 index 0000000..37dbf7a Binary files /dev/null and b/public/posts/attachments/ocean-view.webp differ diff --git a/public/posts/attachments/sound.wav b/public/posts/attachments/sound.wav new file mode 100644 index 0000000..90649df Binary files /dev/null and b/public/posts/attachments/sound.wav differ diff --git a/public/posts/attachments/spring-flowers.webp b/public/posts/attachments/spring-flowers.webp new file mode 100644 index 0000000..2480721 Binary files /dev/null and b/public/posts/attachments/spring-flowers.webp differ diff --git a/public/posts/attachments/summer-beach.webp b/public/posts/attachments/summer-beach.webp new file mode 100644 index 0000000..5928a3a Binary files /dev/null and b/public/posts/attachments/summer-beach.webp differ diff --git a/public/posts/attachments/sunset.webp b/public/posts/attachments/sunset.webp new file mode 100644 index 0000000..716ef98 Binary files /dev/null and b/public/posts/attachments/sunset.webp differ diff --git a/public/posts/attachments/vault-cms-cover.webp b/public/posts/attachments/vault-cms-cover.webp new file mode 100644 index 0000000..d96d310 Binary files /dev/null and b/public/posts/attachments/vault-cms-cover.webp differ diff --git a/public/posts/attachments/video.mp4 b/public/posts/attachments/video.mp4 new file mode 100644 index 0000000..42c748c Binary files /dev/null and b/public/posts/attachments/video.mp4 differ diff --git a/public/posts/attachments/winter-landscape.webp b/public/posts/attachments/winter-landscape.webp new file mode 100644 index 0000000..e33903e Binary files /dev/null and b/public/posts/attachments/winter-landscape.webp differ diff --git a/public/posts/sample-folder-based-post/cover.png b/public/posts/sample-folder-based-post/cover.png new file mode 100644 index 0000000..b8cc42d Binary files /dev/null and b/public/posts/sample-folder-based-post/cover.png differ diff --git a/public/posts/sample-folder-based-post/cover.webp b/public/posts/sample-folder-based-post/cover.webp new file mode 100644 index 0000000..a3c6786 Binary files /dev/null and b/public/posts/sample-folder-based-post/cover.webp differ diff --git a/public/posts/sample-folder-based-post/forest.png b/public/posts/sample-folder-based-post/forest.png new file mode 100644 index 0000000..c8f72ac Binary files /dev/null and b/public/posts/sample-folder-based-post/forest.png differ diff --git a/public/posts/sample-folder-based-post/forest.webp b/public/posts/sample-folder-based-post/forest.webp new file mode 100644 index 0000000..52ed69f Binary files /dev/null and b/public/posts/sample-folder-based-post/forest.webp differ diff --git a/public/posts/sample-folder-based-post/lush-forest.webp b/public/posts/sample-folder-based-post/lush-forest.webp new file mode 100644 index 0000000..e426645 Binary files /dev/null and b/public/posts/sample-folder-based-post/lush-forest.webp differ diff --git a/public/posts/sample-folder-post/cover.jpg b/public/posts/sample-folder-post/cover.jpg new file mode 100644 index 0000000..3386450 Binary files /dev/null and b/public/posts/sample-folder-post/cover.jpg differ diff --git a/public/posts/sample-folder-post/cover.png b/public/posts/sample-folder-post/cover.png new file mode 100644 index 0000000..b8cc42d Binary files /dev/null and b/public/posts/sample-folder-post/cover.png differ diff --git a/public/posts/sample-folder-post/forest.png b/public/posts/sample-folder-post/forest.png new file mode 100644 index 0000000..c8f72ac Binary files /dev/null and b/public/posts/sample-folder-post/forest.png differ diff --git a/public/posts/sample-folder-post/sample-image.jpg b/public/posts/sample-folder-post/sample-image.jpg new file mode 100644 index 0000000..3386450 Binary files /dev/null and b/public/posts/sample-folder-post/sample-image.jpg differ diff --git a/public/profile.jpg b/public/profile.jpg new file mode 100644 index 0000000..4d0c18d Binary files /dev/null and b/public/profile.jpg differ diff --git a/public/projects/another-project/hero.png b/public/projects/another-project/hero.png new file mode 100644 index 0000000..85cd82e Binary files /dev/null and b/public/projects/another-project/hero.png differ diff --git a/public/projects/attachments/rock.png b/public/projects/attachments/rock.png new file mode 100644 index 0000000..656db11 Binary files /dev/null and b/public/projects/attachments/rock.png differ diff --git a/public/projects/attachments/rock.webp b/public/projects/attachments/rock.webp new file mode 100644 index 0000000..a094f87 Binary files /dev/null and b/public/projects/attachments/rock.webp differ diff --git a/public/projects/obsidian-astro-suite/glacier.png b/public/projects/obsidian-astro-suite/glacier.png new file mode 100644 index 0000000..d75ce02 Binary files /dev/null and b/public/projects/obsidian-astro-suite/glacier.png differ diff --git a/public/projects/obsidian-astro-suite/glacier.webp b/public/projects/obsidian-astro-suite/glacier.webp new file mode 100644 index 0000000..b714fa6 Binary files /dev/null and b/public/projects/obsidian-astro-suite/glacier.webp differ diff --git a/public/projects/vault-cms/glacier.webp b/public/projects/vault-cms/glacier.webp new file mode 100644 index 0000000..b714fa6 Binary files /dev/null and b/public/projects/vault-cms/glacier.webp differ diff --git a/public/scripts/category-filtering.js b/public/scripts/category-filtering.js new file mode 100644 index 0000000..555b5ab --- /dev/null +++ b/public/scripts/category-filtering.js @@ -0,0 +1,99 @@ +/** + * Category Filtering Script for Projects Page + * Handles clickable category pills to filter project cards + */ + +function initializeCategoryFiltering() { + const categoryItems = document.querySelectorAll('.category-item'); + const projectCards = document.querySelectorAll('[data-project-categories]'); + let currentActiveCategory = null; + + if (categoryItems.length === 0) { + return; + } + + // Remove existing event listeners and add new ones + categoryItems.forEach((item, index) => { + // Clone the element to remove all event listeners + const newItem = item.cloneNode(true); + item.parentNode?.replaceChild(newItem, item); + + newItem.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + + const category = newItem.getAttribute('data-category'); + + // Visual feedback + newItem.style.transform = 'scale(0.95)'; + setTimeout(() => { + newItem.style.transform = ''; + }, 150); + + if (!category) return; + + // Check if this category is already active + const isCurrentlyActive = currentActiveCategory === category; + + // Reset all buttons to inactive state + categoryItems.forEach(btn => { + btn.classList.remove('bg-highlight-100', 'dark:bg-highlight-900/40', 'text-highlight-800', 'dark:text-highlight-200', 'ring-1', 'ring-highlight-300', 'dark:ring-highlight-700'); + btn.classList.add('bg-primary-100', 'dark:bg-primary-800', 'text-primary-700', 'dark:text-primary-300'); + }); + + if (isCurrentlyActive) { + // If clicking the same category, show all projects + projectCards.forEach(card => { + card.style.display = 'block'; + }); + currentActiveCategory = null; + } else { + // Filter projects by category + projectCards.forEach((card, cardIndex) => { + const cardCategories = card.getAttribute('data-project-categories') || ''; + + if (cardCategories.includes(category)) { + card.style.display = 'block'; + } else { + card.style.display = 'none'; + } + }); + + // Make clicked button active + newItem.classList.remove('bg-primary-100', 'dark:bg-primary-800', 'text-primary-700', 'dark:text-primary-300'); + newItem.classList.add('bg-highlight-100', 'dark:bg-highlight-900/40', 'text-highlight-800', 'dark:text-highlight-200', 'ring-1', 'ring-highlight-300', 'dark:ring-highlight-700'); + currentActiveCategory = category; + } + + // Dispatch custom event for analytics + window.dispatchEvent(new CustomEvent('categoryClicked', { + detail: { category, isActive: currentActiveCategory === category } + })); + }); + }); +} + +// Initialize with multiple strategies to ensure it works +function tryInitialize() { + initializeCategoryFiltering(); +} + +// Initialize on DOM ready +document.addEventListener('DOMContentLoaded', tryInitialize); + +// Re-initialize after Swup page transitions +document.addEventListener('swup:contentReplaced', tryInitialize); + +// Also try to initialize immediately in case DOM is already ready +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', tryInitialize); +} else { + // Use setTimeout to ensure DOM is fully ready + setTimeout(tryInitialize, 100); +} + +// Fallback: try again after a short delay +setTimeout(tryInitialize, 500); + +// Export for manual initialization if needed +window.initializeCategoryFiltering = initializeCategoryFiltering; diff --git a/scripts/check-missing-images.js b/scripts/check-missing-images.js new file mode 100644 index 0000000..a1fac74 --- /dev/null +++ b/scripts/check-missing-images.js @@ -0,0 +1,233 @@ +#!/usr/bin/env node + +/** + * Script to check for missing images in content + * Run with: node scripts/check-missing-images.js + */ + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const projectRoot = path.join(__dirname, '..'); + +// Get all markdown files in content directory +function getAllMarkdownFiles(dir) { + const files = []; + const items = fs.readdirSync(dir); + + for (const item of items) { + const fullPath = path.join(dir, item); + const stat = fs.statSync(fullPath); + + if (stat.isDirectory()) { + files.push(...getAllMarkdownFiles(fullPath)); + } else if (item.endsWith('.md')) { + files.push(fullPath); + } + } + + return files; +} + +// Extract image references from markdown content +function extractImageReferences(content) { + const images = []; + + // Match markdown images ![alt](src) + const markdownImages = content.match(/!\[([^\]]*)\]\(([^)]+)\)/g) || []; + for (const match of markdownImages) { + const src = match.match(/!\[[^\]]*\]\(([^)]+)\)/)[1]; + images.push({ type: 'markdown', src, line: content.substring(0, content.indexOf(match)).split('\n').length }); + } + + // Match wikilink images ![[src]] + const wikilinkImages = content.match(/!\[\[([^\]]+)\]\]/g) || []; + for (const match of wikilinkImages) { + const src = match.match(/!\[\[([^\]]+)\]\]/)[1]; + images.push({ type: 'wikilink', src, line: content.substring(0, content.indexOf(match)).split('\n').length }); + } + + // Match frontmatter images + const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/); + if (frontmatterMatch) { + const frontmatter = frontmatterMatch[1]; + const imageMatch = frontmatter.match(/^image:\s*["']?([^"'\n]+)["']?/m); + if (imageMatch) { + images.push({ type: 'frontmatter', src: imageMatch[1], line: 1 }); + } + } + + return images; +} + +// Check if image exists +function checkImageExists(imageSrc, filePath) { + // Handle different image path formats + let imagePath = imageSrc; + + // Remove Obsidian brackets + if (imagePath.startsWith('[[') && imagePath.endsWith(']]')) { + imagePath = imagePath.slice(2, -2); + } + + // Determine content type and folder structure + const isPostsFile = filePath.includes('posts'); + const isPagesFile = filePath.includes('pages'); + const isProjectsFile = filePath.includes('projects'); + const isDocsFile = filePath.includes('docs'); + const isFolderBasedPost = filePath.endsWith('index.md') && isPostsFile; + const isFolderBasedProject = filePath.endsWith('index.md') && isProjectsFile; + const isFolderBasedDoc = filePath.endsWith('index.md') && isDocsFile; + + // 1. Check in the same folder as the markdown file (for folder-based content) + if (isFolderBasedPost || isFolderBasedProject || isFolderBasedDoc) { + const contentDir = path.dirname(filePath); + const sameFolderPath = path.join(contentDir, imagePath); + if (fs.existsSync(sameFolderPath)) { + return { exists: true, path: sameFolderPath }; + } + + // Check in /attachments/ subfolder within the content folder + const imagesSubfolderPath = path.join(contentDir, 'images', imagePath); + if (fs.existsSync(imagesSubfolderPath)) { + return { exists: true, path: imagesSubfolderPath }; + } + } + + // 2. Check in general images directory for each content type + if (isPostsFile) { + const generalImagesPath = path.join(projectRoot, 'src', 'content', 'posts', 'images', imagePath); + if (fs.existsSync(generalImagesPath)) { + return { exists: true, path: generalImagesPath }; + } + } + + if (isPagesFile) { + const generalImagesPath = path.join(projectRoot, 'src', 'content', 'pages', 'images', imagePath); + if (fs.existsSync(generalImagesPath)) { + return { exists: true, path: generalImagesPath }; + } + } + + if (isProjectsFile) { + const generalImagesPath = path.join(projectRoot, 'src', 'content', 'projects', 'images', imagePath); + if (fs.existsSync(generalImagesPath)) { + return { exists: true, path: generalImagesPath }; + } + } + + if (isDocsFile) { + const generalImagesPath = path.join(projectRoot, 'src', 'content', 'docs', 'images', imagePath); + if (fs.existsSync(generalImagesPath)) { + return { exists: true, path: generalImagesPath }; + } + } + + // 3. Check in public directory (for synced images) + if (isFolderBasedPost) { + const postSlug = path.basename(path.dirname(filePath)); + const publicPath = path.join(projectRoot, 'public', 'posts', postSlug, imagePath); + if (fs.existsSync(publicPath)) { + return { exists: true, path: publicPath }; + } + } + + if (isFolderBasedProject) { + const projectSlug = path.basename(path.dirname(filePath)); + const publicPath = path.join(projectRoot, 'public', 'projects', projectSlug, imagePath); + if (fs.existsSync(publicPath)) { + return { exists: true, path: publicPath }; + } + } + + if (isFolderBasedDoc) { + const docSlug = path.basename(path.dirname(filePath)); + const publicPath = path.join(projectRoot, 'public', 'docs', docSlug, imagePath); + if (fs.existsSync(publicPath)) { + return { exists: true, path: publicPath }; + } + } + + // Handle absolute paths (starting with /) + if (imagePath.startsWith('/')) { + const publicPath = path.join(projectRoot, 'public', imagePath); + if (fs.existsSync(publicPath)) { + return { exists: true, path: publicPath }; + } + } + + // Handle relative paths from public directory + const publicPath = path.join(projectRoot, 'public', imagePath); + if (fs.existsSync(publicPath)) { + return { exists: true, path: publicPath }; + } + + // Handle external URLs (don't check these) + if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) { + return { exists: true, path: imagePath }; + } + + return { exists: false, path: imagePath }; +} + +// Main function +function main() { + console.log('🔍 Checking for missing images...\n'); + + const contentDir = path.join(projectRoot, 'src', 'content'); + const markdownFiles = getAllMarkdownFiles(contentDir); + + let totalImages = 0; + let missingImages = 0; + const missingImageDetails = []; + + for (const filePath of markdownFiles) { + const content = fs.readFileSync(filePath, 'utf-8'); + const images = extractImageReferences(content); + + for (const image of images) { + totalImages++; + const result = checkImageExists(image.src, filePath); + + if (!result.exists) { + missingImages++; + const relativePath = path.relative(projectRoot, filePath); + missingImageDetails.push({ + file: relativePath, + line: image.line, + type: image.type, + src: image.src, + expectedPath: result.path + }); + } + } + } + + // Report results + console.log(`📊 Summary:`); + console.log(` Total images: ${totalImages}`); + console.log(` Missing images: ${missingImages}`); + console.log(` Found images: ${totalImages - missingImages}\n`); + + if (missingImages > 0) { + console.log('❌ Missing images:'); + for (const detail of missingImageDetails) { + console.log(` ${detail.file}:${detail.line} (${detail.type})`); + console.log(` ${detail.src}`); + console.log(` Expected: ${detail.expectedPath}\n`); + } + + console.log('💡 Tips:'); + console.log(' - In development mode, missing images will show placeholder images'); + console.log(' - Check if images are in the correct folder for folder-based posts'); + console.log(' - Verify image paths match exactly (case-sensitive)'); + console.log(' - For Obsidian wikilinks, ensure the image exists in the same folder'); + } else { + console.log('✅ All images found!'); + } +} + +main(); diff --git a/scripts/dev-with-port.js b/scripts/dev-with-port.js new file mode 100644 index 0000000..6da9974 --- /dev/null +++ b/scripts/dev-with-port.js @@ -0,0 +1,80 @@ +/** + * Astro server launcher with automatic port detection + * Checks if port 5000 is available, falls back to 5001 if occupied + * Supports both 'dev' and 'preview' commands + */ + +import { spawn } from 'node:child_process'; +import { createServer } from 'node:net'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.resolve(__dirname, '..'); + +function checkPort(port) { + return new Promise((resolve) => { + const server = createServer(); + + server.listen(port, () => { + server.once('close', () => { + resolve(true); // Port is available + }); + server.close(); + }); + + server.on('error', () => { + resolve(false); // Port is occupied + }); + }); +} + +async function getAvailablePort() { + const port5000Available = await checkPort(5000); + + if (port5000Available) { + return 5000; + } else { + // Port 5000 is occupied (likely AirPlay on macOS) + console.log('⚠️ Port 5000 is occupied, using port 5001 instead'); + return 5001; + } +} + +async function main() { + // Get command from first argument (defaults to 'dev') + const command = process.argv[2] || 'dev'; + + if (!['dev', 'preview'].includes(command)) { + console.error(`Invalid command: ${command}. Must be 'dev' or 'preview'.`); + process.exit(1); + } + + const port = await getAvailablePort(); + + // Use pnpm exec to ensure we use the local Astro installation + // On Windows, use 'pnpm.cmd', on Unix use 'pnpm' + const pnpmCmd = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'; + + // Spawn astro with the detected port + const astroProcess = spawn(pnpmCmd, ['exec', 'astro', command, '--host', '0.0.0.0', '--port', port.toString()], { + cwd: projectRoot, + stdio: 'inherit', + shell: true + }); + + astroProcess.on('error', (error) => { + console.error(`Failed to start Astro ${command} server:`, error); + process.exit(1); + }); + + astroProcess.on('exit', (code) => { + process.exit(code || 0); + }); +} + +main().catch((error) => { + console.error('Error:', error); + process.exit(1); +}); + diff --git a/scripts/generate-deployment-config.js b/scripts/generate-deployment-config.js new file mode 100644 index 0000000..40c86e9 --- /dev/null +++ b/scripts/generate-deployment-config.js @@ -0,0 +1,955 @@ +#!/usr/bin/env node + +import { promises as fs } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Simple logging utility +const isDev = process.env.NODE_ENV !== 'production'; +const log = { + info: (...args) => isDev && console.log(...args), + error: (...args) => console.error(...args), + warn: (...args) => console.warn(...args) +}; + +// Import deployment platform helper +import getDeploymentPlatform from './get-deployment-platform.js'; + +// Deployment platform configuration - use config if no env var is set +const DEPLOYMENT_PLATFORM = process.env.DEPLOYMENT_PLATFORM || getDeploymentPlatform(); +const DRY_RUN = process.argv.includes('--dry-run'); +const VALIDATE_ONLY = process.argv.includes('--validate'); + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Define content directories to process +const CONTENT_DIRS = [ + 'src/content/pages', + 'src/content/posts', + 'src/content/projects', + 'src/content/docs' +]; + +// Function to parse frontmatter from markdown content +function parseFrontmatter(content) { + const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/; + const match = content.match(frontmatterRegex); + + if (!match) { + return { frontmatter: null, content: content }; + } + + const frontmatterText = match[1]; + const body = match[2]; + + // Parse YAML-like frontmatter (simple parser) + const frontmatter = {}; + const lines = frontmatterText.split('\n'); + let currentKey = null; + let currentValue = []; + let inArray = false; + + for (const line of lines) { + const trimmed = line.trim(); + + if (trimmed === '' || trimmed.startsWith('#')) { + continue; + } + + if (trimmed.includes(':') && (!inArray || !trimmed.startsWith(' '))) { + // Save previous key-value pair + if (currentKey) { + if (currentValue.length === 1) { + frontmatter[currentKey] = currentValue[0]; + } else { + frontmatter[currentKey] = currentValue; + } + } + + // Start new key-value pair + const colonIndex = trimmed.indexOf(':'); + currentKey = trimmed.substring(0, colonIndex).trim(); + const value = trimmed.substring(colonIndex + 1).trim(); + + // Reset array state when starting a new key + inArray = false; + + if (value.startsWith('[')) { + // Array value + inArray = true; + currentValue = []; + if (value !== '[') { + // Single line array + const arrayContent = value.substring(1, value.endsWith(']') ? value.length - 1 : value.length); + if (arrayContent.trim()) { + currentValue = arrayContent.split(',').map(item => item.trim().replace(/^["']|["']$/g, '')); + } + inArray = false; + } + } else if (value) { + // Single value + currentValue = [value.replace(/^["']|["']$/g, '')]; + } else { + // Empty value, might be start of array + currentValue = []; + inArray = true; + } + } else if (inArray && trimmed.startsWith('-')) { + // Array item + const item = trimmed.substring(1).trim().replace(/^["']|["']$/g, ''); + currentValue.push(item); + } else if (inArray && trimmed === ']') { + // End of array + inArray = false; + } else if (currentKey && !inArray) { + // Continuation of single value + currentValue = [currentValue[0] + ' ' + trimmed]; + } + } + + // Save last key-value pair + if (currentKey) { + if (currentValue.length === 1) { + frontmatter[currentKey] = currentValue[0]; + } else { + frontmatter[currentKey] = currentValue; + } + } + + return { frontmatter, content: body }; +} + +// Function to get the final URL for a content file +function getContentUrl(filePath, isPost = false) { + // Normalize path separators and extract the relevant part + const normalizedPath = filePath.replace(/\\/g, '/'); + + if (isPost) { + // For posts: extract path after 'src/content/posts/' and remove '.md' + let postPath = normalizedPath.replace(/^.*src\/content\/posts\//, '').replace(/\.md$/, ''); + // Handle folder-based content: remove '/index' suffix + if (postPath.endsWith('/index')) { + postPath = postPath.replace('/index', ''); + } + return `/posts/${postPath}`; + } else if (normalizedPath.includes('src/content/projects/')) { + // For projects: extract path after 'src/content/projects/' and remove '.md' + let projectPath = normalizedPath.replace(/^.*src\/content\/projects\//, '').replace(/\.md$/, ''); + // Handle folder-based content: remove '/index' suffix + if (projectPath.endsWith('/index')) { + projectPath = projectPath.replace('/index', ''); + } + return `/projects/${projectPath}`; + } else if (normalizedPath.includes('src/content/docs/')) { + // For docs: extract path after 'src/content/docs/' and remove '.md' + let docPath = normalizedPath.replace(/^.*src\/content\/docs\//, '').replace(/\.md$/, ''); + // Handle folder-based content: remove '/index' suffix + if (docPath.endsWith('/index')) { + docPath = docPath.replace('/index', ''); + } + return `/docs/${docPath}`; + } else { + // For pages: extract path after 'src/content/pages/' and remove '.md' + let pagePath = normalizedPath.replace(/^.*src\/content\/pages\//, '').replace(/\.md$/, ''); + // Handle folder-based content: remove '/index' suffix + if (pagePath.endsWith('/index')) { + pagePath = pagePath.replace('/index', ''); + } + if (pagePath === 'index') { + return '/'; + } + return `/${pagePath}`; + } +} + + + +// Function to process a single markdown file +async function processMarkdownFile(filePath, isPost = false) { + try { + const content = await fs.readFile(filePath, 'utf-8'); + const { frontmatter } = parseFrontmatter(content); + + if (!frontmatter || !frontmatter.aliases) { + return []; // No redirects to process + } + + // Ensure aliases is an array + const aliasesArray = Array.isArray(frontmatter.aliases) + ? frontmatter.aliases + : [frontmatter.aliases]; + + const targetUrl = getContentUrl(filePath, isPost); + const redirects = []; + + for (const alias of aliasesArray) { + const cleanAlias = alias.startsWith('/') ? alias.substring(1) : alias; + + // Normalize path separators for consistent checking + const normalizedFilePath = filePath.replace(/\\/g, '/'); + + // Determine redirect pattern based on content type + let redirectFrom; + if (isPost) { + // Posts: /posts/alias → /posts/actual-slug + redirectFrom = `/posts/${cleanAlias}`; + } else if (normalizedFilePath.includes('src/content/projects/')) { + // Projects: /projects/alias → /projects/actual-slug + redirectFrom = `/projects/${cleanAlias}`; + } else if (normalizedFilePath.includes('src/content/docs/')) { + // Docs: /docs/alias → /docs/actual-slug + redirectFrom = `/docs/${cleanAlias}`; + } else { + // Pages: /alias → /actual-slug + redirectFrom = `/${cleanAlias}`; + } + + // Skip self-redirects (redirecting to the same URL causes infinite loops) + if (redirectFrom !== targetUrl) { + redirects.push({ + from: redirectFrom, + to: targetUrl, + alias: cleanAlias + }); + } + } + + return redirects; + } catch (error) { + log.error(`❌ Error processing ${filePath}:`, error.message); + return []; + } +} + +// Function to process all markdown files in a directory +async function processDirectory(dirPath, isPost = false) { + try { + const files = await fs.readdir(dirPath, { withFileTypes: true }); + let allRedirects = []; + let processedFiles = 0; + + for (const file of files) { + if (file.isDirectory()) { + // Handle folder-based content (e.g., folder-name/index.md) + const folderPath = path.join(dirPath, file.name); + try { + const indexPath = path.join(folderPath, 'index.md'); + await fs.access(indexPath); + const redirects = await processMarkdownFile(indexPath, isPost); + allRedirects = allRedirects.concat(redirects); + if (redirects.length > 0) { + processedFiles++; + } + } catch (error) { + // index.md doesn't exist in this folder, skip + } + } else if (file.isFile() && file.name.endsWith('.md')) { + // Handle single-file content + const filePath = path.join(dirPath, file.name); + const redirects = await processMarkdownFile(filePath, isPost); + allRedirects = allRedirects.concat(redirects); + if (redirects.length > 0) { + processedFiles++; + } + } + } + + return { redirects: allRedirects, processedFiles }; + } catch (error) { + log.error(`❌ Error processing directory ${dirPath}:`, error.message); + return { redirects: [], processedFiles: 0 }; + } +} + +// Function to update astro.config.mjs with redirects (dev-only) +async function updateAstroConfig(redirects) { + const astroConfigPath = 'astro.config.mjs'; + + try { + let astroContent = await fs.readFile(astroConfigPath, 'utf-8'); + + // Create redirects object + const redirectsObj = {}; + for (const redirect of redirects) { + redirectsObj[redirect.from] = redirect.to; + } + + // Format redirects with conditional dev-only check + // Using process.env.NODE_ENV for reliable environment detection at config load time + const redirectsString = JSON.stringify(redirectsObj, null, 2).replace(/"/g, "'"); + const newRedirectsSection = `redirects: (process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'build') ? ${redirectsString} : {}`; + + // Remove ALL existing redirects entries (including any comments before them) + // This handles multiple redirects entries that may have been duplicated + // Match from optional comments + redirects: through the entire conditional expression + // Pattern: redirects: (condition) ? { object } : {}, + // Use [\s\S]*? to match any characters including newlines (non-greedy) + const redirectsRegex = /(\s*\/\/[^\n]*\n)*\s*redirects:\s*\([^)]+\)\s*\?\s*\{[\s\S]*?\}\s*:\s*\{\},\s*/g; + + // Remove all existing redirects entries (run multiple times to catch all duplicates) + let previousContent = ''; + while (previousContent !== astroContent) { + previousContent = astroContent; + astroContent = astroContent.replace(redirectsRegex, ''); + } + + // Add redirects after devToolbar config + const devToolbarRegex = /(devToolbar:\s*\{[^}]*\},)/; + if (devToolbarRegex.test(astroContent)) { + astroContent = astroContent.replace(devToolbarRegex, `$1\n ${newRedirectsSection},\n`); + } else { + // Fallback: add after deployment config if devToolbar not found + const deploymentRegex = /(deployment:\s*\{[^}]*\},)/; + if (deploymentRegex.test(astroContent)) { + astroContent = astroContent.replace(deploymentRegex, `$1\n ${newRedirectsSection},\n`); + } else { + // Last resort: add after site config + const siteRegex = /(site:\s*[^,]+),/; + astroContent = astroContent.replace(siteRegex, `$1,\n ${newRedirectsSection},\n`); + } + } + + await fs.writeFile(astroConfigPath, astroContent, 'utf-8'); + log.info(`📝 Updated astro.config.mjs with ${redirects.length} redirects (dev-only)`); + } catch (error) { + log.error(`❌ Error updating astro.config.mjs:`, error.message); + } +} + + +// Platform-specific configuration generators +function generateVercelConfig(redirects) { + // Filter out self-redirects (redirecting to the same URL causes infinite loops) + const validRedirects = redirects.filter(redirect => redirect.from !== redirect.to); + + const config = { + redirects: validRedirects.map(redirect => ({ + source: redirect.from, + destination: redirect.to, + permanent: (redirect.status || 301) === 301 + })), + headers: [ + { + source: "/_assets/(.*)", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=31536000, immutable" + } + ] + }, + { + source: "/(.*\\.(webp|jpg|jpeg|png|gif|svg))", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=31536000, immutable" + } + ] + }, + { + source: "/(.*\\.pdf)", + headers: [ + { + key: "Cache-Control", + value: "public, max-age=3600" + }, + { + key: "X-Frame-Options", + value: "SAMEORIGIN" + } + ] + }, + { + source: "/(.*)", + headers: [ + { + key: "Content-Security-Policy", + value: "default-src 'self'; script-src 'self' 'unsafe-inline' https://unpkg.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://giscus.app https://platform.twitter.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; img-src 'self' data: https:; connect-src 'self' https://giscus.app; frame-src 'self' https://www.youtube.com https://giscus.app https://platform.twitter.com; object-src 'none'; base-uri 'self';" + } + ] + } + ] + }; + + return JSON.stringify(config, null, 2); +} + +function generateGitHubPagesConfig(redirects) { + // Filter out self-redirects (redirecting to the same URL causes infinite loops) + const validRedirects = redirects.filter(redirect => redirect.from !== redirect.to); + + // Note: Removed '!' suffix to avoid interstitial page - direct redirects like Netlify + const redirectLines = validRedirects.map(redirect => + `${redirect.from} ${redirect.to} ${redirect.status || 301}` + ); + + return redirectLines.join('\n') + '\n'; +} + +function generateNetlifyConfig(redirects) { + const redirectLines = []; + + // Filter out self-redirects (redirecting to the same URL causes infinite loops) + const validRedirects = redirects.filter(redirect => redirect.from !== redirect.to); + + for (const redirect of validRedirects) { + redirectLines.push('[[redirects]]'); + redirectLines.push(` from = "${redirect.from}"`); + redirectLines.push(` to = "${redirect.to}"`); + redirectLines.push(` status = ${redirect.status || 301}`); + redirectLines.push(' force = true'); + redirectLines.push(''); + } + + // Always add the catch-all 404 redirect at the end + redirectLines.push('[[redirects]]'); + redirectLines.push(' from = "/*"'); + redirectLines.push(' to = "/404"'); + redirectLines.push(' status = 404'); + + return redirectLines.join('\n'); +} + +function generateCloudflareWorkersConfig(projectName) { + // Get current date for compatibility_date + const today = new Date(); + const compatibilityDate = today.toISOString().split('T')[0]; + + // Generate Workers-compatible config (recommended by Cloudflare) + // Workers uses assets.directory instead of pages_build_output_dir + // See: https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/ + const configLines = []; + configLines.push(`name = "${projectName}"`); + configLines.push(`compatibility_date = "${compatibilityDate}"`); + configLines.push(``); + configLines.push(`[assets]`); + configLines.push(` directory = "./dist"`); + configLines.push(` not_found_handling = "404-page" # Serve custom 404 page from src/pages/404.astro`); + + return configLines.join('\n') + '\n'; +} + +// Clean up platform-specific files that don't match the selected platform +async function cleanupOtherPlatformFiles(currentPlatform) { + const projectRoot = path.join(__dirname, '..'); + + // Clean up GitHub Pages/Cloudflare Workers files if not using those platforms + // (Both platforms use the same _redirects and _headers format) + // These files should ONLY exist for github-pages and cloudflare-workers + if (currentPlatform !== 'github-pages' && currentPlatform !== 'cloudflare-workers') { + const sharedFiles = [ + path.join(projectRoot, 'public', '_redirects'), + path.join(projectRoot, 'public', '_headers') + ]; + + for (const file of sharedFiles) { + try { + await fs.access(file); + await fs.unlink(file); + log.info(`🧹 Removed ${path.basename(file)} (not needed for ${currentPlatform})`); + } catch (error) { + // File doesn't exist, nothing to clean up + } + } + } + + // Note: We don't remove vercel.json, netlify.toml, or wrangler.toml as they may contain + // custom configuration (serverless functions, environment variables, bindings, etc.) + // Only _redirects and _headers are platform-specific and should be cleaned up +} + +// Platform-specific file writers +async function writeVercelConfig(redirects) { + const projectRoot = path.join(__dirname, '..'); + const vercelJsonPath = path.join(projectRoot, 'vercel.json'); + + if (DRY_RUN) { + log.info('📝 [DRY RUN] Would generate vercel.json:'); + console.log(generateVercelConfig(redirects)); + return; + } + + try { + // Read existing vercel.json to preserve custom settings + let existingConfig = {}; + try { + const existingContent = await fs.readFile(vercelJsonPath, 'utf-8'); + existingConfig = JSON.parse(existingContent); + } catch (error) { + // File doesn't exist or is invalid JSON, create new one + } + + // Generate new redirects and headers + const newConfig = JSON.parse(generateVercelConfig(redirects)); + + // Merge configs - new redirects/headers override existing ones + const mergedConfig = { + ...existingConfig, + redirects: newConfig.redirects, + headers: newConfig.headers + }; + + await fs.writeFile(vercelJsonPath, JSON.stringify(mergedConfig, null, 2), 'utf-8'); + log.info(`📝 Updated vercel.json with ${redirects.length} redirects`); + } catch (error) { + log.error(`❌ Error updating vercel.json:`, error.message); + } +} + +async function writeGitHubPagesConfig(redirects) { + const projectRoot = path.join(__dirname, '..'); + const redirectsPath = path.join(projectRoot, 'public', '_redirects'); + const headersPath = path.join(projectRoot, 'public', '_headers'); + + if (DRY_RUN) { + log.info('📝 [DRY RUN] Would generate public/_redirects:'); + console.log(generateGitHubPagesConfig(redirects)); + return; + } + + try { + // Write redirects file + const config = generateGitHubPagesConfig(redirects); + await fs.writeFile(redirectsPath, config, 'utf-8'); + log.info(`📝 Updated public/_redirects with ${redirects.length} redirects`); + + // Write headers file (for GitHub Pages and Cloudflare Pages) + // Note: Custom headers require GitHub Pages on a paid plan or GitHub Enterprise + // Cloudflare Pages supports custom headers on all plans (including free tier) + const headersContent = `# Custom Headers for GitHub Pages / Cloudflare Pages +# Note: GitHub Pages requires paid plan for custom headers +# Cloudflare Pages supports custom headers on all plans + +# HTML files +/*.html + Cache-Control: public, max-age=3600, s-maxage=86400 + +# CSS files +/*.css + Cache-Control: public, max-age=31536000, immutable + +# JavaScript files +/*.js + Cache-Control: public, max-age=31536000, immutable + +# JSON files +/*.json + Cache-Control: public, max-age=3600 + +# XML files +/*.xml + Cache-Control: public, max-age=3600 + +# Text files +/*.txt + Cache-Control: public, max-age=3600 + +# Pre-compressed files +/*.gz + Content-Encoding: gzip + Cache-Control: public, max-age=31536000, immutable + +/*.br + Content-Encoding: br + Cache-Control: public, max-age=31536000, immutable + +# Static assets with long-term caching +/_assets/* + Cache-Control: public, max-age=31536000, immutable + +# WebP images +/*.webp + Cache-Control: public, max-age=31536000, immutable + +# Font files +/*.woff2 + Cache-Control: public, max-age=31536000, immutable + +/*.woff + Cache-Control: public, max-age=31536000, immutable + +/*.ttf + Cache-Control: public, max-age=31536000, immutable + +/*.eot + Cache-Control: public, max-age=31536000, immutable + +# Image files +/*.jpg + Cache-Control: public, max-age=31536000, immutable + +/*.jpeg + Cache-Control: public, max-age=31536000, immutable + +/*.png + Cache-Control: public, max-age=31536000, immutable + +/*.gif + Cache-Control: public, max-age=31536000, immutable + +/*.svg + Cache-Control: public, max-age=31536000, immutable + +/*.ico + Cache-Control: public, max-age=31536000, immutable + +# Favicon files +/favicon* + Cache-Control: public, max-age=31536000, immutable + +# All pages - Security headers and Content Security Policy +/* + X-Frame-Options: DENY + X-XSS-Protection: 1; mode=block + X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: camera=(), microphone=(), geolocation=() + Cross-Origin-Embedder-Policy: unsafe-none + Cross-Origin-Opener-Policy: same-origin + Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://unpkg.com https://cdnjs.cloudflare.com https://cdn.jsdelivr.net https://giscus.app https://platform.twitter.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; font-src 'self' data: https://fonts.gstatic.com https://cdnjs.cloudflare.com; img-src 'self' data: https:; connect-src 'self' https://giscus.app; frame-src 'self' https://www.youtube.com https://giscus.app https://platform.twitter.com; object-src 'none'; base-uri 'self'; + +# PDF files - allow iframe embedding (override X-Frame-Options for PDFs) +/*.pdf + Cache-Control: public, max-age=3600 + X-Frame-Options: SAMEORIGIN +`; + await fs.writeFile(headersPath, headersContent, 'utf-8'); + log.info(`📝 Created public/_headers for GitHub Pages / Cloudflare Pages`); + } catch (error) { + log.error(`❌ Error updating GitHub Pages config:`, error.message); + } +} + +async function writeNetlifyConfig(redirects) { + const projectRoot = path.join(__dirname, '..'); + const netlifyTomlPath = path.join(projectRoot, 'netlify.toml'); + + if (DRY_RUN) { + log.info('📝 [DRY RUN] Would generate netlify.toml:'); + console.log(generateNetlifyConfig(redirects)); + return; + } + + try { + // Read existing netlify.toml to preserve other settings + let existingContent = ''; + try { + existingContent = await fs.readFile(netlifyTomlPath, 'utf-8'); + } catch (error) { + // File doesn't exist, create new one + } + + // Split content at redirects section + const configLines = existingContent.split('[[redirects]]')[0].trim(); + const redirectConfig = generateNetlifyConfig(redirects); + + const newContent = configLines + '\n\n' + redirectConfig; + await fs.writeFile(netlifyTomlPath, newContent, 'utf-8'); + + log.info(`📝 Updated netlify.toml with ${redirects.length} redirects`); + } catch (error) { + log.error(`❌ Error updating netlify.toml:`, error.message); + } +} + +async function copyAssetsIgnoreFile() { + const projectRoot = path.join(__dirname, '..'); + const templatePath = path.join(projectRoot, '.assetsignore.template'); + const distPath = path.join(projectRoot, 'dist'); + const assetsIgnorePath = path.join(distPath, '.assetsignore'); + + if (DRY_RUN) { + log.info('📝 [DRY RUN] Would copy .assetsignore.template to dist/.assetsignore'); + return; + } + + try { + // Check if template exists + try { + await fs.access(templatePath); + } catch (error) { + // Template doesn't exist, that's okay - skip copying (optional file) + return; + } + + // Check if dist directory exists + // Note: This script runs before Astro build, so dist may not exist yet + // That's okay - the file will be copied if dist exists, or can be added manually + try { + await fs.access(distPath); + + // dist exists, copy the file + const templateContent = await fs.readFile(templatePath, 'utf-8'); + await fs.writeFile(assetsIgnorePath, templateContent, 'utf-8'); + log.info('📝 Copied .assetsignore to dist/'); + } catch (error) { + // dist doesn't exist yet - that's fine, it will be created during Astro build + // The .assetsignore file is optional and mainly for safety + // Users can manually copy it to dist/ if needed, or it will be there on subsequent builds + } + } catch (error) { + // Non-critical error - just log it + log.warn(`⚠️ Could not copy .assetsignore file: ${error.message}`); + } +} + +async function writeCloudflareWorkersConfig(projectName) { + const projectRoot = path.join(__dirname, '..'); + const wranglerTomlPath = path.join(projectRoot, 'wrangler.toml'); + + if (DRY_RUN) { + log.info('📝 [DRY RUN] Would generate wrangler.toml:'); + console.log(generateCloudflareWorkersConfig(projectName)); + return; + } + + try { + // Read existing wrangler.toml to preserve custom settings + let existingContent = ''; + try { + existingContent = await fs.readFile(wranglerTomlPath, 'utf-8'); + } catch (error) { + // File doesn't exist, create new one + } + + // Generate new config with managed fields (Workers format) + const newConfig = generateCloudflareWorkersConfig(projectName); + + if (existingContent) { + // Update only the fields we manage while preserving everything else + // Migrate from Pages format (pages_build_output_dir) to Workers format (assets.directory) + let updatedContent = existingContent; + + // Update name field + updatedContent = updatedContent.replace(/^name\s*=\s*["'][^"']*["']/m, `name = "${projectName}"`); + if (!updatedContent.match(/^name\s*=/m)) { + // name doesn't exist, add it at the beginning + updatedContent = `name = "${projectName}"\n${updatedContent}`; + } + + // Migrate from Pages format to Workers format + // Remove old pages_build_output_dir if it exists + updatedContent = updatedContent.replace(/^pages_build_output_dir\s*=\s*["'][^"']*["']\s*\n?/m, ''); + + // Update or add assets.directory (Workers format) + if (updatedContent.match(/^\[assets\]/m)) { + // [assets] section exists, update directory + updatedContent = updatedContent.replace(/^(\[assets\]\s*\n\s*)directory\s*=\s*["'][^"']*["']/m, `$1directory = "./dist"`); + if (!updatedContent.match(/^\[assets\]\s*\n\s*directory\s*=/m)) { + // directory doesn't exist in [assets], add it + updatedContent = updatedContent.replace(/^(\[assets\]\s*\n)/m, `$1 directory = "./dist"\n`); + } + // Ensure not_found_handling is set + if (!updatedContent.match(/not_found_handling\s*=/m)) { + updatedContent = updatedContent.replace(/^(\[assets\]\s*\n\s*directory\s*=[^\n]+)/m, `$1\n not_found_handling = "404-page" # Serve custom 404 page from src/pages/404.astro`); + } + } else { + // [assets] section doesn't exist, add it after compatibility_date + const today = new Date(); + const compatibilityDate = today.toISOString().split('T')[0]; + updatedContent = updatedContent.replace(/^compatibility_date\s*=\s*["'][^"']*["']/m, `compatibility_date = "${compatibilityDate}"`); + if (!updatedContent.match(/^compatibility_date\s*=/m)) { + // compatibility_date doesn't exist, add both + updatedContent = updatedContent.replace(/^(name\s*=[^\n]+)/m, `$1\ncompatibility_date = "${compatibilityDate}"`); + } + // Add [assets] section + updatedContent = updatedContent.replace(/^(compatibility_date\s*=[^\n]+)/m, `$1\n\n[assets]\n directory = "./dist"\n not_found_handling = "404-page" # Serve custom 404 page from src/pages/404.astro`); + } + + // Update compatibility_date field + const today = new Date(); + const compatibilityDate = today.toISOString().split('T')[0]; + updatedContent = updatedContent.replace(/^compatibility_date\s*=\s*["'][^"']*["']/m, `compatibility_date = "${compatibilityDate}"`); + + // Remove old [build] section if it exists (not needed for Workers) + updatedContent = updatedContent.replace(/\n*\[build\]\s*\n\s*command\s*=\s*["'][^"']*["']\s*\n*/g, '\n'); + + await fs.writeFile(wranglerTomlPath, updatedContent, 'utf-8'); + log.info(`📝 Updated wrangler.toml (Workers format, preserved custom settings)`); + } else { + // File doesn't exist, create new one with Workers format + await fs.writeFile(wranglerTomlPath, newConfig, 'utf-8'); + log.info(`📝 Created wrangler.toml (Workers format)`); + } + } catch (error) { + log.error(`❌ Error updating wrangler.toml:`, error.message); + } +} + +// Validation functions +function validateVercelConfig(redirects) { + const config = JSON.parse(generateVercelConfig(redirects)); + + // Validate redirects + for (const redirect of config.redirects) { + if (!redirect.source || !redirect.destination) { + throw new Error(`Invalid Vercel redirect: ${JSON.stringify(redirect)}`); + } + } + + log.info('✅ Vercel configuration is valid'); + return true; +} + +function validateGitHubPagesConfig(redirects) { + const config = generateGitHubPagesConfig(redirects); + + // Basic validation - check format (no '!' suffix - direct redirects) + const lines = config.trim().split('\n'); + for (const line of lines) { + if (line.trim() && !line.match(/^[^\s]+\s+[^\s]+\s+\d+$/)) { + throw new Error(`Invalid GitHub Pages redirect format: ${line}`); + } + } + + log.info('✅ GitHub Pages configuration is valid'); + return true; +} + +function validateNetlifyConfig(redirects) { + const config = generateNetlifyConfig(redirects); + + // Basic validation - check TOML-like format + if (!config.includes('[[redirects]]')) { + throw new Error('Invalid Netlify configuration format'); + } + + log.info('✅ Netlify configuration is valid'); + return true; +} + +// Main function +async function generateRedirects() { + log.info(`🔄 Generating redirects from content aliases for ${DEPLOYMENT_PLATFORM}...`); + + if (VALIDATE_ONLY) { + log.info('🔍 Validation mode - checking all platform configurations...'); + } + + // Get project name from package.json for Cloudflare Workers + const projectRoot = path.join(__dirname, '..'); + let projectName = 'astro-modular'; + try { + const packageJsonPath = path.join(projectRoot, 'package.json'); + const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8')); + projectName = packageJson.name || 'astro-modular'; + } catch (error) { + // Use default if package.json can't be read + } + + let allRedirects = []; + let totalProcessedFiles = 0; + + // Process pages + const pagesPath = path.join(projectRoot, 'src/content/pages'); + try { + await fs.access(pagesPath); + const pageResult = await processDirectory(pagesPath, false); + allRedirects = allRedirects.concat(pageResult.redirects); + totalProcessedFiles += pageResult.processedFiles; + } catch (error) { + // Pages directory doesn't exist, skipping + } + + // Process posts + const postsPath = path.join(projectRoot, 'src/content/posts'); + try { + await fs.access(postsPath); + const postResult = await processDirectory(postsPath, true); + allRedirects = allRedirects.concat(postResult.redirects); + totalProcessedFiles += postResult.processedFiles; + } catch (error) { + // Posts directory doesn't exist, skipping + } + + // Process projects + const projectsPath = path.join(projectRoot, 'src/content/projects'); + try { + await fs.access(projectsPath); + const projectResult = await processDirectory(projectsPath, false); + allRedirects = allRedirects.concat(projectResult.redirects); + totalProcessedFiles += projectResult.processedFiles; + } catch (error) { + // Projects directory doesn't exist, skipping + } + + // Process docs + const docsPath = path.join(projectRoot, 'src/content/docs'); + try { + await fs.access(docsPath); + const docResult = await processDirectory(docsPath, false); + allRedirects = allRedirects.concat(docResult.redirects); + totalProcessedFiles += docResult.processedFiles; + } catch (error) { + // Docs directory doesn't exist, skipping + } + + if (allRedirects.length > 0) { + log.info(`📁 Processing pages directory...`); + log.info(`📁 Processing posts directory...`); + log.info(`📁 Processing projects directory...`); + log.info(`📁 Processing docs directory...`); + log.info(` Processed ${totalProcessedFiles} files with redirects`); + + // Update Astro config with redirects (only used in dev mode - instant HTTP redirects) + // In production builds, redirects are set to {} to prevent HTML meta refresh files + await updateAstroConfig(allRedirects); + + // Generate platform-specific configs + if (VALIDATE_ONLY) { + // Validate all platforms + validateVercelConfig(allRedirects); + validateGitHubPagesConfig(allRedirects); + validateNetlifyConfig(allRedirects); + log.info('🎉 All platform configurations are valid!'); + return; + } + + // Clean up files from other platforms before generating new config + // This ensures we only have config files for the selected platform + await cleanupOtherPlatformFiles(DEPLOYMENT_PLATFORM); + + // Write platform-specific config - only generate files needed for the selected platform + // IMPORTANT: We use platform-specific redirect files (HTTP redirects) for production + // Astro config redirects are only active in dev mode (instant HTTP redirects) + // In production builds, Astro redirects are set to {} to prevent HTML meta refresh files + switch (DEPLOYMENT_PLATFORM) { + case 'vercel': + // Vercel: Uses vercel.json for instant HTTP redirects + // No Astro config needed - Vercel handles redirects at edge level + await writeVercelConfig(allRedirects); + break; + case 'github-pages': + // GitHub Pages: Uses _redirects file for instant HTTP redirects + // No Astro config needed - would create slow meta refresh HTML files + await writeGitHubPagesConfig(allRedirects); + break; + case 'cloudflare-workers': + // Cloudflare Workers: Uses _redirects file for instant HTTP redirects + // See migration guide: https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/ + // No Astro config needed - would create slow meta refresh HTML files + // Generate Workers-compatible wrangler.toml (uses assets.directory instead of pages_build_output_dir) + await writeGitHubPagesConfig(allRedirects); // Uses same _redirects/_headers format + await writeCloudflareWorkersConfig(projectName); // Generate Workers-compatible config + await copyAssetsIgnoreFile(); // Copy .assetsignore to dist/ for Workers + break; + case 'netlify': + default: + // Netlify: Uses netlify.toml for instant HTTP redirects + // No Astro config needed - Netlify handles redirects at edge level + await writeNetlifyConfig(allRedirects); + break; + } + } + + if (DRY_RUN) { + log.info('🎉 [DRY RUN] Redirect generation complete! No files were modified.'); + } else { + log.info(`🎉 Redirect generation complete! Created ${allRedirects.length} redirects for ${DEPLOYMENT_PLATFORM}.`); + } +} + +// Run the script +generateRedirects(); diff --git a/scripts/generate-graph-data.js b/scripts/generate-graph-data.js new file mode 100644 index 0000000..c357f0e --- /dev/null +++ b/scripts/generate-graph-data.js @@ -0,0 +1,537 @@ +#!/usr/bin/env node + +/** + * Graph Data Generation Script + * + * This script generates graph data for the local graph feature by analyzing + * post connections (both wikilinks and standard links) and tag relationships. + * + * The generated data includes: + * - Post nodes with metadata (title, slug, date, tags) + * - Tag nodes with metadata (name, color) + * - Connections between posts (direct links) + * - Connections between posts and tags (shared tags) + * + * This data is used by the LocalGraph component to render an Obsidian-like graph view. + * + * ID Generation Strategy: + * - Uses path-based IDs (no frontmatter required) + * - Single files: "my-post.md" → ID: "my-post" + * - Folder-based: "my-folder/index.md" → ID: "my-folder" + * - Nested content: "category/my-post.md" → ID: "category-my-post" + */ + +import { + readFileSync, + writeFileSync, + mkdirSync, + existsSync, + readdirSync, + statSync, +} from "fs"; +import { join, dirname } from "path"; +import { fileURLToPath } from "url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const projectRoot = join(__dirname, ".."); + +// Configuration +const OUTPUT_DIR = join(projectRoot, "public", "graph"); +const OUTPUT_FILE = join(OUTPUT_DIR, "graph-data.json"); + +/** + * Read maxNodes from config file + */ +function getMaxNodesFromConfig() { + try { + const configPath = join(projectRoot, "src", "config.ts"); + const configContent = readFileSync(configPath, "utf-8"); + + // Extract maxNodes value from config + const maxNodesMatch = configContent.match(/maxNodes:\s*(\d+)/); + if (maxNodesMatch) { + return parseInt(maxNodesMatch[1], 10); + } + + // Default fallback + return 100; + } catch (error) { + log.warn("Could not read config file, using default maxNodes: 100"); + return 100; + } +} + +// Simple logging utility +const isDev = process.env.NODE_ENV !== "production" && !process.argv.includes("--production"); +const log = { + info: (...args) => isDev && console.log(...args), + error: (...args) => console.error(...args), + warn: (...args) => console.warn(...args), +}; + +// Ensure output directory exists +if (!existsSync(OUTPUT_DIR)) { + mkdirSync(OUTPUT_DIR, { recursive: true }); +} + +/** + * Generate a stable ID from file path + * @param {string} filePath - The file path + * @param {string} collectionType - The collection type (e.g., 'posts') + * @returns {string} - The generated ID + */ +function generateNodeId(filePath, collectionType) { + // Remove collection prefix and extension + let id = filePath.replace(`src/content/${collectionType}/`, ""); + id = id.replace(".md", ""); + id = id.replace("/index", ""); // Handle folder-based posts + + // Clean up the ID: lowercase, replace spaces/special chars with hyphens + id = id.toLowerCase().replace(/[^a-z0-9-]/g, "-"); + + // Remove multiple consecutive hyphens + id = id.replace(/-+/g, "-"); + + // Remove leading/trailing hyphens + id = id.replace(/^-+|-+$/g, ""); + + return id; +} + +/** + * Extract wikilinks from content (Obsidian-style) + */ +function extractWikilinks(content) { + const matches = []; + const wikilinkRegex = /!?\[\[([^\]]+)\]\]/g; + let match; + + while ((match = wikilinkRegex.exec(content)) !== null) { + const [fullMatch, linkContent] = match; + const isImageWikilink = fullMatch.startsWith("!"); + + // Skip image wikilinks, only process link wikilinks + if (!isImageWikilink) { + const [link, displayText] = linkContent.includes("|") + ? linkContent.split("|", 2) + : [linkContent, linkContent]; + + // Parse anchor if present + const anchorIndex = link.indexOf("#"); + const baseLink = + anchorIndex === -1 ? link : link.substring(0, anchorIndex); + + // Generate target ID from the link + const targetId = generateNodeId(baseLink, "posts"); + + matches.push({ + link: baseLink, + display: displayText.trim(), + slug: targetId, + }); + } + } + + return matches; +} + +/** + * Extract standard markdown links from content + */ +function extractStandardLinks(content) { + const matches = []; + const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g; + let match; + + while ((match = markdownLinkRegex.exec(content)) !== null) { + const [fullMatch, displayText, url] = match; + + // Check if this is an internal link + if (isInternalLink(url)) { + const { linkText } = extractLinkTextFromUrl(url); + if (linkText) { + // Only include posts in graph data - this includes: + // - posts/ prefixed links + // - /posts/ relative links + // - .md files (assumed to be posts) + // - Simple slugs (assumed to be posts for backward compatibility) + const isPostLink = + linkText.startsWith("posts/") || + url.startsWith("/posts/") || + url.startsWith("posts/") || + url.endsWith(".md") || + (!linkText.includes("/") && !url.startsWith("/")); + + if (isPostLink) { + // Generate target ID from the link + const targetId = generateNodeId(linkText, "posts"); + + matches.push({ + link: linkText, + display: displayText.trim(), + slug: targetId, + }); + } + } + } + } + + return matches; +} + +/** + * Check if a URL is an internal link + */ +function isInternalLink(url) { + url = url.trim(); + + // Skip external URLs + if (url.startsWith("http://") || url.startsWith("https://")) { + return false; + } + + // Skip email links + if (url.startsWith("mailto:")) { + return false; + } + + // Skip anchors only + if (url.startsWith("#")) { + return false; + } + + // Check if it's an internal link: + // - Ends with .md (markdown files) + // - Starts with /posts/ or posts/ (post relative URLs) + // - Is just a slug (no slashes) - assumes posts for backward compatibility + const isInternal = + url.endsWith(".md") || + url.startsWith("/posts/") || + url.startsWith("posts/") || + !url.includes("/"); + + return isInternal; +} + +/** + * Extract link text from URL + */ +function extractLinkTextFromUrl(url) { + url = url.trim(); + + // Parse anchor if present + const anchorIndex = url.indexOf("#"); + const link = anchorIndex === -1 ? url : url.substring(0, anchorIndex); + const anchor = anchorIndex === -1 ? null : url.substring(anchorIndex + 1); + + // Handle posts/ prefixed links + if (link.startsWith("posts/")) { + let linkText = link.replace("posts/", "").replace(/\.md$/, ""); + // Remove /index for folder-based posts + if (linkText.endsWith("/index") && linkText.split("/").length === 2) { + linkText = linkText.replace("/index", ""); + } + return { + linkText: linkText, + anchor: anchor, + }; + } + + // Handle /posts/ URLs (relative links) + if (link.startsWith("/posts/")) { + let linkText = link.replace("/posts/", "").replace(/\.md$/, ""); + // Remove /index for folder-based posts + if (linkText.endsWith("/index") && linkText.split("/").length === 2) { + linkText = linkText.replace("/index", ""); + } + return { + linkText: linkText, + anchor: anchor, + }; + } + + // Handle .md files + if (link.endsWith(".md")) { + let linkText = link.replace(/\.md$/, ""); + // Remove /index for folder-based posts + if (linkText.endsWith("/index") && linkText.split("/").length === 1) { + linkText = linkText.replace("/index", ""); + } + return { + linkText: linkText, + anchor: anchor, + }; + } + + // If it's just a slug (no slashes), use it directly + if (!link.includes("/")) { + return { + linkText: link, + anchor: anchor, + }; + } + + return { linkText: null, anchor: null }; +} + +/** + * Read and parse markdown files from content directory + */ +function readContentFiles(dirPath) { + const posts = []; + + try { + const items = readdirSync(dirPath); + + for (const item of items) { + const itemPath = join(dirPath, item); + const stat = statSync(itemPath); + + if (stat.isDirectory()) { + // Handle folder-based posts + const indexPath = join(itemPath, "index.md"); + if (existsSync(indexPath)) { + const content = readFileSync(indexPath, "utf-8"); + const parsed = parseMarkdownFile(content, item); + if (parsed) { + posts.push(parsed); + } + } + } else if (item.endsWith(".md")) { + // Handle single-file posts + const content = readFileSync(itemPath, "utf-8"); + const slug = item.replace(".md", ""); + const parsed = parseMarkdownFile(content, slug); + if (parsed) { + posts.push(parsed); + } + } + } + } catch (error) { + log.error("Error reading content directory:", error); + } + + return posts; +} + +/** + * Parse markdown file and extract frontmatter and content + */ +function parseMarkdownFile(content, slug) { + try { + // Extract frontmatter (handle both \n and \r\n line endings) + const frontmatterMatch = content.match( + /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/ + ); + if (!frontmatterMatch) { + return null; + } + + const [, frontmatter, body] = frontmatterMatch; + const lines = frontmatter.split(/\r?\n/); + const data = {}; + + // Parse frontmatter (improved YAML parser) + let currentKey = null; + let currentArray = []; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const trimmedLine = line.trim(); + + // Skip empty lines + if (!trimmedLine) continue; + + // Check if this is a key-value pair + const colonIndex = line.indexOf(":"); + if (colonIndex > 0 && !line.startsWith(" ")) { + // Save previous array if we have one + if (currentKey && currentArray.length > 0) { + data[currentKey] = [...currentArray]; + currentArray = []; + } + + const key = line.substring(0, colonIndex).trim(); + let value = line.substring(colonIndex + 1).trim(); + + // Remove quotes if present + if ( + (value.startsWith('"') && value.endsWith('"')) || + (value.startsWith("'") && value.endsWith("'")) + ) { + value = value.slice(1, -1); + } + + // Check if this is an array key (next line starts with dash) + if (i + 1 < lines.length && lines[i + 1].trim().startsWith("- ")) { + currentKey = key; + currentArray = []; + } else { + // Single value + if (key === "date") { + data[key] = new Date(value); + } else if (key === "draft") { + data[key] = value === "true"; + } else if ( + key === "imageOG" || + key === "hideCoverImage" || + key === "noIndex" || + key === "featured" + ) { + data[key] = value === "true"; + } else { + data[key] = value; + } + } + } else if (trimmedLine.startsWith("- ")) { + // This is an array item + const item = trimmedLine.substring(2).trim(); + currentArray.push(item); + } + } + + // Save final array if we have one + if (currentKey && currentArray.length > 0) { + data[currentKey] = [...currentArray]; + } + + return { + id: slug, + data, + body, + }; + } catch (error) { + log.warn(`Error parsing file ${slug}:`, error.message); + return null; + } +} + +/** + * Generate graph data from posts + */ +async function generateGraphData() { + log.info("🔍 Analyzing post connections..."); + + try { + // Get configuration values + const maxNodes = getMaxNodesFromConfig(); + + // Read all posts from the content directory + const postsDir = join(projectRoot, "src", "content", "posts"); + log.info("📁 Reading posts from:", postsDir); + + const posts = readContentFiles(postsDir); + log.info(`📄 Found ${posts.length} posts`); + + // Filter out draft posts in production + const isDev = process.env.NODE_ENV !== "production" && !process.argv.includes("--production"); + const visiblePosts = posts.filter((post) => isDev || !post.data.draft); + + log.info(`📄 Processing ${visiblePosts.length} visible posts`); + + // Generate nodes and connections + const nodes = []; + const connections = []; + + // Process each post + for (const post of visiblePosts) { + // Add post node + const postNode = { + id: post.id, + type: "post", + title: post.data.title, + slug: post.id, + date: post.data.date + ? post.data.date.toISOString() + : new Date().toISOString(), + connections: 0, + }; + nodes.push(postNode); + + // Extract links from post content + const wikilinks = extractWikilinks(post.body); + const standardLinks = extractStandardLinks(post.body); + const allLinks = [...wikilinks, ...standardLinks]; + + // Process links to other posts + for (const link of allLinks) { + const targetPost = visiblePosts.find((p) => p.id === link.slug); + if (targetPost && targetPost.id !== post.id) { + // Add post-to-post connection + connections.push({ + source: post.id, + target: targetPost.id, + type: "link", + }); + + // Update connection counts + postNode.connections++; + const targetNode = nodes.find((n) => n.id === targetPost.id); + if (targetNode) { + targetNode.connections++; + } + } + } + } + + // Apply maxNodes filtering if configured + let filteredNodes = nodes; + let filteredConnections = connections; + + if (maxNodes && nodes.length > maxNodes) { + // Sort posts by connection count (descending), then by date (descending) + const sortedPosts = nodes.sort((a, b) => { + if (b.connections !== a.connections) { + return b.connections - a.connections; + } + return new Date(b.date) - new Date(a.date); + }); + + filteredNodes = sortedPosts.slice(0, maxNodes); + + // Filter connections to only include those between selected nodes + const selectedNodeIds = new Set(filteredNodes.map((n) => n.id)); + filteredConnections = connections.filter( + (conn) => + selectedNodeIds.has(conn.source) && selectedNodeIds.has(conn.target) + ); + } + + // Remove date field from nodes before exporting (only needed for sorting) + const nodesForExport = filteredNodes.map(({ date, ...node }) => node); + + // Generate graph data + const graphData = { + nodes: nodesForExport, + connections: filteredConnections, + metadata: { + totalPosts: filteredNodes.length, + totalConnections: filteredConnections.length, + maxNodesApplied: maxNodes && nodes.length > maxNodes, + originalNodeCount: nodes.length, + }, + }; + + // Write graph data to file + writeFileSync(OUTPUT_FILE, JSON.stringify(graphData, null, 2)); + + log.info("✅ Graph data generated successfully!"); + if (graphData.metadata.maxNodesApplied) { + log.info( + `📊 Stats: ${graphData.metadata.totalPosts} posts, ${graphData.metadata.totalConnections} connections (filtered from ${graphData.metadata.originalNodeCount} total nodes)` + ); + } else { + log.info( + `📊 Stats: ${graphData.metadata.totalPosts} posts, ${graphData.metadata.totalConnections} connections` + ); + } + log.info(`💾 Saved to: ${OUTPUT_FILE}`); + } catch (error) { + log.error("❌ Error generating graph data:", error); + process.exit(1); + } +} + +// Run the script +generateGraphData(); diff --git a/scripts/get-deployment-platform.js b/scripts/get-deployment-platform.js new file mode 100644 index 0000000..aca5b42 --- /dev/null +++ b/scripts/get-deployment-platform.js @@ -0,0 +1,37 @@ +#!/usr/bin/env node + +/** + * Get deployment platform from config + * This script reads the deployment platform from src/config.ts + */ + +import { readFileSync } from 'fs'; +import { join } from 'path'; + +function getDeploymentPlatform() { + try { + const configPath = join(process.cwd(), 'src', 'config.ts'); + const configContent = readFileSync(configPath, 'utf8'); + + // Extract platform from config + const platformMatch = configContent.match(/platform:\s*["']([^"']+)["']/); + + if (platformMatch) { + return platformMatch[1]; + } + + // Fallback to environment variable + return process.env.DEPLOYMENT_PLATFORM || 'netlify'; + } catch (error) { + console.error('Error reading config:', error.message); + return process.env.DEPLOYMENT_PLATFORM || 'netlify'; + } +} + +// Export for use in other scripts +export default getDeploymentPlatform; + +// If run directly, output the platform +if (import.meta.url === `file://${process.argv[1]}`) { + console.log(getDeploymentPlatform()); +} \ No newline at end of file diff --git a/scripts/get-version.js b/scripts/get-version.js new file mode 100644 index 0000000..648ad31 --- /dev/null +++ b/scripts/get-version.js @@ -0,0 +1,73 @@ +#!/usr/bin/env node + +/** + * Get version information for Astro Modular theme + * This script provides version information for use in other scripts + */ + +import { readFileSync, writeFileSync } from 'fs'; +import { join } from 'path'; + +/** + * Get the current theme version + */ +export function getThemeVersion() { + try { + // Try to read from VERSION file first + const versionFile = join(process.cwd(), 'VERSION'); + const version = readFileSync(versionFile, 'utf8').trim(); + return version; + } catch (error) { + try { + // Fallback to package.json + const packageJson = JSON.parse(readFileSync('package.json', 'utf8')); + return packageJson.version || '0.1.0'; + } catch (error) { + return '0.1.0'; + } + } +} + +/** + * Get the theme name + */ +export function getThemeName() { + try { + const packageJson = JSON.parse(readFileSync('package.json', 'utf8')); + return packageJson.name || 'astro-modular'; + } catch (error) { + return 'astro-modular'; + } +} + +/** + * Get the full theme identifier (name@version) + */ +export function getThemeIdentifier() { + return `${getThemeName()}@${getThemeVersion()}`; +} + +/** + * Update the version in both VERSION file and package.json + */ +export function updateVersion(newVersion) { + try { + // Update VERSION file + writeFileSync('VERSION', newVersion + '\n'); + + // Update package.json + const packageJson = JSON.parse(readFileSync('package.json', 'utf8')); + packageJson.version = newVersion; + writeFileSync('package.json', JSON.stringify(packageJson, null, 2) + '\n'); + + return true; + } catch (error) { + console.error('Failed to update version:', error.message); + return false; + } +} + +// If run directly, output the version +if (process.argv[1] && process.argv[1].endsWith('get-version.js')) { + console.log(getThemeVersion()); +} diff --git a/scripts/process-aliases.js b/scripts/process-aliases.js new file mode 100644 index 0000000..7950498 --- /dev/null +++ b/scripts/process-aliases.js @@ -0,0 +1,337 @@ +#!/usr/bin/env node + +import { promises as fs } from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +// Simple logging utility +const isDev = process.env.NODE_ENV !== 'production'; +const log = { + info: (...args) => isDev && console.log(...args), + error: (...args) => console.error(...args), + warn: (...args) => console.warn(...args) +}; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Define content directories to process +const CONTENT_DIRS = [ + 'src/content/pages', + 'src/content/posts', + 'src/content/projects', + 'src/content/docs' +]; + +// Function to parse frontmatter from markdown content +function parseFrontmatter(content) { + const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/; + const match = content.match(frontmatterRegex); + + if (!match) { + return { frontmatter: null, content: content }; + } + + const frontmatterText = match[1]; + const body = match[2]; + + // Parse YAML-like frontmatter (simple parser) + const frontmatter = {}; + const lines = frontmatterText.split('\n'); + let currentKey = null; + let currentValue = []; + let inArray = false; + + for (const line of lines) { + const trimmed = line.trim(); + + if (trimmed === '' || trimmed.startsWith('#')) { + continue; + } + + if (trimmed.includes(':') && (!inArray || !trimmed.startsWith(' '))) { + // Save previous key-value pair + if (currentKey) { + if (currentValue.length === 1) { + frontmatter[currentKey] = currentValue[0]; + } else { + frontmatter[currentKey] = currentValue; + } + } + + // Start new key-value pair + const colonIndex = trimmed.indexOf(':'); + currentKey = trimmed.substring(0, colonIndex).trim(); + const value = trimmed.substring(colonIndex + 1).trim(); + + // Reset array state when starting a new key + inArray = false; + + if (value.startsWith('[')) { + // Array value + inArray = true; + currentValue = []; + if (value !== '[') { + // Single line array + const arrayContent = value.substring(1, value.endsWith(']') ? value.length - 1 : value.length); + if (arrayContent.trim()) { + currentValue = arrayContent.split(',').map(item => { + const trimmed = item.trim(); + if (trimmed.startsWith('"[[') && trimmed.endsWith(']]"')) { + // Keep quotes for Obsidian bracket syntax + return trimmed; + } else { + // Remove quotes for regular values + return trimmed.replace(/^["']|["']$/g, ''); + } + }); + } + inArray = false; + } + } else if (value) { + // Single value - preserve quotes for Obsidian bracket syntax + if (value.startsWith('"[[') && value.endsWith(']]"')) { + // Keep quotes for Obsidian bracket syntax + currentValue = [value]; + } else { + // Remove quotes for regular values + currentValue = [value.replace(/^["']|["']$/g, '')]; + } + } else { + // Empty value, might be start of array + currentValue = []; + inArray = true; + } + } else if (inArray && trimmed.startsWith('-')) { + // Array item - preserve quotes for Obsidian bracket syntax + const item = trimmed.substring(1).trim(); + if (item.startsWith('"[[') && item.endsWith(']]"')) { + // Keep quotes for Obsidian bracket syntax + currentValue.push(item); + } else { + // Remove quotes for regular values + currentValue.push(item.replace(/^["']|["']$/g, '')); + } + } else if (inArray && trimmed === ']') { + // End of array + inArray = false; + } else if (currentKey && !inArray) { + // Continuation of single value + currentValue = [currentValue[0] + ' ' + trimmed]; + } + } + + // Save last key-value pair + if (currentKey) { + if (currentValue.length === 1) { + frontmatter[currentKey] = currentValue[0]; + } else { + frontmatter[currentKey] = currentValue; + } + } + + return { frontmatter, content: body }; +} + +// Function to convert frontmatter back to YAML string +function frontmatterToString(frontmatter) { + const lines = ['---']; + + for (const [key, value] of Object.entries(frontmatter)) { + if (Array.isArray(value)) { + lines.push(`${key}:`); + for (const item of value) { + // Preserve quotes for Obsidian bracket syntax in arrays + if (typeof item === 'string' && item.startsWith('"[[') && item.endsWith(']]"')) { + lines.push(` - ${item}`); + } else { + lines.push(` - ${item}`); + } + } + } else { + // Preserve quotes for Obsidian bracket syntax in single values + if (typeof value === 'string' && value.startsWith('"[[') && value.endsWith(']]"')) { + lines.push(`${key}: ${value}`); + } else { + lines.push(`${key}: ${value}`); + } + } + } + + lines.push('---'); + return lines.join('\n'); +} + +// Function to get the current slug from a file path +function getCurrentSlug(filePath) { + // Normalize path separators + const normalizedPath = filePath.replace(/\\/g, '/'); + + // Extract slug based on content type + if (normalizedPath.includes('/posts/')) { + let postPath = normalizedPath.replace(/^.*\/posts\//, '').replace(/\.md$/, ''); + if (postPath.endsWith('/index')) { + postPath = postPath.replace('/index', ''); + } + return postPath; + } else if (normalizedPath.includes('/projects/')) { + let projectPath = normalizedPath.replace(/^.*\/projects\//, '').replace(/\.md$/, ''); + if (projectPath.endsWith('/index')) { + projectPath = projectPath.replace('/index', ''); + } + return projectPath; + } else if (normalizedPath.includes('/docs/')) { + let docPath = normalizedPath.replace(/^.*\/docs\//, '').replace(/\.md$/, ''); + if (docPath.endsWith('/index')) { + docPath = docPath.replace('/index', ''); + } + return docPath; + } else if (normalizedPath.includes('/pages/')) { + let pagePath = normalizedPath.replace(/^.*\/pages\//, '').replace(/\.md$/, ''); + if (pagePath.endsWith('/index')) { + pagePath = pagePath.replace('/index', ''); + } + if (pagePath === 'index') { + return 'index'; + } + return pagePath; + } + + return null; +} + +// Function to process a single markdown file +async function processMarkdownFile(filePath) { + try { + const content = await fs.readFile(filePath, 'utf-8'); + const { frontmatter, content: body } = parseFrontmatter(content); + + if (!frontmatter || !frontmatter.aliases) { + return false; // No aliases to process + } + + // Get the current slug for this file + const currentSlug = getCurrentSlug(filePath); + + // Ensure aliases is an array + const aliasesArray = Array.isArray(frontmatter.aliases) + ? frontmatter.aliases + : [frontmatter.aliases]; + + // Ensure aliases are in the correct format (no leading slash) and filter out self-aliases + const cleanAliases = aliasesArray + .map(alias => alias.startsWith('/') ? alias.substring(1) : alias) + .filter(alias => { + // Remove aliases that match the current slug (prevents self-redirects) + if (currentSlug && alias === currentSlug) { + log.warn(`⚠️ Removing self-alias "${alias}" from ${filePath} (matches current slug)`); + return false; + } + return true; + }); + + // If no valid aliases remain, remove the aliases field entirely + if (cleanAliases.length === 0) { + delete frontmatter.aliases; + } else { + // Update frontmatter with cleaned aliases + frontmatter.aliases = cleanAliases.length === 1 ? cleanAliases[0] : cleanAliases; + } + + // Only write back if we made changes (removed aliases or cleaned them) + const originalAliasesCount = aliasesArray.length; + const hadChanges = cleanAliases.length !== originalAliasesCount || + (cleanAliases.length === 0 && originalAliasesCount > 0); + + if (hadChanges) { + // Rebuild the file content + const newFrontmatter = frontmatterToString(frontmatter); + const newContent = `${newFrontmatter}\n${body}`; + + // Write back to file + await fs.writeFile(filePath, newContent, 'utf-8'); + } + + return { processed: hadChanges, aliases: cleanAliases.length }; + } catch (error) { + log.error(`❌ Error processing ${filePath}:`, error.message); + return { processed: false, aliases: 0 }; + } +} + +// Function to process all markdown files in a directory (including folder-based content) +async function processDirectory(dirPath) { + try { + const files = await fs.readdir(dirPath, { withFileTypes: true }); + let processedCount = 0; + let totalAliases = 0; + + for (const file of files) { + if (file.isDirectory()) { + // Handle folder-based content (e.g., folder-name/index.md) + const folderPath = path.join(dirPath, file.name); + try { + const indexPath = path.join(folderPath, 'index.md'); + await fs.access(indexPath); + const result = await processMarkdownFile(indexPath); + if (result.processed) { + processedCount++; + totalAliases += result.aliases; + } + } catch (error) { + // index.md doesn't exist in this folder, skip + } + } else if (file.isFile() && file.name.endsWith('.md')) { + // Handle single-file content + const filePath = path.join(dirPath, file.name); + const result = await processMarkdownFile(filePath); + if (result.processed) { + processedCount++; + totalAliases += result.aliases; + } + } + } + + return { processedCount, totalAliases }; + } catch (error) { + log.error(`❌ Error processing directory ${dirPath}:`, error.message); + return { processedCount: 0, totalAliases: 0 }; + } +} + +// Main function +async function processAllAliases() { + log.info('🔄 Processing aliases and converting to redirect_from...'); + + const projectRoot = path.join(__dirname, '..'); + let totalProcessed = 0; + let totalAliases = 0; + + for (const dir of CONTENT_DIRS) { + const fullPath = path.join(projectRoot, dir); + + try { + await fs.access(fullPath); + const result = await processDirectory(fullPath); + totalProcessed += result.processedCount; + totalAliases += result.totalAliases; + } catch (error) { + if (error.code !== 'ENOENT') { + log.error(`❌ Error accessing directory ${dir}:`, error.message); + } + } + } + + if (totalProcessed > 0) { + log.info(`📁 Processing pages directory...`); + log.info(`📁 Processing posts directory...`); + log.info(`📁 Processing projects directory...`); + log.info(`📁 Processing docs directory...`); + log.info(` Processed ${totalProcessed} files with ${totalAliases} aliases`); + } + + log.info(`🎉 Alias processing complete! Processed ${totalProcessed} files.`); +} + +// Run the script +processAllAliases(); diff --git a/scripts/setup-dev.mjs b/scripts/setup-dev.mjs new file mode 100644 index 0000000..b391087 --- /dev/null +++ b/scripts/setup-dev.mjs @@ -0,0 +1,38 @@ +import { existsSync, rmSync, mkdirSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import path from 'node:path'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const projectRoot = path.resolve(__dirname, '..'); + +const astroCacheDir = path.join(projectRoot, '.astro'); +const viteCacheDir = path.join(projectRoot, 'node_modules', '.vite'); + +console.log('⚙️ Setting up development environment...'); + +// Wipe .astro completely so content layer and route cache are fresh every dev run +try { + if (existsSync(astroCacheDir)) { + console.log(`Cleaning .astro cache: ${astroCacheDir}`); + rmSync(astroCacheDir, { recursive: true, force: true }); + } + mkdirSync(astroCacheDir, { recursive: true }); +} catch (error) { + console.error(`Failed to clean .astro: ${error.message}`); +} + +// Wipe Vite deps cache so modules are re-resolved +try { + const viteDeps = path.join(viteCacheDir, 'deps'); + if (existsSync(viteDeps)) { + console.log(`Cleaning Vite deps cache: ${viteDeps}`); + rmSync(viteDeps, { recursive: true, force: true }); + } + if (!existsSync(viteCacheDir)) { + mkdirSync(viteCacheDir, { recursive: true }); + } +} catch (error) { + console.error(`Failed to clean Vite cache: ${error.message}`); +} + +console.log('✅ Development environment setup complete.'); diff --git a/scripts/sync-images.js b/scripts/sync-images.js new file mode 100644 index 0000000..ea0d658 --- /dev/null +++ b/scripts/sync-images.js @@ -0,0 +1,378 @@ +#!/usr/bin/env node + +import { promises as fs } from 'fs'; +import path from 'path'; +import sharp from 'sharp'; + +// Simple logging utility +const isDev = process.env.NODE_ENV !== 'production'; +const log = { + info: (...args) => isDev && console.log(...args), + error: (...args) => console.error(...args), + warn: (...args) => console.warn(...args) +}; + +// Define source and target directories for posts, pages, projects, docs, and special +const IMAGE_SYNC_CONFIGS = [ + { + source: 'src/content/posts/attachments', + target: 'public/posts/attachments', + name: 'posts' + }, + { + source: 'src/content/pages/attachments', + target: 'public/pages/attachments', + name: 'pages' + }, + { + source: 'src/content/projects/attachments', + target: 'public/projects/attachments', + name: 'projects' + }, + { + source: 'src/content/docs/attachments', + target: 'public/docs/attachments', + name: 'docs' + }, + { + source: 'src/content/special/attachments', + target: 'public/special/attachments', + name: 'special' + } +]; + +// Recursively find all media files in a directory (images, audio, video, PDF) +async function findImageFiles(dir, relativePath = '') { + const imageFiles = []; + + try { + const items = await fs.readdir(dir); + + for (const item of items) { + const itemPath = path.join(dir, item); + const itemRelativePath = path.join(relativePath, item); + const stat = await fs.stat(itemPath); + + if (stat.isDirectory()) { + // Recursively search subdirectories + const subImages = await findImageFiles(itemPath, itemRelativePath); + imageFiles.push(...subImages); + } else if (/\.(jpg|jpeg|png|gif|webp|svg|bmp|tiff|tif|ico|mp3|wav|ogg|m4a|3gp|flac|aac|mp4|webm|ogv|mov|mkv|avi|pdf)$/i.test(item)) { + // Skip WebP files if we already have the original (to avoid duplicate processing) + // We'll generate WebP from originals + if (item.toLowerCase().endsWith('.webp')) { + const originalName = item.replace(/\.webp$/i, ''); + const hasOriginal = items.some(i => { + const nameWithoutExt = i.replace(/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i, ''); + return nameWithoutExt === originalName && /\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i.test(i); + }); + if (hasOriginal) { + // Skip WebP if we have the original - we'll generate it + continue; + } + } + imageFiles.push({ + sourcePath: itemPath, + relativePath: itemRelativePath + }); + } + } + } catch (error) { + // Directory might not exist or be readable, continue + if (error.code !== 'ENOENT') { + log.warn(`Warning: Could not read directory ${dir}:`, error.message); + } + } + + return imageFiles; +} + +// Function to find folder-based content and sync their images +async function syncFolderBasedImages(contentType) { + const contentDir = `src/content/${contentType}`; + const publicContentDir = `public/${contentType}`; + + try { + const items = await fs.readdir(contentDir); + let totalSynced = 0; + let totalSkipped = 0; + + for (const item of items) { + const itemPath = path.join(contentDir, item); + const stat = await fs.stat(itemPath); + + // Check if it's a directory (folder-based content) + if (stat.isDirectory()) { + const targetDir = path.join(publicContentDir, item); + + // Find all media files recursively + const imageFiles = await findImageFiles(itemPath); + + for (const imageFile of imageFiles) { + // Handle attachments subfolder within folder-based content + // Convert src/content/posts/post-name/attachments/image.png -> public/posts/post-name/image.png + let targetRelativePath = imageFile.relativePath; + // Handle both forward and backward slashes for cross-platform compatibility + if (targetRelativePath.startsWith('attachments/') || targetRelativePath.startsWith('attachments\\')) { + targetRelativePath = targetRelativePath.replace(/^attachments[/\\]/, ''); + } + + const targetPath = path.join(targetDir, targetRelativePath); + const targetDirForFile = path.dirname(targetPath); + + // Ensure target directory exists + await ensureDir(targetDirForFile); + + // Check if file needs updating - check both original and WebP versions + let needsUpdate = true; + + // Check if this is an image that would be converted to WebP + if (/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i.test(imageFile.relativePath)) { + const webpPath = path.join(targetDir, targetRelativePath.replace(/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i, '.webp')); + try { + const sourceStats = await fs.stat(imageFile.sourcePath); + const webpStats = await fs.stat(webpPath); + // Only update if source is newer than WebP + needsUpdate = sourceStats.mtime > webpStats.mtime; + } catch { + // WebP doesn't exist, needs update + needsUpdate = true; + } + } else { + try { + const sourceStats = await fs.stat(imageFile.sourcePath); + const targetStats = await fs.stat(targetPath); + // Only update if source is newer or different size + needsUpdate = sourceStats.mtime > targetStats.mtime || sourceStats.size !== targetStats.size; + } catch { + // Target doesn't exist, definitely needs update + needsUpdate = true; + } + } + + if (needsUpdate) { + // Optimize image if it's an image format (not audio, video, or PDF) + if (/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i.test(imageFile.relativePath)) { + try { + // Convert to WebP and optimize + const webpPath = targetPath.replace(/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i, '.webp'); + await sharp(imageFile.sourcePath) + .webp({ quality: 85 }) + .toFile(webpPath); + totalSynced++; + } catch (error) { + // If Sharp fails, fall back to copying original + log.warn(`⚠️ Could not optimize ${imageFile.relativePath}, copying original:`, error.message); + await fs.copyFile(imageFile.sourcePath, targetPath); + totalSynced++; + } + } else { + // Non-image files (audio, video, PDF) - just copy as-is + await fs.copyFile(imageFile.sourcePath, targetPath); + totalSynced++; + } + } else { + totalSkipped++; + } + } + } + } + + if (totalSynced > 0 || totalSkipped > 0) { + log.info(`📁 Syncing folder-based ${contentType} images...`); + if (totalSynced > 0) log.info(` Synced ${totalSynced} files`); + if (totalSkipped > 0) log.info(` Skipped ${totalSkipped} files that were unchanged`); + } + + return { synced: totalSynced, skipped: totalSkipped }; + } catch (error) { + log.error(`❌ Error syncing folder-based ${contentType} images:`, error); + return { synced: 0, skipped: 0 }; + } +} + +async function ensureDir(dir) { + try { + await fs.access(dir); + } catch { + await fs.mkdir(dir, { recursive: true }); + } +} + +async function syncImagesForConfig(config) { + // Ensure target directory exists + await ensureDir(config.target); + + try { + // Check if source directory exists + let sourceFiles = []; + try { + sourceFiles = await fs.readdir(config.source); + } catch (error) { + if (error.code === 'ENOENT') { + return { synced: 0, skipped: 0, removed: 0 }; + } + throw error; + } + + // Find all image files recursively (including subdirectories) + const imageFiles = await findImageFiles(config.source); + + let synced = 0; + let skipped = 0; + + for (const imageFile of imageFiles) { + const targetPath = path.join(config.target, imageFile.relativePath); + const targetDirForFile = path.dirname(targetPath); + + // Ensure target directory exists (including subdirectories) + await ensureDir(targetDirForFile); + + // Check if file needs updating - check both original and WebP versions + let needsUpdate = true; + + // Check if this is an image that would be converted to WebP + if (/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i.test(imageFile.relativePath)) { + const webpPath = targetPath.replace(/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i, '.webp'); + try { + const sourceStats = await fs.stat(imageFile.sourcePath); + const webpStats = await fs.stat(webpPath); + // Only update if source is newer than WebP + needsUpdate = sourceStats.mtime > webpStats.mtime; + } catch { + // WebP doesn't exist, needs update + needsUpdate = true; + } + } else { + try { + const sourceStats = await fs.stat(imageFile.sourcePath); + const targetStats = await fs.stat(targetPath); + // Only update if source is newer or different size + needsUpdate = sourceStats.mtime > targetStats.mtime || sourceStats.size !== targetStats.size; + } catch { + // Target doesn't exist, definitely needs update + needsUpdate = true; + } + } + + if (needsUpdate) { + // Optimize image if it's an image format (not audio, video, or PDF) + if (/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i.test(imageFile.relativePath)) { + try { + // Convert to WebP and optimize + const webpPath = targetPath.replace(/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i, '.webp'); + await sharp(imageFile.sourcePath) + .webp({ quality: 85 }) + .toFile(webpPath); + synced++; + } catch (error) { + // If Sharp fails, fall back to copying original + log.warn(`⚠️ Could not optimize ${imageFile.relativePath}, copying original:`, error.message); + await fs.copyFile(imageFile.sourcePath, targetPath); + synced++; + } + } else { + // Non-image files (audio, video, PDF) - just copy as-is + await fs.copyFile(imageFile.sourcePath, targetPath); + synced++; + } + } else { + skipped++; + } + } + + // Cleanup: Remove files from target that no longer exist in source + // We need to recursively clean up the target directory + await cleanupTargetDirectory(config.target, imageFiles); + + return { synced, skipped, removed: 0 }; // removed count handled in cleanup function + } catch (error) { + log.error(`❌ Error syncing ${config.name} images:`, error); + process.exit(1); + } +} + +// Recursively clean up target directory, removing files that no longer exist in source +async function cleanupTargetDirectory(targetDir, sourceImageFiles) { + // Create a set that maps both original paths and attachments subfolder paths + const sourceFileSet = new Set(); + sourceImageFiles.forEach(f => { + sourceFileSet.add(f.relativePath); + // Also add the path without attachments/ prefix for cleanup + if (f.relativePath.startsWith('attachments/') || f.relativePath.startsWith('attachments\\')) { + sourceFileSet.add(f.relativePath.replace(/^attachments[/\\]/, '')); + } + // Add WebP version of image paths (since we generate WebP from originals) + if (/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i.test(f.relativePath)) { + const webpPath = f.relativePath.replace(/\.(jpg|jpeg|png|gif|bmp|tiff|tif)$/i, '.webp'); + sourceFileSet.add(webpPath); + if (f.relativePath.startsWith('attachments/') || f.relativePath.startsWith('attachments\\')) { + const webpPathNoAttachments = webpPath.replace(/^attachments[/\\]/, ''); + sourceFileSet.add(webpPathNoAttachments); + } + } + }); + let removed = 0; + + try { + const items = await fs.readdir(targetDir); + + for (const item of items) { + const itemPath = path.join(targetDir, item); + const stat = await fs.stat(itemPath); + + if (stat.isDirectory()) { + // Recursively clean subdirectories + const subRemoved = await cleanupTargetDirectory(itemPath, sourceImageFiles); + removed += subRemoved; + + // Remove empty directories + try { + const remainingItems = await fs.readdir(itemPath); + if (remainingItems.length === 0) { + await fs.rmdir(itemPath); + } + } catch { + // Directory might not be empty or might have been removed already + } + } else { + // Check if this file exists in source + const relativePath = path.relative(targetDir, itemPath).replace(/\\/g, '/'); + if (!sourceFileSet.has(relativePath)) { + await fs.unlink(itemPath); + removed++; + } + } + } + } catch (error) { + // Directory might not exist or be readable + if (error.code !== 'ENOENT') { + log.warn(`Warning: Could not clean directory ${targetDir}:`, error.message); + } + } + + return removed; +} + +async function syncAllImages() { + log.info('🖼️ Syncing images from content to public directory...'); + + for (const config of IMAGE_SYNC_CONFIGS) { + const result = await syncImagesForConfig(config); + if (result.synced > 0 || result.skipped > 0) { + log.info(`📁 Syncing ${config.name} images...`); + if (result.synced > 0) log.info(` Synced ${result.synced} files`); + if (result.skipped > 0) log.info(` Skipped ${result.skipped} files that were unchanged`); + } + } + + // Sync folder-based images for all content types + const contentTypes = ['posts', 'pages', 'projects', 'docs', 'special']; + for (const contentType of contentTypes) { + await syncFolderBasedImages(contentType); + } + + log.info('🎉 Image sync complete!'); +} + +syncAllImages(); \ No newline at end of file diff --git a/scripts/update.mjs b/scripts/update.mjs new file mode 100644 index 0000000..48f883d --- /dev/null +++ b/scripts/update.mjs @@ -0,0 +1,317 @@ +#!/usr/bin/env node + +/** + * Astro Modular Update Script + * + * Downloads the latest release from GitHub, replaces framework files, + * and preserves user content and assets. After updating, open Obsidian + * and click "Apply all settings" in the Astro Modular Settings plugin + * to rewrite your config.ts with your saved settings. + * + * Usage: pnpm run update + */ + +import { execSync } from 'child_process'; +import { createWriteStream, existsSync, mkdirSync, cpSync, rmSync, readFileSync, readdirSync, statSync, renameSync, writeFileSync } from 'fs'; +import { join, resolve, basename } from 'path'; +import { tmpdir } from 'os'; +import { get as httpsGet } from 'https'; +import { pipeline } from 'stream/promises'; + +const ROOT = resolve(import.meta.dirname, '..'); +const REPO = 'davidvkimball/astro-modular'; + +// Files and directories that belong to the USER and must be preserved +const USER_PATHS = [ + 'src/content', // All user content + .obsidian vault (plugin data.json files) + 'public/profile.jpg', + 'public/profile.png', + 'public/profile.webp', + 'public/favicon.png', + 'public/favicon-dark.png', + 'public/favicon-light.png', + 'public/open-graph.png', + '.env', + '.env.local', + '.env.production', +]; + +// Directories that should never be touched +const SKIP_PATHS = [ + 'node_modules', + '.git', + '.astro', + '.netlify', +]; + +// ── Helpers ───────────────────────────────────────────────────────────────── + +function log(msg) { console.log(` ${msg}`); } +function logStep(msg) { console.log(`\n> ${msg}`); } +function logError(msg) { console.error(`\n ERROR: ${msg}`); } + +function getCurrentVersion() { + const versionFile = join(ROOT, 'VERSION'); + if (existsSync(versionFile)) { + return readFileSync(versionFile, 'utf-8').trim(); + } + const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')); + return pkg.version; +} + +async function fetchJSON(url) { + return new Promise((resolve, reject) => { + httpsGet(url, { headers: { 'User-Agent': 'astro-modular-updater' } }, (res) => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + return fetchJSON(res.headers.location).then(resolve, reject); + } + let data = ''; + res.on('data', chunk => data += chunk); + res.on('end', () => { + try { resolve(JSON.parse(data)); } + catch { reject(new Error(`Invalid JSON from ${url}`)); } + }); + res.on('error', reject); + }).on('error', reject); + }); +} + +async function downloadFile(url, dest) { + return new Promise((resolve, reject) => { + httpsGet(url, { headers: { 'User-Agent': 'astro-modular-updater' } }, (res) => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + return downloadFile(res.headers.location, dest).then(resolve, reject); + } + if (res.statusCode !== 200) { + return reject(new Error(`Download failed: HTTP ${res.statusCode}`)); + } + const ws = createWriteStream(dest); + pipeline(res, ws).then(resolve, reject); + }).on('error', reject); + }); +} + +function copyIfExists(src, dest) { + if (!existsSync(src)) return false; + const stat = statSync(src); + if (stat.isDirectory()) { + cpSync(src, dest, { recursive: true }); + } else { + const dir = join(dest, '..'); + if (!existsSync(dir)) mkdirSync(dir, { recursive: true }); + cpSync(src, dest); + } + return true; +} + +// ── Main ──────────────────────────────────────────────────────────────────── + +async function main() { + console.log('\nAstro Modular Updater'); + console.log('===================='); + + // 1. Get current version + const currentVersion = getCurrentVersion(); + log(`Current version: ${currentVersion}`); + + // 2. Check latest release + logStep('Checking for updates...'); + let release; + try { + release = await fetchJSON(`https://api.github.com/repos/${REPO}/releases/latest`); + } catch (err) { + logError(`Could not reach GitHub: ${err.message}`); + process.exit(1); + } + + const latestVersion = release.tag_name.replace(/^v/, ''); + log(`Latest version: ${latestVersion}`); + + if (currentVersion === latestVersion) { + log('Already up to date!'); + process.exit(0); + } + + // 3. Download release archive + logStep(`Downloading v${latestVersion}...`); + const isWindows = process.platform === 'win32'; + const archiveUrl = isWindows ? release.zipball_url : release.tarball_url; + const tempDir = join(tmpdir(), `astro-modular-update-${Date.now()}`); + mkdirSync(tempDir, { recursive: true }); + const archivePath = join(tempDir, isWindows ? 'release.zip' : 'release.tar.gz'); + + try { + await downloadFile(archiveUrl, archivePath); + } catch (err) { + logError(`Download failed: ${err.message}`); + rmSync(tempDir, { recursive: true, force: true }); + process.exit(1); + } + log(`Downloaded to temp directory.`); + + // 4. Extract archive + logStep('Extracting...'); + const extractDir = join(tempDir, 'extracted'); + mkdirSync(extractDir, { recursive: true }); + try { + if (isWindows) { + execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${extractDir}' -Force"`, { stdio: 'pipe' }); + } else { + execSync(`tar -xzf "${archivePath}" -C "${extractDir}"`, { stdio: 'pipe' }); + } + } catch (err) { + logError(`Extraction failed: ${err.message}`); + rmSync(tempDir, { recursive: true, force: true }); + process.exit(1); + } + + // GitHub tarballs extract into a directory like "owner-repo-hash/" + const extractedContents = readdirSync(extractDir); + if (extractedContents.length !== 1) { + logError('Unexpected archive structure.'); + rmSync(tempDir, { recursive: true, force: true }); + process.exit(1); + } + const sourceDir = join(extractDir, extractedContents[0]); + log('Extracted successfully.'); + + // 5. Back up user files + logStep('Backing up user content...'); + const backupDir = join(tempDir, 'backup'); + mkdirSync(backupDir, { recursive: true }); + + let backedUp = 0; + for (const userPath of USER_PATHS) { + const src = join(ROOT, userPath); + const dest = join(backupDir, userPath); + if (copyIfExists(src, dest)) { + log(` Backed up: ${userPath}`); + backedUp++; + } + } + + // Also back up any user-added public/ files not in the new release + const publicDir = join(ROOT, 'public'); + const newPublicDir = join(sourceDir, 'public'); + if (existsSync(publicDir)) { + for (const file of readdirSync(publicDir)) { + const fullPath = join(publicDir, file); + if (statSync(fullPath).isFile()) { + const alreadyBacked = USER_PATHS.some(p => p === `public/${file}`); + if (!alreadyBacked) { + // Check if this file does NOT exist in the new release (user-added) + if (!existsSync(join(newPublicDir, file))) { + const dest = join(backupDir, 'public', file); + mkdirSync(join(backupDir, 'public'), { recursive: true }); + cpSync(fullPath, dest); + log(` Backed up (user asset): public/${file}`); + backedUp++; + } + } + } + } + } + + log(`${backedUp} item(s) backed up.`); + + // 6. Replace framework files + logStep('Updating framework files...'); + + // Get list of all paths in the new release (excluding user/skip paths) + function listPaths(dir, base = '') { + const results = []; + for (const entry of readdirSync(dir)) { + const rel = base ? `${base}/${entry}` : entry; + const full = join(dir, entry); + + // Skip paths we should never touch + if (SKIP_PATHS.includes(rel)) continue; + // Skip user content paths (we'll restore from backup) + if (USER_PATHS.includes(rel)) continue; + + if (statSync(full).isDirectory()) { + // If it's a user directory root, skip recursing + if (USER_PATHS.some(p => p.startsWith(rel + '/'))) { + // Only skip exact user-path prefixes like src/content + if (USER_PATHS.includes(rel)) continue; + results.push(...listPaths(full, rel)); + } else { + results.push(...listPaths(full, rel)); + } + } else { + results.push(rel); + } + } + return results; + } + + const newFiles = listPaths(sourceDir); + let updated = 0; + + for (const relPath of newFiles) { + const src = join(sourceDir, relPath); + const dest = join(ROOT, relPath); + const destDir = join(dest, '..'); + + if (!existsSync(destDir)) mkdirSync(destDir, { recursive: true }); + cpSync(src, dest); + updated++; + } + log(`${updated} framework file(s) updated.`); + + // 7. Restore user files from backup + logStep('Restoring user content...'); + let restored = 0; + + for (const userPath of USER_PATHS) { + const src = join(backupDir, userPath); + const dest = join(ROOT, userPath); + if (copyIfExists(src, dest)) { + log(` Restored: ${userPath}`); + restored++; + } + } + + // Restore user-added public/ files + const backupPublicDir = join(backupDir, 'public'); + if (existsSync(backupPublicDir)) { + for (const file of readdirSync(backupPublicDir)) { + const alreadyRestored = USER_PATHS.some(p => p === `public/${file}`); + if (!alreadyRestored) { + cpSync(join(backupPublicDir, file), join(ROOT, 'public', file)); + log(` Restored (user asset): public/${file}`); + restored++; + } + } + } + + log(`${restored} item(s) restored.`); + + // 8. Install dependencies + logStep('Installing dependencies...'); + try { + execSync('pnpm install', { cwd: ROOT, stdio: 'inherit' }); + } catch { + logError('pnpm install failed. You may need to run it manually.'); + } + + // 9. Clean up temp directory + rmSync(tempDir, { recursive: true, force: true }); + + // 10. Done + console.log('\n===================================='); + console.log(` Updated to v${latestVersion}!`); + console.log('===================================='); + console.log('\n Next steps:'); + console.log(' 1. Open your vault in Obsidian'); + console.log(' 2. Go to Astro Modular Settings > Advanced tab'); + console.log(' 3. Click "Apply to config.ts" under "Apply all settings"'); + console.log(' to write your saved settings to the new config.ts'); + console.log(' 4. Run `pnpm dev` to verify everything works'); + console.log(''); +} + +main().catch(err => { + logError(err.message); + process.exit(1); +}); diff --git a/selhostedbg-web.code-workspace b/selhostedbg-web.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/selhostedbg-web.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/src/components/BaseTable.astro b/src/components/BaseTable.astro new file mode 100644 index 0000000..cc42743 --- /dev/null +++ b/src/components/BaseTable.astro @@ -0,0 +1,29 @@ +--- +export interface Props { + columns: string[]; + rows: Record[]; +} +const { columns, rows } = Astro.props as Props; +--- +
+ + + + {columns.map((col) => ( + + ))} + + + + {rows.map((row) => ( + + {columns.map((col) => ( + + ))} + + ))} + +
{col}
{String(row[col] ?? '')}
+
+ + diff --git a/src/components/Button.astro b/src/components/Button.astro new file mode 100644 index 0000000..d1a0a16 --- /dev/null +++ b/src/components/Button.astro @@ -0,0 +1,105 @@ + +--- +export interface Props { + variant?: 'primary' | 'secondary' | 'outline' | 'ghost'; + size?: 'sm' | 'md' | 'lg'; + href?: string; + target?: string; + rel?: string; + type?: 'button' | 'submit' | 'reset'; + disabled?: boolean; + class?: string; +} + +const { + variant = 'primary', + size = 'md', + href, + target, + rel, + type = 'button', + disabled = false, + class: className = '', + ...rest +} = Astro.props; + +// Base button classes +const baseClasses = 'btn inline-flex items-center justify-center font-medium rounded-lg transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background cursor-pointer border no-underline'; + +// Size variations +const sizeClasses = { + sm: 'px-3 py-1.5 text-sm', + md: 'px-4 py-2 text-sm', + lg: 'px-6 py-3 text-base' +}; + +// Variant classes that use your existing design tokens +const variantClasses = { + primary: 'btn-primary', + secondary: 'btn-secondary', + outline: 'btn-outline', + ghost: 'btn-ghost' +}; + +const allClasses = `${baseClasses} ${sizeClasses[size]} ${variantClasses[variant]} ${className}`; + +// Determine if this should be a link or button +const Element = href ? 'a' : 'button'; +--- + +{Element === 'a' ? ( + + + +) : ( + +)} + + diff --git a/src/components/CategoryFilter.astro b/src/components/CategoryFilter.astro new file mode 100644 index 0000000..ed8dae8 --- /dev/null +++ b/src/components/CategoryFilter.astro @@ -0,0 +1,111 @@ +--- +import { siteConfig } from '../config'; +--- + + + + + diff --git a/src/components/CommandPalette.astro b/src/components/CommandPalette.astro new file mode 100644 index 0000000..6964da4 --- /dev/null +++ b/src/components/CommandPalette.astro @@ -0,0 +1,1444 @@ +--- +import { siteConfig, getThemeDisplayName } from '../config'; +import Icon from './Icon.astro'; +--- + + + + + + + + \ No newline at end of file diff --git a/src/components/DocsSidebar.astro b/src/components/DocsSidebar.astro new file mode 100644 index 0000000..00adc92 --- /dev/null +++ b/src/components/DocsSidebar.astro @@ -0,0 +1,183 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import Icon from './Icon.astro'; + +export interface Props { + currentDocId: string; + currentCategory: string | null; + allDocs: CollectionEntry<'docs'>[]; +} + +const { currentDocId, currentCategory, allDocs } = Astro.props; + +// Filter docs by category +// If current page has no category (or "General"), show all docs +// Otherwise, show only docs matching the current category +let filteredDocs: CollectionEntry<'docs'>[] = []; + +if (!currentCategory || currentCategory.trim() === '' || currentCategory === 'General') { + // Show all docs if no category + filteredDocs = allDocs; +} else { + // Filter by category - handle "Unsorted" specially + if (currentCategory === 'Unsorted') { + filteredDocs = allDocs.filter(doc => + !doc.data.category || + doc.data.category.trim() === '' || + doc.data.category === 'General' + ); + } else { + filteredDocs = allDocs.filter(doc => + doc.data.category && + doc.data.category.trim() !== '' && + doc.data.category !== 'General' && + doc.data.category === currentCategory + ); + } +} + +// Sort by order, then by title +filteredDocs.sort((a, b) => { + if (a.data.order !== b.data.order) { + return a.data.order - b.data.order; + } + return a.data.title.localeCompare(b.data.title); +}); + +// Determine sidebar header text +const sidebarHeader = currentCategory && currentCategory !== 'General' ? currentCategory : 'Documentation'; +--- + + + + + + + diff --git a/src/components/DocumentationCard.astro b/src/components/DocumentationCard.astro new file mode 100644 index 0000000..b357d42 --- /dev/null +++ b/src/components/DocumentationCard.astro @@ -0,0 +1,163 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import { formatDate, processMarkdown, isValidDate } from '../utils/markdown'; +import { siteConfig } from '../config'; +import ImageWrapper from './ImageWrapper.astro'; +import Icon from './Icon.astro'; + +interface Props { + documentation: CollectionEntry<'docs'>; + featured?: boolean; + eager?: boolean; + context?: 'featured' | 'recent' | 'docs' | 'tags' | 'home'; +} + +const { documentation, featured = false, eager = false, context = 'docs' } = Astro.props; + +// Get excerpt from markdown processing +const { excerpt } = processMarkdown(documentation.body); + +const { title, description: rawDescription, lastModified, image: rawImage, imageAlt, category, version } = documentation.data; + +// Process Obsidian bracket syntax in image field (copy from PostCard) +const image = (() => { + if (!rawImage) return rawImage; + + // Handle case where rawImage is an array (unquoted YAML syntax) + let imageValue = rawImage; + if (Array.isArray(rawImage)) { + // If it's an array, take the first element + imageValue = rawImage[0]; + } + + // Ensure imageValue is a string before calling string methods + if (typeof imageValue !== 'string') { + console.warn('DocumentationCard: imageValue is not a string:', imageValue); + return imageValue; + } + + // Check if it's Obsidian double bracket syntax + if (imageValue.startsWith('[[') && imageValue.endsWith(']]')) { + // Extract the content inside the double brackets + return imageValue.slice(2, -2); + } + + return imageValue; +})(); + +const description = rawDescription || excerpt; + +// Determine if we should show the cover image +// Documentation should always show images when available (not controlled by postOptions) +const shouldShowCoverImage = true; + +// Hide images for docs on homepage for cleaner look +const showCoverImage = shouldShowCoverImage && image && context !== 'home'; +--- + +
+ + +
+ + {version && ( + + v{version} + + )} +
+ + + {image && showCoverImage && ( +
+
+ { + // Clean the image path by removing Obsidian brackets + // Remove Obsidian brackets to get the actual image path + let cleanImagePath = image; + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // Remove Obsidian subfolder prefixes (images/, attachments/) + if (typeof cleanImagePath === 'string') { + // Remove images/ prefix if present (Obsidian subfolder setting) + if (cleanImagePath.startsWith('images/')) { + return cleanImagePath.replace('images/', ''); + } + // Remove attachments/ prefix - basePath will add it back + if (cleanImagePath.startsWith('attachments/')) { + return cleanImagePath.replace('attachments/', ''); + } + } + + return cleanImagePath || ''; + })()} + basePath={(() => { + // 1. External URLs - no basePath needed + if (typeof image === 'string' && image.startsWith('http')) { + return ''; + } + + // 2. Clean the image path to check for attachments/ prefix + let cleanImagePath = image; + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // 3. Detect folder-based vs file-based: if image path starts with 'attachments/', + // it's a single-file doc (shared attachments folder) + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('attachments/')) { + // Single-file doc with image in attachments folder + // The sync script copies these to /docs/attachments/ + return "/docs/attachments/"; + } + + // 4. Folder-based doc - sync script copies images to doc folder root + // Safety check: ensure documentation.id exists before using it + if (documentation.id) { + return `/docs/${documentation.id}/`; + } else { + // Fallback to attachments directory if documentation.id is undefined + return '/docs/attachments/'; + } + })()} + alt={imageAlt || `Cover image for documentation: ${title}`} + width={400} + height={200} + loading={eager ? 'eager' : 'lazy'} + fetchpriority={eager ? 'high' : 'auto'} + class="w-full h-32 object-cover group-hover:scale-105 transition-transform duration-300" + /> +
+
+ )} + + +
+ +

+ {title} +

+ + + {description && ( +

+ {description} +

+ )} + + + {lastModified && ( +
+ {isValidDate(lastModified) && ( + + )} +
+ )} +
+
+
diff --git a/src/components/Footer.astro b/src/components/Footer.astro new file mode 100644 index 0000000..59fed34 --- /dev/null +++ b/src/components/Footer.astro @@ -0,0 +1,154 @@ +--- +import { siteConfig } from '@/config'; +import Icon from './Icon.astro'; + +const currentYear = new Date().getFullYear(); +const socialLinks = (siteConfig.navigation.social || []).filter((social) => social && social.url && social.icon); +const showSocialIcons = siteConfig.footer.showSocialIconsInFooter && socialLinks.length > 0; +const showProfilePicture = siteConfig.profilePicture.enabled && siteConfig.profilePicture.placement === 'footer'; +const profilePicture = siteConfig.profilePicture; +const footerEnabled = siteConfig.footer.enabled; + +// Replace placeholder with actual author name +const footerContent = siteConfig.footer.content.replace('{author}', siteConfig.author); + +// Size and style classes for profile picture +const getProfilePictureClasses = (size: string, style: string) => { + let sizeClasses = ''; + switch (size) { + case 'sm': sizeClasses = 'h-8'; break; + case 'lg': sizeClasses = 'h-16'; break; + default: sizeClasses = 'h-12'; // md + } + + let styleClasses = ''; + switch (style) { + case 'circle': styleClasses = 'rounded-full object-cover border-2 border-primary-200 dark:border-primary-700'; break; + case 'square': styleClasses = 'rounded-lg object-cover border-2 border-primary-200 dark:border-primary-700'; break; + default: styleClasses = 'object-contain'; // none + } + + return `${sizeClasses} ${styleClasses}`; +}; +--- + +
+
+ + {showProfilePicture && footerEnabled && ( +
+ {profilePicture.url ? ( + + {profilePicture.alt} + + ) : ( + {profilePicture.alt} + )} +
+ )} + + + {showSocialIcons && ( +
+
+ {socialLinks.map((social) => ( + + + {social.title} + + ))} +
+
+ )} + + + {footerEnabled && ( +
+

+

+ + + {showSocialIcons && ( + + )} +
+ )} + + + {!footerEnabled && ( +
+ {showProfilePicture ? ( +
+ {profilePicture.url ? ( + + {profilePicture.alt} + + ) : ( + {profilePicture.alt} + )} +
+ ) : null} + + + {showSocialIcons && ( +
+ {socialLinks.map((social) => ( + + + {social.title} + + ))} +
+ )} +
+ )} +
+
diff --git a/src/components/GiscusComments.astro b/src/components/GiscusComments.astro new file mode 100644 index 0000000..f75747d --- /dev/null +++ b/src/components/GiscusComments.astro @@ -0,0 +1,109 @@ +--- +import { siteConfig } from '@/config'; + +// Only render if comments are enabled +if (!siteConfig.postOptions.comments.enabled) { + return null; +} + +const { comments } = siteConfig.postOptions; + +--- + +
+
+
+ + + + diff --git a/src/components/GraphModal.astro b/src/components/GraphModal.astro new file mode 100644 index 0000000..1050478 --- /dev/null +++ b/src/components/GraphModal.astro @@ -0,0 +1,725 @@ +--- +import { siteConfig } from '@/config'; +import Icon from './Icon.astro'; +--- + + + + + \ No newline at end of file diff --git a/src/components/Header.astro b/src/components/Header.astro new file mode 100644 index 0000000..66591a6 --- /dev/null +++ b/src/components/Header.astro @@ -0,0 +1,601 @@ +--- +import { siteConfig } from '../config'; +import ThemeToggle from './ThemeToggle.astro'; +import Icon from './Icon.astro'; + +const showProfilePicture = siteConfig.profilePicture.enabled && siteConfig.profilePicture.placement === 'header'; +const profilePicture = siteConfig.profilePicture; + +// Style classes for profile picture in header +const getHeaderProfilePictureClasses = (style: string) => { + switch (style) { + case 'circle': return 'w-8 h-8 rounded-full object-cover border-2 border-primary-200 dark:border-primary-700'; + case 'square': return 'w-8 h-8 rounded-lg object-cover border-2 border-primary-200 dark:border-primary-700'; + default: return 'h-8 object-contain'; // none - height constrained, width flexible + } +}; + +// Check if shortcut is defined and not empty +const hasShortcut = siteConfig.commandPalette.shortcut && siteConfig.commandPalette.shortcut.trim(); + +// Extract the key from the shortcut (e.g., 'ctrl+k' -> 'K') +const shortcutKey = hasShortcut ? siteConfig.commandPalette.shortcut.split('+').pop()?.toUpperCase() || 'K' : ''; + +// Check if all command palette sections are disabled +const allSectionsDisabled = !siteConfig.commandPalette.sections.quickActions && + !siteConfig.commandPalette.sections.pages && + !siteConfig.commandPalette.sections.social; + +// Choose icon based on whether all sections are disabled (for no shortcut case) +const paletteIcon = allSectionsDisabled ? 'search' : 'command'; +--- + +
+
+
+ + + + +
+ + {siteConfig.navigation.showNavigation && ( + + )} +
+ + +
+ + {siteConfig.featureButton === "mode" && } + {siteConfig.featureButton === "graph" && siteConfig.postOptions.graphView.enabled && ( + + )} + {siteConfig.featureButton === "theme" && ( + + )} + + {siteConfig.commandPalette.enabled && ( + hasShortcut ? ( + + ) : ( + + ) + )} + + + {siteConfig.navigation.showNavigation && siteConfig.navigation.showMobileMenu && ( + + )} +
+
+ + + {siteConfig.navigation.showNavigation && siteConfig.navigation.showMobileMenu && ( + + )} +
+
+ + + + \ No newline at end of file diff --git a/src/components/Icon.astro b/src/components/Icon.astro new file mode 100644 index 0000000..a725f21 --- /dev/null +++ b/src/components/Icon.astro @@ -0,0 +1,126 @@ +--- +import { library, icon } from '@fortawesome/fontawesome-svg-core'; +import { fab } from '@fortawesome/free-brands-svg-icons'; + +export interface Props { + name: string; + class?: string; + size?: number; + title?: string; +} + +const { name, class: className = '', size = 24, title } = Astro.props; + +function escapeHtml(s: string): string { + return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); +} + +// Add ALL Font Awesome brand icons to library at once +library.add(fab); + +const icons = { + // Navigation icons + 'arrow-up': '', + 'chevron-up': '', + 'chevron-down': '', + 'arrow-down': '', + 'arrow-left': '', + 'arrow-right': '', + 'arrow-up-right': '', + 'chevron-left': '', + 'chevron-right': '', + + // UI icons + 'x': '', + 'menu': '', + 'search': '', + 'search-x': '', + 'external-link': '', + 'command': '', + 'list': '', + 'zoom-in': '', + + // Theme icons + 'sun': '', + 'moon': '', + 'sun-moon': '', + 'palette': '', + + // Content icons + 'file-text': '', + 'file-x': '', + 'tag': '', + 'link-2': '', + 'rss': '', + 'atom': '', + 'navigation': '', + 'git-fork': '', + + // Social and brand icons + 'github': '', + 'gitlab': '', + 'folder-git-2': '', + 'book-open': '', + 'book-text': '', + 'folder': '', + 'folder-open': '', + 'sticky-note': '', + 'loader-2': '', + 'grid-3x3': '', + + // Status and alert icons + 'info': '', + 'lightbulb': '', + 'star': '', + 'triangle-alert': '', + 'circle-alert': '', + 'circle-x': '', + 'circle-help': '', + 'circle-check': '', + 'bug': '', + 'code': '', + 'quote': '', +}; + +const iconPath = icons[name as keyof typeof icons]; + +// Try Font Awesome brands first (for social icons) +const faIcon = icon({ prefix: 'fab', iconName: name as any }); + +// Use a graceful fallback icon (link-2) if neither FA nor custom icon exists +const fallbackIcon = 'link-2'; +const fallbackPath = icons[fallbackIcon]; +--- + +{faIcon ? ( +
+) : iconPath ? ( + ${escapeHtml(title)}${iconPath}` : iconPath} + /> +) : fallbackPath ? ( +
+ ${escapeHtml(title)}${fallbackPath}` : fallbackPath} + /> +
+) : null} \ No newline at end of file diff --git a/src/components/ImageGallery.astro b/src/components/ImageGallery.astro new file mode 100644 index 0000000..6040eff --- /dev/null +++ b/src/components/ImageGallery.astro @@ -0,0 +1,141 @@ +--- +import type { ImageInfo } from '@/types'; +import { processImageLayout } from '@/utils/images'; +import Icon from './Icon.astro'; +import ImageWrapper from './ImageWrapper.astro'; + +export interface Props { + images: ImageInfo[]; + layout?: 'single' | 'grid-2' | 'grid-3' | 'grid-4' | 'auto'; +} + +const { images, layout = 'auto' } = Astro.props; + +// Process layout if auto +const processedLayout = layout === 'auto' ? processImageLayout(images) : { layout, images }; +const { layout: finalLayout, images: finalImages } = processedLayout; +--- + +{finalImages.length > 0 && ( + +)} + + + + diff --git a/src/components/ImageGalleryManager.astro b/src/components/ImageGalleryManager.astro new file mode 100644 index 0000000..0ab9557 --- /dev/null +++ b/src/components/ImageGalleryManager.astro @@ -0,0 +1,171 @@ +--- +import { siteConfig } from '../config'; +--- + + + + + diff --git a/src/components/ImageWrapper.astro b/src/components/ImageWrapper.astro new file mode 100644 index 0000000..b4f4b20 --- /dev/null +++ b/src/components/ImageWrapper.astro @@ -0,0 +1,194 @@ +--- +import path from "node:path"; +import { Image } from "astro:assets"; +import { devConfig, isDev } from "@/config/dev"; + +interface Props { + id?: string; + src: string; + class?: string; + alt?: string; + caption?: string; + position?: string; + basePath?: string; + width?: number; + height?: number; + format?: "webp" | "avif" | "png" | "jpg" | "jpeg" | "svg"; + quality?: number; + loading?: "lazy" | "eager"; + decoding?: "async" | "sync" | "auto"; + fetchpriority?: "high" | "low" | "auto"; + densities?: number[]; +} + +const { + id, + src, + alt = "", + caption, + position = "center", + basePath = "/", + width = 800, + height = 450, + format = "webp", + quality = 85, + loading = "lazy", + decoding = "async", + fetchpriority = "auto", + densities = [1, 2] +} = Astro.props; + +const className = Astro.props.class; + +// Clean the src path first - remove Obsidian brackets if present +let cleanSrc = src; +if (!cleanSrc) { + console.warn('ImageWrapper: src is undefined'); + cleanSrc = ''; +} +if (cleanSrc.startsWith('[[') && cleanSrc.endsWith(']]')) { + cleanSrc = cleanSrc.slice(2, -2); +} + +// Determine image type using cleaned src +// For folder-based content, if basePath indicates a synced folder, treat as local for optimization +// Also treat global attachments directories as synced folders for Astro Image optimization +const isSyncedFolder = basePath && basePath.includes('/') && ( + !basePath.endsWith('/attachments/') || + basePath === '/posts/attachments/' || + basePath === '/projects/attachments/' || + basePath === '/docs/attachments/' || + basePath === '/pages/attachments/' || + basePath === '/special/attachments/' +); +const isLocal = !( + cleanSrc.startsWith("/") || + cleanSrc.startsWith("http") || + cleanSrc.startsWith("https") || + cleanSrc.startsWith("data:") +) || isSyncedFolder; // Treat synced folders as local for Astro Image optimization +const isPublic = cleanSrc.startsWith("/") && !isSyncedFolder; + +// Dynamic import for local images +let img: any = null; +let fallbackSrc: string | null = null; +let isImageMissing = false; + +if (isLocal) { + try { + const files = import.meta.glob("/public/**", { + import: "default", + }); + + // Remove leading "./" if present for folder-based posts + if (cleanSrc.startsWith('./')) { + cleanSrc = cleanSrc.slice(2); + } + + // Remove leading "images/" if present since basePath already includes it + // But only for global images, not folder-based images + if (cleanSrc.startsWith('images/') && (basePath === '/posts/attachments/' || basePath === '/projects/attachments/' || basePath === '/docs/attachments/' || basePath === '/pages/attachments/' || basePath === '/special/attachments/')) { + cleanSrc = cleanSrc.slice(7); + } + + // For folder-based content, if basePath already includes 'images/' and cleanSrc starts with 'images/', + // remove the prefix from cleanSrc to avoid double 'images/' + if (cleanSrc.startsWith('images/') && basePath.includes('/attachments/') && basePath !== '/posts/attachments/' && basePath !== '/projects/attachments/' && basePath !== '/docs/attachments/' && basePath !== '/pages/attachments/' && basePath !== '/special/attachments/') { + cleanSrc = cleanSrc.slice(7); + } + + // For content with attachments/ prefix, remove it since the sync script already handles this + if (cleanSrc.startsWith('attachments/') && basePath.includes('/projects/') && !basePath.includes('/attachments/')) { + cleanSrc = cleanSrc.slice(12); // Remove 'attachments/' prefix + } + + // For single-file projects, also remove attachments/ prefix when using global attachments directory + if (cleanSrc.startsWith('attachments/') && basePath === '/projects/attachments/') { + cleanSrc = cleanSrc.slice(12); // Remove 'attachments/' prefix + } + + // Normalize the path for the glob pattern + let normalizedPath = path + .normalize(path.join("/public", basePath, cleanSrc)) + .replace(/\\/g, "/"); + + // Ensure the path starts with /public + if (!normalizedPath.startsWith("/public")) { + normalizedPath = `/public${normalizedPath}`; + } + + // Debug logging + if (isDev && devConfig.images.logMissingImages) { + // Debug logging removed for production + } + + const file = files[normalizedPath]; + if (file) { + img = await file(); + } else { + isImageMissing = true; + // No fallback images - just mark as missing + } + } catch (error) { + isImageMissing = true; + // No fallback images - just mark as missing + } +} + +const imageClass = "w-full h-full object-cover"; +const imageStyle = `object-position: ${position}`; +--- + +
+ {isLocal && img ? ( + {alt} + ) : isPublic ? ( + {alt} + ) : isImageMissing ? ( + // Don't render anything for missing local images + null + ) : ( + {alt} + )} + + {caption && ( +
+ {caption} +
+ )} +
diff --git a/src/components/Lightbox.astro b/src/components/Lightbox.astro new file mode 100644 index 0000000..e80f413 --- /dev/null +++ b/src/components/Lightbox.astro @@ -0,0 +1,497 @@ +--- +// Lightbox component for image viewing +import Icon from './Icon.astro'; +--- + + + + + + \ No newline at end of file diff --git a/src/components/LinkedMentions.astro b/src/components/LinkedMentions.astro new file mode 100644 index 0000000..14d3ad8 --- /dev/null +++ b/src/components/LinkedMentions.astro @@ -0,0 +1,471 @@ +--- +import type { Post, LinkedMention } from '@/types'; +import { findLinkedMentions } from '@/utils/internallinks'; +import { getCollection } from 'astro:content'; +import { getFeature, siteConfig } from '@/config'; +import Icon from './Icon.astro'; + +export interface Props { + currentSlug: string; +} + +const { currentSlug } = Astro.props; +const isCompact = (siteConfig.postOptions.linkedMentions as any).linkedMentionsCompact; + +// Get all posts and pages to find linked mentions +const posts = await getCollection('posts'); +const pages = await getCollection('pages'); +const linkedMentions = findLinkedMentions(posts as any[], currentSlug, posts as any[], pages as any[]); + + +// Function to process links in excerpt text +function processExcerptLinks(text: string, targetSlug: string): string { + // IMPORTANT: Process markdown links FIRST, before wikilinks + // This prevents markdown links from being processed as incomplete links + // Then, process wikilinks - they're already in [[link]] or [[link|display]] format from excerpts + + // First, process standard markdown links - convert to wikilink format + text = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, displayText, url) => { + // Skip if this looks like it's already been processed (has mark tag) + if (match.includes(' p.id === targetSlug); + if (targetPost) { + const titleSlug = targetPost.data.title.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + const displaySlug = displayText.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + isRelevantLink = displaySlug === titleSlug; + } + } + + const wikilinkFormat = `[[${displayText}]]`; + + if (isRelevantLink) { + return `${wikilinkFormat}`; + } else { + return wikilinkFormat; + } + }); + + // Then, process wikilinks - skip if already processed (has mark tag or triple brackets) + // CRITICAL: Use a replacement approach that tracks positions to avoid processing inside mark tags + const wikilinkMatches: Array<{index: number, match: string, link: string, display: string | undefined, replacement: string}> = []; + const wikilinkRegex = /\[\[([^\]|]+)(?:\|([^\]]+))?\]\](?!\])/g; + let wikilinkMatch; + + while ((wikilinkMatch = wikilinkRegex.exec(text)) !== null) { + const match = wikilinkMatch[0]; + const link = wikilinkMatch[1]; + const display = wikilinkMatch[2]; + const matchIndex = wikilinkMatch.index; + + // Skip if already processed (has mark tag or weird formatting) + if (match.includes(''); + + // If there's an unclosed mark tag before us, we're inside it + if (lastMarkStart > lastMarkEnd && lastMarkStart !== -1) { + // Check if the mark tag extends past our position + const markTagEnd = text.indexOf('', lastMarkStart); + if (markTagEnd > matchIndex) { + continue; // We're inside a mark tag, skip + } + } + + // Process the wikilink + const anchorIndex = link.indexOf('#'); + const baseLink = anchorIndex === -1 ? link : link.substring(0, anchorIndex); + let linkSlug = baseLink.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + + if (baseLink.startsWith('posts/')) { + const postPath = baseLink.replace('posts/', ''); + const cleanPath = postPath.endsWith('/index') ? postPath.replace('/index', '') : postPath; + linkSlug = cleanPath.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + } else if (baseLink.includes('/')) { + if (baseLink.endsWith('/index') && baseLink.split('/').length === 2) { + const folderName = baseLink.replace('/index', ''); + linkSlug = folderName.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + } + } + + let isRelevantLink = linkSlug === targetSlug; + + if (!isRelevantLink && display) { + const targetPost = posts.find(p => p.id === targetSlug); + if (targetPost) { + const displaySlug = display.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + const titleSlug = targetPost.data.title.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + isRelevantLink = displaySlug === titleSlug || displaySlug === targetSlug; + } + } + + if (!isRelevantLink && !baseLink.includes('/') && !baseLink.includes('posts/')) { + const targetPost = posts.find(p => p.id === targetSlug); + if (targetPost) { + const titleSlug = targetPost.data.title.toLowerCase().replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + isRelevantLink = linkSlug === titleSlug || linkSlug === targetSlug; + } + } + + const displayText = display || (anchorIndex !== -1 ? link.substring(0, anchorIndex) : link); + const wikilinkFormat = `[[${displayText}]]`; + const replacement = isRelevantLink + ? `${wikilinkFormat}` + : wikilinkFormat; + + wikilinkMatches.push({ index: matchIndex, match, link, display, replacement }); + } + + // Replace in reverse order + wikilinkMatches.reverse().forEach(({ index, match, replacement }) => { + text = text.substring(0, index) + replacement + text.substring(index + match.length); + }); + + // Finally, handle incomplete markdown links (truncated ones like "[Obsidian Vault..." or "[Astro Suite Obsidian Vault") + // CRITICAL: This must be VERY careful to not process links that are already part of wikilinks or markdown links + // We'll use a more careful approach: find incomplete links but exclude any that are inside processed content + + // First, find all positions where we have mark tags (already processed links) + const markTagPositions: Array<{start: number, end: number}> = []; + const markTagRegex = /]*>.*?<\/mark>/g; + let markMatch; + while ((markMatch = markTagRegex.exec(text)) !== null) { + markTagPositions.push({ start: markMatch.index, end: markMatch.index + markMatch[0].length }); + } + + // Also find all complete wikilinks and markdown links (processed or not) + const completeLinkPositions: Array<{start: number, end: number}> = []; + // Find wikilinks [[...]] + const completeWikilinkRegex = /\[\[[^\]]+\]\]/g; + let completeWikilinkMatch; + while ((completeWikilinkMatch = completeWikilinkRegex.exec(text)) !== null) { + completeLinkPositions.push({ start: completeWikilinkMatch.index, end: completeWikilinkMatch.index + completeWikilinkMatch[0].length }); + } + // Find markdown links [...](...) + const completeMarkdownLinkRegex = /\[[^\]]+\]\([^)]+\)/g; + let completeMarkdownLinkMatch; + while ((completeMarkdownLinkMatch = completeMarkdownLinkRegex.exec(text)) !== null) { + completeLinkPositions.push({ start: completeMarkdownLinkMatch.index, end: completeMarkdownLinkMatch.index + completeMarkdownLinkMatch[0].length }); + } + + // Helper to check if a position is inside any processed/complete link + const isInsideProcessedLink = (index: number, length: number): boolean => { + const end = index + length; + // Check if overlaps with any mark tag + for (const pos of markTagPositions) { + if (index < pos.end && end > pos.start) return true; + } + // Check if overlaps with any complete link + for (const pos of completeLinkPositions) { + if (index < pos.end && end > pos.start) return true; + } + return false; + }; + + // Now find incomplete links, but skip if they're inside processed content + const incompleteLinkPattern = /\[([^\]]+?)(?:\]|$)(?!\[)(?!\()/g; + let incompleteMatches: Array<{index: number, match: string, displayText: string}> = []; + let incompleteMatch; + + while ((incompleteMatch = incompleteLinkPattern.exec(text)) !== null) { + const matchIndex = incompleteMatch.index; + const match = incompleteMatch[0]; + const displayText = incompleteMatch[1]; + + // Skip if this match is inside already-processed content + if (isInsideProcessedLink(matchIndex, match.length)) { + continue; + } + + // Skip if character before is `[` (part of `[[`) + if (matchIndex > 0 && text[matchIndex - 1] === '[') { + continue; + } + + // Skip if followed by `(` (part of markdown link) + const afterMatch = text.substring(matchIndex + match.length, matchIndex + match.length + 5); + if (afterMatch.trim().startsWith('(')) { + continue; + } + + // Only process if there's actual text + if (!displayText || displayText.trim().length === 0) { + continue; + } + + // Check if this incomplete link's display text matches the target post title + let isRelevantLink = false; + const trimmedDisplay = displayText.trim(); + const targetPost = posts.find(p => p.id === targetSlug); + if (targetPost) { + const displayLower = trimmedDisplay.toLowerCase(); + const titleLower = targetPost.data.title.toLowerCase(); + const displaySlug = displayLower.replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + const titleSlug = titleLower.replace(/[^a-z0-9\s-]/g, '').replace(/\s+/g, '-').replace(/-+/g, '-').replace(/^-+|-+$/g, ''); + const titleWords = titleLower.split(/\s+/).filter(w => w.length >= 3 && !['the', 'and', 'for', 'with'].includes(w)); + const displayWords = displayLower.split(/\s+/).filter(w => w.length >= 3 && !['the', 'and', 'for', 'with'].includes(w)); + isRelevantLink = + displaySlug === titleSlug || + titleSlug.includes(displaySlug) || + displaySlug.includes(titleSlug) || + titleWords.some(word => displayLower.includes(word) && word.length >= 5) || + displayWords.some(word => titleLower.includes(word) && word.length >= 5); + } + + const replacement = isRelevantLink + ? `[[${trimmedDisplay}]]` + : `[[${trimmedDisplay}]]`; + + incompleteMatches.push({ index: matchIndex, match, displayText: replacement }); + } + + // Process matches in reverse order to preserve indices + incompleteMatches.reverse().forEach(({ index, match, displayText }) => { + // Double-check we're not overlapping with processed content + if (!isInsideProcessedLink(index, match.length)) { + text = text.substring(0, index) + displayText + text.substring(index + match.length); + } + }); + + return text; +} +--- + +{linkedMentions.length > 0 && ( +
+ + +
+ {isCompact ? ( +
+ {linkedMentions.filter(mention => mention !== null).map(mention => ( + + + {mention.title} + + + + ))} +
+ ) : ( +
+ {linkedMentions.filter(mention => mention !== null).map(mention => ( +
+ + + {mention.excerpt && (() => { + const processedExcerpt = processExcerptLinks(mention.excerpt, currentSlug); + // Check if excerpt appears to be at the end of content + // Structural patterns only - no word/phrase matching + // Check if excerpt contains or ends with a link (wikilink, markdown link, or processed link in HTML) + // Links can be: ]] (wikilink), ) (markdown), (processed link) + const hasLink = /(\[\[[^\]]+\]\]|\[[^\]]+\]\([^\)]+\)|<\/mark>)/i.test(processedExcerpt.trim()); + const endsWithLink = /(\]\]|\)|<\/mark>)\s*$/i.test(processedExcerpt.trim()); + // Check if it ends with a complete sentence (period, exclamation, question mark) + const endsWithCompleteSentence = /[.!?]\s*$/.test(processedExcerpt.trim()); + // Check if excerpt ends with structural patterns that suggest incompleteness + // (ends with comma, colon, dash, semicolon - suggesting more content) + const endsWithIncompletePunctuation = /[,:;-]+\s*$/.test(processedExcerpt.trim()); + // Check if excerpt ends without proper sentence punctuation (ends with letter/word, not .!?) + // Only check this if it doesn't end with a link (links are valid endings) + const endsWithoutSentenceEnding = !endsWithLink && !/[.!?]\s*$/.test(processedExcerpt.trim()) && /[a-zA-Z]\s*$/.test(processedExcerpt.trim()); + + // Determine if excerpt is at natural end: + // - Ends with a link (valid ending - links are complete thoughts), OR + // - Has complete sentence AND not incomplete punctuation AND not ending with just a letter + const isAtEnd = endsWithLink || (endsWithCompleteSentence && !endsWithIncompletePunctuation && !endsWithoutSentenceEnding); + + // Check if excerpt appears to be at the start + // If it starts with a complete sentence (capital letter), likely at start + const isAtStart = /^[A-Z]/.test(processedExcerpt.trim()); + + // Only add ellipses if content was clearly truncated from middle + const needsStartEllipsis = !isAtStart && processedExcerpt.length > 60; + // Need end ellipses ONLY if: + // - Not at natural end (doesn't end with link or complete sentence), AND + // - Doesn't end with incomplete punctuation (which already suggests truncation), AND + // - Doesn't end without sentence ending (which already suggests truncation) + // Simplified: if it ends with a link, never add ellipses; otherwise use existing logic + const needsEndEllipsis = !endsWithLink && (!isAtEnd || endsWithIncompletePunctuation || endsWithoutSentenceEnding); + + const finalExcerpt = `${needsStartEllipsis ? '...' : ''}${processedExcerpt}${needsEndEllipsis ? '...' : ''}`; + + return ( +

+ ); + })()} + +

+ + Referenced in this post +
+
+ ))} +
+ )} +
+
+)} + + + + diff --git a/src/components/LocalGraph.astro b/src/components/LocalGraph.astro new file mode 100644 index 0000000..1844d03 --- /dev/null +++ b/src/components/LocalGraph.astro @@ -0,0 +1,911 @@ +--- +import type { Post } from '@/types'; +import { getCollection } from 'astro:content'; +import { shouldShowPost } from '@/utils/markdown'; +import { siteConfig } from '@/config'; +import Icon from './Icon.astro'; + +export interface Props { + currentSlug?: string; +} + +export interface LocalGraphData { + shouldRender: boolean; +} + +const { currentSlug } = Astro.props; + +// Get all posts for graph data +const allPosts = await getCollection('posts'); +const isDev = import.meta.env.DEV; +const visiblePosts = allPosts.filter(p => shouldShowPost(p, isDev)); + +// Check if we should show the graph based on connections +// This component should only be rendered when there are connections (checked in PostLayout) +// But we'll add an additional client-side check as a safety measure +const shouldShowGraph = true; +--- + +{shouldShowGraph && ( +
+ + +
+ + + + +
+ + +
+ +
+
+)} + + + + \ No newline at end of file diff --git a/src/components/MermaidDiagram.astro b/src/components/MermaidDiagram.astro new file mode 100644 index 0000000..1963b64 --- /dev/null +++ b/src/components/MermaidDiagram.astro @@ -0,0 +1,117 @@ +--- +// MermaidDiagram.astro +// Component for rendering Mermaid diagrams with proper styling and error handling + +export interface Props { + id: string; + source: string; + class?: string; +} + +const { id, source, class: className = '' } = Astro.props; +--- + +
+
+
{source}
+
+
+ + diff --git a/src/components/Pagination.astro b/src/components/Pagination.astro new file mode 100644 index 0000000..5fc240b --- /dev/null +++ b/src/components/Pagination.astro @@ -0,0 +1,151 @@ +--- +import type { PaginationInfo } from '@/types'; +import Icon from './Icon.astro'; + +export interface Props { + pagination: PaginationInfo; + baseUrl?: string; +} + +const { pagination, baseUrl = '/posts' } = Astro.props; +const { currentPage, totalPages, hasNext, hasPrev } = pagination; + +// Generate page numbers to show +function generatePageNumbers(current: number, total: number) { + const pages: (number | string)[] = []; + const delta = 2; // Number of pages to show on each side of current page + + // Always show first page + pages.push(1); + + // Add ellipsis if needed + if (current - delta > 2) { + pages.push('...'); + } + + // Add pages around current page + for (let i = Math.max(2, current - delta); i <= Math.min(total - 1, current + delta); i++) { + pages.push(i); + } + + // Add ellipsis if needed + if (current + delta < total - 1) { + pages.push('...'); + } + + // Always show last page if there's more than one page + if (total > 1) { + pages.push(total); + } + + return pages; +} + +const pageNumbers = generatePageNumbers(currentPage, totalPages); + +const prevUrl = hasPrev + ? (currentPage === 2 ? baseUrl : `${baseUrl}/${currentPage - 1}`) + : undefined; + + const nextUrl = hasNext + ? `${baseUrl}/${currentPage + 1}` + : undefined; +--- + +{totalPages > 1 && ( + +)} + + \ No newline at end of file diff --git a/src/components/PostCard.astro b/src/components/PostCard.astro new file mode 100644 index 0000000..d5459d0 --- /dev/null +++ b/src/components/PostCard.astro @@ -0,0 +1,219 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import { formatDate, formatDateMobile, processMarkdown, calculateReadingTime, getReadingTimeMobile } from '../utils/markdown'; +import { siteConfig, getPostCardAspectRatio } from '../config'; +import { getOptimizedFormat } from '@/utils/images'; +import ImageWrapper from './ImageWrapper.astro'; + +interface Props { + post: CollectionEntry<'posts'>; + featured?: boolean; + eager?: boolean; + context?: 'featured' | 'recent' | 'posts' | 'tags'; +} + +const { post, featured = false, eager = false, context = 'posts' } = Astro.props; + +// Get reading time and word count from markdown processing +const { excerpt, wordCount } = processMarkdown(post.body || ''); +const readingTime = calculateReadingTime(post.body || ''); + +const { title, description, date, tags, image: rawImage, imageAlt } = post.data; + +// Process Obsidian bracket syntax in image field +const image = (() => { + if (!rawImage) return rawImage; + + // Handle case where rawImage is an array (unquoted YAML syntax) + let imageValue = rawImage; + if (Array.isArray(rawImage)) { + // If it's an array, take the first element + imageValue = rawImage[0]; + } + + // Ensure imageValue is a string before calling string methods + if (typeof imageValue !== 'string') { + console.warn('PostCard: imageValue is not a string:', imageValue); + return imageValue; + } + + // Check if it's Obsidian double bracket syntax + if (imageValue.startsWith('[[') && imageValue.endsWith(']]')) { + // Extract the content inside the double brackets + return imageValue.slice(2, -2); + } + + return imageValue; +})(); + +// Determine if we should show the cover image based on configuration and context +const shouldShowCoverImage = (() => { + // Only check if image exists - hideCoverImage only affects post content, not cards + if (!image) { + return false; + } + + const showCoverImages = siteConfig.postOptions.showPostCardCoverImages; + + switch (showCoverImages) { + case 'all': + return true; + case 'featured': + return context === 'featured' || featured; + case 'home': + return context === 'featured' || context === 'recent'; + case 'posts': + return context === 'posts' || context === 'tags'; + case 'featured-and-posts': + return context === 'featured' || context === 'posts' || context === 'tags' || featured; + case 'none': + default: + return false; + } +})(); + +// No need for dynamic image import - ImageWrapper handles this +--- + +
+ + {image && shouldShowCoverImage && ( +
+ { + // Clean the image path by removing Obsidian brackets + let cleanImagePath = image; + if (!cleanImagePath || typeof cleanImagePath !== 'string') return ''; + if (cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // Handle external URLs + if (cleanImagePath.startsWith('http')) { + return cleanImagePath; + } + + // Detect folder-based vs file-based: if image path starts with 'attachments/', + // it's a single-file post (shared attachments folder) + const isFileBased = cleanImagePath.startsWith('attachments/'); + + if (isFileBased) { + // Single-file post - remove attachments/ prefix + cleanImagePath = cleanImagePath.replace('attachments/', ''); + } else { + // Folder-based post - sync script copies images to post folder root + // Remove 'images/' or 'attachments/' prefixes if present (sync script removes them) + if (cleanImagePath.startsWith('images/') || cleanImagePath.startsWith('attachments/')) { + cleanImagePath = cleanImagePath.replace(/^(images|attachments)\//, ''); + } + } + + // Convert to WebP if applicable (sync-images.js creates WebP versions) + return getOptimizedFormat(cleanImagePath); + })()} + basePath={(() => { + // 1. External URLs - no basePath needed + if (typeof image === 'string' && image.startsWith('http')) { + return ''; + } + + // 2. Clean the image path to check for attachments/ prefix + let cleanImagePath = image; + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // 3. Detect folder-based vs file-based: if image path starts with 'attachments/', + // it's a single-file post (shared attachments folder) + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('attachments/')) { + // Single-file post with image in attachments folder + return '/posts/attachments/'; + } + + // 4. Folder-based post - sync script copies images to post folder root + // Safety check: ensure post.id exists before using it + if (post.id) { + return `/posts/${post.id}/`; + } else { + // Fallback to attachments directory if post.id is undefined + return '/posts/attachments/'; + } + })()} + alt={imageAlt || `Featured image for post: ${title}`} + class="w-full h-full group-hover:scale-102 dark:group-hover:brightness-100 transition-all duration-300" + width={800} + height={450} + format="webp" + quality={85} + loading={featured || eager ? "eager" : "lazy"} + fetchpriority={featured || eager ? "high" : "auto"} + /> +
+ )} + +
+ +
diff --git a/src/components/PostContent.astro b/src/components/PostContent.astro new file mode 100644 index 0000000..e9c85d0 --- /dev/null +++ b/src/components/PostContent.astro @@ -0,0 +1,306 @@ +--- +import type { Post } from '@/types'; +import { processImagesForLightbox, getOptimizedFormat } from '@/utils/images'; +import { siteConfig } from '@/config'; +import { formatDate, formatDateMobile, getReadingTimeMobile } from '@/utils/markdown'; +import ImageGallery from './ImageGallery.astro'; +import TableOfContents from './TableOfContents.astro'; +import Button from './Button.astro'; +import ImageWrapper from './ImageWrapper.astro'; + +export interface Props { + post: Post & { + Content: any; + toc: any[]; + readingTime?: any; + wordCount?: number; + }; +} + +const { post } = Astro.props; +const { Content, toc, readingTime, wordCount } = post; + +// Process Obsidian bracket syntax in image field +const processedImage = (() => { + if (!post.data.image) return post.data.image; + + // Handle case where image is an array (unquoted YAML syntax) + let imageValue = post.data.image; + if (Array.isArray(post.data.image)) { + // If it's an array, take the first element + imageValue = post.data.image[0]; + } + + // Ensure imageValue is a string before calling string methods + if (typeof imageValue !== 'string') { + console.warn('PostContent: imageValue is not a string:', imageValue); + return imageValue; + } + + // Check if it's Obsidian double bracket syntax + if (imageValue.startsWith('[[') && imageValue.endsWith(']]')) { + // Extract the content inside the double brackets + return imageValue.slice(2, -2); + } + + return imageValue; +})(); +--- + +
+
+ +
+ +
+

+ {post.data.title} +

+ +
+ + + {siteConfig.postOptions.readingTime && readingTime && ( + <> + + + + + {getReadingTimeMobile(readingTime)} + + + )} + + {siteConfig.postOptions.wordCount && wordCount && ( + <> + + + + + {wordCount.toLocaleString()} words + + + )} +
+ + {post.data.tags && post.data.tags.length > 0 && siteConfig.postOptions.tags && ( +
+ {post.data.tags.map(tag => ( + + #{tag} + + ))} +
+ )} + + {processedImage && ( +
+ { + // Clean the image path by removing Obsidian brackets + let cleanImagePath = processedImage; + if (!cleanImagePath || typeof cleanImagePath !== 'string') return ''; + if (cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // Handle external URLs + if (cleanImagePath.startsWith('http')) { + return cleanImagePath; + } + + // Detect folder-based vs file-based: if image path starts with 'attachments/', + // it's a single-file post (shared attachments folder) + const isFileBased = cleanImagePath.startsWith('attachments/'); + + if (isFileBased) { + // Single-file post - remove attachments/ prefix + cleanImagePath = cleanImagePath.replace('attachments/', ''); + } else { + // Folder-based post - sync script copies images to post folder root + // Remove 'images/' or 'attachments/' prefixes if present (sync script removes them) + if (cleanImagePath.startsWith('images/') || cleanImagePath.startsWith('attachments/')) { + cleanImagePath = cleanImagePath.replace(/^(images|attachments)\//, ''); + } + } + + // Convert to WebP if applicable (sync-images.js creates WebP versions) + return getOptimizedFormat(cleanImagePath); + })()} + basePath={(() => { + // 1. External URLs - no basePath needed + if (typeof processedImage === 'string' && processedImage.startsWith('http')) { + return ''; + } + + // 2. Clean the image path to check for attachments/ prefix + let cleanImagePath = processedImage; + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // 3. Detect folder-based vs file-based: if image path starts with 'attachments/', + // it's a single-file post (shared attachments folder) + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('attachments/')) { + // Single-file post with image in attachments folder + return '/posts/attachments/'; + } + + // 4. Folder-based post - sync script copies images to post folder root + // Safety check: ensure post.id exists before using it + if (post.id) { + return `/posts/${post.id}/`; + } + + // Fallback to attachments directory if post.id is undefined + return '/posts/attachments/'; + })()} + alt={post.data.imageAlt || `Image in post: ${post.data.title}`} + class="w-full h-full" + width={1200} + height={675} + format={typeof processedImage === 'string' && processedImage.endsWith('.svg') ? undefined : "webp"} + quality={90} + densities={[1, 2]} + loading="eager" + fetchpriority="high" + /> +
+ )} +
+ + +
+ +
+
+ + +
+
+ + {siteConfig.tableOfContents.enabled && toc && toc.length > 0 && ( + + )} + + +
+

+ Post Information +

+
+
+ Published + + {formatDate(post.data.date)} + +
+ + {readingTime && ( +
+ Reading time + {readingTime.text} +
+ )} + + {wordCount && ( +
+ Word count + {wordCount.toLocaleString()} +
+ )} + + {post.data.targetKeyword && ( +
+ Target keyword + {post.data.targetKeyword} +
+ )} +
+
+
+
+
+
+ + diff --git a/src/components/ProjectCard.astro b/src/components/ProjectCard.astro new file mode 100644 index 0000000..d6e68c4 --- /dev/null +++ b/src/components/ProjectCard.astro @@ -0,0 +1,304 @@ +--- +import type { CollectionEntry } from 'astro:content'; +import { formatDate, processMarkdown, isValidDate } from '../utils/markdown'; +import { siteConfig, getPostCardAspectRatio } from '../config'; +import { normalizeStatus, getStatusDisplayText, hasStatusStyling, getStatusClasses } from '../utils/status'; +import { optimizeContentImagePath, getOptimizedFormat } from '../utils/images'; +import ImageWrapper from './ImageWrapper.astro'; +import Icon from './Icon.astro'; + +interface Props { + project: CollectionEntry<'projects'>; + featured?: boolean; + eager?: boolean; + context?: 'featured' | 'recent' | 'projects' | 'tags' | 'home'; + showCategories?: boolean; +} + +const { project, featured = false, eager = false, context = 'projects', showCategories = true } = Astro.props; + +// Get excerpt from markdown processing +const { excerpt } = processMarkdown(project.body || ''); + +const { title, description: rawDescription, date, image: rawImage, imageAlt } = project.data; + +// Process Obsidian bracket syntax in image field (copy from PostCard) +const image = (() => { + if (!rawImage) return rawImage; + + // Handle case where rawImage is an array (unquoted YAML syntax) + let imageValue = rawImage; + if (Array.isArray(rawImage)) { + // If it's an array, take the first element + imageValue = rawImage[0]; + } + + // Ensure imageValue is a string before calling string methods + if (typeof imageValue !== 'string') { + console.warn('ProjectCard: imageValue is not a string:', imageValue); + return imageValue; + } + + // Check if it's Obsidian double bracket syntax + if (imageValue.startsWith('[[') && imageValue.endsWith(']]')) { + // Extract the content inside the double brackets + return imageValue.slice(2, -2); + } + + return imageValue; +})(); + +const description = rawDescription || excerpt; +const categories = project.data.categories || []; +const status = normalizeStatus(project.data.status); +const repositoryUrl = project.data.repositoryUrl; +const projectUrl = project.data.projectUrl || project.data.demoUrl || project.data.demoURL; + +// Determine content availability for layout +const hasDescription = description && description.trim().length > 0; +const hasCategories = showCategories && categories.length > 0; +const hasHoverContent = hasDescription || hasCategories; + +// Determine if we should show the cover image +// Projects should always show images when available (not controlled by postOptions) +const shouldShowCoverImage = true; +--- + +
+ + + {image && shouldShowCoverImage && ( +
+ { + // Clean the image path by removing Obsidian brackets + let cleanImagePath = image; + if (!cleanImagePath || typeof cleanImagePath !== 'string') return ''; + if (cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // Remove Obsidian subfolder prefixes (images/, attachments/) + if (typeof cleanImagePath === 'string') { + // Remove images/ prefix if present (Obsidian subfolder setting) + if (cleanImagePath.startsWith('images/')) { + cleanImagePath = cleanImagePath.replace('images/', ''); + } + // Remove attachments/ prefix - basePath will add it back + if (cleanImagePath.startsWith('attachments/')) { + cleanImagePath = cleanImagePath.replace('attachments/', ''); + } + } + + const finalSrc = cleanImagePath || ''; + // Convert to WebP if applicable (sync-images.js creates WebP versions) + return getOptimizedFormat(finalSrc); + })()} + basePath={(() => { + // 1. External URLs - no basePath needed + if (typeof image === 'string' && image.startsWith('http')) { + return ''; + } + + // 2. Clean the image path to check for attachments/ prefix + let cleanImagePath = image; + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('[[') && cleanImagePath.endsWith(']]')) { + cleanImagePath = cleanImagePath.slice(2, -2); + } + + // 3. Detect folder-based vs file-based: if image path starts with 'attachments/', + // it's a single-file project (shared attachments folder) + if (typeof cleanImagePath === 'string' && cleanImagePath.startsWith('attachments/')) { + // Single-file project with image in attachments folder + // The sync script copies these to /projects/attachments/ + return "/projects/attachments/"; + } + + // 4. Folder-based project - sync script copies images to project folder root + // Safety check: ensure project.id exists before using it + if (project.id) { + return `/projects/${project.id}/`; + } else { + // Fallback to attachments directory if project.id is undefined + return '/projects/attachments/'; + } + })()} + alt={imageAlt || `Cover image for project: ${title}`} + width={800} + height={600} + loading={eager ? 'eager' : 'lazy'} + fetchpriority={eager ? 'high' : 'auto'} + class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300" + /> + +
+
+ )} + + {!image && ( + +
+ )} + + + {status && ( +
+ + {getStatusDisplayText(status)} + +
+ )} + + + {isValidDate(date) && ( +
+ +
+ )} + + +
+ +

+ {title} +

+ + {hasHoverContent ? ( + +
+ + {hasDescription && ( +

+ {description} +

+ )} + + + {hasCategories && ( +
+ {categories.slice(0, 3).map(category => ( + + {category} + + ))} + {categories.length > 3 && ( + + +{categories.length - 3} more + + )} +
+ )} +
+ ) : ( + +
+ {hasDescription && ( +

+ {description} +

+ )} + + {hasCategories && ( +
+ {categories.slice(0, 3).map(category => ( + + {category} + + ))} + {categories.length > 3 && ( + + +{categories.length - 3} more + + )} +
+ )} +
+ )} +
+
+
+ + \ No newline at end of file diff --git a/src/components/ProjectCategories.astro b/src/components/ProjectCategories.astro new file mode 100644 index 0000000..244110d --- /dev/null +++ b/src/components/ProjectCategories.astro @@ -0,0 +1,242 @@ +--- +import { siteConfig } from '@/config'; +import Icon from './Icon.astro'; + +export interface Props { + categories: string[]; + currentCategory?: string; + showCount?: boolean; + variant?: 'default' | 'outline' | 'minimal'; +} + +const { categories, currentCategory, showCount = false, variant = 'default' } = Astro.props; + +// Sort categories alphabetically +const sortedCategories = [...categories].sort(); +--- + +{sortedCategories.length > 0 && ( +
+

+ + Categories +

+ +
+ {sortedCategories.map(category => ( + + ))} +
+
+)} + + + + + diff --git a/src/components/ScrollToTop.astro b/src/components/ScrollToTop.astro new file mode 100644 index 0000000..114978c --- /dev/null +++ b/src/components/ScrollToTop.astro @@ -0,0 +1,78 @@ + +--- +import Icon from './Icon.astro'; +// Scroll to top button component +--- + + + + + + diff --git a/src/components/SearchResults.astro b/src/components/SearchResults.astro new file mode 100644 index 0000000..53e1cb1 --- /dev/null +++ b/src/components/SearchResults.astro @@ -0,0 +1,57 @@ +--- +// This component is used by the command palette for rendering search results +import Icon from './Icon.astro'; + +export interface Props { + results: Array<{ + id: string; + title: string; + description?: string; + url: string; + type: 'post' | 'page' | 'external'; + }>; +} + +const { results } = Astro.props; +--- + +{results.length > 0 ? ( + +) : ( +
+ +

No results found

+

Try a different search term

+
+)} diff --git a/src/components/TableOfContents.astro b/src/components/TableOfContents.astro new file mode 100644 index 0000000..69b7b54 --- /dev/null +++ b/src/components/TableOfContents.astro @@ -0,0 +1,455 @@ +--- +import type { Heading } from '@/types'; +import Icon from './Icon.astro'; +import { getTableOfContentsDepth } from '@/config'; + +export interface Props { + headings: Heading[]; +} + +const { headings } = Astro.props; + +// Filter and structure headings using configurable depth +const maxDepth = getTableOfContentsDepth(); +const filteredHeadings = headings.filter(h => h.depth >= 2 && h.depth <= maxDepth); +// Hide TOC if there's only 1 heading (not useful) +const shouldShowTOC = filteredHeadings.length > 1; +--- + +{shouldShowTOC && ( + +)} + + + + diff --git a/src/components/Tags.astro b/src/components/Tags.astro new file mode 100644 index 0000000..0beeb15 --- /dev/null +++ b/src/components/Tags.astro @@ -0,0 +1,116 @@ +--- +import { siteConfig } from '@/config'; +import Icon from './Icon.astro'; + +export interface Props { + tags: string[]; + currentTag?: string; + showCount?: boolean; + variant?: 'default' | 'outline' | 'minimal'; +} + +const { tags, currentTag, showCount = false, variant = 'default' } = Astro.props; + +// Sort tags alphabetically +const sortedTags = [...tags].sort(); +--- + +{siteConfig.postOptions.tags && sortedTags.length > 0 && ( + +)} + + + + \ No newline at end of file diff --git a/src/components/ThemeSelector.astro b/src/components/ThemeSelector.astro new file mode 100644 index 0000000..94136c0 --- /dev/null +++ b/src/components/ThemeSelector.astro @@ -0,0 +1,338 @@ +--- +import { siteConfig, getThemeDisplayName } from '../config'; +import Icon from './Icon.astro'; +--- + + + + + + + + + + diff --git a/src/components/ThemeToggle.astro b/src/components/ThemeToggle.astro new file mode 100644 index 0000000..eb99701 --- /dev/null +++ b/src/components/ThemeToggle.astro @@ -0,0 +1,49 @@ +--- +import Icon from './Icon.astro'; +--- + + + + \ No newline at end of file diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..f81bae8 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,782 @@ +// Site configuration with TypeScript types +import type { NavigationItem } from "./types"; + +// Aspect ratio options for post cards +export type AspectRatio = + | "16:9" + | "4:3" + | "3:2" + | "og" + | "square" + | "golden" + | "custom"; + +export interface SiteConfig { + // Site Information + site: string; + title: string; + /** Homepage-specific meta title. Falls back to title if empty. */ + homepageTitle: string; + description: string; + author: string; + language: string; + faviconThemeAdaptive: boolean; + defaultOgImageAlt: string; + + // Global Settings + theme: "minimal" | "oxygen" | "atom" | "ayu" | "catppuccin" | "charcoal" | "dracula" | "everforest" | "flexoki" | "gruvbox" | "macos" | "nord" | "obsidian" | "rose-pine" | "sky" | "solarized" | "things" | "custom"; + customThemeFile?: string; // Filename in src/themes/custom/ (e.g., "my-cool-theme" for my-cool-theme.ts) + availableThemes: "default" | Array; // Control which themes users can select - "default" shows all built-in themes, array can include custom theme filenames + fonts: { + source: "local" | "cdn"; + families: { + body: string; + heading: string; + mono: string; + }; + display: "swap" | "fallback" | "optional"; + }; + layout: { + contentWidth: string; + }; + tableOfContents: { + enabled: boolean; + depth: number; + }; + footer: { + enabled: boolean; + content: string; + showSocialIconsInFooter: boolean; + }; + // [CONFIG:HIDE_SCROLL_BAR] + hideScrollBar: boolean; + scrollToTop: boolean; + featureButton: "mode" | "graph" | "theme" | "none"; + deployment: { + platform: "netlify" | "vercel" | "github-pages" | "cloudflare-workers"; + }; + + // Command Palette + commandPalette: { + enabled: boolean; + shortcut: string; + placeholder: string; + search: { + posts: boolean; + pages: boolean; + projects: boolean; + docs: boolean; + }; + sections: { + quickActions: boolean; + pages: boolean; + social: boolean; + }; + quickActions: { + enabled: boolean; + toggleMode: boolean; + graphView: boolean; + changeTheme: boolean; + }; + }; + + // Profile Picture + profilePicture: { + enabled: boolean; + image: string; + alt: string; + size: "sm" | "md" | "lg"; + url?: string; + placement: "footer" | "header"; + style: "circle" | "square" | "none"; + }; + + // Navigation + navigation: { + showNavigation: boolean; + style: "minimal" | "traditional"; + showMobileMenu: boolean; + pages: NavigationItem[]; + social: Array<{ title: string; url: string; icon: string }>; + }; + + // Home Options + homeOptions: { + featuredPost: { + enabled: boolean; + type: "latest" | "featured"; + slug?: string; // Only used when type is "featured" + }; + recentPosts: { + enabled: boolean; + count: number; + }; + projects: { + enabled: boolean; + count: number; + }; + docs: { + enabled: boolean; + count: number; + }; + blurb: { + placement: "above" | "below" | "none"; + }; + }; + + // Post Options + postOptions: { + postsPerPage: number; + readingTime: boolean; + wordCount: boolean; + tags: boolean; + linkedMentions: { + enabled: boolean; + linkedMentionsCompact: boolean; + }; + graphView: { + enabled: boolean; + showInSidebar: boolean; + maxNodes: number; + showOrphanedPosts: boolean; + }; + postNavigation: boolean; + showPostCardCoverImages: "all" | "featured" | "home" | "posts" | "featured-and-posts" | "none"; + postCardAspectRatio: AspectRatio; + customPostCardAspectRatio?: string; + comments: { + enabled: boolean; + provider: string; + repo: string; + repoId: string; + category: string; + categoryId: string; + mapping: string; + strict: string; + reactions: string; + metadata: string; + inputPosition: string; + theme: string; + lang: string; + loading: string; + }; + }; + + // Optional Content Types + optionalContentTypes: { + projects: boolean; + docs: boolean; + }; +} + +// ═══════════════════════════════════════════════════════════════════════════════ +// ASTRO MODULAR CONFIGURATION +// ═══════════════════════════════════════════════════════════════════════════════ +// +// ⚠️ IMPORTANT: Comment markers like // [CONFIG:KEY] are used by the Astro Modular +// Settings Obsidian plugin. Do not remove these markers or the plugin will not be +// able to update your configuration automatically. +// +// Most settings have helpful comments explaining what they do. +// +// ═══════════════════════════════════════════════════════════════════════════════ +export const siteConfig: SiteConfig = { + // Site Information + // [CONFIG:SITE_URL] + site: "https://astro-modular.netlify.app", + // [CONFIG:SITE_TITLE] + title: "Astro Modular", + // [CONFIG:HOMEPAGE_TITLE] + homepageTitle: "", + // [CONFIG:SITE_DESCRIPTION] + description: "A flexible blog theme designed for Obsidian users.", + // [CONFIG:SITE_AUTHOR] + author: "David V. Kimball", + // [CONFIG:SITE_LANGUAGE] + language: "en", + // [CONFIG:FAVICON_THEME_ADAPTIVE] + faviconThemeAdaptive: true, // If true, favicon switches between favicon-dark.png and favicon-light.png based on browser's system theme preference. If false, always uses favicon.png + // [CONFIG:DEFAULT_OG_IMAGE_ALT] + defaultOgImageAlt: "Astro Modular logo.", // Alt text for the default Open Graph image, public/open-graph.png + + // Global Settings + // [CONFIG:THEME] + theme: "oxygen", // Available themes: "minimal" | "oxygen" | "atom" | "ayu" | "catppuccin" | "charcoal" | "dracula" | "everforest" | "flexoki" | "gruvbox" | "macos" | "nord" | "obsidian" | "rose-pine" | "sky" | "solarized" | "things" | "custom" + // [CONFIG:CUSTOM_THEME_FILE] + customThemeFile: "custom", // Only used if theme is set to "custom" above. Filename in src/themes/custom/ (without .ts extension) + // [CONFIG:AVAILABLE_THEMES] + availableThemes: "default", // "default" to show all built-in themes, or array of theme names like ["oxygen", "minimal", "obsidianite"] to limit choices (can include custom theme filenames) + fonts: { + // [CONFIG:FONT_SOURCE] + source: "local", // "local" for self-hosted @fontsource fonts, "cdn" for Google Fonts CDN + families: { + // [CONFIG:FONT_BODY] + body: "Inter", // Body text font family + // [CONFIG:FONT_HEADING] + heading: "Inter", // Heading font family + // [CONFIG:FONT_MONO] + mono: "JetBrains Mono", // Monospace font family + }, + // [CONFIG:FONT_DISPLAY] + display: "swap", // Font display strategy: "swap" (recommended), "fallback", or "optional" + }, + layout: { + // [CONFIG:LAYOUT_CONTENT_WIDTH] + contentWidth: "45rem", + }, + tableOfContents: { + // [CONFIG:TABLE_OF_CONTENTS_ENABLED] + enabled: true, + // [CONFIG:TABLE_OF_CONTENTS_DEPTH] + depth: 4, // Maximum heading depth to include in ToC (2-6, where 2=H2, 3=H3, etc.) + }, + footer: { + // [CONFIG:FOOTER_ENABLED] + enabled: true, + // [CONFIG:FOOTER_CONTENT] + content: `© 2025 {author}. Built with the Astro Modular theme.`, + // [CONFIG:FOOTER_SHOW_SOCIAL_ICONS] + showSocialIconsInFooter: true, + }, + //[CONFIG:HIDE_SCROLL_BAR] + hideScrollBar: false, + // [CONFIG:SCROLL_TO_TOP] + scrollToTop: true, + // [CONFIG:FEATURE_BUTTON] + featureButton: "mode", // "mode" | "graph" | "theme" | "none" + deployment: { + // [CONFIG:DEPLOYMENT_PLATFORM] + platform: "netlify", // "netlify" | "vercel" | "github-pages" | "cloudflare-workers" - sets redirect configuration for the chosen platform (Cloudflare Workers uses Workers-compatible config) + }, + + // Command Palette + commandPalette: { + // [CONFIG:COMMAND_PALETTE_ENABLED] + enabled: true, + // [CONFIG:COMMAND_PALETTE_SHORTCUT] + shortcut: "ctrl+K", + // [CONFIG:COMMAND_PALETTE_PLACEHOLDER] + placeholder: "Search posts", + search: { + // [CONFIG:COMMAND_PALETTE_SEARCH_POSTS] + posts: true, + // [CONFIG:COMMAND_PALETTE_SEARCH_PAGES] + pages: false, + // [CONFIG:COMMAND_PALETTE_SEARCH_PROJECTS] + projects: false, + // [CONFIG:COMMAND_PALETTE_SEARCH_DOCS] + docs: false, + }, + sections: { + // [CONFIG:COMMAND_PALETTE_SECTIONS_QUICK_ACTIONS] + quickActions: true, + // [CONFIG:COMMAND_PALETTE_SECTIONS_PAGES] + pages: true, + // [CONFIG:COMMAND_PALETTE_SECTIONS_SOCIAL] + social: true, + }, + quickActions: { + // [CONFIG:COMMAND_PALETTE_QUICK_ACTIONS_ENABLED] + enabled: true, + // [CONFIG:COMMAND_PALETTE_QUICK_ACTIONS_TOGGLE_MODE] + toggleMode: true, + // [CONFIG:COMMAND_PALETTE_QUICK_ACTIONS_GRAPH_VIEW] + graphView: true, + // [CONFIG:COMMAND_PALETTE_QUICK_ACTIONS_CHANGE_THEME] + changeTheme: true, + }, + }, + + // Profile Picture + profilePicture: { + // [CONFIG:PROFILE_PICTURE_ENABLED] + enabled: false, + // [CONFIG:PROFILE_PICTURE_IMAGE] + image: "/profile.jpg", // Path to your profile image (place in public/ directory) + // [CONFIG:PROFILE_PICTURE_ALT] + alt: "Profile picture", + // [CONFIG:PROFILE_PICTURE_SIZE] + size: "md", // "sm" (32px), "md" (48px), or "lg" (64px) - only affects footer placement + // [CONFIG:PROFILE_PICTURE_URL] + url: "", // Optional + // [CONFIG:PROFILE_PICTURE_PLACEMENT] + placement: "footer", // "footer" or "header" + // [CONFIG:PROFILE_PICTURE_STYLE] + style: "circle", // "circle", "square", or "none" + }, + + // Navigation + navigation: { + // [CONFIG:NAVIGATION_SHOW_NAVIGATION] + showNavigation: true, + // [CONFIG:NAVIGATION_STYLE] + style: "traditional", // 'minimal' or 'traditional' + // [CONFIG:NAVIGATION_SHOW_MOBILE_MENU] + showMobileMenu: true, + // [CONFIG:NAVIGATION_PAGES] + pages: [ + { title: "Posts", url: "/posts/" }, + { title: "Projects", url: "/projects/" }, + { title: "Docs", url: "/docs/" }, + { title: "About", url: "/about/", + children: [ + { title: "Privacy Policy", url: "/privacy-policy/" } + ] }, + { title: "GitHub", url: "https://github.com/davidvkimball/astro-modular" } + ], + // [CONFIG:NAVIGATION_SOCIAL] + social: [ + { + title: "X", + url: "https://x.com/davidvkimball", + icon: "x-twitter", + }, + { + title: "GitHub", + url: "https://github.com/davidvkimball", + icon: "github", + }, + ], + }, + + // Optional Content Types - Enable/disable optional content sections (takes priority over homeOptions) + optionalContentTypes: { + // [CONFIG:OPTIONAL_CONTENT_TYPES_PROJECTS] + projects: true, // Enable projects section + // [CONFIG:OPTIONAL_CONTENT_TYPES_DOCS] + docs: true, // Enable documentation section + }, + + // Home Options + homeOptions: { + featuredPost: { + // [CONFIG:HOME_OPTIONS_FEATURED_POST_ENABLED] + enabled: true, // Show featured post on homepage + // [CONFIG:HOME_OPTIONS_FEATURED_POST_TYPE] + type: "latest", // "latest" or "featured" + // [CONFIG:HOME_OPTIONS_FEATURED_POST_SLUG] + slug: "getting-started", // Slug of post after '/posts/' to be featured (e.g. "post-title"). Only used when type is "featured" + }, + recentPosts: { + // [CONFIG:HOME_OPTIONS_RECENT_POSTS_ENABLED] + enabled: true, // Show recent posts on homepage + // [CONFIG:HOME_OPTIONS_RECENT_POSTS_COUNT] + count: 7, // Number of recent posts to show + }, + projects: { + // [CONFIG:HOME_OPTIONS_PROJECTS_ENABLED] + enabled: true, // Show featured projects on homepage + // [CONFIG:HOME_OPTIONS_PROJECTS_COUNT] + count: 2, // Number of projects to show + }, + docs: { + // [CONFIG:HOME_OPTIONS_DOCS_ENABLED] + enabled: true, // Show featured docs on homepage + // [CONFIG:HOME_OPTIONS_DOCS_COUNT] + count: 3, // Number of docs to show + }, + blurb: { + // [CONFIG:HOME_OPTIONS_BLURB_PLACEMENT] + placement: "below", // 'above' (at the top), 'below' (after content), or 'none' (disabled) + }, + }, + + // Post Options + postOptions: { + // [CONFIG:POST_OPTIONS_POSTS_PER_PAGE] + postsPerPage: 6, + // [CONFIG:POST_OPTIONS_READING_TIME] + readingTime: true, + // [CONFIG:POST_OPTIONS_WORD_COUNT] + wordCount: true, + // [CONFIG:POST_OPTIONS_TAGS] + tags: true, + linkedMentions: { + // [CONFIG:POST_OPTIONS_LINKED_MENTIONS_ENABLED] + enabled: true, + // [CONFIG:POST_OPTIONS_LINKED_MENTIONS_COMPACT] + linkedMentionsCompact: false, + }, + graphView: { + // [CONFIG:POST_OPTIONS_GRAPH_VIEW_ENABLED] + enabled: true, + // [CONFIG:POST_OPTIONS_GRAPH_VIEW_SHOW_IN_SIDEBAR] + showInSidebar: true, + // [CONFIG:POST_OPTIONS_GRAPH_VIEW_MAX_NODES] + maxNodes: 100, + // [CONFIG:POST_OPTIONS_GRAPH_VIEW_SHOW_ORPHANED_POSTS] + showOrphanedPosts: true, + }, + // [CONFIG:POST_OPTIONS_POST_NAVIGATION] + postNavigation: true, + // [CONFIG:POST_OPTIONS_SHOW_POST_CARD_COVER_IMAGES] + showPostCardCoverImages: "featured-and-posts", // "all" | "featured" | "home" | "posts" | "featured-and-posts" | "none" + // [CONFIG:POST_OPTIONS_POST_CARD_ASPECT_RATIO] + postCardAspectRatio: "og", // "16:9" | "4:3" | "3:2" | "og" | "square" | "golden" | "custom" + // [CONFIG:POST_OPTIONS_CUSTOM_POST_CARD_ASPECT_RATIO] + customPostCardAspectRatio: "2.5/1", // Only used when postCardAspectRatio is "custom" (e.g., "2.5/1") + comments: { + // [CONFIG:POST_OPTIONS_COMMENTS_ENABLED] + enabled: false, + // [CONFIG:POST_OPTIONS_COMMENTS_PROVIDER] + provider: "giscus", + // [CONFIG:POST_OPTIONS_COMMENTS_REPO] + repo: "", + // [CONFIG:POST_OPTIONS_COMMENTS_REPO_ID] + repoId: "", + // [CONFIG:POST_OPTIONS_COMMENTS_CATEGORY] + category: "", + // [CONFIG:POST_OPTIONS_COMMENTS_CATEGORY_ID] + categoryId: "", + // [CONFIG:POST_OPTIONS_COMMENTS_MAPPING] + mapping: "", + // [CONFIG:POST_OPTIONS_COMMENTS_STRICT] + strict: "", + // [CONFIG:POST_OPTIONS_COMMENTS_REACTIONS] + reactions: "", + // [CONFIG:POST_OPTIONS_COMMENTS_METADATA] + metadata: "", + // [CONFIG:POST_OPTIONS_COMMENTS_INPUT_POSITION] + inputPosition: "", + // [CONFIG:POST_OPTIONS_COMMENTS_THEME] + theme: "", + // [CONFIG:POST_OPTIONS_COMMENTS_LANG] + lang: "", + // [CONFIG:POST_OPTIONS_COMMENTS_LOADING] + loading: "", + }, + }, +}; + +// Utility functions +export function getFeature(feature: keyof Omit): boolean { + return siteConfig.postOptions[feature]; +} + +export function getCommandPaletteShortcut(): string { + return siteConfig.commandPalette.shortcut; +} + +export function getContentWidth(): string { + return siteConfig.layout.contentWidth; +} + +export function getTheme(): "minimal" | "oxygen" | "atom" | "ayu" | "catppuccin" | "charcoal" | "dracula" | "everforest" | "flexoki" | "gruvbox" | "macos" | "nord" | "obsidian" | "rose-pine" | "sky" | "solarized" | "things" | "custom" { + return siteConfig.theme; +} + +export function getPostCardAspectRatio(): string { + const { postCardAspectRatio, customPostCardAspectRatio } = siteConfig.postOptions; + + switch (postCardAspectRatio) { + case "16:9": + return "16 / 9"; + case "4:3": + return "4 / 3"; + case "3:2": + return "3 / 2"; + case "og": + return "1.91 / 1"; + case "square": + return "1 / 1"; + case "golden": + return "1.618 / 1"; + case "custom": + return customPostCardAspectRatio || "1.91 / 1"; // Fallback to OpenGraph if custom not provided + default: + return "1.91 / 1"; // Default to OpenGraph + } +} + +export function getHeadingFont(): string { + return siteConfig.fonts.families.heading; +} + +export function getProseFont(): string { + return siteConfig.fonts.families.body; +} + +export function getTableOfContentsDepth(): number { + return siteConfig.tableOfContents.depth; +} + +export function getTableOfContentsEnabled(): boolean { + return siteConfig.tableOfContents.enabled; +} + +export function getFontFamily(fontName: string): string { + // Convert font name to CSS font-family with fallbacks + const fontMap: Record = { + 'Inter': "'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif", + 'Roboto': "'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Open Sans': "'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Lato': "'Lato', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Poppins': "'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Source Sans Pro': "'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Nunito': "'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Montserrat': "'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif", + 'Playfair Display': "'Playfair Display', Georgia, 'Times New Roman', serif", + 'Merriweather': "'Merriweather', Georgia, 'Times New Roman', serif", + 'Lora': "'Lora', Georgia, 'Times New Roman', serif", + 'Crimson Text': "'Crimson Text', Georgia, 'Times New Roman', serif", + 'PT Serif': "'PT Serif', Georgia, 'Times New Roman', serif", + 'Libre Baskerville': "'Libre Baskerville', Georgia, 'Times New Roman', serif", + 'Fira Code': "'Fira Code', 'Monaco', 'Consolas', 'Courier New', monospace", + 'JetBrains Mono': "'JetBrains Mono', 'Monaco', 'Consolas', 'Courier New', monospace", + 'Source Code Pro': "'Source Code Pro', 'Monaco', 'Consolas', 'Courier New', monospace", + 'IBM Plex Mono': "'IBM Plex Mono', 'Monaco', 'Consolas', 'Courier New', monospace", + 'Cascadia Code': "'Cascadia Code', 'Monaco', 'Consolas', 'Courier New', monospace", + }; + + return fontMap[fontName] || `'${fontName}', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif`; +} + +export function getGoogleFontsUrl(headingFont: string, bodyFont: string): string { + // Google Fonts that are commonly used and available + const googleFonts = [ + 'Inter', 'Roboto', 'Open Sans', 'Lato', 'Poppins', 'Source Sans Pro', + 'Nunito', 'Montserrat', 'Playfair Display', 'Merriweather', 'Lora', + 'Crimson Text', 'PT Serif', 'Libre Baskerville', 'Fira Code', + 'JetBrains Mono', 'Source Code Pro', 'IBM Plex Mono', 'Cascadia Code' + ]; + + const fonts = new Set(); + + // Add fonts if they're Google Fonts + if (googleFonts.includes(headingFont)) { + fonts.add(headingFont); + } + if (googleFonts.includes(bodyFont)) { + fonts.add(bodyFont); + } + + // If no Google Fonts are needed, return empty string + if (fonts.size === 0) { + return ''; + } + + // Generate Google Fonts URL + const fontList = Array.from(fonts).map(font => { + // Add common weights for each font + const weights = font.includes('Mono') ? '300;400;500;600;700' : '300;400;500;600;700'; + return `${font.replace(/\s+/g, '+')}:wght@${weights}`; + }).join('&family='); + + return `https://fonts.googleapis.com/css2?family=${fontList}&display=swap`; +} + +// Font loading utilities +export function getFontSource(): "local" | "cdn" { + return siteConfig.fonts.source; +} + +export function getFontDisplay(): "swap" | "fallback" | "optional" { + return siteConfig.fonts.display; +} + +// Theme display name utility for UI formatting +export function getThemeDisplayName(themeName: string): string { + // Special cases for proper formatting + const specialCases: Record = { + 'rose-pine': 'Rosé Pine', + 'macos': 'macOS' + }; + + // Return special case if it exists + if (specialCases[themeName]) { + return specialCases[themeName]; + } + + // General formatting: capitalize first letter and replace hyphens with spaces + return themeName + .split('-') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); +} + +export function getFontFamilies() { + return siteConfig.fonts.families; +} + +export function shouldLoadLocalFonts(): boolean { + return siteConfig.fonts.source === "local"; +} + +export function shouldLoadCdnFonts(): boolean { + return siteConfig.fonts.source === "cdn"; +} + +// Validation function for siteConfig +function validateSiteConfig(config: SiteConfig): { isValid: boolean; errors: string[] } { + const errors: string[] = []; + + // Required fields + if (!config.site || !config.site.startsWith('http')) { + errors.push('Site URL is missing or invalid. Please set a complete URL like "https://yourdomain.com" in the site field.'); + } + if (!config.title || config.title.trim() === '') { + errors.push('Site title is required and cannot be empty. Set a descriptive title for your blog.'); + } + if (!config.description || config.description.trim() === '') { + errors.push('Site description is required and cannot be empty. Set a brief description of your blog.'); + } + if (!config.author || config.author.trim() === '') { + errors.push('Author name is required and cannot be empty. Set your name or the blog author.'); + } + + // Theme validation + const validThemes = ['minimal', 'oxygen', 'atom', 'ayu', 'catppuccin', 'charcoal', 'dracula', 'everforest', 'flexoki', 'gruvbox', 'macos', 'nord', 'obsidian', 'rose-pine', 'sky', 'solarized', 'things', 'custom']; + if (!validThemes.includes(config.theme)) { + errors.push(`Invalid theme selected: "${config.theme}". Choose from: Minimal, Oxygen, Atom, Ayu, Catppuccin, Charcoal, Dracula, Everforest, Flexoki, Gruvbox, macOS, Nord, Obsidian, Rose Pine, Sky, Solarized, or Things. For custom themes, use "custom" and set customThemeFile.`); + } + if (config.theme === 'custom') { + if (!config.customThemeFile || config.customThemeFile.trim() === '') { + errors.push('Custom theme file is required when theme is set to "custom". Set customThemeFile to the filename (without .ts extension) in src/themes/custom/'); + } + } + + // Available themes validation + if (config.availableThemes !== 'default' && !Array.isArray(config.availableThemes)) { + errors.push('availableThemes must be either "default" or an array of theme names.'); + } + if (Array.isArray(config.availableThemes)) { + if (config.availableThemes.length === 0) { + errors.push('availableThemes array cannot be empty. Use "default" to show all built-in themes or specify theme names in the array.'); + } + // Note: We can't validate custom theme files exist at build time since they're dynamic + // The runtime will handle missing custom theme files gracefully + } + + // Font configuration validation + if (!['local', 'cdn'].includes(config.fonts.source)) { + errors.push(`Font source must be either "local" (self-hosted fonts) or "cdn" (Google Fonts). Current value "${config.fonts.source}" is invalid.`); + } + if (!config.fonts.families.body || config.fonts.families.body.trim() === '') { + errors.push('Body font family is required. Set fonts.families.body to a valid font name like "Inter", "Roboto", or "Open Sans".'); + } + if (!config.fonts.families.heading || config.fonts.families.heading.trim() === '') { + errors.push('Heading font family is required. Set fonts.families.heading to a valid font name like "Inter", "Roboto", or "Playfair Display".'); + } + if (!config.fonts.families.mono || config.fonts.families.mono.trim() === '') { + errors.push('Monospace font family is required. Set fonts.families.mono to a valid font name like "JetBrains Mono", "Fira Code", or "Source Code Pro".'); + } + if (!['swap', 'fallback', 'optional'].includes(config.fonts.display)) { + errors.push('Font display strategy must be one of: "swap", "fallback", or "optional". Current value is invalid.'); + } + + // Numeric validations + if (config.postOptions.postsPerPage < 1 || config.postOptions.postsPerPage > 50) { + errors.push(`Posts per page must be between 1 and 50. Current value is ${config.postOptions.postsPerPage}. Adjust postOptions.postsPerPage.`); + } + if (config.tableOfContents.depth < 2 || config.tableOfContents.depth > 6) { + errors.push(`Table of contents depth must be between 2 and 6 (where 2=H2, 3=H3, etc.). Current value is ${config.tableOfContents.depth}. Adjust tableOfContents.depth.`); + } + if (config.homeOptions.recentPosts.count < 1) { + errors.push('Recent posts count must be at least 1. Adjust homeOptions.recentPosts.count.'); + } + if (config.homeOptions.projects.count < 1) { + errors.push('Projects count must be at least 1. Adjust homeOptions.projects.count.'); + } + if (config.homeOptions.docs.count < 1) { + errors.push('Documentation count must be at least 1. Adjust homeOptions.docs.count.'); + } + + // Content width validation + if (!config.layout.contentWidth || !config.layout.contentWidth.match(/^\d+(\.\d+)?(rem|px|em)$/)) { + errors.push(`Content width must be a valid CSS length value like "45rem", "800px", or "90em". Current value "${config.layout.contentWidth}" is invalid.`); + } + + // Navigation style validation + if (!['minimal', 'traditional'].includes(config.navigation.style)) { + errors.push(`Navigation style must be either "minimal" or "traditional". Current value "${config.navigation.style}" is invalid.`); + } + + // Cover image options validation + const validCoverImageOptions = ['all', 'featured', 'home', 'posts', 'featured-and-posts', 'none']; + if (!validCoverImageOptions.includes(config.postOptions.showPostCardCoverImages)) { + errors.push(`Show post card cover images must be one of: "all", "featured", "home", "posts", "featured-and-posts", or "none". Current value "${config.postOptions.showPostCardCoverImages}" is invalid.`); + } + + // Aspect ratio validation + const validAspectRatios = ['16:9', '4:3', '3:2', 'og', 'square', 'golden', 'custom']; + if (!validAspectRatios.includes(config.postOptions.postCardAspectRatio)) { + errors.push(`Post card aspect ratio must be one of: "16:9", "4:3", "3:2", "og", "square", "golden", or "custom". Current value "${config.postOptions.postCardAspectRatio}" is invalid.`); + } + + // Custom aspect ratio validation + if (config.postOptions.postCardAspectRatio === 'custom') { + if (!config.postOptions.customPostCardAspectRatio || !config.postOptions.customPostCardAspectRatio.match(/^\d+(\.\d+)?\s*\/\s*\d+(\.\d+)?$/)) { + errors.push(`Custom aspect ratio must be provided in format "width / height" (e.g., "2.5 / 1") when postCardAspectRatio is "custom". Current value "${config.postOptions.customPostCardAspectRatio}" is invalid.`); + } + } + + // Home options validation + if (!['above', 'below', 'none'].includes(config.homeOptions.blurb.placement)) { + errors.push(`Home blurb placement must be "above", "below", or "none". Current value "${config.homeOptions.blurb.placement}" is invalid.`); + } + + // Featured post validation + if (!['latest', 'featured'].includes(config.homeOptions.featuredPost.type)) { + errors.push(`Featured post type must be either "latest" or "featured". Current value "${config.homeOptions.featuredPost.type}" is invalid.`); + } + + // Only validate slug when type is "featured" - slug is optional when type is "latest" + if (config.homeOptions.featuredPost.type === 'featured' && (!config.homeOptions.featuredPost.slug || config.homeOptions.featuredPost.slug.trim() === '')) { + errors.push('Featured post slug is required when type is "featured". Set homeOptions.featuredPost.slug to the post slug (the part after /posts/ in the URL).'); + } + + // Language validation + if (!config.language || !config.language.match(/^[a-z]{2}(-[A-Z]{2})?$/)) { + errors.push('Language must be a valid language code like "en" or "en-US". Current value is invalid.'); + } + + // Footer validation + if (typeof config.footer.enabled !== 'boolean') { + errors.push('Footer enabled setting must be a boolean value (true or false).'); + } + if (config.footer.enabled && (!config.footer.content || config.footer.content.trim() === '')) { + errors.push('Footer content is required when footer is enabled. Set footer.content to your footer text.'); + } + if (typeof config.footer.showSocialIconsInFooter !== 'boolean') { + errors.push('Footer social icons setting must be a boolean value (true or false).'); + } + + // Profile picture validation + if (config.profilePicture.enabled) { + if (!config.profilePicture.image || config.profilePicture.image.trim() === '') { + errors.push('Profile picture image path is required when profilePicture.enabled is true. Set profilePicture.image to the path of your image (e.g., "/profile.jpg" in the public/ directory).'); + } + if (!config.profilePicture.alt || config.profilePicture.alt.trim() === '') { + errors.push('Profile picture alt text is required when profilePicture.enabled is true. Set profilePicture.alt to describe your profile picture for accessibility.'); + } + if (!['sm', 'md', 'lg'].includes(config.profilePicture.size)) { + errors.push(`Profile picture size must be "sm" (32px), "md" (48px), or "lg" (64px). Current value "${config.profilePicture.size}" is invalid.`); + } + if (!['footer', 'header'].includes(config.profilePicture.placement)) { + errors.push(`Profile picture placement must be "footer" or "header". Current value "${config.profilePicture.placement}" is invalid.`); + } + if (!['circle', 'square', 'none'].includes(config.profilePicture.style)) { + errors.push(`Profile picture style must be "circle", "square", or "none". Current value "${config.profilePicture.style}" is invalid.`); + } + if (config.profilePicture.url && !config.profilePicture.url.startsWith('/') && !config.profilePicture.url.startsWith('http')) { + errors.push(`Profile picture URL must be a valid path starting with "/" or "http". Current value "${config.profilePicture.url}" is invalid.`); + } + if (config.profilePicture.url && config.profilePicture.url.trim() === '') { + errors.push('Profile picture URL cannot be empty if provided.'); + } + } + + return { + isValid: errors.length === 0, + errors + }; +} + +// Validate configuration on import +const validation = validateSiteConfig(siteConfig); +if (!validation.isValid) { + throw new Error(`Site configuration is invalid. Please fix the following issues:\n${validation.errors.join('\n')}`); +} + +// Export the configuration as default +export default siteConfig; \ No newline at end of file diff --git a/src/config/dev.ts b/src/config/dev.ts new file mode 100644 index 0000000..012db9c --- /dev/null +++ b/src/config/dev.ts @@ -0,0 +1,59 @@ +/** + * Development configuration + * This file contains settings that are only active in development mode + */ + +export const devConfig = { + // Image handling + images: { + // Show placeholder images for missing assets in development + showPlaceholders: true, + // Log missing images to console in development + logMissingImages: true, + // Fallback image paths + fallbacks: { + posts: '/posts/attachments/placeholder.jpg', + pages: '/pages/attachments/placeholder.jpg', + default: '/posts/attachments/placeholder.jpg' + } + }, + + // Content processing + content: { + // Continue processing even if some assets are missing + continueOnMissingAssets: true, + // Log content processing warnings + logWarnings: false + }, + + // Error handling + errors: { + // Show detailed error information in development + showDetails: true, + // Continue build process even with non-critical errors + continueOnNonCriticalErrors: true + }, + + // Tag handling + tags: { + // Gracefully handle missing or deleted tags in development + handleMissingTags: true, + // Log tag-related warnings in development + logTagWarnings: false, + // Continue processing even if some tags are missing + continueOnMissingTags: true + } +}; + +// Check if we're in development mode +export const isDev = import.meta.env.DEV; + +// Get development configuration +export function getDevConfig() { + return isDev ? devConfig : null; +} + +// Check if a feature is enabled in development +export function isDevFeatureEnabled(feature: keyof typeof devConfig) { + return isDev && devConfig[feature]; +} diff --git a/src/content.config.ts b/src/content.config.ts new file mode 100644 index 0000000..91298cb --- /dev/null +++ b/src/content.config.ts @@ -0,0 +1,151 @@ +import { defineCollection, z } from 'astro:content'; +import { glob } from 'astro/loaders'; + +// Define schema for blog posts +const postsCollection = defineCollection({ + loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/posts' }), + schema: z.object({ + title: z.string().default('Untitled Post'), + description: z.string().nullable().optional().default('No description provided'), + date: z.coerce.date().default(() => new Date()), + tags: z.array(z.string()).nullable().optional(), + draft: z.boolean().optional(), + image: z.any().nullable().optional().transform((val) => { + // Handle various Obsidian syntax formats + if (Array.isArray(val)) { + // Handle array format from [[...]] syntax - take first element + return val[0] || null; + } + if (typeof val === 'string') { + // Handle string format - return as-is + return val; + } + return null; + }), + imageOG: z.boolean().optional(), + imageAlt: z.string().nullable().optional(), + hideCoverImage: z.boolean().optional(), + hideTOC: z.boolean().optional(), + showTOC: z.boolean().optional(), + targetKeyword: z.string().nullable().optional(), + author: z.string().nullable().optional(), + noIndex: z.boolean().optional(), + }), +}); + +// Define schema for static pages +const pagesCollection = defineCollection({ + loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/pages' }), + schema: z.object({ + title: z.string().default('Untitled Page'), + description: z.string().nullable().optional().default('No description provided'), + draft: z.boolean().optional(), + lastModified: z.coerce.date().optional(), + image: z.any().nullable().optional().transform((val) => { + // Handle various Obsidian syntax formats + if (Array.isArray(val)) { + // Handle array format from [[...]] syntax - take first element + return val[0] || null; + } + if (typeof val === 'string') { + // Handle string format - return as-is + return val; + } + return null; + }), + imageAlt: z.string().nullable().optional(), + hideCoverImage: z.boolean().optional(), + hideTOC: z.boolean().optional(), + showTOC: z.boolean().optional(), + noIndex: z.boolean().optional(), + }), +}); + +// Define schema for projects +const projectsCollection = defineCollection({ + loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/projects' }), + schema: z.object({ + title: z.string().default('Untitled Project'), + description: z.string().nullable().optional().default('No description provided'), + date: z.coerce.date().default(() => new Date()), + categories: z.array(z.string()).nullable().optional().default([]), + repositoryUrl: z.union([z.string(), z.null(), z.undefined()]).optional().transform(val => val || ''), + projectUrl: z.union([z.string(), z.null(), z.undefined()]).optional().transform(val => val || ''), + demoUrl: z.union([z.string(), z.null(), z.undefined()]).optional().transform(val => val || ''), + demoURL: z.union([z.string(), z.null(), z.undefined()]).optional().transform(val => val || ''), + status: z.string().nullable().optional(), + image: z.any().nullable().optional().transform((val) => { + // Handle various Obsidian syntax formats + if (Array.isArray(val)) { + // Handle array format from [[...]] syntax - take first element + return val[0] || null; + } + if (typeof val === 'string') { + // Handle string format - return as-is + return val; + } + return null; + }), + imageAlt: z.string().nullable().optional(), + hideCoverImage: z.boolean().optional(), + hideTOC: z.boolean().optional(), + showTOC: z.boolean().optional(), + draft: z.boolean().optional(), + noIndex: z.boolean().optional(), + featured: z.boolean().optional(), + }), +}); + +// Define schema for docs +const docsCollection = defineCollection({ + loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/docs' }), + schema: z.object({ + title: z.string().default('Untitled Documentation'), + description: z.string().nullable().optional().default('No description provided'), + category: z.string().nullable().optional().default('General'), + order: z.number().default(0), + lastModified: z.coerce.date().optional(), + version: z.string().nullable().optional(), + image: z.any().nullable().optional().transform((val) => { + // Handle various Obsidian syntax formats + if (Array.isArray(val)) { + // Handle array format from [[...]] syntax - take first element + return val[0] || null; + } + if (typeof val === 'string') { + // Handle string format - return as-is + return val; + } + return null; + }), + imageAlt: z.string().nullable().optional(), + hideCoverImage: z.boolean().optional(), + hideTOC: z.boolean().optional(), + draft: z.boolean().optional(), + noIndex: z.boolean().optional(), + showTOC: z.boolean().optional(), + featured: z.boolean().optional(), + }), +}); + +// Define schema for special home pages (homepage blurb, 404, projects index, docs index) +const specialCollection = defineCollection({ + loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/special' }), + schema: z.object({ + title: z.string().default('Untitled Page'), + description: z.string().nullable().optional().default('No description provided'), + hideTOC: z.boolean().optional(), + // These pages have fixed URLs and special logic + // URLs are determined by the file location, not frontmatter + }), +}); + +// Export collections +export const collections = { + posts: postsCollection, + pages: pagesCollection, + projects: projectsCollection, + docs: docsCollection, + special: specialCollection, +}; + diff --git a/src/content/.obsidian/app.json b/src/content/.obsidian/app.json new file mode 100644 index 0000000..e4e1ae5 --- /dev/null +++ b/src/content/.obsidian/app.json @@ -0,0 +1,44 @@ +{ + "showInlineTitle": false, + "promptDelete": true, + "showIndentGuide": false, + "attachmentFolderPath": "./attachments", + "userIgnoreFilters": [ + "bases/" + ], + "focusNewTab": false, + "mobilePullAction": "command-palette:open", + "trashOption": "system", + "alwaysUpdateLinks": true, + "useMarkdownLinks": true, + "mobileToolbarCommands": [ + "editor:undo", + "editor:redo", + "editor:insert-wikilink", + "editor:insert-embed", + "editor:insert-tag", + "editor:attach-file", + "editor:set-heading", + "editor:toggle-bold", + "editor:toggle-italics", + "editor:toggle-strikethrough", + "editor:toggle-highlight", + "editor:toggle-code", + "editor:toggle-blockquote", + "editor:insert-link", + "editor:toggle-bullet-list", + "editor:toggle-numbered-list", + "editor:toggle-checklist-status", + "editor:indent-list", + "editor:unindent-list", + "editor:configure-toolbar" + ], + "newFileLocation": "folder", + "newFileFolderPath": "posts", + "newLinkFormat": "relative", + "mobileQuickRibbonItem": "", + "vimMode": false, + "readableLineLength": true, + "defaultViewMode": "source", + "openBehavior": "" +} \ No newline at end of file diff --git a/src/content/.obsidian/appearance.json b/src/content/.obsidian/appearance.json new file mode 100644 index 0000000..fa82656 --- /dev/null +++ b/src/content/.obsidian/appearance.json @@ -0,0 +1,10 @@ +{ + "cssTheme": "Oxygen", + "showViewHeader": true, + "showRibbon": false, + "enabledCssSnippets": [ + "astro-modular-styling" + ], + "theme": "system", + "accentColor": "" +} \ No newline at end of file diff --git a/src/content/.obsidian/backlink.json b/src/content/.obsidian/backlink.json new file mode 100644 index 0000000..48ee913 --- /dev/null +++ b/src/content/.obsidian/backlink.json @@ -0,0 +1,3 @@ +{ + "backlinkInDocument": true +} \ No newline at end of file diff --git a/src/content/.obsidian/bookmarks.json b/src/content/.obsidian/bookmarks.json new file mode 100644 index 0000000..c3ef621 --- /dev/null +++ b/src/content/.obsidian/bookmarks.json @@ -0,0 +1,10 @@ +{ + "items": [ + { + "type": "file", + "ctime": 1755331588238, + "path": "_formatting-reference.md", + "title": "Formatting Reference" + } + ] +} \ No newline at end of file diff --git a/src/content/.obsidian/community-plugins.json b/src/content/.obsidian/community-plugins.json new file mode 100644 index 0000000..1adb913 --- /dev/null +++ b/src/content/.obsidian/community-plugins.json @@ -0,0 +1,21 @@ +[ + "astro-modular-settings", + "bases-cms", + "editing-toolbar", + "image-manager", + "oxygen-settings", + "property-over-file-name", + "seo", + "settings-search", + "tag-wrangler", + "explorer-focus", + "astro-composer", + "home-base", + "omnisearch", + "zenmode", + "ui-tweaker", + "obsidian42-brat", + "obsidian-git", + "vault-cms", + "file-name-history" +] \ No newline at end of file diff --git a/src/content/.obsidian/core-plugins.json b/src/content/.obsidian/core-plugins.json new file mode 100644 index 0000000..9fa988b --- /dev/null +++ b/src/content/.obsidian/core-plugins.json @@ -0,0 +1,33 @@ +{ + "file-explorer": true, + "global-search": true, + "switcher": true, + "graph": true, + "backlink": true, + "canvas": false, + "outgoing-link": true, + "tag-pane": true, + "footnotes": false, + "properties": false, + "page-preview": false, + "daily-notes": false, + "templates": false, + "note-composer": false, + "command-palette": true, + "slash-command": true, + "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, + "bases": true, + "webviewer": true +} \ No newline at end of file diff --git a/src/content/.obsidian/graph.json b/src/content/.obsidian/graph.json new file mode 100644 index 0000000..671ac4c --- /dev/null +++ b/src/content/.obsidian/graph.json @@ -0,0 +1,30 @@ +{ + "collapse-filter": true, + "search": "path:posts/", + "showTags": false, + "showAttachments": false, + "hideUnresolved": false, + "showOrphans": true, + "collapse-color-groups": true, + "colorGroups": [ + { + "query": "", + "color": { + "a": 1, + "rgb": 14701138 + } + } + ], + "collapse-display": true, + "showArrow": false, + "textFadeMultiplier": 0, + "nodeSizeMultiplier": 1, + "lineSizeMultiplier": 1, + "collapse-forces": true, + "centerStrength": 0.518713248970312, + "repelStrength": 10, + "linkStrength": 1, + "linkDistance": 250, + "scale": 1.0147822288211767, + "close": true +} \ No newline at end of file diff --git a/src/content/.obsidian/hotkeys.json b/src/content/.obsidian/hotkeys.json new file mode 100644 index 0000000..73bf9e5 --- /dev/null +++ b/src/content/.obsidian/hotkeys.json @@ -0,0 +1,274 @@ +{ + "app:go-back": [ + { + "modifiers": [ + "Mod", + "Alt" + ], + "key": "ArrowLeft" + }, + { + "modifiers": [ + "Alt" + ], + "key": "ArrowLeft" + } + ], + "app:go-forward": [ + { + "modifiers": [ + "Mod", + "Alt" + ], + "key": "ArrowRight" + }, + { + "modifiers": [ + "Alt" + ], + "key": "ArrowRight" + } + ], + "homepage:open-homepage": [ + { + "modifiers": [ + "Mod" + ], + "key": "M" + } + ], + "app:toggle-left-sidebar": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "Z" + } + ], + "app:toggle-right-sidebar": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "X" + } + ], + "obsidian-git:push": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "S" + } + ], + "insert-unsplash-image:insert": [ + { + "modifiers": [ + "Mod" + ], + "key": "'" + } + ], + "custom-save:save": [], + "editor:insert-callout": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "C" + } + ], + "astro-composer:rename-note": [ + { + "modifiers": [ + "Mod" + ], + "key": "R" + } + ], + "astro-composer:rename-content": [ + { + "modifiers": [ + "Mod" + ], + "key": "R" + } + ], + "editor:toggle-fold-properties": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "P" + } + ], + "seo:seo-open-global": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "A" + } + ], + "insert-unsplash-image:insert-in-frontmatter": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "'" + } + ], + "astro-modular-settings:open-settings": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "," + } + ], + "seo:open-global": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "A" + } + ], + "oxygen-settings:toggle-minimal-focus-mode": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "F" + } + ], + "zenmode:exit-zen-mode": [], + "oxygen-settings:toggle-zen-mode": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "Z" + } + ], + "oxygen-settings:toggle-tab-containers": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "S" + } + ], + "app:toggle-ribbon": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "A" + } + ], + "zenmode:toggle-zen-mode": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "Z" + } + ], + "app:reload": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "R" + } + ], + "theme:toggle-light-dark": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "M" + } + ], + "astro-composer:open-project-terminal": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "D" + } + ], + "editing-toolbar:workplace-fullscreen-focus": [], + "editing-toolbar:fullscreen-focus": [], + "editing-toolbar:hide-show-menu": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "E" + } + ], + "webviewer:open": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "V" + } + ], + "image-manager:search-image": [ + { + "modifiers": [ + "Mod" + ], + "key": "'" + } + ], + "image-manager:insert-remote-image-to-property": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "'" + } + ], + "ui-tweaker:toggle-tab-bar": [ + { + "modifiers": [ + "Alt", + "Mod" + ], + "key": "S" + } + ], + "omnisearch:show-modal": [ + { + "modifiers": [ + "Mod", + "Shift" + ], + "key": "O" + } + ] +} \ No newline at end of file diff --git a/src/content/.obsidian/plugins/astro-composer/data.json b/src/content/.obsidian/plugins/astro-composer/data.json new file mode 100644 index 0000000..11fc1c6 --- /dev/null +++ b/src/content/.obsidian/plugins/astro-composer/data.json @@ -0,0 +1,91 @@ +{ + "defaultTemplate": "---\ntitle: \"{{title}}\"\ndate: {{date}}\ndescription: \"\"\ntags: []\nimage: \"\"\nimageAlt: \"\"\nimageOG: false\nhideCoverImage: false\nhideTOC: false\ntargetKeyword: \"\"\ndraft: false\n---\n", + "autoInsertProperties": true, + "dateFormat": "YYYY-MM-DD", + "enableCopyHeadingLink": true, + "copyHeadingLinkFormat": "obsidian", + "addTrailingSlashToLinks": true, + "enableOpenTerminalCommand": true, + "terminalProjectRootPath": "../../", + "terminalApplicationName": "", + "enableTerminalDebugLogging": false, + "enableTerminalRibbonIcon": true, + "enableOpenConfigFileCommand": true, + "configFilePath": "../config.ts", + "enableConfigRibbonIcon": true, + "contentTypes": [ + { + "id": "posts-1765432337485", + "name": "Posts", + "folder": "posts", + "linkBasePath": "/posts/", + "template": "---\ntitle: \"{{title}}\"\ndate: {{date}}\ndescription: \"\"\ntags: []\nimage: \"\"\nimageAlt: \"\"\nimageOG: false\nhideCoverImage: false\nhideTOC: false\ntargetKeyword: \"\"\ndraft: false\n---\n", + "enabled": true, + "creationMode": "file", + "indexFileName": "index", + "ignoreSubfolders": false, + "enableUnderscorePrefix": false + }, + { + "id": "pages-1765432337485", + "name": "Pages", + "folder": "pages", + "linkBasePath": "/", + "template": "---\ntitle: \"{{title}}\"\ndescription: \"\"\nnoIndex: false\nhideTOC: false\ndraft: false\n---\n", + "enabled": true, + "creationMode": "file", + "indexFileName": "index", + "ignoreSubfolders": false, + "enableUnderscorePrefix": false + }, + { + "id": "content-1765432392567", + "name": "Projects", + "folder": "projects", + "linkBasePath": "/projects/", + "template": "---\ntitle: \"{{title}}\"\ndescription: \"\"\ndate: {{date}}\ncategories: []\nrepositoryUrl:\nprojectUrl: \"\"\nstatus: \"\"\nimage: \"\"\nimageAlt: \"\"\nhideCoverImage: false\nhideTOC: false\ndraft: true\nfeatured: false\n---\n", + "enabled": true, + "creationMode": "file", + "indexFileName": "index", + "ignoreSubfolders": false, + "enableUnderscorePrefix": false + }, + { + "id": "content-1765432406133", + "name": "Documentation", + "folder": "docs", + "linkBasePath": "/docs/", + "template": "---\ntitle: \"{{title}}\"\ndescription: \"\"\ncategory: \"\"\norder: \nversion: \"\"\nlastModified: {{date}}\nimage: \"\"\nimageAlt: \"\"\nhideCoverImage: false\nhideTOC: false\ndraft: false\nfeatured: false\n---\n", + "enabled": true, + "creationMode": "file", + "indexFileName": "index", + "ignoreSubfolders": false, + "enableUnderscorePrefix": false, + "modifiedDateField": "lastModified" + } + ], + "migrationCompleted": true, + "helpButtonReplacement": { + "enabled": true, + "commandId": "astro-modular-settings:open-settings", + "iconId": "rocket" + }, + "showMdxFilesInExplorer": false, + "processBackgroundFileChanges": true, + "syncDraftDate": true, + "enableScheduledPublishing": true, + "draftProperty": "draft", + "draftLogic": "true-is-draft", + "publishDateField": "date", + "renameOnTitleClick": true, + "updateModifiedDate": true, + "modifiedDateField": "lastModified", + "integratedTerminalShell": "powershell", + "newInstanceBehavior": "newHorizontalSplit", + "createInstanceNearExistingOnes": true, + "focusOnNewInstance": true, + "pinNewInstance": true, + "hideStatusBar": "focused", + "noticeTimeout": 5, + "errorNoticeTimeout": 0 +} \ No newline at end of file diff --git a/src/content/.obsidian/plugins/astro-composer/main.js b/src/content/.obsidian/plugins/astro-composer/main.js new file mode 100644 index 0000000..2e860a9 --- /dev/null +++ b/src/content/.obsidian/plugins/astro-composer/main.js @@ -0,0 +1,4479 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ + +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/main.ts +var main_exports = {}; +__export(main_exports, { + default: () => AstroComposerPlugin +}); +module.exports = __toCommonJS(main_exports); +var import_obsidian14 = require("obsidian"); + +// src/types.ts +var KNOWN_ARRAY_KEYS = ["tags", "aliases", "cssclasses"]; +var CONSTANTS = { + DEBOUNCE_MS: 500, + STAT_MTIME_THRESHOLD: 5e3, + EDITOR_STABILIZE_DELAY: 100, + FILE_EXPLORER_REVEAL_DELAY: 200 +}; + +// src/settings.ts +var DEFAULT_SETTINGS = { + defaultTemplate: '---\ntitle: "{{title}}"\ndate: {{date}}\ntags: []\n---\n', + autoInsertProperties: true, + dateFormat: "YYYY-MM-DD", + enableCopyHeadingLink: true, + copyHeadingLinkFormat: "obsidian", + addTrailingSlashToLinks: false, + enableOpenTerminalCommand: false, + terminalProjectRootPath: "", + terminalApplicationName: "", + enableTerminalDebugLogging: false, + enableTerminalRibbonIcon: false, + enableOpenConfigFileCommand: false, + configFilePath: "", + enableConfigRibbonIcon: false, + contentTypes: [], + migrationCompleted: false, + helpButtonReplacement: { + enabled: false, + commandId: "edit-astro-config", + iconId: "rocket" + }, + showMdxFilesInExplorer: false, + processBackgroundFileChanges: true, + syncDraftDate: false, + draftDetectionMode: "property", + draftProperty: "", + draftLogic: "true-is-draft", + publishDateField: "", + renameOnTitleClick: false +}; + +// src/commands/index.ts +var import_obsidian5 = require("obsidian"); + +// src/utils/file-operations.ts +var import_obsidian = require("obsidian"); + +// src/utils/path-matching.ts +function matchesFolderPattern(filePath, folderPattern) { + const normalizedFilePath = filePath.toLowerCase(); + const normalizedPattern = folderPattern.toLowerCase().replace(/^\/|\/$/g, ""); + if (!normalizedPattern || normalizedPattern.trim() === "") { + return !normalizedFilePath.includes("/") || normalizedFilePath.split("/").length === 1; + } + if (!normalizedPattern.includes("*")) { + return normalizedFilePath === normalizedPattern || normalizedFilePath.startsWith(normalizedPattern + "/"); + } + const escapedPattern = normalizedPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]+"); + const regexPattern = `^${escapedPattern}(?:/|$)`; + const regex = new RegExp(regexPattern); + return regex.test(normalizedFilePath); +} +function getPatternDepth(folderPattern) { + if (!folderPattern || folderPattern.trim() === "") return 0; + return folderPattern.split("/").length; +} +function sortByPatternSpecificity(types) { + return [...types].sort((a, b) => { + const depthA = getPatternDepth(a.folder); + const depthB = getPatternDepth(b.folder); + return depthB - depthA; + }); +} + +// src/utils/string-utils.ts +function toKebabCase(str) { + return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2$3").toLowerCase().replace(/[^a-z0-9\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); +} + +// src/utils/file-operations.ts +var FileOperations = class { + constructor(app, settings, plugin) { + this.app = app; + this.settings = settings; + this.plugin = plugin; + } + // Get fresh settings from plugin if available, otherwise use stored settings + getSettings() { + var _a; + if ((_a = this.plugin) == null ? void 0 : _a.settings) { + return this.plugin.settings; + } + return this.settings; + } + generateFilename(title, enableUnderscorePrefix = false) { + const kebabTitle = toKebabCase(title); + const safeKebabTitle = kebabTitle || "untitled"; + const prefix = enableUnderscorePrefix ? "_" : ""; + return `${prefix}${safeKebabTitle}`; + } + determineType(file) { + const filePath = file.path; + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + const sortedTypes = sortByPatternSpecificity(contentTypes); + for (const contentType of sortedTypes) { + if (!contentType.enabled) continue; + if (!contentType.folder || contentType.folder.trim() === "") { + if (!filePath.includes("/") || filePath.split("/").length === 1) { + return contentType.id; + } + } else if (matchesFolderPattern(filePath, contentType.folder)) { + if (contentType.ignoreSubfolders) { + const pathSegments = filePath.split("/"); + const pathDepth = pathSegments.length; + const patternSegments = contentType.folder.split("/"); + const expectedDepth = patternSegments.length; + if (contentType.creationMode === "folder") { + const folderDepth = pathDepth - 1; + if (folderDepth === expectedDepth || folderDepth === expectedDepth + 1) { + return contentType.id; + } + } else { + if (pathDepth === expectedDepth) { + return contentType.id; + } + } + } else { + return contentType.id; + } + } + } + return "note"; + } + getContentType(typeId) { + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + return contentTypes.find((ct) => ct.id === typeId) || null; + } + /** + * Helper to get content type for a given file path + */ + getContentTypeByPath(filePath) { + const dummyFile = { path: filePath }; + const typeId = this.determineType(dummyFile); + if (typeId === "note") return null; + return this.getContentType(typeId); + } + getTitleKey(type) { + if (type === "note") return "title"; + const contentType = this.getContentType(type); + if (!contentType) return "title"; + const template = contentType.template; + const lines = template.split("\n"); + let inProperties = false; + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed === "---") { + inProperties = !inProperties; + continue; + } + if (inProperties) { + const match = trimmed.match(/^(\w+):\s*(.+)$/); + if (match) { + const key = match[1]; + const value = match[2]; + if (value.includes("{{title}}")) { + return key; + } + } + } + } + return "title"; + } + async createFile(options) { + var _a; + const { file, title, type } = options; + if (!title) { + new import_obsidian.Notice(`Title is required to create a ${type}.`); + return null; + } + const contentType = this.getContentType(type); + if (!contentType && type !== "note") { + new import_obsidian.Notice(`Content type ${type} not found.`); + return null; + } + const kebabTitle = toKebabCase(title); + const enableUnderscorePrefix = (contentType == null ? void 0 : contentType.enableUnderscorePrefix) || false; + const prefix = enableUnderscorePrefix ? "_" : ""; + let targetFolder = ""; + if (type === "note") { + targetFolder = ""; + } else if (contentType) { + const originalDir = ((_a = file.parent) == null ? void 0 : _a.path) || ""; + if (originalDir === "" || originalDir === "/") { + targetFolder = contentType.folder || ""; + } else { + targetFolder = originalDir; + } + } + if (targetFolder) { + const folder = this.app.vault.getAbstractFileByPath(targetFolder); + if (!(folder instanceof import_obsidian.TFolder)) { + await this.app.vault.createFolder(targetFolder); + } + } + const creationMode = (contentType == null ? void 0 : contentType.creationMode) || "file"; + if (creationMode === "folder") { + return this.createFolderStructure(file, kebabTitle, prefix, targetFolder, type, contentType); + } else { + return this.createFileStructure(file, kebabTitle, prefix, targetFolder, contentType); + } + } + async createFolderStructure(file, kebabTitle, prefix, targetFolder, type, contentType) { + const folderName = `${prefix}${kebabTitle}`; + let folderPath; + if (targetFolder) { + folderPath = `${targetFolder}/${folderName}`; + } else { + const currentDir = file.parent ? file.parent.path : ""; + if (currentDir && currentDir !== "/") { + folderPath = `${currentDir}/${folderName}`; + } else { + folderPath = folderName; + } + } + try { + const folder = this.app.vault.getAbstractFileByPath(folderPath); + if (!(folder instanceof import_obsidian.TFolder)) { + await this.app.vault.createFolder(folderPath); + } + } catch (e) { + } + const indexFileName = (contentType == null ? void 0 : contentType.indexFileName) || "index"; + const extension = (contentType == null ? void 0 : contentType.useMdxExtension) ? ".mdx" : ".md"; + const fileName = `${indexFileName}${extension}`; + const newPath = `${folderPath}/${fileName}`; + const existingFile = this.app.vault.getAbstractFileByPath(newPath); + if (existingFile instanceof import_obsidian.TFile) { + new import_obsidian.Notice(`File already exists at ${newPath}.`); + return null; + } + if (this.plugin) { + this.plugin.pluginCreatedFiles.set(newPath, Date.now()); + } + try { + await this.app.fileManager.renameFile(file, newPath); + const newFile = this.app.vault.getAbstractFileByPath(newPath); + if (!(newFile instanceof import_obsidian.TFile)) { + return null; + } + setTimeout(() => { + const fileExplorer = this.app.workspace.getLeavesOfType("file-explorer")[0]; + if (fileExplorer && fileExplorer.view) { + const view = fileExplorer.view; + if (view && typeof view === "object" && "tree" in view) { + const fileTree = view.tree; + if (fileTree && newFile instanceof import_obsidian.TFile && typeof fileTree.revealFile === "function") { + fileTree.revealFile(newFile); + } + } + } + }, 200); + const leaf = this.app.workspace.getLeaf(false); + await leaf.openFile(newFile); + const positionCursor = () => { + var _a; + const view = leaf.view; + if (view && "editor" in view) { + const editor = view.editor; + if (editor) { + const content = editor.getValue(); + if (content) { + const lines = content.split("\n"); + const lastLine = lines.length - 1; + const lastLineLength = ((_a = lines[lastLine]) == null ? void 0 : _a.length) || 0; + editor.setCursor({ line: lastLine, ch: lastLineLength }); + editor.focus(); + return true; + } + } + } + return false; + }; + setTimeout(() => { + if (!positionCursor()) { + setTimeout(() => { + positionCursor(); + }, 200); + } + }, 100); + return newFile; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian.Notice(`Failed to create folder structure: ${errorMessage}.`); + return null; + } + } + async createFileStructure(file, kebabTitle, prefix, targetFolder, contentType) { + const extension = (contentType == null ? void 0 : contentType.useMdxExtension) ? ".mdx" : ".md"; + const newName = `${prefix}${kebabTitle}${extension}`; + let newPath; + if (targetFolder) { + newPath = `${targetFolder}/${newName}`; + } else { + const currentDir = file.parent ? file.parent.path : ""; + if (currentDir && currentDir !== "/") { + newPath = `${currentDir}/${newName}`; + } else { + newPath = newName; + } + } + const existingFile = this.app.vault.getAbstractFileByPath(newPath); + if (existingFile instanceof import_obsidian.TFile && existingFile !== file) { + new import_obsidian.Notice(`File with name "${newName}" already exists.`); + return null; + } + if (this.plugin) { + this.plugin.pluginCreatedFiles.set(newPath, Date.now()); + } + try { + await this.app.fileManager.renameFile(file, newPath); + const newFile = this.app.vault.getAbstractFileByPath(newPath); + if (!(newFile instanceof import_obsidian.TFile)) { + new import_obsidian.Notice("Failed to locate renamed file."); + return null; + } + const leaf = this.app.workspace.getLeaf(false); + await leaf.openFile(newFile); + const positionCursor = () => { + var _a; + const view = leaf.view; + if (view && "editor" in view) { + const editor = view.editor; + if (editor) { + const content = editor.getValue(); + if (content) { + const lines = content.split("\n"); + const lastLine = lines.length - 1; + const lastLineLength = ((_a = lines[lastLine]) == null ? void 0 : _a.length) || 0; + editor.setCursor({ line: lastLine, ch: lastLineLength }); + editor.focus(); + return true; + } + } + } + return false; + }; + setTimeout(() => { + if (!positionCursor()) { + setTimeout(() => { + positionCursor(); + }, 200); + } + }, 100); + return newFile; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian.Notice(`Failed to rename file: ${errorMessage}.`); + return null; + } + } + async renameFile(options) { + const { file, title, type } = options; + if (!title) { + new import_obsidian.Notice(`Title is required to rename the content.`); + return null; + } + const contentType = this.getContentType(type); + if (!contentType && type !== "note") { + new import_obsidian.Notice(`Content type ${type} not found.`); + return null; + } + const kebabTitle = toKebabCase(title); + const prefix = ""; + const creationMode = (contentType == null ? void 0 : contentType.creationMode) || "file"; + if (creationMode === "folder") { + return this.renameFolderStructure(file, kebabTitle, prefix, type, contentType); + } else { + return this.renameFileStructure(file, kebabTitle, prefix, contentType); + } + } + async renameFolderStructure(file, kebabTitle, prefix, type, contentType) { + const indexFileName = (contentType == null ? void 0 : contentType.indexFileName) || "index"; + const isIndex = file.basename === indexFileName; + if (isIndex) { + if (!file.parent) { + new import_obsidian.Notice("Cannot rename: file has no parent folder."); + return null; + } + prefix = file.parent.name.startsWith("_") ? "_" : ""; + const newFolderName = `${prefix}${kebabTitle}`; + const parentFolder = file.parent.parent; + if (!parentFolder) { + new import_obsidian.Notice("Cannot rename: parent folder has no parent."); + return null; + } + let newFolderPath; + if (parentFolder.path === "" || parentFolder.path === "/") { + newFolderPath = newFolderName; + } else { + newFolderPath = `${parentFolder.path}/${newFolderName}`; + } + const existingFolder = this.app.vault.getAbstractFileByPath(newFolderPath); + if (existingFolder instanceof import_obsidian.TFolder) { + new import_obsidian.Notice(`Folder already exists at ${newFolderPath}.`); + return null; + } + try { + await this.app.fileManager.renameFile(file.parent, newFolderPath); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian.Notice(`Failed to rename folder: ${errorMessage}.`); + return null; + } + const newFilePath = `${newFolderPath}/${file.name}`; + const newFile = this.app.vault.getAbstractFileByPath(newFilePath); + if (!(newFile instanceof import_obsidian.TFile)) { + new import_obsidian.Notice("Failed to locate renamed file."); + return null; + } + return newFile; + } else { + if (!file.parent) { + new import_obsidian.Notice("Cannot rename: file has no parent folder."); + return null; + } + prefix = file.basename.startsWith("_") ? "_" : ""; + const extension = file.extension; + const newName = `${prefix}${kebabTitle}.${extension}`; + const newPath = `${file.parent.path}/${newName}`; + const existingFile = this.app.vault.getAbstractFileByPath(newPath); + if (existingFile instanceof import_obsidian.TFile && existingFile !== file) { + new import_obsidian.Notice(`File already exists at ${newPath}.`); + return null; + } + await this.app.fileManager.renameFile(file, newPath); + const newFile = this.app.vault.getAbstractFileByPath(newPath); + if (!(newFile instanceof import_obsidian.TFile)) { + new import_obsidian.Notice("Failed to locate renamed file."); + return null; + } + return newFile; + } + } + async renameFileStructure(file, kebabTitle, prefix, contentType) { + if (!file.parent) { + new import_obsidian.Notice("Cannot rename: file has no parent folder."); + return null; + } + const indexFileName = (contentType == null ? void 0 : contentType.indexFileName) || ""; + const isIndex = indexFileName && indexFileName.trim() !== "" && file.basename === indexFileName; + if (isIndex) { + prefix = file.parent.name.startsWith("_") ? "_" : ""; + const newFolderName = `${prefix}${kebabTitle}`; + const parentFolder = file.parent.parent; + if (!parentFolder) { + new import_obsidian.Notice("Cannot rename: parent folder has no parent."); + return null; + } + let newFolderPath; + if (parentFolder.path === "" || parentFolder.path === "/") { + newFolderPath = newFolderName; + } else { + newFolderPath = `${parentFolder.path}/${newFolderName}`; + } + const existingFolder = this.app.vault.getAbstractFileByPath(newFolderPath); + if (existingFolder instanceof import_obsidian.TFolder) { + new import_obsidian.Notice(`Folder already exists at ${newFolderPath}.`); + return null; + } + const newFilePath = `${newFolderPath}/${file.name}`; + if (this.plugin) { + this.plugin.pluginCreatedFiles.set(newFilePath, Date.now()); + } + try { + await this.app.fileManager.renameFile(file.parent, newFolderPath); + } catch (error) { + console.error("FileOperations: Folder rename failed:", error); + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian.Notice(`Failed to rename folder: ${errorMessage}.`); + return null; + } + const newFile2 = this.app.vault.getAbstractFileByPath(newFilePath); + if (!(newFile2 instanceof import_obsidian.TFile)) { + new import_obsidian.Notice("Failed to locate renamed file."); + return null; + } + return newFile2; + } + prefix = file.basename.startsWith("_") ? "_" : ""; + const extension = file.extension; + const newName = `${prefix}${kebabTitle}.${extension}`; + let newPath; + if (file.parent.path === "" || file.parent.path === "/") { + newPath = newName; + } else { + newPath = `${file.parent.path}/${newName}`; + } + const existingFile = this.app.vault.getAbstractFileByPath(newPath); + if (existingFile instanceof import_obsidian.TFile && existingFile !== file) { + new import_obsidian.Notice(`File already exists at ${newPath}.`); + return null; + } + if (this.plugin) { + this.plugin.pluginCreatedFiles.set(newPath, Date.now()); + } + try { + await this.app.fileManager.renameFile(file, newPath); + } catch (error) { + console.error("FileOperations: File rename failed:", error); + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian.Notice(`Failed to rename file: ${errorMessage}.`); + return null; + } + const newFile = this.app.vault.getAbstractFileByPath(newPath); + if (!(newFile instanceof import_obsidian.TFile)) { + new import_obsidian.Notice("Failed to locate renamed file."); + return null; + } + return newFile; + } +}; + +// src/utils/template-parsing.ts +var import_obsidian2 = require("obsidian"); +var TemplateParser = class { + constructor(app, settings, plugin) { + this.app = app; + this.settings = settings; + this.plugin = plugin; + } + // Get fresh settings from plugin if available, otherwise use stored settings + getSettings() { + var _a; + if ((_a = this.plugin) == null ? void 0 : _a.settings) { + return this.plugin.settings; + } + return this.settings; + } + /** + * Convert a string to kebab-case for slug generation + */ + toKebabCase(str) { + return str.toLowerCase().replace(/[^a-z0-9\s-]/g, "").trim().replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, ""); + } + parseFrontmatter(content) { + let propertiesEnd = 0; + let propertiesText = ""; + const existingProperties = {}; + if (content.startsWith("---")) { + propertiesEnd = content.indexOf("\n---", 3); + if (propertiesEnd === -1) { + propertiesEnd = content.length; + } else { + propertiesEnd += 4; + } + propertiesText = content.slice(4, propertiesEnd - 4).trim(); + try { + let currentKey = null; + const arrayKeys = /* @__PURE__ */ new Set(); + propertiesText.split("\n").forEach((line) => { + const trimmedLine = line.trim(); + const match = trimmedLine.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*)$/); + if (match) { + const [, key, value] = match; + currentKey = key; + const trimmedValue = value ? value.trim() : ""; + const bracketArrayMatch = trimmedValue.match(/^\[(.*)\]$/); + if (bracketArrayMatch) { + const arrayContent = bracketArrayMatch[1].trim(); + existingProperties[key] = []; + arrayKeys.add(key); + if (arrayContent) { + const items = []; + let currentItem = ""; + let inQuotes = false; + let quoteChar = ""; + for (let i = 0; i < arrayContent.length; i++) { + const char = arrayContent[i]; + if (!inQuotes && (char === '"' || char === "'")) { + inQuotes = true; + quoteChar = char; + } else if (inQuotes && char === quoteChar) { + if (i > 0 && arrayContent[i - 1] === "\\") { + currentItem += char; + } else { + inQuotes = false; + quoteChar = ""; + } + } else if (!inQuotes && char === ",") { + const trimmedItem = currentItem.trim(); + if (trimmedItem) { + const unquoted = trimmedItem.replace(/^["']|["']$/g, ""); + items.push(unquoted); + } + currentItem = ""; + } else { + currentItem += char; + } + } + if (currentItem.trim()) { + const trimmedItem = currentItem.trim(); + const unquoted = trimmedItem.replace(/^["']|["']$/g, ""); + items.push(unquoted); + } + existingProperties[key] = items; + } + } else { + const isKnownArrayKey = KNOWN_ARRAY_KEYS.includes(key); + const isEmptyArray = !trimmedValue || trimmedValue === ""; + const isArrayProperty = isKnownArrayKey || isEmptyArray; + if (isArrayProperty) { + existingProperties[key] = []; + arrayKeys.add(key); + } else { + const unquotedValue = trimmedValue.replace(/^["']|["']$/g, ""); + existingProperties[key] = [unquotedValue]; + } + } + } else if (currentKey && trimmedLine.startsWith("- ")) { + const isArrayProperty = arrayKeys.has(currentKey); + if (isArrayProperty) { + const item = trimmedLine.replace(/^-\s*/, ""); + if (item) existingProperties[currentKey].push(item); + } + } else if (trimmedLine && !trimmedLine.startsWith("- ") && !trimmedLine.startsWith("#")) { + const keyMatch = trimmedLine.match(/^([^:]+):\s*(.*)$/); + if (keyMatch) { + const [, key, value] = keyMatch; + if (!existingProperties[key]) { + existingProperties[key] = [value ? value.trim() : ""]; + } + } + } + }); + KNOWN_ARRAY_KEYS.forEach((key) => { + if (propertiesText.includes(key + ":") && !existingProperties[key]) { + existingProperties[key] = []; + } + }); + } catch (e) { + new import_obsidian2.Notice("Falling back to template due to parsing error."); + } + } + const bodyContent = content.slice(propertiesEnd); + return { + properties: existingProperties, + propertiesText, + propertiesEnd, + bodyContent + }; + } + parseTemplate(templateString, title) { + const templateLines = templateString.split("\n"); + const templateProps = []; + const templateValues = {}; + let inProperties = false; + for (let i = 0; i < templateLines.length; i++) { + const line = templateLines[i].trim(); + if (line === "---") { + inProperties = !inProperties; + if (!inProperties) { + break; + } + continue; + } + if (inProperties) { + const match = line.match(/^(\w+):\s*(.*)$/); + if (match) { + const [, key, value] = match; + templateProps.push(key); + const isKnownArrayKey = KNOWN_ARRAY_KEYS.includes(key); + const isEmptyArray = !value || value.trim() === "" || value.trim() === "[]"; + const isArrayProperty = isKnownArrayKey || isEmptyArray; + if (isArrayProperty) { + if (value && value.startsWith("[")) { + const items = value.replace(/[[\]]/g, "").split(",").map((t) => t.trim()).filter((t) => t); + templateValues[key] = items; + } else { + templateValues[key] = []; + for (let j = i + 1; j < templateLines.length; j++) { + const nextLine = templateLines[j].trim(); + if (nextLine.startsWith("- ")) { + const item = nextLine.replace(/^-\s*/, "").trim(); + if (item) { + const arrayValue = templateValues[key]; + if (Array.isArray(arrayValue)) { + arrayValue.push(item); + } + } + } else if (nextLine === "---" || nextLine && !nextLine.startsWith("- ") && nextLine.includes(":")) { + break; + } + } + } + } else { + const slug = this.toKebabCase(title); + const settings = this.getSettings(); + const stringValue = (value || "").replace(/\{\{title\}\}/g, title).replace(/\{\{date\}\}/g, window.moment(/* @__PURE__ */ new Date()).format(settings.dateFormat)).replace(/\{\{slug\}\}/g, slug); + templateValues[key] = stringValue; + } + } + } + } + return { templateProps, templateValues }; + } + buildFrontmatterContent(finalProps, arrayKeys) { + let newContent = "---\n"; + for (const key in finalProps) { + const isArrayProperty = KNOWN_ARRAY_KEYS.includes(key) || arrayKeys && arrayKeys.has(key); + if (isArrayProperty) { + newContent += `${key}: +`; + if (finalProps[key].length > 0) { + finalProps[key].forEach((item) => { + newContent += ` - ${item} +`; + }); + } + } else { + newContent += `${key}: ${finalProps[key][0] || ""} +`; + } + } + newContent += "---"; + return newContent; + } + async updateTitleInFrontmatter(file, newTitle, type) { + const titleKey = this.getTitleKey(type); + const hasTitleInTemplate = this.templateHasTitle(type); + if (!hasTitleInTemplate) { + return; + } + const content = await this.app.vault.read(file); + let propertiesEnd = 0; + let propertiesText = ""; + let hasFrontmatter = false; + if (content.startsWith("---")) { + hasFrontmatter = true; + propertiesEnd = content.indexOf("\n---", 3); + if (propertiesEnd === -1) { + propertiesEnd = content.length; + } else { + propertiesEnd += 4; + } + propertiesText = content.slice(4, propertiesEnd - 4).trim(); + } + const propOrder = []; + const existing = {}; + let currentKey = null; + let titleKeyPosition = -1; + const arrayKeys = /* @__PURE__ */ new Set(); + propertiesText.split("\n").forEach((line, index) => { + const trimmedLine = line.trim(); + const match = trimmedLine.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*)$/); + if (match) { + const [, key, value] = match; + propOrder.push(key); + currentKey = key; + if (key === titleKey) { + titleKeyPosition = index; + } + const isKnownArrayKey = KNOWN_ARRAY_KEYS.includes(key); + const isEmptyArray = !value || value.trim() === "" || value.trim() === "[]"; + const isArrayProperty = isKnownArrayKey || isEmptyArray; + if (isArrayProperty) { + existing[key] = []; + arrayKeys.add(key); + } else { + existing[key] = value ? value.trim() : ""; + } + } else if (currentKey && arrayKeys.has(currentKey) && trimmedLine.startsWith("- ")) { + const item = trimmedLine.replace(/^-\s*/, ""); + if (item) existing[currentKey].push(item); + } else if (trimmedLine && !trimmedLine.startsWith("- ") && !trimmedLine.startsWith("#")) { + const keyMatch = trimmedLine.match(/^([^:]+):\s*(.*)$/); + if (keyMatch) { + const [, key, value] = keyMatch; + if (!propOrder.includes(key)) { + propOrder.push(key); + existing[key] = value ? value.trim() : ""; + } + } + } + }); + let titleVal; + if (newTitle.includes('"') || newTitle.includes("'") || newTitle.includes("\n") || newTitle.includes("\\")) { + titleVal = `'${newTitle.replace(/'/g, "''")}'`; + } else if (newTitle.includes(" ") || newTitle.includes(":") || newTitle.includes("#") || newTitle.includes("@")) { + titleVal = `"${newTitle.replace(/"/g, '\\"')}"`; + } else { + titleVal = newTitle; + } + existing[titleKey] = titleVal; + if ("slug" in existing) { + const newSlug = this.toKebabCase(newTitle); + existing["slug"] = newSlug; + } + if (titleKeyPosition === -1) { + propOrder.push(titleKey); + } + if (!hasFrontmatter) { + return; + } + let newContent = "---\n"; + for (const key of propOrder) { + const val = existing[key]; + if (Array.isArray(val)) { + newContent += `${key}: +`; + if (val.length > 0) { + val.forEach((item) => { + newContent += ` - ${item} +`; + }); + } + } else { + newContent += `${key}: ${val || ""} +`; + } + } + newContent += "---\n"; + const bodyContent = content.slice(propertiesEnd); + newContent += bodyContent; + await this.app.vault.modify(file, newContent); + } + getTitleKey(type) { + if (type === "note") return "title"; + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + const contentType = contentTypes.find((ct) => ct.id === type); + if (!contentType) return "title"; + const template = contentType.template; + const lines = template.split("\n"); + let inProperties = false; + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed === "---") { + inProperties = !inProperties; + continue; + } + if (inProperties) { + const match = trimmed.match(/^(\w+):\s*(.+)$/); + if (match) { + const key = match[1]; + const value = match[2]; + if (value.includes("{{title}}")) { + return key; + } + } + } + } + return "title"; + } + // Check if the template for this content type has {{title}} + templateHasTitle(type) { + if (type === "note") return true; + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + const contentType = contentTypes.find((ct) => ct.id === type); + if (!contentType) return true; + const template = contentType.template; + return template.includes("{{title}}"); + } +}; + +// src/utils/link-conversion.ts +var import_obsidian3 = require("obsidian"); +var LinkConverter = class { + constructor(settings, plugin) { + this.settings = settings; + this.plugin = plugin; + } + // Get fresh settings from plugin if available, otherwise use stored settings + getSettings() { + var _a; + if ((_a = this.plugin) == null ? void 0 : _a.settings) { + return this.plugin.settings; + } + return this.settings; + } + // Local toKebabCase removed, using imported one instead + getAstroUrlFromInternalLink(link) { + const hashIndex = link.indexOf("#"); + let path = hashIndex >= 0 ? link.slice(0, hashIndex) : link; + const anchor = hashIndex >= 0 ? link.slice(hashIndex) : ""; + path = decodeURIComponent(path); + path = path.replace(/\.(md|mdx)$/, ""); + const fileExtension = link.endsWith(".mdx") ? ".mdx" : ".md"; + const contentTypeInfo = this.getContentTypeForPath(path + fileExtension); + let basePath = contentTypeInfo.basePath || ""; + let contentFolder = contentTypeInfo.contentFolder || ""; + let indexFileName = contentTypeInfo.indexFileName || ""; + if (contentFolder) { + path = path.slice(contentFolder.length + 1); + } + let addTrailingSlash = false; + const parts = path.split("/"); + const lastPart = parts[parts.length - 1]; + if (indexFileName && indexFileName.trim() !== "" && lastPart === indexFileName) { + parts.pop(); + path = parts.join("/"); + addTrailingSlash = true; + } else if ((!indexFileName || indexFileName.trim() === "") && lastPart === "index") { + parts.pop(); + path = parts.join("/"); + addTrailingSlash = true; + } + const slugParts = path.split("/").map((part) => toKebabCase(part)); + const slug = slugParts.join("/"); + if (basePath) { + if (!basePath.startsWith("/")) { + basePath = "/" + basePath; + } + if (!basePath.endsWith("/")) { + basePath += "/"; + } + } else { + basePath = "/"; + } + const settings = this.getSettings(); + const shouldAddTrailingSlash = (settings.addTrailingSlashToLinks || addTrailingSlash) && !anchor; + return `${basePath}${slug}${shouldAddTrailingSlash ? "/" : ""}${anchor}`; + } + getAstroUrlFromInternalLinkWithContext(link, currentFilePath, currentFileContentType) { + const hashIndex = link.indexOf("#"); + let path = hashIndex >= 0 ? link.slice(0, hashIndex) : link; + const anchor = hashIndex >= 0 ? link.slice(hashIndex) : ""; + path = decodeURIComponent(path); + path = path.replace(/\.(md|mdx)$/, ""); + let basePath = ""; + let contentFolder = ""; + let indexFileName = ""; + const fileExtension = link.endsWith(".mdx") ? ".mdx" : ".md"; + const targetContentType = this.getContentTypeForPath(path + fileExtension); + if (!targetContentType.basePath && currentFileContentType.basePath) { + basePath = currentFileContentType.basePath; + indexFileName = currentFileContentType.indexFileName; + contentFolder = currentFileContentType.contentFolder; + } else { + basePath = targetContentType.basePath; + indexFileName = targetContentType.indexFileName; + contentFolder = targetContentType.contentFolder; + } + if (contentFolder) { + path = path.slice(contentFolder.length + 1); + } + let addTrailingSlash = false; + const parts = path.split("/"); + const lastPart = parts[parts.length - 1]; + if (indexFileName && indexFileName.trim() !== "" && lastPart === indexFileName) { + parts.pop(); + path = parts.join("/"); + addTrailingSlash = true; + } else if ((!indexFileName || indexFileName.trim() === "") && lastPart === "index") { + parts.pop(); + path = parts.join("/"); + addTrailingSlash = true; + } + const slugParts = path.split("/").map((part) => toKebabCase(part)); + const slug = slugParts.join("/"); + if (basePath) { + if (!basePath.startsWith("/")) { + basePath = "/" + basePath; + } + if (!basePath.endsWith("/")) { + basePath += "/"; + } + } else { + basePath = "/"; + } + const settings = this.getSettings(); + const shouldAddTrailingSlash = (settings.addTrailingSlashToLinks || addTrailingSlash) && !anchor; + return `${basePath}${slug}${shouldAddTrailingSlash ? "/" : ""}${anchor}`; + } + isInConfiguredContentDirectory(filePath) { + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + const sortedTypes = sortByPatternSpecificity(contentTypes); + for (const contentType of sortedTypes) { + if (!contentType.enabled) continue; + if (!contentType.folder || contentType.folder.trim() === "") { + if (!filePath.includes("/") || filePath.split("/").length === 1) { + return true; + } + } else if (matchesFolderPattern(filePath, contentType.folder)) { + if (contentType.ignoreSubfolders) { + const pathSegments = filePath.split("/"); + const pathDepth = pathSegments.length; + const patternSegments = contentType.folder.split("/"); + const expectedDepth = patternSegments.length; + if (contentType.creationMode === "folder") { + const folderDepth = pathDepth - 1; + if (folderDepth === expectedDepth || folderDepth === expectedDepth + 1) { + return true; + } + } else { + if (pathDepth === expectedDepth) { + return true; + } + } + } else { + return true; + } + } + } + return false; + } + getContentTypeForPath(filePath) { + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + const sortedTypes = sortByPatternSpecificity(contentTypes); + for (const contentType of sortedTypes) { + if (!contentType.enabled) continue; + if (!contentType.folder || contentType.folder.trim() === "") { + if (!filePath.includes("/") || filePath.split("/").length === 1) { + return { + basePath: contentType.linkBasePath || "", + creationMode: contentType.creationMode, + indexFileName: contentType.indexFileName || "", + contentFolder: "" + }; + } + } else if (matchesFolderPattern(filePath, contentType.folder)) { + if (contentType.ignoreSubfolders) { + const pathSegments = filePath.split("/"); + const pathDepth = pathSegments.length; + const patternSegments = contentType.folder.split("/"); + const expectedDepth = patternSegments.length; + if (contentType.creationMode === "folder") { + const folderDepth = pathDepth - 1; + if (folderDepth === expectedDepth || folderDepth === expectedDepth + 1) { + return { + basePath: contentType.linkBasePath || "", + creationMode: contentType.creationMode, + indexFileName: contentType.indexFileName || "", + contentFolder: contentType.folder + }; + } + } else { + if (pathDepth === expectedDepth) { + return { + basePath: contentType.linkBasePath || "", + creationMode: contentType.creationMode, + indexFileName: contentType.indexFileName || "", + contentFolder: contentType.folder + }; + } + } + } else { + return { + basePath: contentType.linkBasePath || "", + creationMode: contentType.creationMode, + indexFileName: contentType.indexFileName || "", + contentFolder: contentType.folder + }; + } + } + } + return { + basePath: "", + creationMode: "file", + indexFileName: "", + contentFolder: "" + }; + } + convertWikilinksForAstro(editor, file) { + var _a, _b; + if (!(file instanceof import_obsidian3.TFile)) { + new import_obsidian3.Notice("No active file."); + return; + } + const cursor = editor.getCursor(); + const originalLine = cursor.line; + const originalCh = cursor.ch; + const originalContent = editor.getValue(); + const originalLineCount = originalContent.split("\n").length; + const originalLineLength = ((_a = originalContent.split("\n")[originalLine]) == null ? void 0 : _a.length) || 0; + const content = editor.getValue(); + let newContent = content; + let convertedCount = 0; + let skippedCount = 0; + const skippedLinks = []; + const currentFileContentType = this.getContentTypeForPath(file.path); + const imageExtensions = /\.(png|jpg|jpeg|gif|svg)$/i; + const canConvertLink = (linkText) => { + if (imageExtensions.test(linkText)) { + return false; + } + if (linkText.match(/^https?:\/\//)) { + return false; + } + if (!linkText.includes(".md") && !linkText.includes(".mdx") && !linkText.match(/^[a-zA-Z0-9_-]+(\/[a-zA-Z0-9_-]+)*$/)) { + return false; + } + let targetPath; + if (linkText.endsWith(".md") || linkText.endsWith(".mdx")) { + targetPath = linkText; + } else { + targetPath = linkText + ".md"; + } + const isInConfiguredDirectory = this.isInConfiguredContentDirectory(targetPath); + const isSimpleFilename = !targetPath.includes("/"); + const hasCurrentContentType = currentFileContentType.basePath !== "" || currentFileContentType.creationMode !== "file" || currentFileContentType.indexFileName !== ""; + return isInConfiguredDirectory || isSimpleFilename && hasCurrentContentType; + }; + newContent = newContent.replace( + /\[\[([^\]|]+)(\|([^\]]+))?\]\]/g, + (match, linkText, _pipe, displayText) => { + if (imageExtensions.test(linkText)) { + skippedCount++; + skippedLinks.push(linkText); + return match; + } + if (!canConvertLink(linkText)) { + skippedCount++; + skippedLinks.push(linkText); + return match; + } + const display = displayText || linkText.replace(/\.(md|mdx)$/, ""); + const url = this.getAstroUrlFromInternalLinkWithContext(linkText, file.path, currentFileContentType); + convertedCount++; + return `[${display}](${url})`; + } + ); + newContent = newContent.replace( + /\[([^\]]+)\]\(([^)]+\.(md|mdx)[^)]*)\)/g, + (match, displayText, link) => { + if (link.match(/^https?:\/\//) || imageExtensions.test(link)) { + skippedCount++; + skippedLinks.push(link); + return match; + } + if (!canConvertLink(link)) { + skippedCount++; + skippedLinks.push(link); + return match; + } + const url = this.getAstroUrlFromInternalLinkWithContext(link, file.path, currentFileContentType); + convertedCount++; + return `[${displayText}](${url})`; + } + ); + newContent = newContent.replace( + /!\[(.*?)\]\(([^)]+)\)/g, + (match) => { + skippedCount++; + return match; + } + ); + newContent = newContent.replace(/\{\{([^}]+)\}\}/g, (match, fileName) => { + if (imageExtensions.test(fileName)) { + skippedCount++; + skippedLinks.push(fileName); + return match; + } + if (!canConvertLink(fileName)) { + skippedCount++; + skippedLinks.push(fileName); + return match; + } + const url = this.getAstroUrlFromInternalLinkWithContext(fileName, file.path, currentFileContentType); + convertedCount++; + return `[Embedded: ${fileName}](${url})`; + }); + editor.setValue(newContent); + const newLineCount = newContent.split("\n").length; + const newLineLength = ((_b = newContent.split("\n")[originalLine]) == null ? void 0 : _b.length) || 0; + let newLine = originalLine; + let newCh = originalCh; + if (newLineCount !== originalLineCount) { + if (newLine >= newLineCount) { + newLine = Math.max(0, newLineCount - 1); + } + } + if (newLineLength !== originalLineLength) { + if (newCh > newLineLength) { + newCh = Math.max(0, newLineLength); + } + } + editor.setCursor({ line: newLine, ch: newCh }); + if (convertedCount > 0 && skippedCount === 0) { + new import_obsidian3.Notice(`Converted ${convertedCount} internal link${convertedCount > 1 ? "s" : ""} for Astro.`); + } else if (convertedCount > 0 && skippedCount > 0) { + new import_obsidian3.Notice(`Converted ${convertedCount} link${convertedCount > 1 ? "s" : ""} for Astro. Skipped ${skippedCount} link${skippedCount > 1 ? "s" : ""} outside configured content directories.`); + } else if (skippedCount > 0) { + new import_obsidian3.Notice(`No links converted. All ${skippedCount} link${skippedCount > 1 ? "s" : ""} are outside configured content directories or are images/external links.`); + } else { + new import_obsidian3.Notice("No internal links found to convert."); + } + } +}; + +// src/ui/title-modal.ts +var import_obsidian4 = require("obsidian"); +var TitleModal = class extends import_obsidian4.Modal { + constructor(app, file, plugin, type, isRename = false, isNewNote = false) { + super(app); + this.file = file; + this.plugin = plugin; + this.type = type; + this.isRename = isRename; + this.isNewNote = isNewNote; + const settings = plugin.settings; + this.fileOps = new FileOperations(app, settings, plugin); + this.templateParser = new TemplateParser(app, settings); + } + async getCurrentTitleAsync() { + if (!this.file) { + return ""; + } + try { + const content = await this.app.vault.read(this.file); + const titleKey = this.fileOps.getTitleKey(this.type); + const { properties } = this.templateParser.parseFrontmatter(content); + if (titleKey in properties) { + const titleValue = properties[titleKey]; + if (Array.isArray(titleValue) && titleValue.length > 0) { + return String(titleValue[0]); + } + if (titleValue !== null && titleValue !== void 0) { + return String(titleValue); + } + } + } catch (error) { + console.error("Error reading file for title:", error); + } + return this.getFallbackTitle(); + } + getCurrentTitle() { + if (!this.file) { + return ""; + } + const titleKey = this.fileOps.getTitleKey(this.type); + const cache = this.app.metadataCache.getFileCache(this.file); + if ((cache == null ? void 0 : cache.frontmatter) && titleKey in cache.frontmatter) { + const titleValue = cache.frontmatter[titleKey]; + if (typeof titleValue === "string") { + return titleValue; + } + if (Array.isArray(titleValue) && titleValue.length > 0) { + const firstValue = titleValue[0]; + if (typeof firstValue === "string") { + return firstValue; + } + if (firstValue != null) { + if (typeof firstValue === "number" || typeof firstValue === "boolean") { + return String(firstValue); + } + if (typeof firstValue === "string") { + return firstValue; + } + } + } + if (titleValue == null) { + return ""; + } + if (typeof titleValue === "number" || typeof titleValue === "boolean") { + return String(titleValue); + } + if (typeof titleValue === "string") { + return titleValue; + } + return ""; + } + return this.getFallbackTitle(); + } + getFallbackTitle() { + if (!this.file) { + return ""; + } + let basename = this.file.basename; + if (this.file.parent && this.type !== "note") { + const contentType = this.fileOps.getContentType(this.type); + const indexFileName = (contentType == null ? void 0 : contentType.indexFileName) || ""; + if (indexFileName.trim() !== "" && basename === indexFileName) { + basename = this.file.parent.name; + } + } + if (basename.startsWith("_")) { + basename = basename.slice(1); + } + return basename.replace(/-/g, " ").split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "); + } + /** + * Extracts a suggested title from the file basename for newly created files. + * This is used when a file is created from a link (e.g., [[sEfsleif]]). + * Preserves the original text as much as possible. + */ + getSuggestedTitleFromBasename() { + if (!this.file) { + return ""; + } + let basename = this.file.basename; + if (this.file.parent && this.type !== "note") { + const contentType = this.fileOps.getContentType(this.type); + const indexFileName = (contentType == null ? void 0 : contentType.indexFileName) || ""; + if (indexFileName.trim() !== "" && basename === indexFileName) { + basename = this.file.parent.name; + } + } + if (basename.startsWith("_")) { + basename = basename.slice(1); + } + return basename; + } + onOpen() { + const { contentEl } = this; + contentEl.empty(); + const isMobile = window.innerWidth <= 768 || import_obsidian4.Platform.isMobile; + if (isMobile) { + this.modalEl.addClass("astro-composer-mobile-modal"); + } + if (this.isRename) { + const typeName = this.getTypeDisplayName(); + if (this.type === "note") { + contentEl.createEl("h2", { text: "Rename content" }); + contentEl.createEl("p", { text: "Enter a title for this content:" }); + } else { + contentEl.createEl("h2", { text: `Rename ${typeName} content` }); + contentEl.createEl("p", { text: `Enter new title for your ${typeName} content:` }); + } + this.titleInput = contentEl.createEl("input", { + type: "text", + placeholder: "New Title", + cls: "astro-composer-title-input" + }); + void this.getCurrentTitleAsync().then((title) => { + this.titleInput.value = title; + }); + } else if (this.isNewNote) { + const typeName = this.getTypeDisplayName(); + if (this.type === "note") { + contentEl.createEl("h2", { text: "New content" }); + contentEl.createEl("p", { text: "Enter a title for this content:" }); + } else { + contentEl.createEl("h2", { text: `Create new ${typeName} content` }); + contentEl.createEl("p", { text: `Enter a title for your new ${typeName} content:` }); + } + this.titleInput = contentEl.createEl("input", { + type: "text", + placeholder: "New Title", + cls: "astro-composer-title-input" + }); + } else { + const typeName = this.getTypeDisplayName(); + if (this.type === "note") { + contentEl.createEl("h2", { text: "New content" }); + contentEl.createEl("p", { text: "Enter a title for this content:" }); + } else { + contentEl.createEl("h2", { text: `Create new ${typeName} content` }); + contentEl.createEl("p", { text: `Enter a title for your new ${typeName} content:` }); + } + this.titleInput = contentEl.createEl("input", { + type: "text", + placeholder: "New Title", + cls: "astro-composer-title-input" + }); + if (this.file) { + const suggestedTitle = this.getSuggestedTitleFromBasename(); + if (suggestedTitle) { + this.titleInput.value = suggestedTitle; + } + } + } + this.titleInput.focus(); + if (this.isNewNote) { + setTimeout(() => { + this.titleInput.setSelectionRange(0, 0); + }, 0); + } + const buttonContainer = contentEl.createDiv({ cls: "astro-composer-button-container" }); + const cancelButton = buttonContainer.createEl("button", { text: "Cancel", cls: "astro-composer-cancel-button" }); + cancelButton.onclick = () => this.close(); + const submitButton = buttonContainer.createEl("button", { text: this.isRename ? "Rename" : "Create", cls: ["astro-composer-create-button", "mod-cta"] }); + submitButton.onclick = () => this.submit(); + this.titleInput.addEventListener("keypress", (e) => { + if (e.key === "Enter") void this.submit(); + }); + } + async submit() { + const title = this.titleInput.value.trim(); + if (!title) { + new import_obsidian4.Notice("Please enter a title."); + return; + } + try { + let newFile = null; + if (this.isRename) { + newFile = await this.fileOps.renameFile({ file: this.file, title, type: this.type }); + if (newFile) { + await this.templateParser.updateTitleInFrontmatter(newFile, title, this.type); + } else { + this.close(); + return; + } + } else if (this.isNewNote) { + if (this.file) { + newFile = await this.fileOps.createFile({ file: this.file, title, type: this.type }); + const shouldInsertProperties = this.plugin.settings.autoInsertProperties; + if (newFile && shouldInsertProperties) { + await this.addPropertiesToFile(newFile, title, this.type); + this.positionCursorAtEnd(newFile); + } + } + } else if (this.file) { + newFile = await this.fileOps.createFile({ file: this.file, title, type: this.type }); + const shouldInsertProperties = this.plugin.settings.autoInsertProperties; + if (newFile && shouldInsertProperties) { + await this.addPropertiesToFile(newFile, title, this.type); + this.positionCursorAtEnd(newFile); + } + } else { + newFile = await this.createNewFile(title); + } + if (!newFile) { + new import_obsidian4.Notice(`Failed to ${this.isRename ? "rename" : "create"} ${this.type}.`); + this.close(); + return; + } + } catch (error) { + console.error("TitleModal: Error during process:", error); + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian4.Notice(`Error ${this.isRename ? "renaming" : "creating"} ${this.type}: ${errorMessage}.`); + this.close(); + return; + } + this.close(); + } + getTypeDisplayName() { + if (this.type === "note") { + return "Content"; + } + const contentType = this.fileOps.getContentType(this.type); + return contentType ? contentType.name : "Content"; + } + async createNewFile(title) { + var _a, _b; + let targetFolder; + const originalDir = ((_b = (_a = this.file) == null ? void 0 : _a.parent) == null ? void 0 : _b.path) || ""; + if (this.type !== "note") { + const contentType2 = this.fileOps.getContentType(this.type); + if (originalDir === "" || originalDir === "/") { + targetFolder = (contentType2 == null ? void 0 : contentType2.folder) || ""; + } else { + targetFolder = originalDir; + } + } else { + targetFolder = originalDir; + } + const filename = this.fileOps.generateFilename(title); + const contentType = this.fileOps.getContentType(this.type); + const extension = (contentType == null ? void 0 : contentType.useMdxExtension) ? ".mdx" : ".md"; + const filePath = targetFolder ? `${targetFolder}/${filename}${extension}` : `${filename}${extension}`; + if (this.plugin) { + this.plugin.pluginCreatedFiles.set(filePath, Date.now()); + } + let initialContent = ""; + if (this.plugin.settings.autoInsertProperties) { + initialContent = this.generateInitialContent(title); + } + try { + const newFile = await this.app.vault.create(filePath, initialContent); + const leaf = this.app.workspace.getLeaf(); + await leaf.openFile(newFile); + const positionCursor = () => { + var _a2; + const view = leaf.view; + if (view instanceof import_obsidian4.MarkdownView && view.editor) { + const editor = view.editor; + const content = editor.getValue(); + if (content) { + const lines = content.split("\n"); + const lastLine = lines.length - 1; + const lastLineLength = ((_a2 = lines[lastLine]) == null ? void 0 : _a2.length) || 0; + editor.setCursor({ line: lastLine, ch: lastLineLength }); + editor.focus(); + return true; + } + } + return false; + }; + setTimeout(() => { + if (!positionCursor()) { + setTimeout(() => { + positionCursor(); + }, 200); + } + }, 100); + return newFile; + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + throw new Error(`Failed to create file: ${errorMessage}`); + } + } + generateInitialContent(title) { + const now = /* @__PURE__ */ new Date(); + const dateString = window.moment(now).format(this.plugin.settings.dateFormat); + const slug = toKebabCase(title); + let template; + if (this.type === "note") { + const escapedTitle = this.escapeYamlString(title); + template = `--- +title: ${escapedTitle} +date: ${dateString} +--- +`; + } else { + const contentType = this.fileOps.getContentType(this.type); + if (!contentType) { + const escapedTitle = this.escapeYamlString(title); + template = `--- +title: ${escapedTitle} +date: ${dateString} +--- +`; + } else { + template = contentType.template; + } + } + template = template.replace(/\{\{title\}\}/g, title); + template = template.replace(/\{\{date\}\}/g, dateString); + template = template.replace(/\{\{slug\}\}/g, slug); + return template; + } + async addPropertiesToFile(file, title, type) { + const now = /* @__PURE__ */ new Date(); + const dateString = window.moment(now).format(this.plugin.settings.dateFormat); + const slug = toKebabCase(title); + let template; + if (type === "note") { + const escapedTitle = this.escapeYamlString(title); + template = `--- +title: ${escapedTitle} +date: ${dateString} +--- +`; + } else { + const contentType = this.fileOps.getContentType(type); + if (!contentType) { + const escapedTitle = this.escapeYamlString(title); + template = `--- +title: ${escapedTitle} +date: ${dateString} +--- +`; + } else { + template = contentType.template; + } + } + template = template.replace(/\{\{title\}\}/g, title); + template = template.replace(/\{\{date\}\}/g, dateString); + template = template.replace(/\{\{slug\}\}/g, slug); + await this.app.vault.modify(file, template); + } + positionCursorAtEnd(file) { + const positionCursor = () => { + var _a; + const view = this.app.workspace.getActiveViewOfType(import_obsidian4.MarkdownView); + if (view && view.file === file && view.editor) { + const editor = view.editor; + const content = editor.getValue(); + if (content) { + const lines = content.split("\n"); + const lastLine = lines.length - 1; + const lastLineLength = ((_a = lines[lastLine]) == null ? void 0 : _a.length) || 0; + editor.setCursor({ line: lastLine, ch: lastLineLength }); + editor.focus(); + return true; + } + } + return false; + }; + setTimeout(() => { + if (!positionCursor()) { + setTimeout(() => { + positionCursor(); + }, 200); + } + }, 100); + } + escapeYamlString(str) { + if (str.includes('"') || str.includes("'") || str.includes("\n") || str.includes("\\")) { + return `'${str.replace(/'/g, "''")}'`; + } else if (str.includes(" ") || str.includes(":") || str.includes("#") || str.includes("@")) { + return `"${str.replace(/"/g, '\\"')}"`; + } else { + return str; + } + } + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +}; + +// src/commands/index.ts +function registerCommands(plugin, settings) { + const isMobile = import_obsidian5.Platform.isMobile; + if (isMobile) { + let hasMatchingContentType2 = function(file, settings2) { + const type = fileOps.determineType(file); + if (type === "note") { + return false; + } + const contentType = fileOps.getContentType(type); + return contentType !== null && contentType.enabled; + }; + var hasMatchingContentType = hasMatchingContentType2; + const pluginInterface2 = plugin; + const fileOps = new FileOperations(plugin.app, settings, pluginInterface2); + const linkConverter = new LinkConverter(settings, pluginInterface2); + plugin.addCommand({ + id: "standardize-properties", + name: "Standardize properties", + icon: "file-check", + editorCallback: (editor, ctx) => { + const file = ctx instanceof import_obsidian5.MarkdownView ? ctx.file : ctx.file; + if (file instanceof import_obsidian5.TFile) { + const currentSettings = pluginInterface2.settings || settings; + void standardizeProperties(plugin.app, currentSettings, file, pluginInterface2, editor); + } + } + }); + plugin.addCommand({ + id: "convert-wikilinks-astro", + name: "Convert internal links for astro", + icon: "link-2", + editorCallback: (editor, ctx) => { + const file = ctx instanceof import_obsidian5.MarkdownView ? ctx.file : ctx.file; + if (file instanceof import_obsidian5.TFile) { + linkConverter.convertWikilinksForAstro(editor, file); + } + } + }); + plugin.addCommand({ + id: "rename-content", + name: "Rename current content", + icon: "pencil", + editorCallback: (editor, ctx) => { + const file = ctx instanceof import_obsidian5.MarkdownView ? ctx.file : ctx.file; + if (file instanceof import_obsidian5.TFile) { + if (!hasMatchingContentType2(file, settings)) { + new import_obsidian5.Notice("Cannot rename: this file is not part of a configured content type folder."); + return; + } + const type = fileOps.determineType(file); + const cache = plugin.app.metadataCache.getFileCache(file); + const titleKey = fileOps.getTitleKey(type); + if (!(cache == null ? void 0 : cache.frontmatter) || !(titleKey in cache.frontmatter)) { + new import_obsidian5.Notice(`Cannot rename: No ${titleKey} found in properties`); + return; + } + new TitleModal(plugin.app, file, plugin, type, true).open(); + } + } + }); + return; + } + const pluginInterface = plugin; + function hasMatchingContentType(file, settings2) { + const currentSettings = (plugin == null ? void 0 : plugin.settings) || settings2; + const tempFileOps = new FileOperations(plugin.app, currentSettings, plugin); + const type = tempFileOps.determineType(file); + if (type === "note") { + return false; + } + const contentType = tempFileOps.getContentType(type); + return contentType !== null && contentType.enabled; + } + plugin.addCommand({ + id: "standardize-properties", + name: "Standardize properties", + icon: "file-check", + editorCallback: (editor, ctx) => { + const file = ctx instanceof import_obsidian5.MarkdownView ? ctx.file : ctx.file; + if (file instanceof import_obsidian5.TFile) { + void standardizeProperties(plugin.app, settings, file, plugin, editor); + } + } + }); + plugin.addCommand({ + id: "convert-wikilinks-astro", + name: "Convert internal links for astro", + icon: "link-2", + editorCallback: (editor, ctx) => { + const file = ctx instanceof import_obsidian5.MarkdownView ? ctx.file : ctx.file; + if (file instanceof import_obsidian5.TFile) { + const currentSettings = pluginInterface.settings || settings; + const currentLinkConverter = new LinkConverter(currentSettings, pluginInterface); + currentLinkConverter.convertWikilinksForAstro(editor, file); + } + } + }); + plugin.addCommand({ + id: "rename-content", + name: "Rename current content", + icon: "pencil", + editorCallback: (editor, ctx) => { + const file = ctx instanceof import_obsidian5.MarkdownView ? ctx.file : ctx.file; + if (file instanceof import_obsidian5.TFile) { + const currentSettings = pluginInterface.settings || settings; + const currentFileOps = new FileOperations(plugin.app, currentSettings, pluginInterface); + if (!hasMatchingContentType(file, currentSettings)) { + new import_obsidian5.Notice("Cannot rename: this file is not part of a configured content type folder."); + return; + } + const type = currentFileOps.determineType(file); + new TitleModal(plugin.app, file, pluginInterface, type, true).open(); + } + } + }); + if (!isMobile) { + plugin.addCommand({ + id: "open-project-terminal", + name: "Open project terminal", + icon: "terminal-square", + callback: () => { + const currentSettings = plugin.settings; + if (!currentSettings.enableOpenTerminalCommand) { + new import_obsidian5.Notice("Open terminal command is disabled. Enable it in settings to use this command."); + return; + } + openTerminalInProjectRoot(plugin.app, currentSettings); + } + }); + } + if (!isMobile) { + plugin.addCommand({ + id: "edit-astro-config", + name: "Edit astro config", + icon: "rocket", + callback: async () => { + const currentSettings = plugin.settings; + if (!currentSettings.enableOpenConfigFileCommand) { + new import_obsidian5.Notice("Edit config file command is disabled. Enable it in settings to use this command."); + return; + } + await openConfigFile(plugin.app, currentSettings); + } + }); + } +} +async function standardizeProperties(app, settings, file, plugin, editor) { + var _a; + const currentSettings = (plugin == null ? void 0 : plugin.settings) || settings; + const templateParser = new TemplateParser(app, currentSettings); + const fileOps = new FileOperations(app, currentSettings, plugin); + let cursorPosition = null; + let originalContent = ""; + if (editor) { + const cursor = editor.getCursor(); + cursorPosition = { line: cursor.line, ch: cursor.ch }; + originalContent = editor.getValue(); + } + const type = fileOps.determineType(file); + if (type === "note") { + new import_obsidian5.Notice("No properties template specified for this content. This file doesn't match any configured content type folders."); + return; + } + let templateString; + if (type === "note") { + new import_obsidian5.Notice("No properties template specified for this content. This file doesn't match any configured content type folders."); + return; + } + const contentType = fileOps.getContentType(type); + if (!contentType) { + new import_obsidian5.Notice("Content type not found."); + return; + } + templateString = contentType.template; + await new Promise((resolve) => setTimeout(resolve, 100)); + const content = await app.vault.read(file); + const title = file.basename.replace(/^_/, ""); + const parsed = templateParser.parseFrontmatter(content); + const { templateProps, templateValues } = templateParser.parseTemplate(templateString, title); + const finalProps = { ...parsed.properties }; + const arrayKeys = /* @__PURE__ */ new Set(); + const slug = toKebabCase(title); + for (const key of templateProps) { + if (!(key in parsed.properties)) { + const templateValue = templateValues[key]; + if (Array.isArray(templateValue)) { + finalProps[key] = templateValue; + arrayKeys.add(key); + } else { + finalProps[key] = [templateValue || ""]; + } + } else { + const templateValue = templateValues[key]; + const isArrayValue = Array.isArray(templateValue); + if (isArrayValue) { + const existingItems = parsed.properties[key] || []; + const newItems = templateValue.filter((item) => !existingItems.includes(item)); + finalProps[key] = [...existingItems, ...newItems]; + arrayKeys.add(key); + } else { + if (key === "slug") { + const existingSlug = parsed.properties[key][0] || ""; + if (!existingSlug || existingSlug.trim() === "") { + finalProps[key] = [slug]; + } + } + } + } + } + if ("slug" in parsed.properties && templateString.includes("{{slug}}")) { + const existingSlug = parsed.properties["slug"][0] || ""; + if (!existingSlug || existingSlug.trim() === "") { + finalProps["slug"] = [slug]; + } + } + for (const key in parsed.properties) { + if (parsed.properties[key].length > 1) { + arrayKeys.add(key); + } + } + const newContent = templateParser.buildFrontmatterContent(finalProps, arrayKeys) + parsed.bodyContent; + await app.vault.modify(file, newContent); + if (editor && cursorPosition) { + await new Promise((resolve) => setTimeout(resolve, 50)); + const activeView = app.workspace.getActiveViewOfType(import_obsidian5.MarkdownView); + if (activeView && activeView.file === file && activeView.editor) { + const activeEditor = activeView.editor; + const newLineCount = newContent.split("\n").length; + const originalLineCount = originalContent.split("\n").length; + let newLine = cursorPosition.line; + let newCh = cursorPosition.ch; + if (newLineCount !== originalLineCount) { + if (newLine >= newLineCount) { + newLine = Math.max(0, newLineCount - 1); + } + } + const newLineLength = ((_a = newContent.split("\n")[newLine]) == null ? void 0 : _a.length) || 0; + if (newCh > newLineLength) { + newCh = Math.max(0, newLineLength); + } + activeEditor.setCursor({ line: newLine, ch: newCh }); + } + } + new import_obsidian5.Notice("Properties standardized using template."); +} +function renameContentByPath(app, filePath, settings, plugin) { + const file = app.vault.getAbstractFileByPath(filePath); + if (!(file instanceof import_obsidian5.TFile)) { + new import_obsidian5.Notice(`File not found: ${filePath}`); + return; + } + const fileOps = new FileOperations(app, settings, plugin); + function hasMatchingContentType(file2, settings2) { + const type2 = fileOps.determineType(file2); + if (type2 === "note") { + return false; + } + const contentType = fileOps.getContentType(type2); + return contentType !== null && contentType.enabled; + } + if (!hasMatchingContentType(file, settings)) { + new import_obsidian5.Notice("Cannot rename: this file is not part of a configured content type folder."); + return; + } + const type = fileOps.determineType(file); + new TitleModal(app, file, plugin, type, true).open(); +} +function registerContentTypeCommands(plugin, settings) { + const pluginInterface = plugin; + const contentTypes = settings.contentTypes || []; + for (const contentType of contentTypes) { + if (!contentType.enabled) { + continue; + } + const commandId = `create-content-type-${contentType.id}`; + const commandName = `Create new content type: ${contentType.name}`; + plugin.addCommand({ + id: commandId, + name: commandName, + callback: async () => { + let targetFolder = contentType.folder || ""; + if (targetFolder && targetFolder.trim() !== "") { + const folder = plugin.app.vault.getAbstractFileByPath(targetFolder); + if (!(folder instanceof import_obsidian5.TFolder)) { + try { + await plugin.app.vault.createFolder(targetFolder); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian5.Notice(`Failed to create folder: ${errorMessage}`); + return; + } + } + } + const tempFileName = "Untitled.md"; + const filePath = targetFolder ? `${targetFolder}/${tempFileName}` : tempFileName; + const existingFile = plugin.app.vault.getAbstractFileByPath(filePath); + if (existingFile instanceof import_obsidian5.TFile) { + new TitleModal(plugin.app, existingFile, pluginInterface, contentType.id, false, true).open(); + return; + } + if (pluginInterface && "pluginCreatedFiles" in pluginInterface) { + pluginInterface.pluginCreatedFiles.set(filePath, Date.now()); + } + try { + const tempFile = await plugin.app.vault.create(filePath, ""); + new TitleModal(plugin.app, tempFile, pluginInterface, contentType.id, false, true).open(); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + new import_obsidian5.Notice(`Failed to create file: ${errorMessage}`); + if (pluginInterface && "pluginCreatedFiles" in pluginInterface) { + pluginInterface.pluginCreatedFiles.delete(filePath); + } + } + } + }); + } +} +var terminalLogger = { + enabled: false, + setEnabled(value) { + this.enabled = value; + }, + log(...args) { + if (this.enabled) { + console.debug("[astro-composer:terminal]", ...args); + } + } +}; +function getDefaultTerminalApp() { + if (!import_obsidian5.Platform.isDesktopApp) { + return ""; + } + if (import_obsidian5.Platform.isMacOS) { + return "Terminal"; + } + if (import_obsidian5.Platform.isWin) { + try { + const os = require("os"); + const release = os.release(); + const majorVersion = parseInt(release.split(".")[0]); + const buildNumber = parseInt(release.split(".")[2]); + if (majorVersion > 10 || majorVersion === 10 && buildNumber >= 22e3) { + return "wt.exe"; + } + } catch (e) { + } + return "cmd.exe"; + } + if (import_obsidian5.Platform.isLinux) { + return "gnome-terminal"; + } + return ""; +} +function sanitizeTerminalApp(value) { + return value.trim(); +} +function escapeDoubleQuotes(value) { + return value.replace(/"/g, '\\"'); +} +function openTerminalInProjectRoot(app, settings) { + terminalLogger.setEnabled(settings.enableTerminalDebugLogging); + try { + const { exec } = require("child_process"); + const path = require("path"); + const fs = require("fs"); + const adapter = app.vault.adapter; + const vaultPath = adapter.basePath || adapter.path; + const vaultPathString = typeof vaultPath === "string" ? vaultPath : String(vaultPath); + let projectPath; + if (settings.terminalProjectRootPath && settings.terminalProjectRootPath.trim()) { + projectPath = path.resolve(vaultPathString, settings.terminalProjectRootPath); + } else { + projectPath = vaultPathString; + } + if (!fs.existsSync(projectPath)) { + new import_obsidian5.Notice(`Project root directory not found at: ${projectPath}`); + return; + } + const configuredApp = sanitizeTerminalApp(settings.terminalApplicationName || ""); + const terminalApp = configuredApp || getDefaultTerminalApp(); + if (!configuredApp && !terminalApp) { + new import_obsidian5.Notice("Terminal application name is empty. Please configure it in settings."); + return; + } + const platform = process.platform; + terminalLogger.log("Opening terminal", { platform, terminalApp, projectPath }); + if (platform === "win32") { + const escapedPath = projectPath.replace(/"/g, '"'); + const lowerApp = terminalApp.toLowerCase(); + if (lowerApp === "wt.exe" || lowerApp === "wt" || lowerApp === "windows terminal") { + exec("where wt", (error) => { + if (!error) { + const command = `start "" wt.exe -d "${escapedPath}"`; + terminalLogger.log("Windows launch (wt)", { command, projectPath }); + exec(command, (execError) => { + if (execError) { + terminalLogger.log("Windows Terminal failed, falling back to cmd", { error: execError.message }); + const fallbackCommand = `start "" cmd.exe /K "cd /d "${escapedPath}""`; + exec(fallbackCommand, (cmdError) => { + if (cmdError) { + new import_obsidian5.Notice(`Error opening terminal: ${cmdError.message || "Unknown error"}`); + } + }); + } + }); + } else { + terminalLogger.log("Windows Terminal not found, using cmd", {}); + const fallbackCommand = `start "" cmd.exe /K "cd /d "${escapedPath}""`; + exec(fallbackCommand, (cmdError) => { + if (cmdError) { + new import_obsidian5.Notice(`Error opening terminal: ${cmdError.message || "Unknown error"}`); + } + }); + } + }); + } else if (lowerApp === "powershell" || lowerApp === "powershell.exe") { + const escapedPathForPS = projectPath.replace(/'/g, "''"); + const command = `start "" powershell -NoExit -Command "Set-Location '${escapedPathForPS}';"`; + terminalLogger.log("Windows launch (powershell)", { command, projectPath }); + exec(command, (error) => { + if (error) { + new import_obsidian5.Notice(`Error opening terminal: ${error.message || "Unknown error"}`); + } + }); + } else if (lowerApp === "cmd.exe" || lowerApp === "cmd") { + const command = `start "" cmd.exe /K "cd /d "${escapedPath}""`; + terminalLogger.log("Windows launch (cmd)", { command, projectPath }); + exec(command, (error) => { + if (error) { + new import_obsidian5.Notice(`Error opening terminal: ${error.message || "Unknown error"}`); + } + }); + } else { + const command = `start "" "${terminalApp}"`; + terminalLogger.log("Windows launch (generic)", { command, terminalApp, projectPath }); + exec(command, (error) => { + if (error) { + terminalLogger.log("Generic terminal failed, falling back to cmd", { error: error.message }); + const fallbackCommand = `start "" cmd.exe /K "cd /d "${escapedPath}""`; + exec(fallbackCommand, (cmdError) => { + if (cmdError) { + new import_obsidian5.Notice(`Error opening terminal: ${cmdError.message || "Unknown error"}`); + } + }); + } + }); + } + } else if (platform === "darwin") { + const escapedApp = escapeDoubleQuotes(terminalApp); + const escapedPath = escapeDoubleQuotes(projectPath); + const command = `open -na "${escapedApp}" "${escapedPath}"`; + terminalLogger.log("macOS launch", { command, terminalApp, projectPath }); + exec(command, (error) => { + if (error) { + new import_obsidian5.Notice(`Error opening terminal: ${error.message || "Unknown error"}`); + } + }); + } else { + const terminals = terminalApp ? [terminalApp] : ["gnome-terminal", "konsole", "xterm"]; + const projectPathEscaped = projectPath.replace(/"/g, '\\"'); + const tryTerminal = (index) => { + if (index >= terminals.length) { + new import_obsidian5.Notice("No supported terminal found. Please install a terminal application or configure one in settings."); + return; + } + const currentTerminal = terminals[index]; + const terminalName = currentTerminal.split(" ")[0]; + exec(`which ${terminalName}`, (error) => { + if (!error) { + let command; + if (currentTerminal.includes("gnome-terminal")) { + command = `gnome-terminal --working-directory="${projectPathEscaped}"`; + } else if (currentTerminal.includes("konsole")) { + command = `konsole --workdir "${projectPathEscaped}"`; + } else { + command = `${currentTerminal} -e "cd \\"${projectPathEscaped}\\" && bash"`; + } + terminalLogger.log("Linux launch", { command, terminal: currentTerminal, projectPath }); + exec(command, (execError) => { + if (execError && index < terminals.length - 1) { + terminalLogger.log("Terminal launch failed, trying next", { terminal: currentTerminal, error: execError.message }); + tryTerminal(index + 1); + } else if (execError) { + new import_obsidian5.Notice(`Error opening terminal: ${execError.message || "Unknown error"}`); + } + }); + } else { + terminalLogger.log("Terminal not found, trying next", { terminal: currentTerminal }); + tryTerminal(index + 1); + } + }); + }; + tryTerminal(0); + } + } catch (error) { + terminalLogger.log("Unexpected error", { error }); + new import_obsidian5.Notice(`Error opening terminal: ${error instanceof Error ? error.message : String(error)}`); + } +} +async function openConfigFile(app, settings) { + try { + const fs = require("fs"); + const path = require("path"); + const { shell } = require("electron"); + const adapter = app.vault.adapter; + const vaultPath = adapter.basePath || adapter.path; + const vaultPathString = typeof vaultPath === "string" ? vaultPath : String(vaultPath); + if (!settings.configFilePath || !settings.configFilePath.trim()) { + new import_obsidian5.Notice("Please specify a config file path in settings."); + return; + } + const configPath = path.resolve(vaultPathString, settings.configFilePath); + if (!fs.existsSync(configPath)) { + new import_obsidian5.Notice(`Config file not found at: ${configPath}`); + return; + } + await shell.openPath(configPath); + } catch (error) { + new import_obsidian5.Notice(`Error opening config file: ${error instanceof Error ? error.message : String(error)}`); + } +} + +// src/ui/settings-tab.ts +var import_obsidian9 = require("obsidian"); + +// src/ui/components/CommandPickerModal.ts +var import_obsidian6 = require("obsidian"); +var CommandPickerModal = class extends import_obsidian6.FuzzySuggestModal { + constructor(app, onSelect) { + super(app); + this.onSelect = onSelect; + } + getItems() { + const commandRegistry = this.app.commands; + const commandMap = /* @__PURE__ */ new Map(); + if (commandRegistry && typeof commandRegistry.listCommands === "function") { + try { + const commands = commandRegistry.listCommands(); + for (const command of commands) { + if (command && command.id && command.name && !commandMap.has(command.id)) { + commandMap.set(command.id, { + id: command.id, + name: command.name + }); + } + } + } catch (e) { + console.warn("[Astro Composer] Error getting commands via listCommands():", e); + } + } + try { + const registry = commandRegistry == null ? void 0 : commandRegistry.commands; + if (registry && typeof registry === "object") { + const allCommands = Object.values(registry); + for (const command of allCommands) { + if (command && command.id && command.name && !commandMap.has(command.id)) { + commandMap.set(command.id, { + id: command.id, + name: command.name + }); + } + } + } + } catch (e) { + console.warn("[Astro Composer] Error getting commands via registry:", e); + } + try { + const internalRegistry = commandRegistry == null ? void 0 : commandRegistry.commandRegistry; + if (internalRegistry && typeof internalRegistry === "object") { + const allCommands = Object.values(internalRegistry); + for (const command of allCommands) { + if (command && command.id && command.name && !commandMap.has(command.id)) { + commandMap.set(command.id, { + id: command.id, + name: command.name + }); + } + } + } + } catch (e) { + console.warn("[Astro Composer] Error getting commands via internal registry:", e); + } + const commandOptions = Array.from(commandMap.values()); + commandOptions.sort((a, b) => a.name.localeCompare(b.name)); + return commandOptions; + } + getItemText(item) { + return item.name; + } + onChooseItem(item, evt) { + this.onSelect(item.id); + } + // Override to show command name only + renderSuggestion(match, el) { + const item = match.item; + el.createDiv({ cls: "suggestion-title", text: item.name }); + } +}; + +// src/ui/components/IconPickerModal.ts +var import_obsidian7 = require("obsidian"); +var getIconList = () => { + if (import_obsidian7.requireApiVersion && (0, import_obsidian7.requireApiVersion)("1.7.3") && import_obsidian7.getIconIds) { + try { + return (0, import_obsidian7.getIconIds)(); + } catch (e) { + console.warn("[Astro Composer] Error getting icon IDs from Obsidian:", e); + } + } + return [ + "settings-2", + "settings", + "help-circle", + "info", + "star", + "heart", + "bookmark", + "home", + "search", + "bell", + "mail", + "user", + "users", + "folder", + "file", + "file-text", + "image", + "video", + "music", + "calendar", + "clock", + "edit", + "pencil", + "trash", + "copy", + "cut", + "paste", + "download", + "upload", + "save", + "share", + "link", + "external-link", + "lock", + "unlock", + "eye", + "eye-off", + "key", + "shield", + "check", + "x", + "plus", + "minus", + "arrow-left", + "arrow-right", + "arrow-up", + "arrow-down", + "chevron-left", + "chevron-right", + "chevron-up", + "chevron-down", + "menu", + "more-horizontal", + "more-vertical", + "grid", + "list", + "layout", + "columns", + "rows", + "maximize", + "minimize", + "zoom-in", + "zoom-out", + "refresh-cw", + "play", + "pause", + "stop", + "sun", + "moon", + "cloud", + "zap", + "wand-2", + "wand", + "wand-sparkles", + "palette", + "brush", + "sliders", + "power", + "wifi", + "bluetooth", + "monitor", + "laptop", + "smartphone", + "camera", + "mic", + "headphones", + "code", + "terminal", + "terminal-square", + "github", + "gitlab", + "git-branch", + "git-commit", + "database", + "server", + "cloud-download", + "cloud-upload", + "tag", + "tags", + "flag", + "pin", + "map-pin", + "compass", + "globe", + "rocket", + "car", + "bike", + "robot", + "apple", + "windows", + "linux", + "chrome", + "firefox", + "safari", + "credit-card", + "wallet", + "coins", + "book", + "book-open", + "award", + "trophy", + "badge", + "wrench", + "tool", + "package", + "box", + "archive", + "send", + "reply", + "forward", + "mail-open", + "tag-plus", + "tag-minus", + "flag-off", + "pin-off", + "map-pin-off", + "navigation", + "map", + "earth", + "plane", + "ship", + "anchor", + "helicopter", + "drone", + "android", + "keyhole", + "keys", + "fingerprint", + "scan", + "qr-code", + "barcode", + "receipt", + "piggy-bank", + "banknote" + ]; +}; +var LUCIDE_ICONS = getIconList().map((id) => ({ + id, + name: id.replace(/^lucide-/, "").replace(/-/g, " ").replace(/(^\w{1})|(\s+\w{1})/g, (letter) => letter.toUpperCase()) +})).sort((a, b) => a.name.localeCompare(b.name)); +var IconPickerModal = class extends import_obsidian7.FuzzySuggestModal { + constructor(app, onSelect) { + super(app); + this.onSelect = onSelect; + } + getItems() { + return LUCIDE_ICONS; + } + getItemText(item) { + return item.name; + } + onChooseItem(item, evt) { + const normalizedId = item.id.replace(/^lucide-/, ""); + this.onSelect(normalizedId); + } + // Override to show icon preview + renderSuggestion(match, el) { + const item = match.item; + el.addClass("mod-complex"); + const content = el.createDiv({ cls: "suggestion-content" }); + content.createDiv({ cls: "suggestion-title", text: item.name }); + const aux = el.createDiv({ cls: "suggestion-aux" }); + (0, import_obsidian7.setIcon)(aux.createSpan({ cls: "suggestion-flair" }), item.id); + } +}; + +// src/ui/components/ConfirmModal.ts +var import_obsidian8 = require("obsidian"); +var ConfirmModal = class extends import_obsidian8.Modal { + constructor(app, message, confirmText = "Confirm", cancelText = "Cancel") { + super(app); + this.message = message; + this.confirmText = confirmText; + this.cancelText = cancelText; + this.result = false; + this.resolvePromise = null; + } + onOpen() { + const { contentEl } = this; + contentEl.empty(); + contentEl.addClass("astro-composer-confirm-modal"); + contentEl.createEl("p", { text: this.message }); + const buttonContainer = contentEl.createDiv({ cls: "modal-button-container" }); + const cancelButton = buttonContainer.createEl("button", { + text: this.cancelText + }); + cancelButton.onclick = () => { + this.result = false; + this.close(); + }; + const confirmButton = buttonContainer.createEl("button", { + text: this.confirmText, + cls: "mod-cta mod-warning" + }); + confirmButton.onclick = () => { + this.result = true; + this.close(); + }; + } + onClose() { + const { contentEl } = this; + contentEl.empty(); + if (this.resolvePromise) { + this.resolvePromise(this.result); + } + } + async waitForResult() { + return new Promise((resolve) => { + this.resolvePromise = resolve; + this.open(); + }); + } +}; + +// src/ui/settings-tab.ts +var AstroComposerSettingTab = class extends import_obsidian9.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.icon = "lucide-pencil-line"; + this.autoRenameContainer = null; + this.postsFolderContainer = null; + this.onlyAutomateContainer = null; + this.creationModeContainer = null; + this.indexFileContainer = null; + this.excludedDirsContainer = null; + this.underscorePrefixContainer = null; + this.autoInsertContainer = null; + this.pagesFieldsContainer = null; + this.pagesIndexFileContainer = null; + this.pagesOnlyAutomateContainer = null; + this.terminalCommandContainer = null; + this.configCommandContainer = null; + this.customContentTypesContainer = null; + this.terminalRibbonToggle = null; + this.configRibbonToggle = null; + this.terminalRibbonToggleComponent = null; + this.configRibbonToggleComponent = null; + this.plugin = plugin; + } + /** + * Refresh just the content types section + * More efficient than refreshing the entire settings tab + */ + refreshContentTypes() { + if (this.customContentTypesContainer) { + this.renderCustomContentTypes(); + } + } + display() { + const { containerEl } = this; + containerEl.empty(); + const settings = this.plugin.settings; + this.renderSettingsTab(containerEl, settings); + } + renderSettingsTab(containerEl, settings) { + var _a; + const generalGroup = new import_obsidian9.SettingGroup(containerEl); + generalGroup.addSetting((setting) => { + setting.setName("Date format").setDesc("Format for the date in properties (yyyy-mm-dd, MMMM D, yyyy, yyyy-mm-dd HH:mm)").addText( + (text) => text.setPlaceholder("YYYY-MM-DD").setValue(settings.dateFormat).onChange(async (value) => { + settings.dateFormat = value || "YYYY-MM-DD"; + await this.plugin.saveSettings(); + }) + ); + }); + generalGroup.addSetting((setting) => { + setting.setName("Enable copy heading links").setDesc("Add right-click context menu option to copy heading links in various formats.").addToggle( + (toggle) => toggle.setValue(settings.enableCopyHeadingLink).onChange(async (value) => { + settings.enableCopyHeadingLink = value; + await this.plugin.saveSettings(); + this.updateCopyHeadingFields(); + }) + ); + }); + generalGroup.addSetting((setting) => { + setting.setName("Default heading link format").setDesc("Choose the default format for copied heading links. Obsidian format respects your Obsidian settings for wikilink vs markdown preference. Astro link uses your link base path from above and converts the heading into kebab-case format as an anchor link").addDropdown( + (dropdown) => dropdown.addOption("obsidian", "Obsidian link").addOption("astro", "Astro link").setValue(settings.copyHeadingLinkFormat).onChange(async (value) => { + settings.copyHeadingLinkFormat = value; + await this.plugin.saveSettings(); + }) + ); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableCopyHeadingLink); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableCopyHeadingLink); + }); + generalGroup.addSetting((setting) => { + setting.setName("Add trailing slash to links").setDesc("Add trailing slashes to all converted internal links (/about/ instead of /about).").addToggle( + (toggle) => toggle.setValue(settings.addTrailingSlashToLinks).onChange(async (value) => { + settings.addTrailingSlashToLinks = value; + await this.plugin.saveSettings(); + }) + ); + }); + generalGroup.addSetting((setting) => { + setting.setName("Process background file changes").setDesc("Automatically process new files when they're changed in the background (by Git or other plugins). Disable to prevent modal spam when files are already processed on other devices during a sync.").addToggle( + (toggle) => toggle.setValue(settings.processBackgroundFileChanges).onChange(async (value) => { + settings.processBackgroundFileChanges = value; + await this.plugin.saveSettings(); + }) + ); + }); + generalGroup.addSetting((setting) => { + setting.setName("Show MDX files in file explorer").setDesc("Make .mdx files visible in Obsidian's file explorer. Requires reload to take effect.").addToggle( + (toggle) => toggle.setValue(settings.showMdxFilesInExplorer).onChange(async (value) => { + settings.showMdxFilesInExplorer = value; + await this.plugin.saveSettings(); + }) + ); + }); + const automationGroup = new import_obsidian9.SettingGroup(containerEl).setHeading("Property automation"); + automationGroup.addSetting((setting) => { + setting.setName("Auto-insert properties").setDesc("Automatically insert the properties template when creating new files.").addToggle( + (toggle) => toggle.setValue(settings.autoInsertProperties).onChange(async (value) => { + settings.autoInsertProperties = value; + await this.plugin.saveSettings(); + }) + ); + }); + automationGroup.addSetting((setting) => { + setting.setName("Rename file on title property click").setDesc("When enabled, clicking into the title property will trigger the rename file command, keeping the file slug in sync.").addToggle( + (toggle) => toggle.setValue(settings.renameOnTitleClick).onChange(async (value) => { + settings.renameOnTitleClick = value; + await this.plugin.saveSettings(); + }) + ); + }); + automationGroup.addSetting((setting) => { + setting.setName("Update date on publish").setDesc("Update 'date' property when switching from draft to published status.").addToggle( + (toggle) => toggle.setValue(settings.syncDraftDate).onChange(async (value) => { + settings.syncDraftDate = value; + await this.plugin.saveSettings(); + const scrollTop = this.containerEl.scrollTop; + this.display(); + this.containerEl.scrollTop = scrollTop; + }) + ); + }); + if (settings.syncDraftDate) { + automationGroup.addSetting((setting) => { + setting.setName("Draft detection mode").setDesc("How draft status is determined. Property-based uses a boolean property (draft: true). Underscore prefix uses the file name (_my-post.md = draft).").addDropdown( + (dropdown) => dropdown.addOption("property", "Property-based").addOption("underscore-prefix", "Underscore prefix").setValue(settings.draftDetectionMode || "property").onChange(async (value) => { + var _a2; + settings.draftDetectionMode = value; + await this.plugin.saveSettings(); + (_a2 = this.plugin.frontmatterService) == null ? void 0 : _a2.initializeDraftStatusMap(); + const scrollTop = this.containerEl.scrollTop; + this.display(); + this.containerEl.scrollTop = scrollTop; + }) + ); + }); + if (settings.draftDetectionMode !== "underscore-prefix") { + automationGroup.addSetting((setting) => { + setting.setName("Draft property name").setDesc("The property field to use for draft status.").addText( + (text) => text.setPlaceholder("draft").setValue(settings.draftProperty || "").onChange(async (value) => { + var _a2; + settings.draftProperty = value; + await this.plugin.saveSettings(); + (_a2 = this.plugin.frontmatterService) == null ? void 0 : _a2.initializeDraftStatusMap(); + }) + ); + }); + automationGroup.addSetting((setting) => { + setting.setName("Draft logic").setDesc("Whether the property value 'true' means it is a draft or published.").addDropdown( + (dropdown) => dropdown.addOption("true-is-draft", "True = Draft").addOption("false-is-draft", "True = Published").setValue(settings.draftLogic || "true-is-draft").onChange(async (value) => { + var _a2; + settings.draftLogic = value; + await this.plugin.saveSettings(); + (_a2 = this.plugin.frontmatterService) == null ? void 0 : _a2.initializeDraftStatusMap(); + }) + ); + }); + } + automationGroup.addSetting((setting) => { + setting.setName("Published date property name").setDesc("The property field to update when published ('date' or 'pubDate').").addText( + (text) => text.setPlaceholder("date").setValue(settings.publishDateField || "").onChange(async (value) => { + settings.publishDateField = value; + await this.plugin.saveSettings(); + }) + ); + }); + } + const contentTypesGroup = new import_obsidian9.SettingGroup(containerEl).setHeading("Content types"); + contentTypesGroup.addSetting((setting) => { + setting.settingEl.addClass("astro-composer-setting-hidden-elements"); + setting.settingEl.addClass("astro-composer-setting-container-full-width"); + this.customContentTypesContainer = setting.settingEl.createDiv({ + cls: "custom-content-types-container astro-composer-custom-types-container-visible" + }); + }); + if (this.customContentTypesContainer) { + this.renderCustomContentTypes(); + } + if (!import_obsidian9.Platform.isMobile) { + const developerGroup = new import_obsidian9.SettingGroup(containerEl).setHeading("Developer commands"); + developerGroup.addSetting((setting) => { + setting.setName("Enable open terminal command").setDesc("Enable command to open terminal in project root directory.").addToggle( + (toggle) => toggle.setValue(settings.enableOpenTerminalCommand).onChange(async (value) => { + settings.enableOpenTerminalCommand = value; + await this.plugin.saveSettings(); + this.updateTerminalCommandFields(); + if (this.plugin.registerRibbonIcons) { + this.plugin.registerRibbonIcons(); + } + }) + ); + }); + this.terminalCommandContainer = containerEl.createDiv({ cls: "terminal-command-fields" }); + this.terminalCommandContainer.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenTerminalCommand); + this.terminalCommandContainer.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenTerminalCommand); + developerGroup.addSetting((setting) => { + const descFragment = document.createDocumentFragment(); + descFragment.createEl("div", { text: "Path relative to the Obsidian vault root folder. Use ../.. for two levels up. Leave blank to use the vault folder" }); + descFragment.createEl("div", { text: "This is where the terminal will open. Absolute paths work also." }); + setting.setName("Project root directory path").setDesc(descFragment).addText( + (text) => text.setPlaceholder("../..").setValue(settings.terminalProjectRootPath).onChange(async (value) => { + settings.terminalProjectRootPath = value; + await this.plugin.saveSettings(); + }) + ); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenTerminalCommand); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenTerminalCommand); + }); + developerGroup.addSetting((setting) => { + const descFragment = document.createDocumentFragment(); + descFragment.createEl("div", { text: "Leave blank to use platform defaults. On macOS, the default is Terminal. On Windows, it's Windows Terminal (Win 11) or cmd.exe (Win 10). On Linux, it's gnome-terminal, konsole, or xterm" }); + descFragment.createEl("div", { text: "Examples include Terminal, iTerm, PowerShell, and Alacritty" }); + setting.setName("Terminal application name").setDesc(descFragment).addText( + (text) => text.setPlaceholder("Terminal").setValue(settings.terminalApplicationName).onChange(async (value) => { + settings.terminalApplicationName = value; + await this.plugin.saveSettings(); + }) + ); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenTerminalCommand); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenTerminalCommand); + }); + developerGroup.addSetting((setting) => { + setting.setName("Enable debug logging").setDesc("Log terminal launch commands and platform decisions to the developer console for troubleshooting.").addToggle( + (toggle) => toggle.setValue(settings.enableTerminalDebugLogging).onChange(async (value) => { + settings.enableTerminalDebugLogging = value; + await this.plugin.saveSettings(); + }) + ); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenTerminalCommand); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenTerminalCommand); + }); + developerGroup.addSetting((setting) => { + setting.setName("Show open terminal ribbon icon").setDesc("Add a ribbon icon to launch the terminal command.").addToggle((toggle) => { + this.terminalRibbonToggleComponent = toggle; + toggle.setValue(settings.enableTerminalRibbonIcon).setDisabled(!settings.enableOpenTerminalCommand).onChange(async (value) => { + this.plugin.settings.enableTerminalRibbonIcon = value; + settings.enableTerminalRibbonIcon = value; + await this.plugin.saveSettings(); + setTimeout(() => { + if (this.plugin.registerRibbonIcons) { + this.plugin.registerRibbonIcons(); + } + }, 50); + }); + }); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenTerminalCommand); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenTerminalCommand); + this.terminalRibbonToggle = setting; + }); + developerGroup.addSetting((setting) => { + setting.setName("Enable edit config file command").setDesc("Enable command to open astro config file in default editor.").addToggle( + (toggle) => toggle.setValue(settings.enableOpenConfigFileCommand).onChange(async (value) => { + settings.enableOpenConfigFileCommand = value; + await this.plugin.saveSettings(); + this.updateConfigCommandFields(); + if (this.plugin.registerRibbonIcons) { + this.plugin.registerRibbonIcons(); + } + }) + ); + }); + this.configCommandContainer = containerEl.createDiv({ cls: "config-command-fields" }); + this.configCommandContainer.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenConfigFileCommand); + this.configCommandContainer.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenConfigFileCommand); + developerGroup.addSetting((setting) => { + const descFragment = document.createDocumentFragment(); + descFragment.createEl("div", { text: "Path to the config file relative to the vault root. Use ../config.ts or ../../astro.config.mjs." }); + descFragment.createEl("div", { text: "Absolute paths work also." }); + setting.setName("Config file path").setDesc(descFragment).addText( + (text) => text.setPlaceholder("../config.ts").setValue(settings.configFilePath).onChange(async (value) => { + settings.configFilePath = value; + await this.plugin.saveSettings(); + }) + ); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenConfigFileCommand); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenConfigFileCommand); + }); + developerGroup.addSetting((setting) => { + setting.setName("Show open config ribbon icon").setDesc("Add a ribbon icon to launch the config file command.").addToggle((toggle) => { + this.configRibbonToggleComponent = toggle; + toggle.setValue(settings.enableConfigRibbonIcon).setDisabled(!settings.enableOpenConfigFileCommand).onChange(async (value) => { + this.plugin.settings.enableConfigRibbonIcon = value; + settings.enableConfigRibbonIcon = value; + await this.plugin.saveSettings(); + setTimeout(() => { + if (this.plugin.registerRibbonIcons) { + this.plugin.registerRibbonIcons(); + } + }, 50); + }); + }); + setting.settingEl.classList.toggle("astro-composer-setting-container-visible", settings.enableOpenConfigFileCommand); + setting.settingEl.classList.toggle("astro-composer-setting-container-hidden", !settings.enableOpenConfigFileCommand); + this.configRibbonToggle = setting; + }); + developerGroup.addSetting((setting) => { + setting.setName("Swap out help button for custom action").setDesc("Replace the help button in the vault profile area with a custom action.").addToggle((toggle) => { + var _a2, _b; + return toggle.setValue((_b = (_a2 = settings.helpButtonReplacement) == null ? void 0 : _a2.enabled) != null ? _b : false).onChange(async (value) => { + if (!settings.helpButtonReplacement) { + settings.helpButtonReplacement = { + enabled: false, + commandId: "edit-astro-config", + iconId: "rocket" + }; + } + settings.helpButtonReplacement.enabled = value; + await this.plugin.saveSettings(); + if (this.plugin.updateHelpButton) { + await this.plugin.updateHelpButton(); + } + this.display(); + }); + }); + }); + if ((_a = settings.helpButtonReplacement) == null ? void 0 : _a.enabled) { + const commandName = this.getCommandName(settings.helpButtonReplacement.commandId); + developerGroup.addSetting((setting) => { + setting.setName("Command").setDesc("Select the command to execute when the button is clicked.").addButton((button) => button.setButtonText(commandName || "Select command").onClick(() => { + const modal = new CommandPickerModal(this.app, (commandId) => { + void (async () => { + if (!settings.helpButtonReplacement) { + settings.helpButtonReplacement = { + enabled: true, + commandId: "edit-astro-config", + iconId: "rocket" + }; + } + settings.helpButtonReplacement.commandId = commandId; + await this.plugin.saveSettings(); + if (this.plugin.updateHelpButton) { + await this.plugin.updateHelpButton(); + } + this.display(); + })(); + }); + modal.open(); + })); + }); + const iconName = this.getIconName(settings.helpButtonReplacement.iconId); + developerGroup.addSetting((setting) => { + setting.setName("Icon").setDesc("Select the icon to display on the button.").addButton((button) => button.setButtonText(iconName || "Select icon...").onClick(() => { + const modal = new IconPickerModal(this.app, (iconId) => { + void (async () => { + if (!settings.helpButtonReplacement) { + settings.helpButtonReplacement = { + enabled: true, + commandId: "edit-astro-config", + iconId: "rocket" + }; + } + settings.helpButtonReplacement.iconId = iconId; + await this.plugin.saveSettings(); + if (this.plugin.updateHelpButton) { + await this.plugin.updateHelpButton(); + } + this.display(); + })(); + }); + modal.open(); + })); + }); + } + } + this.updateCopyHeadingFields(); + if (!import_obsidian9.Platform.isMobile) { + this.updateTerminalCommandFields(); + this.updateConfigCommandFields(); + } + } + updateCopyHeadingFields() { + const settings = this.plugin.settings; + const isVisible = settings.enableCopyHeadingLink; + const containerEl = this.containerEl; + const allSettings = containerEl.querySelectorAll(".setting-item"); + allSettings.forEach((settingEl) => { + var _a; + const nameEl = settingEl.querySelector(".setting-item-name"); + if (nameEl && ((_a = nameEl.textContent) == null ? void 0 : _a.trim()) === "Default heading link format") { + settingEl.classList.toggle("astro-composer-setting-container-visible", isVisible); + settingEl.classList.toggle("astro-composer-setting-container-hidden", !isVisible); + } + }); + } + updateTerminalCommandFields() { + const settings = this.plugin.settings; + const isVisible = settings.enableOpenTerminalCommand; + if (this.terminalCommandContainer) { + this.terminalCommandContainer.classList.toggle("astro-composer-setting-container-visible", isVisible); + this.terminalCommandContainer.classList.toggle("astro-composer-setting-container-hidden", !isVisible); + } + const containerEl = this.containerEl; + const allSettings = containerEl.querySelectorAll(".setting-item"); + allSettings.forEach((settingEl) => { + var _a; + const nameEl = settingEl.querySelector(".setting-item-name"); + if (nameEl) { + const name = (_a = nameEl.textContent) == null ? void 0 : _a.trim(); + if (name === "Project root directory path" || name === "Show open terminal ribbon icon") { + settingEl.classList.toggle("astro-composer-setting-container-visible", isVisible); + settingEl.classList.toggle("astro-composer-setting-container-hidden", !isVisible); + } + } + }); + if (this.terminalRibbonToggleComponent) { + this.terminalRibbonToggleComponent.setDisabled(!this.plugin.settings.enableOpenTerminalCommand); + } + } + updateConfigCommandFields() { + const settings = this.plugin.settings; + const isVisible = settings.enableOpenConfigFileCommand; + if (this.configCommandContainer) { + this.configCommandContainer.classList.toggle("astro-composer-setting-container-visible", isVisible); + this.configCommandContainer.classList.toggle("astro-composer-setting-container-hidden", !isVisible); + } + const containerEl = this.containerEl; + const allSettings = containerEl.querySelectorAll(".setting-item"); + allSettings.forEach((settingEl) => { + var _a; + const nameEl = settingEl.querySelector(".setting-item-name"); + if (nameEl) { + const name = (_a = nameEl.textContent) == null ? void 0 : _a.trim(); + if (name === "Config file path" || name === "Show open config ribbon icon") { + settingEl.classList.toggle("astro-composer-setting-container-visible", isVisible); + settingEl.classList.toggle("astro-composer-setting-container-hidden", !isVisible); + } + } + }); + if (this.configRibbonToggleComponent) { + this.configRibbonToggleComponent.setDisabled(!this.plugin.settings.enableOpenConfigFileCommand); + } + } + checkForFolderConflicts() { + const settings = this.plugin.settings; + const blankFolders = []; + const folderConflicts = {}; + const contentTypes = settings.contentTypes || []; + for (const contentType of contentTypes) { + if (contentType.enabled) { + if (!contentType.folder || contentType.folder.trim() === "") { + blankFolders.push(contentType.name || "Content"); + } else { + if (!folderConflicts[contentType.folder]) { + folderConflicts[contentType.folder] = []; + } + folderConflicts[contentType.folder].push(contentType.name || "Content"); + } + } + } + } + addCustomContentType() { + const settings = this.plugin.settings; + const contentTypes = settings.contentTypes || []; + const newType = { + id: `content-${Date.now()}`, + name: `Content ${contentTypes.length + 1}`, + folder: "", + linkBasePath: "", + template: '---\ntitle: "{{title}}"\ndate: {{date}}\n---\n', + enabled: true, + creationMode: "file", + indexFileName: "", + ignoreSubfolders: false, + enableUnderscorePrefix: false, + useMdxExtension: false, + modifiedDateField: "" + }; + contentTypes.push(newType); + settings.contentTypes = contentTypes; + void this.plugin.saveSettings(); + this.renderCustomContentTypes(); + this.plugin.registerCreateEvent(); + registerContentTypeCommands(this.plugin, settings); + } + renderCustomContentTypes() { + if (!this.customContentTypesContainer) return; + this.customContentTypesContainer.empty(); + const settings = this.plugin.settings; + const contentTypes = settings.contentTypes || []; + contentTypes.forEach((customType, index) => { + var _a, _b; + if (!this.customContentTypesContainer) return; + const typeContainer = this.customContentTypesContainer.createDiv({ + cls: "custom-content-type-item", + attr: { "data-type-id": customType.id } + }); + const header = typeContainer.createDiv({ cls: "custom-content-type-header" }); + header.classList.add("astro-composer-custom-type-header"); + const collapseButton = header.createEl("button", { + cls: "astro-composer-collapse-button", + attr: { "aria-label": "Collapse/expand" } + }); + const isCollapsed = (_a = customType.collapsed) != null ? _a : false; + (0, import_obsidian9.setIcon)(collapseButton, "chevron-down"); + if (isCollapsed) { + collapseButton.classList.add("is-collapsed"); + } + collapseButton.addEventListener("click", () => { + void this.toggleContentTypeCollapse(customType.id); + const updatedType = this.plugin.settings.contentTypes.find((ct) => ct.id === customType.id); + if (updatedType) { + if (updatedType.collapsed) { + collapseButton.classList.add("is-collapsed"); + } else { + collapseButton.classList.remove("is-collapsed"); + } + } + }); + const headerName = header.createDiv({ cls: "astro-composer-header-name" }); + headerName.createEl("div", { text: customType.name || `Content ${index + 1}`, cls: "setting-item-name" }); + const reorderContainer = header.createDiv({ cls: "astro-composer-reorder-buttons" }); + const upButton = reorderContainer.createEl("button", { + cls: "astro-composer-reorder-button", + attr: { "aria-label": "Move up" } + }); + (0, import_obsidian9.setIcon)(upButton, "chevron-up"); + upButton.disabled = index === 0; + upButton.addEventListener("click", () => { + void this.moveContentTypeUp(customType.id); + }); + const downButton = reorderContainer.createEl("button", { + cls: "astro-composer-reorder-button", + attr: { "aria-label": "Move down" } + }); + (0, import_obsidian9.setIcon)(downButton, "chevron-down"); + downButton.disabled = index === contentTypes.length - 1; + downButton.addEventListener("click", () => { + void this.moveContentTypeDown(customType.id); + }); + const toggleContainer = header.createDiv({ cls: "checkbox-container" }); + if (customType.enabled) { + toggleContainer.classList.add("is-enabled"); + } + const toggle = toggleContainer.createEl("input", { type: "checkbox", cls: "checkbox-input" }); + toggle.checked = customType.enabled; + toggleContainer.addEventListener("click", (e) => { + void (async () => { + e.preventDefault(); + const newValue = !customType.enabled; + customType.enabled = newValue; + toggle.checked = newValue; + await this.plugin.saveSettings(); + this.plugin.registerCreateEvent(); + if (newValue) { + toggleContainer.classList.add("is-enabled"); + } else { + toggleContainer.classList.remove("is-enabled"); + } + this.updateCustomContentTypeVisibility(customType.id, newValue); + registerContentTypeCommands(this.plugin, this.plugin.settings); + })(); + }); + toggle.addEventListener("change", (e) => { + void (async () => { + const value = e.target.checked; + customType.enabled = value; + await this.plugin.saveSettings(); + this.plugin.registerCreateEvent(); + if (value) { + toggleContainer.classList.add("is-enabled"); + } else { + toggleContainer.classList.remove("is-enabled"); + } + this.updateCustomContentTypeVisibility(customType.id, value); + registerContentTypeCommands(this.plugin, this.plugin.settings); + })(); + }); + const settingsContainer = typeContainer.createDiv({ + cls: "custom-content-type-settings", + attr: { "data-type-id": customType.id } + }); + const initiallyCollapsed = (_b = customType.collapsed) != null ? _b : false; + const initiallyVisible = customType.enabled && !initiallyCollapsed; + if (initiallyVisible) { + settingsContainer.classList.add("astro-composer-setting-container-visible"); + } else { + settingsContainer.classList.add("astro-composer-setting-container-hidden"); + } + const nameContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(nameContainer).setName("Content type name").setDesc("Display name for this content type ('projects', 'notes', 'tutorials')").addText((text) => { + text.setPlaceholder("Enter content type name").setValue(customType.name).onChange(async (value) => { + customType.name = value; + await this.plugin.saveSettings(); + registerContentTypeCommands(this.plugin, this.plugin.settings); + }); + }); + const folderContainer = settingsContainer.createDiv(); + const folderSetting = new import_obsidian9.Setting(folderContainer).setName("Folder location").setDesc("Folder path where this content type will be created. Leave blank to use the vault folder. Supports wildcards like directory/* or directory/*/* to match specific folder depths.").addText((text) => { + text.setPlaceholder("Enter folder path ('docs', 'docs/*', 'docs/*/*') or leave blank for vault root").setValue(customType.folder).onChange(async (value) => { + customType.folder = value; + await this.plugin.saveSettings(); + this.plugin.registerCreateEvent(); + this.updateCustomContentTypeIgnoreSubfoldersField(customType.id); + const allContentTypes = this.plugin.settings.contentTypes || []; + for (const ct of allContentTypes) { + this.updateFolderConflictWarning(ct.id, null); + } + }); + }); + folderContainer.createDiv({ cls: "astro-composer-conflict-warning hidden", attr: { "data-type-id": customType.id } }); + this.updateFolderConflictWarning(customType.id, folderSetting); + const ignoreSubfoldersContainer = settingsContainer.createDiv({ cls: "custom-ignore-subfolders-field" }); + ignoreSubfoldersContainer.setAttribute("data-type-id", customType.id); + ignoreSubfoldersContainer.classList.toggle("astro-composer-setting-container-visible", !!customType.folder); + ignoreSubfoldersContainer.classList.toggle("astro-composer-setting-container-hidden", !customType.folder); + new import_obsidian9.Setting(ignoreSubfoldersContainer).setName("Ignore subfolders").setDesc("When enabled, automation will only trigger for new .md files within this content type's folder and one level down (for folder-based content). Files in deeper subfolders will be ignored.").addToggle( + (toggle2) => toggle2.setValue(customType.ignoreSubfolders || false).onChange(async (value) => { + customType.ignoreSubfolders = value; + await this.plugin.saveSettings(); + }) + ); + const underscorePrefixContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(underscorePrefixContainer).setName("Use underscore prefix for drafts").setDesc("Add an underscore prefix (_content-title) to new notes by default when enabled. This hides them from astro, which can be helpful for drafts").addToggle( + (toggle2) => toggle2.setValue(customType.enableUnderscorePrefix || false).onChange(async (value) => { + customType.enableUnderscorePrefix = value; + await this.plugin.saveSettings(); + }) + ); + const linkContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(linkContainer).setName("Link base path").setDesc("Base path for converted links ('/projects/', '/notes/tutorials/', leave blank for root /).").addText((text) => { + text.setPlaceholder("Enter link base path").setValue(customType.linkBasePath || "").onChange(async (value) => { + customType.linkBasePath = value; + await this.plugin.saveSettings(); + }); + }); + const creationModeContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(creationModeContainer).setName("Creation mode").setDesc("How to create new entries: file-based or folder-based with an index file.").addDropdown( + (dropdown) => dropdown.addOption("file", "File-based (content-title.md)").addOption("folder", "Folder-based (content-title/index.md)").setValue(customType.creationMode).onChange(async (value) => { + customType.creationMode = value; + await this.plugin.saveSettings(); + this.updateCustomContentTypeIndexFileField(customType.id); + }) + ); + const indexFileContainer = settingsContainer.createDiv({ cls: "custom-index-file-field" }); + indexFileContainer.classList.toggle("astro-composer-setting-container-visible", customType.creationMode === "folder"); + indexFileContainer.classList.toggle("astro-composer-setting-container-hidden", customType.creationMode !== "folder"); + new import_obsidian9.Setting(indexFileContainer).setName("Index file name").setDesc("Name for index files in folder-based content (without .md extension). Defaults to 'index' if left blank.").addText( + (text) => text.setPlaceholder("index").setValue(customType.indexFileName).onChange(async (value) => { + customType.indexFileName = value; + await this.plugin.saveSettings(); + }) + ); + const useMdxContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(useMdxContainer).setName("Use MDX instead of MD").setDesc("Create files with .mdx extension instead of .md extension.").addToggle( + (toggle2) => toggle2.setValue(customType.useMdxExtension || false).onChange(async (value) => { + customType.useMdxExtension = value; + await this.plugin.saveSettings(); + }) + ); + const modifiedDateContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(modifiedDateContainer).setName("Modified date property").setDesc("The property field to update with the modified date for this content type. Leave blank to disable.").addText( + (text) => text.setPlaceholder("modified").setValue(customType.modifiedDateField || "").onChange(async (value) => { + customType.modifiedDateField = value; + await this.plugin.saveSettings(); + }) + ); + const templateContainer = settingsContainer.createDiv(); + new import_obsidian9.Setting(templateContainer).setName("Properties template").addTextArea((text) => { + text.setPlaceholder('---\ntitle: "{{title}}"\ndate: {{date}}\n---\n').setValue(customType.template).onChange(async (value) => { + customType.template = value; + await this.plugin.saveSettings(); + }); + text.inputEl.classList.add("astro-composer-template-textarea"); + return text; + }).then((setting) => { + setting.descEl.empty(); + const descDiv = setting.descEl.createEl("div"); + descDiv.createEl("div", { text: "Template for new files of this content type." }); + descDiv.createEl("div", { text: "Variables include {{title}}, {{date}}, and {{slug}}." }); + descDiv.createEl("div", { text: "Do not wrap {{date}} in quotes as it represents a datetime value, not a string." }); + }); + const removeContainer = settingsContainer.createDiv(); + const removeSetting = new import_obsidian9.Setting(removeContainer).setName("").addButton((button) => { + button.setButtonText("Remove").setWarning().onClick(async () => { + const contentType = this.plugin.settings.contentTypes.find((ct) => ct.id === customType.id); + const typeName = (contentType == null ? void 0 : contentType.name) || "content type"; + const modal = new ConfirmModal( + this.app, + `Are you sure you want to remove "${typeName}"? This action cannot be undone.`, + "Remove", + "Cancel" + ); + const confirmed = await modal.waitForResult(); + if (confirmed) { + await this.removeCustomContentType(customType.id); + } + }); + }); + removeSetting.settingEl.classList.add("astro-composer-remove-setting"); + this.updateCustomContentTypeVisibility(customType.id, customType.enabled); + }); + contentTypes.forEach((customType) => { + this.updateFolderConflictWarning(customType.id, null); + }); + const addButtonContainer = this.customContentTypesContainer.createDiv({ cls: "astro-composer-add-button-container" }); + const addButton = addButtonContainer.createEl("button", { + cls: "mod-cta", + text: "Add content type" + }); + addButton.addEventListener("click", () => { + this.addCustomContentType(); + }); + } + updateCustomContentTypeVisibility(typeId, enabled) { + var _a, _b; + const settingsContainer = (_a = this.customContentTypesContainer) == null ? void 0 : _a.querySelector(`[data-type-id="${typeId}"].custom-content-type-settings`); + if (settingsContainer) { + const contentTypes = this.plugin.settings.contentTypes || []; + const contentType = contentTypes.find((ct) => ct.id === typeId); + const isCollapsed = (_b = contentType == null ? void 0 : contentType.collapsed) != null ? _b : false; + const shouldBeVisible = enabled && !isCollapsed; + settingsContainer.classList.toggle("astro-composer-setting-container-visible", shouldBeVisible); + settingsContainer.classList.toggle("astro-composer-setting-container-hidden", !shouldBeVisible); + } + } + updateCustomContentTypeIndexFileField(typeId) { + var _a; + const contentTypes = this.plugin.settings.contentTypes || []; + const customType = contentTypes.find((type) => type.id === typeId); + if (!customType) return; + const indexFileContainer = (_a = this.customContentTypesContainer) == null ? void 0 : _a.querySelector(`[data-type-id="${typeId}"] .custom-index-file-field`); + if (indexFileContainer) { + indexFileContainer.classList.toggle("astro-composer-setting-container-visible", customType.creationMode === "folder"); + indexFileContainer.classList.toggle("astro-composer-setting-container-hidden", customType.creationMode !== "folder"); + } + } + updateCustomContentTypeIgnoreSubfoldersField(typeId) { + var _a; + const contentTypes = this.plugin.settings.contentTypes || []; + const customType = contentTypes.find((type) => type.id === typeId); + if (!customType) return; + const ignoreSubfoldersContainer = (_a = this.customContentTypesContainer) == null ? void 0 : _a.querySelector(`[data-type-id="${typeId}"].custom-ignore-subfolders-field`); + if (ignoreSubfoldersContainer) { + ignoreSubfoldersContainer.classList.toggle("astro-composer-setting-container-visible", !!customType.folder && customType.folder.trim() !== ""); + ignoreSubfoldersContainer.classList.toggle("astro-composer-setting-container-hidden", !customType.folder || customType.folder.trim() === ""); + } + } + updateFolderConflictWarning(typeId, setting) { + var _a; + const contentTypes = this.plugin.settings.contentTypes || []; + const currentType = contentTypes.find((type) => type.id === typeId); + if (!currentType) return; + const conflictWarningEl = (_a = this.customContentTypesContainer) == null ? void 0 : _a.querySelector(`[data-type-id="${typeId}"].astro-composer-conflict-warning`); + if (!conflictWarningEl) return; + const currentFolder = (currentType.folder || "").trim(); + const conflictingTypes = []; + for (const otherType of contentTypes) { + if (otherType.id === typeId || !otherType.enabled) continue; + const otherFolder = (otherType.folder || "").trim(); + if (currentFolder === "" && otherFolder === "") { + conflictingTypes.push(otherType.name || "Unnamed"); + } else if (currentFolder === otherFolder && currentFolder !== "") { + conflictingTypes.push(otherType.name || "Unnamed"); + } + } + if (conflictingTypes.length > 0) { + conflictWarningEl.removeClass("hidden"); + conflictWarningEl.textContent = `Conflict: ${conflictingTypes.join(", ")} also use${conflictingTypes.length === 1 ? "s" : ""} this folder. More specific patterns will take priority.`; + } else { + conflictWarningEl.addClass("hidden"); + } + } + async moveContentTypeUp(typeId) { + const settings = this.plugin.settings; + const contentTypes = settings.contentTypes || []; + const currentIndex = contentTypes.findIndex((ct) => ct.id === typeId); + if (currentIndex <= 0) return; + [contentTypes[currentIndex], contentTypes[currentIndex - 1]] = [contentTypes[currentIndex - 1], contentTypes[currentIndex]]; + settings.contentTypes = contentTypes; + await this.plugin.saveSettings(); + this.renderCustomContentTypes(); + } + async moveContentTypeDown(typeId) { + const settings = this.plugin.settings; + const contentTypes = settings.contentTypes || []; + const currentIndex = contentTypes.findIndex((ct) => ct.id === typeId); + if (currentIndex < 0 || currentIndex >= contentTypes.length - 1) return; + [contentTypes[currentIndex], contentTypes[currentIndex + 1]] = [contentTypes[currentIndex + 1], contentTypes[currentIndex]]; + settings.contentTypes = contentTypes; + await this.plugin.saveSettings(); + this.renderCustomContentTypes(); + } + async toggleContentTypeCollapse(typeId) { + const settings = this.plugin.settings; + const contentTypes = settings.contentTypes || []; + const contentType = contentTypes.find((ct) => ct.id === typeId); + if (!contentType) return; + contentType.collapsed = !contentType.collapsed; + await this.plugin.saveSettings(); + this.updateCustomContentTypeVisibility(typeId, contentType.enabled); + } + async removeCustomContentType(typeId) { + const settings = this.plugin.settings; + const contentTypes = settings.contentTypes || []; + settings.contentTypes = contentTypes.filter((ct) => ct.id !== typeId); + await this.plugin.saveSettings(); + this.renderCustomContentTypes(); + this.plugin.registerCreateEvent(); + registerContentTypeCommands(this.plugin, settings); + } + getCommandName(commandId) { + if (!commandId) return ""; + try { + const commandRegistry = this.app.commands; + if (commandRegistry && typeof commandRegistry.listCommands === "function") { + try { + const allCommands = commandRegistry.listCommands(); + const command = allCommands.find((cmd) => cmd.id === commandId); + if (command == null ? void 0 : command.name) { + return command.name; + } + } catch (e) { + console.warn("[Astro Composer] Error getting command name via listCommands():", e); + } + } + try { + const registry = commandRegistry == null ? void 0 : commandRegistry.commands; + if (registry && typeof registry === "object") { + const command = registry[commandId]; + if (command == null ? void 0 : command.name) { + return command.name; + } + } + } catch (e) { + console.warn("[Astro Composer] Error getting command name via registry:", e); + } + } catch (e) { + console.warn("[Astro Composer] Error getting command name:", e); + } + return ""; + } + getIconName(iconId) { + if (!iconId) return ""; + return iconId.replace(/^lucide-/, "").split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" "); + } +}; + +// src/utils/heading-link-generator.ts +var HeadingLinkGenerator = class { + constructor(settings, plugin) { + this.settings = settings; + this.plugin = plugin; + } + // Get fresh settings from plugin if available, otherwise use stored settings + getSettings() { + var _a; + if ((_a = this.plugin) == null ? void 0 : _a.settings) { + return this.plugin.settings; + } + return this.settings; + } + /** + * Converts text to kebab-case slug for URLs + */ + // Local toKebabCase removed, using imported one instead + /** + * Gets the Astro-compatible URL from an internal link (copied from LinkConverter) + */ + getAstroUrlFromInternalLink(link) { + const hashIndex = link.indexOf("#"); + let path = hashIndex >= 0 ? link.slice(0, hashIndex) : link; + const anchor = hashIndex >= 0 ? link.slice(hashIndex) : ""; + path = path.replace(/\.md$/, ""); + let basePath = ""; + let contentFolder = ""; + let creationMode = "file"; + let indexFileName = ""; + const settings = this.getSettings(); + const contentTypes = settings.contentTypes || []; + const sortedTypes = sortByPatternSpecificity(contentTypes); + for (const contentType of sortedTypes) { + if (!contentType.enabled) continue; + let matches = false; + if (!contentType.folder || contentType.folder.trim() === "") { + if (!path.includes("/") || path.split("/").length === 1) { + matches = true; + } + } else if (matchesFolderPattern(path, contentType.folder)) { + matches = true; + } + if (matches) { + contentFolder = contentType.folder || ""; + basePath = contentType.linkBasePath || ""; + creationMode = contentType.creationMode; + indexFileName = contentType.indexFileName || ""; + break; + } + } + if (contentFolder) { + path = path.slice(contentFolder.length + 1); + } + let addTrailingSlash = false; + if (indexFileName && indexFileName.trim() !== "") { + const parts = path.split("/"); + if (parts[parts.length - 1] === indexFileName) { + parts.pop(); + path = parts.join("/"); + addTrailingSlash = true; + } + } else if (creationMode === "folder") { + const defaultIndexName = "index"; + const parts = path.split("/"); + if (parts[parts.length - 1] === defaultIndexName) { + parts.pop(); + path = parts.join("/"); + addTrailingSlash = true; + } + } + const slugParts = path.split("/").map((part) => toKebabCase(part)); + const slug = slugParts.join("/"); + if (basePath) { + if (!basePath.startsWith("/")) basePath = "/" + basePath; + if (!basePath.endsWith("/")) basePath += "/"; + } + const shouldAddTrailingSlash = (settings.addTrailingSlashToLinks || addTrailingSlash) && !anchor; + return `${basePath}${slug}${shouldAddTrailingSlash ? "/" : ""}${anchor}`; + } + /** + * Generates a standard Obsidian link to a heading, respecting user's link format preference + */ + generateObsidianLink(app, file, heading) { + const headingText = heading.heading; + const testLink = app.fileManager.generateMarkdownLink(file, "", ""); + if (testLink.startsWith("[[")) { + const fileName = file.basename; + return `[[${fileName}#${headingText}|${headingText}]]`; + } else { + const baseLink = app.fileManager.generateMarkdownLink(file, "", ""); + if (baseLink.startsWith("[[")) { + const fileName = file.basename; + return `[[${fileName}#${headingText}|${headingText}]]`; + } else { + const match = baseLink.match(/\[([^\]]+)\]\(([^)]+)\)/); + if (match) { + const [, , path] = match; + return `[${headingText}](${path}#${encodeURIComponent(headingText)})`; + } else { + const encodedFilename = encodeURIComponent(file.name); + return `[${headingText}](${encodedFilename}#${encodeURIComponent(headingText)})`; + } + } + } + } + /** + * Generates a standard Obsidian wikilink to a heading + */ + generateObsidianWikilink(file, heading) { + const headingText = heading.heading; + const fileName = file.basename; + return `[[${fileName}#${headingText}|${headingText}]]`; + } + /** + * Generates an Astro-compatible markdown link to a heading + */ + generateAstroLink(file, heading) { + const headingText = heading.heading; + const anchor = toKebabCase(headingText); + const internalLink = `${file.path}#${anchor}`; + const astroUrl = this.getAstroUrlFromInternalLink(internalLink); + return `[${headingText}](${astroUrl})`; + } + /** + * Generates an Astro-compatible wikilink to a heading + */ + generateAstroWikilink(file, heading) { + const headingText = heading.heading; + const anchor = toKebabCase(headingText); + const internalLink = `${file.path}#${anchor}`; + const astroUrl = this.getAstroUrlFromInternalLink(internalLink); + return `[[${headingText}|${astroUrl}]]`; + } + /** + * Extracts the URL from a markdown link or wikilink + */ + extractUrl(link) { + const markdownMatch = link.match(/\[([^\]]+)\]\(([^)]+)\)/); + if (markdownMatch) { + return markdownMatch[2]; + } + const wikilinkMatch = link.match(/\[\[([^\]]+)\]\]/); + if (wikilinkMatch) { + const content = wikilinkMatch[1]; + const pathPart = content.split("|")[0]; + return pathPart; + } + return link; + } + /** + * Generates the appropriate link format based on settings + */ + generateLink(app, file, heading) { + const settings = this.getSettings(); + if (settings.copyHeadingLinkFormat === "astro") { + return this.generateAstroLink(file, heading); + } else { + return this.generateObsidianLink(app, file, heading); + } + } + /** + * Finds the heading at a specific line in a file + */ + findHeadingAtLine(app, file, line) { + const cache = app.metadataCache.getFileCache(file); + if (!cache || !cache.headings) { + return null; + } + for (let i = cache.headings.length - 1; i >= 0; i--) { + const heading = cache.headings[i]; + if (heading.position.start.line <= line) { + return heading; + } + } + return null; + } +}; + +// src/services/MigrationService.ts +var import_obsidian11 = require("obsidian"); + +// src/ui/components/MigrationModal.ts +var import_obsidian10 = require("obsidian"); +var MigrationModal = class extends import_obsidian10.Modal { + constructor(app, conflicts) { + super(app); + this.result = null; + this.resolvePromise = null; + } + onOpen() { + const { contentEl } = this; + contentEl.empty(); + contentEl.addClass("astro-composer-migration-modal"); + contentEl.createEl("h2", { text: "Migration conflict detected" }); + contentEl.createEl("p", { + text: "You have existing content types with names that conflict with posts or pages. How would you like to proceed?" + }); + const conflictList = contentEl.createEl("ul"); + conflictList.createEl("li", { text: "Skip migration: keep your existing posts/pages settings (they will be ignored)" }); + conflictList.createEl("li", { text: "Migrate with renamed types: create 'posts (migrated)' and 'pages (migrated)' content types" }); + const buttonContainer = contentEl.createDiv({ cls: "modal-button-container" }); + const skipButton = buttonContainer.createEl("button", { + text: "Skip migration", + cls: "mod-cta" + }); + skipButton.onclick = () => { + this.result = { action: "skip" }; + this.close(); + }; + const migrateButton = buttonContainer.createEl("button", { + text: "Migrate with renamed types", + cls: "mod-cta" + }); + migrateButton.onclick = () => { + this.result = { action: "migrate" }; + this.close(); + }; + } + onClose() { + const { contentEl } = this; + contentEl.empty(); + if (this.resolvePromise && this.result) { + this.resolvePromise(this.result); + } + } + async waitForResult() { + return new Promise((resolve) => { + this.resolvePromise = resolve; + this.open(); + }); + } +}; + +// src/services/MigrationService.ts +var MigrationService = class { + constructor(app, plugin) { + this.app = app; + this.plugin = plugin; + } + /** + * Migrate old posts/pages settings to unified content types + */ + async migrateSettingsIfNeeded() { + const settings = this.plugin.settings; + if (settings.migrationCompleted) { + return; + } + const hasPostsSettings = settings.automatePostCreation !== void 0 && settings.automatePostCreation; + const hasPagesSettings = settings.enablePages !== void 0 && settings.enablePages; + if (!hasPostsSettings && !hasPagesSettings) { + settings.migrationCompleted = true; + await this.plugin.saveSettings(); + return; + } + const legacyContentTypes = settings.customContentTypes; + const existingContentTypes = settings.contentTypes || legacyContentTypes || []; + const conflicts = []; + if (existingContentTypes.some((ct) => ct.name === "Posts")) { + conflicts.push("Posts"); + } + if (existingContentTypes.some((ct) => ct.name === "Pages")) { + conflicts.push("Pages"); + } + let shouldMigrate = true; + if (conflicts.length > 0) { + await new Promise((resolve) => { + setTimeout(() => { + void (async () => { + try { + const modal = new MigrationModal(this.app, conflicts); + const timeoutPromise = new Promise((timeoutResolve) => { + setTimeout(() => { + timeoutResolve({ action: "skip" }); + }, 3e4); + }); + const result = await Promise.race([ + modal.waitForResult(), + timeoutPromise + ]); + if (result.action === "skip") { + shouldMigrate = false; + new import_obsidian11.Notice("Migration skipped. Old posts/pages settings will be ignored."); + } + } catch (error) { + console.warn("Migration modal error:", error); + shouldMigrate = false; + new import_obsidian11.Notice("Migration skipped due to error. You can migrate manually in settings."); + } + resolve(); + })(); + }, 500); + }); + } + if (!shouldMigrate) { + settings.migrationCompleted = true; + await this.plugin.saveSettings(); + return; + } + const migratedTypes = []; + if (hasPostsSettings && !conflicts.includes("Posts")) { + const postsType = { + id: `posts-${Date.now()}`, + name: "Posts", + folder: settings.postsFolder || "", + linkBasePath: settings.postsLinkBasePath || "", + template: settings.defaultTemplate || '---\ntitle: "{{title}}"\ndate: {{date}}\ntags: []\n---\n', + enabled: true, + creationMode: settings.creationMode || "file", + indexFileName: settings.indexFileName || "", + ignoreSubfolders: settings.onlyAutomateInPostsFolder || false, + enableUnderscorePrefix: settings.enableUnderscorePrefix || false, + useMdxExtension: false, + modifiedDateField: "" + }; + migratedTypes.push(postsType); + } + if (hasPagesSettings && !conflicts.includes("Pages")) { + const pagesType = { + id: `pages-${Date.now()}`, + name: "Pages", + folder: settings.pagesFolder || "", + linkBasePath: settings.pagesLinkBasePath || "", + template: settings.pageTemplate || '---\ntitle: "{{title}}"\ndescription: ""\n---\n', + enabled: true, + creationMode: settings.pagesCreationMode || "file", + indexFileName: settings.pagesIndexFileName || "", + ignoreSubfolders: settings.onlyAutomateInPagesFolder || false, + enableUnderscorePrefix: false, + useMdxExtension: false, + modifiedDateField: "" + }; + migratedTypes.push(pagesType); + } + const existingFromNew = settings.contentTypes || []; + const existingFromLegacy = legacyContentTypes || []; + let existingTypes = existingFromNew.length > 0 ? existingFromNew : existingFromLegacy; + let finalTypes = [...existingTypes]; + if (migratedTypes.length > 0) { + const existingNames = new Set(existingTypes.map((ct) => ct.name)); + const newMigratedTypes = migratedTypes.filter((mt) => !existingNames.has(mt.name)); + if (newMigratedTypes.length > 0) { + finalTypes = [...existingTypes, ...newMigratedTypes]; + } + } + settings.contentTypes = finalTypes; + const legacyFields = [ + "customContentTypes", + "enableUnderscorePrefix", + "postsFolder", + "postsLinkBasePath", + "automatePostCreation", + "creationMode", + "indexFileName", + "excludedDirectories", + "onlyAutomateInPostsFolder", + "enablePages", + "pagesFolder", + "pagesLinkBasePath", + "pagesCreationMode", + "pagesIndexFileName", + "pageTemplate", + "onlyAutomateInPagesFolder" + ]; + const settingsRecord = settings; + for (const field of legacyFields) { + delete settingsRecord[field]; + } + settings.migrationCompleted = true; + await this.plugin.saveSettings(); + await this.plugin.loadSettings(); + if (migratedTypes.length > 0) { + new import_obsidian11.Notice(`Migration completed: ${migratedTypes.length} content type(s) migrated.`); + setTimeout(() => { + if (this.plugin.settingsTab instanceof AstroComposerSettingTab) { + const settingsTab = this.plugin.settingsTab; + try { + if (settingsTab.customContentTypesContainer || settingsTab.containerEl) { + settingsTab.display(); + } + } catch (e) { + console.warn("Could not refresh settings tab after migration:", e); + } + } + }, 300); + } + } +}; + +// src/services/CreateEventService.ts +var import_obsidian12 = require("obsidian"); +var CreateEventService = class { + constructor(app, plugin) { + this.app = app; + this.plugin = plugin; + this.lastProcessedFiles = /* @__PURE__ */ new Map(); + } + handleCreate(file) { + void (async () => { + const now = Date.now(); + if (!(file instanceof import_obsidian12.TFile) || file.extension !== "md" && file.extension !== "mdx") { + return; + } + const filePath = file.path; + const createdTime = this.plugin.pluginCreatedFiles.get(filePath); + if (createdTime && now - createdTime < 5 * 60 * 1e3) { + return; + } + const lastProcessed = this.lastProcessedFiles.get(filePath) || 0; + if (lastProcessed > 0 && now - lastProcessed < CONSTANTS.DEBOUNCE_MS) { + return; + } + if (lastProcessed > 0 && now - lastProcessed > 2e3) { + this.lastProcessedFiles.delete(filePath); + } + const periodicCutoff = now - CONSTANTS.DEBOUNCE_MS * 2; + for (const [path, time] of this.lastProcessedFiles.entries()) { + if (time < periodicCutoff) { + this.lastProcessedFiles.delete(path); + } + } + const contentTypes = this.plugin.settings.contentTypes || []; + const hasEnabledContentTypes = contentTypes.some((ct) => ct.enabled); + if (!hasEnabledContentTypes) { + return; + } + const sortedContentTypes = sortByPatternSpecificity(contentTypes); + let matchedContentTypeId = null; + const matchingTypes = []; + for (const contentType of sortedContentTypes) { + if (!contentType.enabled) continue; + let matches = false; + if (!contentType.folder || contentType.folder.trim() === "") { + if (!filePath.includes("/") || filePath.split("/").length === 1) { + matches = true; + } + } else if (matchesFolderPattern(filePath, contentType.folder)) { + if (contentType.ignoreSubfolders) { + const pathSegments = filePath.split("/"); + const pathDepth = pathSegments.length; + const patternSegments = contentType.folder.split("/"); + const expectedDepth = patternSegments.length; + if (contentType.creationMode === "folder") { + const folderDepth = pathDepth - 1; + if (folderDepth === expectedDepth || folderDepth === expectedDepth + 1) { + matches = true; + } + } else { + if (pathDepth === expectedDepth) { + matches = true; + } + } + } else { + matches = true; + } + } + if (matches) { + matchingTypes.push(contentType); + if (!matchedContentTypeId) { + matchedContentTypeId = contentType.id; + } + } + } + if (matchingTypes.length > 1) { + const typeNames = matchingTypes.map((ct) => ct.name || "Unnamed").join(", "); + new import_obsidian12.Notice(`Multiple content types (${typeNames}) match this file. Using most specific: ${matchingTypes[0].name || "Unnamed"}`); + } + if (!matchedContentTypeId) { + return; + } + const stat = await this.app.vault.adapter.stat(file.path); + const isNewNote = (stat == null ? void 0 : stat.mtime) && now - stat.mtime < CONSTANTS.STAT_MTIME_THRESHOLD; + if (!isNewNote) { + return; + } + const activeFile = this.app.workspace.getActiveFile(); + const isActiveFile = activeFile && activeFile.path === file.path; + if (!this.plugin.settings.processBackgroundFileChanges && !isActiveFile) { + return; + } + await new Promise((resolve) => setTimeout(resolve, 50)); + let content; + try { + content = await this.app.vault.read(file); + } catch (error) { + console.error("Error reading file for create detection:", error); + return; + } + if (content.trim().length > 0) { + if (content.startsWith("---")) { + const frontmatterEnd = content.indexOf("\n---", 3); + if (frontmatterEnd !== -1) { + const frontmatterText = content.slice(4, frontmatterEnd).trim(); + const lines = frontmatterText.split("\n").filter((line) => line.trim().length > 0); + if (!this.plugin.settings.processBackgroundFileChanges && lines.length > 0) { + return; + } + if (lines.length > 1 || lines.length === 1 && !lines[0].startsWith("title:")) { + return; + } + } + } + const contentWithoutFrontmatter = content.startsWith("---") ? content.slice(content.indexOf("\n---", 3) + 4).trim() : content.trim(); + if (contentWithoutFrontmatter.length > 0) { + return; + } + } + this.lastProcessedFiles.set(file.path, now); + setTimeout(() => { + this.lastProcessedFiles.delete(file.path); + }, CONSTANTS.DEBOUNCE_MS + 100); + new TitleModal(this.app, file, this.plugin, matchedContentTypeId, false, true).open(); + })(); + } +}; + +// src/services/FrontmatterService.ts +var import_obsidian13 = require("obsidian"); +var FrontmatterService = class { + constructor(app, plugin) { + this.app = app; + this.plugin = plugin; + this.lastProcessedFile = ""; + this.lastProcessedTime = 0; + this.debounceTimeout = null; + this.draftStatusMap = /* @__PURE__ */ new Map(); + this.contentHashCache = /* @__PURE__ */ new Map(); + this.registerEvents(); + this.app.workspace.onLayoutReady(() => { + this.initializeDraftStatusMap(); + }); + } + destroy() { + } + initializeDraftStatusMap() { + var _a; + this.draftStatusMap.clear(); + const settings = this.plugin.settings; + const isUnderscoreMode = settings.draftDetectionMode === "underscore-prefix"; + const draftProp = settings.draftProperty || "draft"; + const files = this.app.vault.getFiles().filter((f) => f instanceof import_obsidian13.TFile && (f.extension === "md" || f.extension === "mdx")); + for (const file of files) { + if (isUnderscoreMode) { + this.draftStatusMap.set(file.path, file.name.startsWith("_")); + } else { + const cache = this.app.metadataCache.getFileCache(file); + const rawValue = (_a = cache == null ? void 0 : cache.frontmatter) == null ? void 0 : _a[draftProp]; + this.draftStatusMap.set(file.path, this.calculateIsDraft(rawValue, settings)); + } + } + } + calculateIsDraft(rawValue, settings) { + if (rawValue === void 0 || rawValue === null) return false; + const val = String(rawValue).toLowerCase(); + if (settings.draftLogic === "false-is-draft") { + return val === "false" || val === "0" || rawValue === false; + } else { + return val === "true" || val === "1" || rawValue === true; + } + } + registerEvents() { + this.plugin.registerEvent( + this.app.metadataCache.on("changed", (file) => { + if (file instanceof import_obsidian13.TFile) { + this.onMetadataChange(file); + } + }) + ); + this.plugin.registerEvent( + this.app.vault.on("rename", (file, oldPath) => { + if (file instanceof import_obsidian13.TFile) { + this.onRename(file, oldPath); + } + }) + ); + this.plugin.registerEvent( + this.app.workspace.on("file-open", (file) => { + if (file instanceof import_obsidian13.TFile) { + void (async () => { + try { + const content = await this.app.vault.read(file); + this.contentHashCache.set(file.path, this.getContentHash(content)); + } catch (e) { + console.error(`Failed to lazily initialize content hash for ${file.path}:`, e); + } + })(); + } + }) + ); + } + onRename(file, oldPath) { + var _a; + const settings = this.plugin.settings; + if (!settings.syncDraftDate) return; + const oldName = oldPath.split("/").pop() || ""; + const newName = file.name; + if (oldName.startsWith("_") && !newName.startsWith("_")) { + if (settings.draftDetectionMode === "underscore-prefix") { + void this.updateDate(file); + } else { + const contentType = (_a = this.plugin.fileOps) == null ? void 0 : _a.getContentTypeByPath(file.path); + if (contentType == null ? void 0 : contentType.enableUnderscorePrefix) { + void this.updateDate(file); + } + } + } + } + onMetadataChange(file) { + var _a, _b, _c; + const settings = this.plugin.settings; + if (settings.draftDetectionMode === "underscore-prefix") { + const contentType2 = (_a = this.plugin.fileOps) == null ? void 0 : _a.getContentTypeByPath(file.path); + const hasModifiedField2 = !!(contentType2 == null ? void 0 : contentType2.modifiedDateField); + if (!hasModifiedField2) return; + const activeFile2 = this.app.workspace.getActiveFile(); + const isActiveFile2 = activeFile2 && activeFile2.path === file.path; + if (!settings.processBackgroundFileChanges && !isActiveFile2) return; + void this.processFile(file, false, contentType2); + return; + } + const activeFile = this.app.workspace.getActiveFile(); + const isActiveFile = activeFile && activeFile.path === file.path; + if (!settings.processBackgroundFileChanges && !isActiveFile) { + return; + } + const contentType = (_b = this.plugin.fileOps) == null ? void 0 : _b.getContentTypeByPath(file.path); + const hasModifiedField = !!(contentType == null ? void 0 : contentType.modifiedDateField); + if (!settings.syncDraftDate && !hasModifiedField) { + return; + } + const cache = this.app.metadataCache.getFileCache(file); + const draftProp = settings.draftProperty || "draft"; + const rawValue = (_c = cache == null ? void 0 : cache.frontmatter) == null ? void 0 : _c[draftProp]; + const isCurrentlyDraft = this.calculateIsDraft(rawValue, settings); + if (!this.draftStatusMap.has(file.path)) { + this.draftStatusMap.set(file.path, isCurrentlyDraft); + return; + } + const previousDraftStatus = this.draftStatusMap.get(file.path); + let draftStatusChangedToPublished = false; + if (previousDraftStatus === true && isCurrentlyDraft === false) { + draftStatusChangedToPublished = true; + } + this.draftStatusMap.set(file.path, isCurrentlyDraft); + if (!draftStatusChangedToPublished && !hasModifiedField) { + return; + } + const now = Date.now(); + if (this.lastProcessedFile === file.path && now - this.lastProcessedTime < 2e3) { + return; + } + if (this.debounceTimeout) { + window.clearTimeout(this.debounceTimeout); + } + this.debounceTimeout = window.setTimeout(async () => { + try { + const content = await this.app.vault.read(file); + const currentHash = this.getContentHash(content); + const previousHash = this.contentHashCache.get(file.path); + this.contentHashCache.set(file.path, currentHash); + if (previousHash === void 0) { + if (!draftStatusChangedToPublished) { + return; + } + } else if (previousHash === currentHash) { + if (!draftStatusChangedToPublished) { + return; + } + } + } catch (e) { + console.error(`Failed to check content hash for ${file.path}:`, e); + return; + } + void this.processFile(file, draftStatusChangedToPublished, contentType); + }, 500); + } + getContentHash(content) { + let body = content; + if (content.startsWith("---")) { + const end = content.indexOf("\n---", 3); + if (end !== -1) { + body = content.slice(end + 4); + } + } + const normalized = body.replace(/\s+/g, " ").trim(); + return this.simpleHash(normalized); + } + simpleHash(str) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = (hash << 5) - hash + char; + hash |= 0; + } + return hash.toString() + "_" + str.length; + } + async updateDate(file) { + const settings = this.plugin.settings; + const dateField = settings.publishDateField || "date"; + await this.app.fileManager.processFrontMatter(file, (frontmatter) => { + const today = (0, import_obsidian13.moment)().format(settings.dateFormat); + if (frontmatter[dateField] !== today) { + frontmatter[dateField] = today; + this.lastProcessedFile = file.path; + this.lastProcessedTime = Date.now(); + } + }); + } + async processFile(file, draftStatusChangedToPublished, contentType) { + const settings = this.plugin.settings; + const publishDateField = settings.publishDateField || "date"; + await this.app.fileManager.processFrontMatter(file, (frontmatter) => { + let changed = false; + if (settings.syncDraftDate && draftStatusChangedToPublished) { + const today = (0, import_obsidian13.moment)().format(settings.dateFormat); + if (frontmatter[publishDateField] !== today) { + frontmatter[publishDateField] = today; + changed = true; + } + } + const modifiedField = contentType == null ? void 0 : contentType.modifiedDateField; + if (modifiedField && frontmatter[modifiedField] !== void 0) { + const now = (0, import_obsidian13.moment)().format(settings.dateFormat); + if (frontmatter[modifiedField] !== now) { + frontmatter[modifiedField] = now; + changed = true; + } + } + if (changed) { + this.lastProcessedFile = file.path; + this.lastProcessedTime = Date.now(); + } + }); + } +}; + +// src/main.ts +var AstroComposerPlugin = class extends import_obsidian14.Plugin { + constructor() { + super(...arguments); + this.pluginCreatedFiles = /* @__PURE__ */ new Map(); + this.processedFiles = /* @__PURE__ */ new Map(); + this.terminalRibbonIcon = null; + this.configRibbonIcon = null; + } + /** + * Migrate old posts/pages settings to unified content types + */ + async migrateSettingsIfNeeded() { + if (!this.migrationService) { + this.migrationService = new MigrationService(this.app, this); + } + await this.migrationService.migrateSettingsIfNeeded(); + } + async onload() { + try { + await this.loadSettings(); + this.fileOps = new FileOperations(this.app, this.settings, this); + this.migrationService = new MigrationService(this.app, this); + this.createEventService = new CreateEventService(this.app, this); + this.frontmatterService = new FrontmatterService(this.app, this); + this.templateParser = new TemplateParser(this.app, this.settings, this); + this.headingLinkGenerator = new HeadingLinkGenerator(this.settings, this); + if (this.settings.showMdxFilesInExplorer) { + try { + this.registerExtensions(["mdx"], "markdown"); + } catch (error) { + console.warn("[Astro Composer] MDX extension already registered:", error); + } + } + this.app.workspace.onLayoutReady(() => { + this.registerCreateEvent(); + if (!import_obsidian14.Platform.isMobile) { + this.startHelpButtonMonitor(); + } + this.registerTitlePropertyClickListener(); + void this.migrateSettingsIfNeeded(); + }); + registerCommands(this, this.settings); + registerContentTypeCommands(this, this.settings); + this.settingsTab = new AstroComposerSettingTab(this.app, this); + this.addSettingTab(this.settingsTab); + this.registerContextMenu(); + this.registerRibbonIcons(); + this.setupRibbonContextMenuHandling(); + } catch (error) { + console.error("[Astro Composer] Critical error during onload:", error); + new import_obsidian14.Notice("Astro Composer failed to load. Check console (Ctrl+Shift+I) for details."); + throw error; + } + } + registerCreateEvent() { + if (this.createEventRef) { + this.app.vault.offref(this.createEventRef); + this.createEventRef = void 0; + } + const createEventRef = this.app.vault.on("create", (file) => { + if (file instanceof import_obsidian14.TFile) { + this.createEventService.handleCreate(file); + this.cleanupPluginCreatedFiles(); + } + }); + this.registerEvent(createEventRef); + this.createEventRef = createEventRef; + } + registerTitlePropertyClickListener() { + this.registerDomEvent(document, "click", (evt) => { + if (!this.settings.renameOnTitleClick) return; + const target = evt.target; + const propertyEl = target.closest(".metadata-property"); + if (!propertyEl) return; + const propertyKey = propertyEl.getAttribute("data-property-key"); + if (!propertyKey) return; + const activeFile = this.app.workspace.getActiveFile(); + if (!activeFile) return; + const typeId = this.fileOps.determineType(activeFile); + const titleKey = this.fileOps.getTitleKey(typeId); + if (propertyKey === titleKey) { + evt.preventDefault(); + evt.stopPropagation(); + this.renameContentByPath(activeFile.path); + } + }, true); + } + cleanupPluginCreatedFiles() { + const now = Date.now(); + const ttl = 5 * 60 * 1e3; + for (const [path, timestamp] of this.pluginCreatedFiles.entries()) { + if (now - timestamp > ttl) { + this.pluginCreatedFiles.delete(path); + } + } + } + async loadSettings() { + const loadedData = await this.loadData(); + if (!this.settings) { + this.settings = Object.assign({}, DEFAULT_SETTINGS, loadedData); + } else { + Object.assign(this.settings, loadedData); + } + if (!this.settings.contentTypes || !Array.isArray(this.settings.contentTypes)) { + this.settings.contentTypes = []; + } + if (!this.settings.migrationCompleted) { + const legacySettings = this.settings; + const hasLegacyTypes = legacySettings.customContentTypes && Array.isArray(legacySettings.customContentTypes) && legacySettings.customContentTypes.length > 0; + const hasNewTypes = this.settings.contentTypes && Array.isArray(this.settings.contentTypes) && this.settings.contentTypes.length > 0; + if (hasLegacyTypes && !hasNewTypes) { + this.settings.contentTypes = legacySettings.customContentTypes || []; + } + } else { + const legacyFields = [ + "customContentTypes", + "enableUnderscorePrefix", + "postsFolder", + "postsLinkBasePath", + "automatePostCreation", + "creationMode", + "indexFileName", + "excludedDirectories", + "onlyAutomateInPostsFolder", + "enablePages", + "pagesFolder", + "pagesLinkBasePath", + "pagesCreationMode", + "pagesIndexFileName", + "pageTemplate", + "onlyAutomateInPagesFolder", + "linkBasePath", + "enableAutoRename", + "enableAutoInsertFrontmatter", + "draftStyle" + ]; + const settingsRecord = this.settings; + let fieldsRemoved = false; + for (const field of legacyFields) { + if (settingsRecord[field] !== void 0) { + delete settingsRecord[field]; + fieldsRemoved = true; + } + } + if (fieldsRemoved) { + await this.saveSettings(); + } + } + } + async saveSettings() { + await this.saveData(this.settings); + } + registerContextMenu() { + this.registerEvent( + this.app.workspace.on("editor-menu", (menu, editor, view) => { + if (!this.settings.enableCopyHeadingLink) { + return; + } + const cursor = editor.getCursor(); + const file = view.file; + if (!(file instanceof import_obsidian14.TFile)) { + return; + } + const heading = this.headingLinkGenerator.findHeadingAtLine(this.app, file, cursor.line); + if (heading) { + const fullLink = this.headingLinkGenerator.generateLink(this.app, file, heading); + const urlOnly = this.headingLinkGenerator.extractUrl(fullLink); + menu.addItem((item) => { + item.setTitle("Copy heading link").setIcon("link-2").onClick(async () => { + await navigator.clipboard.writeText(urlOnly); + new import_obsidian14.Notice("Heading link copied to clipboard"); + }); + }); + menu.addItem((item) => { + item.setTitle("Copy heading link with text").setIcon("heading").onClick(async () => { + await navigator.clipboard.writeText(fullLink); + new import_obsidian14.Notice("Heading link with text copied to clipboard"); + }); + }); + } + }) + ); + } + renameContentByPath(filePath) { + renameContentByPath(this.app, filePath, this.settings, this); + } + registerRibbonIcons() { + if (import_obsidian14.Platform.isMobile) { + if (this.terminalRibbonIcon) { + try { + if (this.terminalRibbonIcon.parentNode) this.terminalRibbonIcon.remove(); + } catch (e) { + } + this.terminalRibbonIcon = null; + } + if (this.configRibbonIcon) { + try { + if (this.configRibbonIcon.parentNode) this.configRibbonIcon.remove(); + } catch (e) { + } + this.configRibbonIcon = null; + } + try { + const terminalIcons = document.querySelectorAll('.side-dock-ribbon-action[aria-label="Open project terminal"]'); + terminalIcons.forEach((icon) => icon.remove()); + const configIcons = document.querySelectorAll('.side-dock-ribbon-action[aria-label="Edit astro config"]'); + configIcons.forEach((icon) => icon.remove()); + } catch (e) { + } + return; + } + const terminalShouldExist = this.settings.enableTerminalRibbonIcon && this.settings.enableOpenTerminalCommand; + const configShouldExist = this.settings.enableConfigRibbonIcon && this.settings.enableOpenConfigFileCommand; + if (this.terminalRibbonIcon) { + try { + if (this.terminalRibbonIcon.parentNode) this.terminalRibbonIcon.remove(); + } catch (e) { + } + this.terminalRibbonIcon = null; + } + if (this.configRibbonIcon) { + try { + if (this.configRibbonIcon.parentNode) this.configRibbonIcon.remove(); + } catch (e) { + } + this.configRibbonIcon = null; + } + try { + document.querySelectorAll('.side-dock-ribbon-action[aria-label="Open project terminal"]').forEach((el) => el.remove()); + document.querySelectorAll('.side-dock-ribbon-action[aria-label="Edit astro config"]').forEach((el) => el.remove()); + } catch (e) { + } + if (terminalShouldExist) { + this.terminalRibbonIcon = this.addRibbonIcon("terminal-square", "Open project terminal", () => { + if (!this.settings.enableOpenTerminalCommand) { + new import_obsidian14.Notice("Open terminal command is disabled."); + return; + } + openTerminalInProjectRoot(this.app, this.settings); + }); + if (this.terminalRibbonIcon) this.terminalRibbonIcon.setAttribute("data-astro-composer-terminal-ribbon", "true"); + } + if (configShouldExist) { + this.configRibbonIcon = this.addRibbonIcon("rocket", "Edit astro config", async () => { + if (!this.settings.enableOpenConfigFileCommand) { + new import_obsidian14.Notice("Edit config file command is disabled."); + return; + } + await openConfigFile(this.app, this.settings); + }); + if (this.configRibbonIcon) this.configRibbonIcon.setAttribute("data-astro-composer-config-ribbon", "true"); + } + this.updateRibbonContextMenuCSS(); + this.setupRibbonContextMenuObserver(); + } + onunload() { + var _a; + (_a = this.frontmatterService) == null ? void 0 : _a.destroy(); + if (this.terminalRibbonIcon) { + this.terminalRibbonIcon.remove(); + this.terminalRibbonIcon = null; + } + if (this.configRibbonIcon) { + this.configRibbonIcon.remove(); + this.configRibbonIcon = null; + } + if (this.ribbonContextMenuObserver) { + this.ribbonContextMenuObserver.disconnect(); + this.ribbonContextMenuObserver = void 0; + } + document.body.removeClass("astro-composer-hide-terminal-icon"); + document.body.removeClass("astro-composer-hide-config-icon"); + if (this.helpButtonObserver) { + this.helpButtonObserver.disconnect(); + this.helpButtonObserver = void 0; + } + if (this.customHelpButton) { + this.customHelpButton.remove(); + this.customHelpButton = void 0; + } + this.helpButtonElement = void 0; + } + setupRibbonContextMenuHandling() { + this.updateRibbonContextMenuCSS(); + this.setupRibbonContextMenuObserver(); + } + updateRibbonContextMenuCSS() { + const terminalShouldBeHidden = !this.settings.enableTerminalRibbonIcon || !this.settings.enableOpenTerminalCommand; + const configShouldBeHidden = !this.settings.enableConfigRibbonIcon || !this.settings.enableOpenConfigFileCommand; + if (terminalShouldBeHidden) document.body.addClass("astro-composer-hide-terminal-icon"); + else document.body.removeClass("astro-composer-hide-terminal-icon"); + if (configShouldBeHidden) document.body.addClass("astro-composer-hide-config-icon"); + else document.body.removeClass("astro-composer-hide-config-icon"); + } + setupRibbonContextMenuObserver() { + if (this.ribbonContextMenuObserver) this.ribbonContextMenuObserver.disconnect(); + const terminalShouldBeHidden = !this.settings.enableTerminalRibbonIcon || !this.settings.enableOpenTerminalCommand; + const configShouldBeHidden = !this.settings.enableConfigRibbonIcon || !this.settings.enableOpenConfigFileCommand; + if (!terminalShouldBeHidden && !configShouldBeHidden) return; + this.ribbonContextMenuObserver = new MutationObserver((mutations) => { + for (const mutation of mutations) { + if (mutation.addedNodes.length > 0) { + for (const node of Array.from(mutation.addedNodes)) { + if (node instanceof HTMLElement) { + if (node.classList.contains("menu") || node.querySelector(".menu")) { + this.removeRibbonIconsFromContextMenu(node); + } + } + } + } + } + }); + this.ribbonContextMenuObserver.observe(document.body, { childList: true, subtree: true }); + } + /** + * Starts a robust monitor that keeps the help button in sync with settings. + */ + startHelpButtonMonitor() { + if (this.helpButtonObserver) this.helpButtonObserver.disconnect(); + this.syncHelpButton(); + let timer = null; + let mutationCount = 0; + this.helpButtonObserver = new MutationObserver(() => { + mutationCount++; + if (timer) window.clearTimeout(timer); + const delay = mutationCount < 20 ? 0 : 100; + if (delay === 0) { + this.syncHelpButton(); + } else { + timer = window.setTimeout(() => this.syncHelpButton(), delay); + } + }); + this.helpButtonObserver.observe(document.body, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ["class", "src", "aria-label"] + }); + } + /** + * Synchronizes the help button state based on settings. + */ + syncHelpButton() { + var _a, _b, _c, _d; + const enabled = (_a = this.settings.helpButtonReplacement) == null ? void 0 : _a.enabled; + if (enabled) document.body.addClass("astro-composer-hide-help-button"); + else document.body.removeClass("astro-composer-hide-help-button"); + if (!enabled) { + if (this.customHelpButton) { + this.customHelpButton.remove(); + this.customHelpButton = void 0; + } + return; + } + const selectors = [ + ".workspace-drawer-vault-actions .clickable-icon svg.help", + ".workspace-sidedock-vault-profile .clickable-icon svg.help", + ".workspace-drawer .clickable-icon svg.help", + ".clickable-icon svg.help" + ]; + let helpButtonSvg = null; + for (const selector of selectors) { + helpButtonSvg = document.querySelector(selector); + if (helpButtonSvg) break; + } + if (!helpButtonSvg) return; + const originalHelpButton = helpButtonSvg.parentElement; + if (!originalHelpButton) return; + const existingReplacement = (_b = originalHelpButton.parentElement) == null ? void 0 : _b.querySelector('[data-astro-composer-help-replacement="true"]'); + if (existingReplacement) { + this.customHelpButton = existingReplacement; + return; + } + const customButton = originalHelpButton.cloneNode(true); + customButton.addClass("astro-composer-help-replacement"); + customButton.removeAttribute("aria-label"); + customButton.setAttribute("data-astro-composer-help-replacement", "true"); + customButton.onclick = null; + const iconContainer = ((_c = customButton.querySelector("svg")) == null ? void 0 : _c.parentElement) || customButton; + try { + if (iconContainer instanceof HTMLElement) { + (0, import_obsidian14.setIcon)(iconContainer, this.settings.helpButtonReplacement.iconId); + } + } catch (error) { + console.warn("[Astro Composer] Error setting replacement icon:", error); + } + customButton.addEventListener("click", (evt) => { + var _a2, _b2; + evt.preventDefault(); + evt.stopPropagation(); + const commandId = (_a2 = this.settings.helpButtonReplacement) == null ? void 0 : _a2.commandId; + if (commandId) { + const appWithCommands = this.app; + if ((_b2 = appWithCommands.commands) == null ? void 0 : _b2.executeCommandById) { + void appWithCommands.commands.executeCommandById(commandId); + } + } + }, true); + (_d = originalHelpButton.parentElement) == null ? void 0 : _d.insertBefore(customButton, originalHelpButton); + this.customHelpButton = customButton; + } + restoreHelpButton() { + document.body.removeClass("astro-composer-hide-help-button"); + if (this.customHelpButton) { + this.customHelpButton.remove(); + this.customHelpButton = void 0; + } + this.helpButtonElement = void 0; + } + removeRibbonIconsFromContextMenu(menuElement) { + var _a, _b; + const terminalShouldBeHidden = !this.settings.enableTerminalRibbonIcon || !this.settings.enableOpenTerminalCommand; + const configShouldBeHidden = !this.settings.enableConfigRibbonIcon || !this.settings.enableOpenConfigFileCommand; + const menuItems = menuElement.querySelectorAll(".menu-item"); + for (const item of Array.from(menuItems)) { + const svg = item.querySelector("svg"); + if (svg) { + let iconName = svg.getAttribute("data-lucide") || svg.getAttribute("xmlns:lucide") || svg.getAttribute("data-icon") || (svg.classList.contains("lucide-terminal-square") ? "terminal-square" : null) || (svg.classList.contains("lucide-rocket") ? "rocket" : null) || (svg.classList.contains("lucide-wrench") ? "wrench" : null); + if (iconName) iconName = iconName.replace(/^lucide-/, ""); + if (terminalShouldBeHidden && iconName === "terminal-square") { + if ((_a = item.textContent) == null ? void 0 : _a.toLowerCase().includes("terminal")) item.remove(); + } + if (configShouldBeHidden && (iconName === "rocket" || iconName === "wrench")) { + if ((_b = item.textContent) == null ? void 0 : _b.toLowerCase().includes("config")) item.remove(); + } + } + } + } +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsic3JjL21haW4udHMiLCAic3JjL3R5cGVzLnRzIiwgInNyYy9zZXR0aW5ncy50cyIsICJzcmMvY29tbWFuZHMvaW5kZXgudHMiLCAic3JjL3V0aWxzL2ZpbGUtb3BlcmF0aW9ucy50cyIsICJzcmMvdXRpbHMvcGF0aC1tYXRjaGluZy50cyIsICJzcmMvdXRpbHMvc3RyaW5nLXV0aWxzLnRzIiwgInNyYy91dGlscy90ZW1wbGF0ZS1wYXJzaW5nLnRzIiwgInNyYy91dGlscy9saW5rLWNvbnZlcnNpb24udHMiLCAic3JjL3VpL3RpdGxlLW1vZGFsLnRzIiwgInNyYy91aS9zZXR0aW5ncy10YWIudHMiLCAic3JjL3VpL2NvbXBvbmVudHMvQ29tbWFuZFBpY2tlck1vZGFsLnRzIiwgInNyYy91aS9jb21wb25lbnRzL0ljb25QaWNrZXJNb2RhbC50cyIsICJzcmMvdWkvY29tcG9uZW50cy9Db25maXJtTW9kYWwudHMiLCAic3JjL3V0aWxzL2hlYWRpbmctbGluay1nZW5lcmF0b3IudHMiLCAic3JjL3NlcnZpY2VzL01pZ3JhdGlvblNlcnZpY2UudHMiLCAic3JjL3VpL2NvbXBvbmVudHMvTWlncmF0aW9uTW9kYWwudHMiLCAic3JjL3NlcnZpY2VzL0NyZWF0ZUV2ZW50U2VydmljZS50cyIsICJzcmMvc2VydmljZXMvRnJvbnRtYXR0ZXJTZXJ2aWNlLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJpbXBvcnQge1xyXG5cdFBsdWdpbixcclxuXHRURmlsZSxcclxuXHROb3RpY2UsXHJcblx0c2V0SWNvbixcclxuXHRQbGF0Zm9ybSxcclxuXHRFdmVudFJlZixcclxufSBmcm9tIFwib2JzaWRpYW5cIjtcclxuXHJcbmltcG9ydCB7IEFzdHJvQ29tcG9zZXJTZXR0aW5ncywgREVGQVVMVF9TRVRUSU5HUyB9IGZyb20gXCIuL3NldHRpbmdzXCI7XHJcbmltcG9ydCB7IEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UsIENvbnRlbnRUeXBlIH0gZnJvbSBcIi4vdHlwZXNcIjtcclxuaW1wb3J0IHsgcmVnaXN0ZXJDb21tYW5kcywgcmVnaXN0ZXJDb250ZW50VHlwZUNvbW1hbmRzLCByZW5hbWVDb250ZW50QnlQYXRoIGFzIHJlbmFtZUNvbnRlbnRCeVBhdGhGdW5jdGlvbiwgb3BlblRlcm1pbmFsSW5Qcm9qZWN0Um9vdCwgb3BlbkNvbmZpZ0ZpbGUgfSBmcm9tIFwiLi9jb21tYW5kc1wiO1xyXG5pbXBvcnQgeyBBc3Ryb0NvbXBvc2VyU2V0dGluZ1RhYiB9IGZyb20gXCIuL3VpL3NldHRpbmdzLXRhYlwiO1xyXG5pbXBvcnQgeyBGaWxlT3BlcmF0aW9ucyB9IGZyb20gXCIuL3V0aWxzL2ZpbGUtb3BlcmF0aW9uc1wiO1xyXG5pbXBvcnQgeyBUZW1wbGF0ZVBhcnNlciB9IGZyb20gXCIuL3V0aWxzL3RlbXBsYXRlLXBhcnNpbmdcIjtcclxuaW1wb3J0IHsgSGVhZGluZ0xpbmtHZW5lcmF0b3IgfSBmcm9tIFwiLi91dGlscy9oZWFkaW5nLWxpbmstZ2VuZXJhdG9yXCI7XHJcbmltcG9ydCB7IE1pZ3JhdGlvblNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9NaWdyYXRpb25TZXJ2aWNlXCI7XHJcbmltcG9ydCB7IENyZWF0ZUV2ZW50U2VydmljZSB9IGZyb20gXCIuL3NlcnZpY2VzL0NyZWF0ZUV2ZW50U2VydmljZVwiO1xyXG5pbXBvcnQgeyBGcm9udG1hdHRlclNlcnZpY2UgfSBmcm9tIFwiLi9zZXJ2aWNlcy9Gcm9udG1hdHRlclNlcnZpY2VcIjtcclxuaW1wb3J0IHsgd2FpdEZvckVsZW1lbnQgfSBmcm9tIFwiLi91dGlscy9kb21cIjtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEFzdHJvQ29tcG9zZXJQbHVnaW4gZXh0ZW5kcyBQbHVnaW4gaW1wbGVtZW50cyBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlIHtcclxuXHRzZXR0aW5ncyE6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncztcclxuXHRwcml2YXRlIGNyZWF0ZUV2ZW50UmVmPzogRXZlbnRSZWY7XHJcblx0cHVibGljIGZpbGVPcHMhOiBGaWxlT3BlcmF0aW9ucztcclxuXHRwdWJsaWMgdGVtcGxhdGVQYXJzZXIhOiBUZW1wbGF0ZVBhcnNlcjtcclxuXHRwdWJsaWMgaGVhZGluZ0xpbmtHZW5lcmF0b3IhOiBIZWFkaW5nTGlua0dlbmVyYXRvcjtcclxuXHRwdWJsaWMgcGx1Z2luQ3JlYXRlZEZpbGVzOiBNYXA8c3RyaW5nLCBudW1iZXI+ID0gbmV3IE1hcCgpO1xyXG5cdHByaXZhdGUgcHJvY2Vzc2VkRmlsZXM6IE1hcDxzdHJpbmcsIG51bWJlcj4gPSBuZXcgTWFwKCk7XHJcblx0cHJpdmF0ZSB0ZXJtaW5hbFJpYmJvbkljb246IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XHJcblx0cHJpdmF0ZSBjb25maWdSaWJib25JY29uOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG5cdHByaXZhdGUgcmliYm9uQ29udGV4dE1lbnVPYnNlcnZlcj86IE11dGF0aW9uT2JzZXJ2ZXI7XHJcblx0cHJpdmF0ZSBoZWxwQnV0dG9uT2JzZXJ2ZXI/OiBNdXRhdGlvbk9ic2VydmVyO1xyXG5cdHByaXZhdGUgaGVscEJ1dHRvbkVsZW1lbnQ/OiBIVE1MRWxlbWVudDtcclxuXHRwcml2YXRlIGN1c3RvbUhlbHBCdXR0b24/OiBIVE1MRWxlbWVudDtcclxuXHRwdWJsaWMgc2V0dGluZ3NUYWI/OiBBc3Ryb0NvbXBvc2VyU2V0dGluZ1RhYjtcclxuXHJcblx0cHJpdmF0ZSBtaWdyYXRpb25TZXJ2aWNlITogTWlncmF0aW9uU2VydmljZTtcclxuXHRwcml2YXRlIGNyZWF0ZUV2ZW50U2VydmljZSE6IENyZWF0ZUV2ZW50U2VydmljZTtcclxuXHRwdWJsaWMgZnJvbnRtYXR0ZXJTZXJ2aWNlITogRnJvbnRtYXR0ZXJTZXJ2aWNlO1xyXG5cclxuXHQvKipcclxuXHQgKiBNaWdyYXRlIG9sZCBwb3N0cy9wYWdlcyBzZXR0aW5ncyB0byB1bmlmaWVkIGNvbnRlbnQgdHlwZXNcclxuXHQgKi9cclxuXHRwcml2YXRlIGFzeW5jIG1pZ3JhdGVTZXR0aW5nc0lmTmVlZGVkKCk6IFByb21pc2U8dm9pZD4ge1xyXG5cdFx0aWYgKCF0aGlzLm1pZ3JhdGlvblNlcnZpY2UpIHtcclxuXHRcdFx0dGhpcy5taWdyYXRpb25TZXJ2aWNlID0gbmV3IE1pZ3JhdGlvblNlcnZpY2UodGhpcy5hcHAsIHRoaXMpO1xyXG5cdFx0fVxyXG5cdFx0YXdhaXQgdGhpcy5taWdyYXRpb25TZXJ2aWNlLm1pZ3JhdGVTZXR0aW5nc0lmTmVlZGVkKCk7XHJcblx0fVxyXG5cclxuXHRhc3luYyBvbmxvYWQoKSB7XHJcblx0XHR0cnkge1xyXG5cdFx0XHRhd2FpdCB0aGlzLmxvYWRTZXR0aW5ncygpO1xyXG5cclxuXHRcdFx0Ly8gSW5pdGlhbGl6ZSBzZXJ2aWNlcyAob3JkZXIgbWF0dGVyczogZmlsZU9wcyBmaXJzdCBhcyBpdCdzIGEgZGVwZW5kZW5jeSlcclxuXHRcdFx0dGhpcy5maWxlT3BzID0gbmV3IEZpbGVPcGVyYXRpb25zKHRoaXMuYXBwLCB0aGlzLnNldHRpbmdzLCB0aGlzKTtcclxuXHRcdFx0dGhpcy5taWdyYXRpb25TZXJ2aWNlID0gbmV3IE1pZ3JhdGlvblNlcnZpY2UodGhpcy5hcHAsIHRoaXMpO1xyXG5cdFx0XHR0aGlzLmNyZWF0ZUV2ZW50U2VydmljZSA9IG5ldyBDcmVhdGVFdmVudFNlcnZpY2UodGhpcy5hcHAsIHRoaXMpO1xyXG5cdFx0XHR0aGlzLmZyb250bWF0dGVyU2VydmljZSA9IG5ldyBGcm9udG1hdHRlclNlcnZpY2UodGhpcy5hcHAsIHRoaXMpO1xyXG5cdFx0XHR0aGlzLnRlbXBsYXRlUGFyc2VyID0gbmV3IFRlbXBsYXRlUGFyc2VyKHRoaXMuYXBwLCB0aGlzLnNldHRpbmdzLCB0aGlzKTtcclxuXHRcdFx0dGhpcy5oZWFkaW5nTGlua0dlbmVyYXRvciA9IG5ldyBIZWFkaW5nTGlua0dlbmVyYXRvcih0aGlzLnNldHRpbmdzLCB0aGlzKTtcclxuXHJcblx0XHRcdC8vIFJlZ2lzdGVyIE1EWCBmaWxlIHZpc2liaWxpdHkgaWYgZW5hYmxlZCAoc2FmZWx5IGhhbmRsZSBpZiBhbHJlYWR5IHJlZ2lzdGVyZWQpXHJcblx0XHRcdGlmICh0aGlzLnNldHRpbmdzLnNob3dNZHhGaWxlc0luRXhwbG9yZXIpIHtcclxuXHRcdFx0XHR0cnkge1xyXG5cdFx0XHRcdFx0dGhpcy5yZWdpc3RlckV4dGVuc2lvbnMoW1wibWR4XCJdLCBcIm1hcmtkb3duXCIpO1xyXG5cdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XHJcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oXCJbQXN0cm8gQ29tcG9zZXJdIE1EWCBleHRlbnNpb24gYWxyZWFkeSByZWdpc3RlcmVkOlwiLCBlcnJvcik7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBIYW5kbGUgbGF5b3V0LXJlYWR5IGluaXRpYWxpemF0aW9uIChkZXNrdG9wIG9ubHkpXHJcblx0XHRcdHRoaXMuYXBwLndvcmtzcGFjZS5vbkxheW91dFJlYWR5KCgpID0+IHtcclxuXHRcdFx0XHR0aGlzLnJlZ2lzdGVyQ3JlYXRlRXZlbnQoKTtcclxuXHRcdFx0XHQvLyBJbml0aWFsaXplIGhlbHAgYnV0dG9uIHJlcGxhY2VtZW50IChkZXNrdG9wIG9ubHkpXHJcblx0XHRcdFx0aWYgKCFQbGF0Zm9ybS5pc01vYmlsZSkge1xyXG5cdFx0XHRcdFx0dGhpcy5zdGFydEhlbHBCdXR0b25Nb25pdG9yKCk7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHR0aGlzLnJlZ2lzdGVyVGl0bGVQcm9wZXJ0eUNsaWNrTGlzdGVuZXIoKTtcclxuXHJcblx0XHRcdFx0Ly8gUnVuIG1pZ3JhdGlvbiBhZnRlciBwbHVnaW4gaXMgZnVsbHkgbG9hZGVkIChub24tYmxvY2tpbmcpXHJcblx0XHRcdFx0dm9pZCB0aGlzLm1pZ3JhdGVTZXR0aW5nc0lmTmVlZGVkKCk7XHJcblx0XHRcdH0pO1xyXG5cclxuXHRcdFx0Ly8gUmVnaXN0ZXIgY29tbWFuZHNcclxuXHRcdFx0cmVnaXN0ZXJDb21tYW5kcyh0aGlzLCB0aGlzLnNldHRpbmdzKTtcclxuXHRcdFx0cmVnaXN0ZXJDb250ZW50VHlwZUNvbW1hbmRzKHRoaXMsIHRoaXMuc2V0dGluZ3MpO1xyXG5cclxuXHRcdFx0Ly8gQWRkIHNldHRpbmdzIHRhYlxyXG5cdFx0XHR0aGlzLnNldHRpbmdzVGFiID0gbmV3IEFzdHJvQ29tcG9zZXJTZXR0aW5nVGFiKHRoaXMuYXBwLCB0aGlzKTtcclxuXHRcdFx0dGhpcy5hZGRTZXR0aW5nVGFiKHRoaXMuc2V0dGluZ3NUYWIpO1xyXG5cclxuXHRcdFx0Ly8gUmVnaXN0ZXIgVUkgZWxlbWVudHNcclxuXHRcdFx0dGhpcy5yZWdpc3RlckNvbnRleHRNZW51KCk7XHJcblx0XHRcdHRoaXMucmVnaXN0ZXJSaWJib25JY29ucygpO1xyXG5cdFx0XHR0aGlzLnNldHVwUmliYm9uQ29udGV4dE1lbnVIYW5kbGluZygpO1xyXG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcclxuXHRcdFx0Y29uc29sZS5lcnJvcihcIltBc3RybyBDb21wb3Nlcl0gQ3JpdGljYWwgZXJyb3IgZHVyaW5nIG9ubG9hZDpcIiwgZXJyb3IpO1xyXG5cdFx0XHRuZXcgTm90aWNlKFwiQXN0cm8gQ29tcG9zZXIgZmFpbGVkIHRvIGxvYWQuIENoZWNrIGNvbnNvbGUgKEN0cmwrU2hpZnQrSSkgZm9yIGRldGFpbHMuXCIpO1xyXG5cdFx0XHR0aHJvdyBlcnJvcjtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdHB1YmxpYyByZWdpc3RlckNyZWF0ZUV2ZW50KCkge1xyXG5cdFx0aWYgKHRoaXMuY3JlYXRlRXZlbnRSZWYpIHtcclxuXHRcdFx0dGhpcy5hcHAudmF1bHQub2ZmcmVmKHRoaXMuY3JlYXRlRXZlbnRSZWYpO1xyXG5cdFx0XHR0aGlzLmNyZWF0ZUV2ZW50UmVmID0gdW5kZWZpbmVkO1xyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGNyZWF0ZUV2ZW50UmVmID0gdGhpcy5hcHAudmF1bHQub24oXCJjcmVhdGVcIiwgKGZpbGUpID0+IHtcclxuXHRcdFx0aWYgKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkge1xyXG5cdFx0XHRcdHRoaXMuY3JlYXRlRXZlbnRTZXJ2aWNlLmhhbmRsZUNyZWF0ZShmaWxlKTtcclxuXHRcdFx0XHR0aGlzLmNsZWFudXBQbHVnaW5DcmVhdGVkRmlsZXMoKTtcclxuXHRcdFx0fVxyXG5cdFx0fSk7XHJcblx0XHR0aGlzLnJlZ2lzdGVyRXZlbnQoY3JlYXRlRXZlbnRSZWYpO1xyXG5cdFx0dGhpcy5jcmVhdGVFdmVudFJlZiA9IGNyZWF0ZUV2ZW50UmVmO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSByZWdpc3RlclRpdGxlUHJvcGVydHlDbGlja0xpc3RlbmVyKCkge1xyXG5cdFx0dGhpcy5yZWdpc3RlckRvbUV2ZW50KGRvY3VtZW50LCBcImNsaWNrXCIsIChldnQ6IE1vdXNlRXZlbnQpID0+IHtcclxuXHRcdFx0aWYgKCF0aGlzLnNldHRpbmdzLnJlbmFtZU9uVGl0bGVDbGljaykgcmV0dXJuO1xyXG5cclxuXHRcdFx0Y29uc3QgdGFyZ2V0ID0gZXZ0LnRhcmdldCBhcyBIVE1MRWxlbWVudDtcclxuXHRcdFx0Y29uc3QgcHJvcGVydHlFbCA9IHRhcmdldC5jbG9zZXN0KFwiLm1ldGFkYXRhLXByb3BlcnR5XCIpO1xyXG5cdFx0XHRpZiAoIXByb3BlcnR5RWwpIHJldHVybjtcclxuXHJcblx0XHRcdGNvbnN0IHByb3BlcnR5S2V5ID0gcHJvcGVydHlFbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXByb3BlcnR5LWtleVwiKTtcclxuXHRcdFx0aWYgKCFwcm9wZXJ0eUtleSkgcmV0dXJuO1xyXG5cclxuXHRcdFx0Y29uc3QgYWN0aXZlRmlsZSA9IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVGaWxlKCk7XHJcblx0XHRcdGlmICghYWN0aXZlRmlsZSkgcmV0dXJuO1xyXG5cclxuXHRcdFx0Y29uc3QgdHlwZUlkID0gdGhpcy5maWxlT3BzLmRldGVybWluZVR5cGUoYWN0aXZlRmlsZSk7XHJcblx0XHRcdGNvbnN0IHRpdGxlS2V5ID0gdGhpcy5maWxlT3BzLmdldFRpdGxlS2V5KHR5cGVJZCk7XHJcblxyXG5cdFx0XHRpZiAocHJvcGVydHlLZXkgPT09IHRpdGxlS2V5KSB7XHJcblx0XHRcdFx0ZXZ0LnByZXZlbnREZWZhdWx0KCk7XHJcblx0XHRcdFx0ZXZ0LnN0b3BQcm9wYWdhdGlvbigpO1xyXG5cdFx0XHRcdHRoaXMucmVuYW1lQ29udGVudEJ5UGF0aChhY3RpdmVGaWxlLnBhdGgpO1xyXG5cdFx0XHR9XHJcblx0XHR9LCB0cnVlKTsgLy8gdXNlIGNhcHR1cmUgcGhhc2VcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgY2xlYW51cFBsdWdpbkNyZWF0ZWRGaWxlcygpIHtcclxuXHRcdGNvbnN0IG5vdyA9IERhdGUubm93KCk7XHJcblx0XHRjb25zdCB0dGwgPSA1ICogNjAgKiAxMDAwOyAvLyA1IG1pbnV0ZXNcclxuXHRcdGZvciAoY29uc3QgW3BhdGgsIHRpbWVzdGFtcF0gb2YgdGhpcy5wbHVnaW5DcmVhdGVkRmlsZXMuZW50cmllcygpKSB7XHJcblx0XHRcdGlmIChub3cgLSB0aW1lc3RhbXAgPiB0dGwpIHtcclxuXHRcdFx0XHR0aGlzLnBsdWdpbkNyZWF0ZWRGaWxlcy5kZWxldGUocGF0aCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdGFzeW5jIGxvYWRTZXR0aW5ncygpIHtcclxuXHRcdGNvbnN0IGxvYWRlZERhdGEgPSAoYXdhaXQgdGhpcy5sb2FkRGF0YSgpKSBhcyB1bmtub3duO1xyXG5cdFx0aWYgKCF0aGlzLnNldHRpbmdzKSB7XHJcblx0XHRcdHRoaXMuc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBERUZBVUxUX1NFVFRJTkdTLCBsb2FkZWREYXRhIGFzIFBhcnRpYWw8QXN0cm9Db21wb3NlclNldHRpbmdzPiB8IG51bGwgfCB1bmRlZmluZWQpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0T2JqZWN0LmFzc2lnbih0aGlzLnNldHRpbmdzLCBsb2FkZWREYXRhIGFzIFBhcnRpYWw8QXN0cm9Db21wb3NlclNldHRpbmdzPiB8IG51bGwgfCB1bmRlZmluZWQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEVuc3VyZSBjb250ZW50VHlwZXMgaXMgYWx3YXlzIGFuIGFycmF5IChuZXZlciB1bmRlZmluZWQgb3IgbnVsbClcclxuXHRcdGlmICghdGhpcy5zZXR0aW5ncy5jb250ZW50VHlwZXMgfHwgIUFycmF5LmlzQXJyYXkodGhpcy5zZXR0aW5ncy5jb250ZW50VHlwZXMpKSB7XHJcblx0XHRcdHRoaXMuc2V0dGluZ3MuY29udGVudFR5cGVzID0gW107XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCF0aGlzLnNldHRpbmdzLm1pZ3JhdGlvbkNvbXBsZXRlZCkge1xyXG5cdFx0XHRjb25zdCBsZWdhY3lTZXR0aW5ncyA9IHRoaXMuc2V0dGluZ3MgYXMgdW5rbm93biBhcyB7IGN1c3RvbUNvbnRlbnRUeXBlcz86IENvbnRlbnRUeXBlW10gfTtcclxuXHRcdFx0Y29uc3QgaGFzTGVnYWN5VHlwZXMgPSBsZWdhY3lTZXR0aW5ncy5jdXN0b21Db250ZW50VHlwZXMgJiYgQXJyYXkuaXNBcnJheShsZWdhY3lTZXR0aW5ncy5jdXN0b21Db250ZW50VHlwZXMpICYmIGxlZ2FjeVNldHRpbmdzLmN1c3RvbUNvbnRlbnRUeXBlcy5sZW5ndGggPiAwO1xyXG5cdFx0XHRjb25zdCBoYXNOZXdUeXBlcyA9IHRoaXMuc2V0dGluZ3MuY29udGVudFR5cGVzICYmIEFycmF5LmlzQXJyYXkodGhpcy5zZXR0aW5ncy5jb250ZW50VHlwZXMpICYmIHRoaXMuc2V0dGluZ3MuY29udGVudFR5cGVzLmxlbmd0aCA+IDA7XHJcblxyXG5cdFx0XHRpZiAoaGFzTGVnYWN5VHlwZXMgJiYgIWhhc05ld1R5cGVzKSB7XHJcblx0XHRcdFx0dGhpcy5zZXR0aW5ncy5jb250ZW50VHlwZXMgPSBsZWdhY3lTZXR0aW5ncy5jdXN0b21Db250ZW50VHlwZXMgfHwgW107XHJcblx0XHRcdH1cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGNvbnN0IGxlZ2FjeUZpZWxkcyA9IFtcclxuXHRcdFx0XHQnY3VzdG9tQ29udGVudFR5cGVzJywgJ2VuYWJsZVVuZGVyc2NvcmVQcmVmaXgnLCAncG9zdHNGb2xkZXInLCAncG9zdHNMaW5rQmFzZVBhdGgnLFxyXG5cdFx0XHRcdCdhdXRvbWF0ZVBvc3RDcmVhdGlvbicsICdjcmVhdGlvbk1vZGUnLCAnaW5kZXhGaWxlTmFtZScsICdleGNsdWRlZERpcmVjdG9yaWVzJyxcclxuXHRcdFx0XHQnb25seUF1dG9tYXRlSW5Qb3N0c0ZvbGRlcicsICdlbmFibGVQYWdlcycsICdwYWdlc0ZvbGRlcicsICdwYWdlc0xpbmtCYXNlUGF0aCcsXHJcblx0XHRcdFx0J3BhZ2VzQ3JlYXRpb25Nb2RlJywgJ3BhZ2VzSW5kZXhGaWxlTmFtZScsICdwYWdlVGVtcGxhdGUnLCAnb25seUF1dG9tYXRlSW5QYWdlc0ZvbGRlcicsXHJcblx0XHRcdFx0J2xpbmtCYXNlUGF0aCcsICdlbmFibGVBdXRvUmVuYW1lJywgJ2VuYWJsZUF1dG9JbnNlcnRGcm9udG1hdHRlcicsICdkcmFmdFN0eWxlJ1xyXG5cdFx0XHRdO1xyXG5cclxuXHRcdFx0Y29uc3Qgc2V0dGluZ3NSZWNvcmQgPSB0aGlzLnNldHRpbmdzIGFzIHVua25vd24gYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XHJcblx0XHRcdGxldCBmaWVsZHNSZW1vdmVkID0gZmFsc2U7XHJcblx0XHRcdGZvciAoY29uc3QgZmllbGQgb2YgbGVnYWN5RmllbGRzKSB7XHJcblx0XHRcdFx0aWYgKHNldHRpbmdzUmVjb3JkW2ZpZWxkXSAhPT0gdW5kZWZpbmVkKSB7XHJcblx0XHRcdFx0XHRkZWxldGUgc2V0dGluZ3NSZWNvcmRbZmllbGRdO1xyXG5cdFx0XHRcdFx0ZmllbGRzUmVtb3ZlZCA9IHRydWU7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdC8vIE9ubHkgc2F2ZSBpZiB3ZSBhY3R1YWxseSBjbGVhbmVkIHVwIGZpZWxkcyB0byBhdm9pZCByZWR1bmRhbnQgd3JpdGVzXHJcblx0XHRcdGlmIChmaWVsZHNSZW1vdmVkKSB7XHJcblx0XHRcdFx0YXdhaXQgdGhpcy5zYXZlU2V0dGluZ3MoKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0YXN5bmMgc2F2ZVNldHRpbmdzKCkge1xyXG5cdFx0YXdhaXQgdGhpcy5zYXZlRGF0YSh0aGlzLnNldHRpbmdzKTtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgcmVnaXN0ZXJDb250ZXh0TWVudSgpIHtcclxuXHRcdHRoaXMucmVnaXN0ZXJFdmVudChcclxuXHRcdFx0dGhpcy5hcHAud29ya3NwYWNlLm9uKCdlZGl0b3ItbWVudScsIChtZW51LCBlZGl0b3IsIHZpZXcpID0+IHtcclxuXHRcdFx0XHRpZiAoIXRoaXMuc2V0dGluZ3MuZW5hYmxlQ29weUhlYWRpbmdMaW5rKSB7XHJcblx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBjdXJzb3IgPSBlZGl0b3IuZ2V0Q3Vyc29yKCk7XHJcblx0XHRcdFx0Y29uc3QgZmlsZSA9IHZpZXcuZmlsZTtcclxuXHJcblx0XHRcdFx0aWYgKCEoZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSkge1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0Y29uc3QgaGVhZGluZyA9IHRoaXMuaGVhZGluZ0xpbmtHZW5lcmF0b3IuZmluZEhlYWRpbmdBdExpbmUodGhpcy5hcHAsIGZpbGUsIGN1cnNvci5saW5lKTtcclxuXHJcblx0XHRcdFx0aWYgKGhlYWRpbmcpIHtcclxuXHRcdFx0XHRcdGNvbnN0IGZ1bGxMaW5rID0gdGhpcy5oZWFkaW5nTGlua0dlbmVyYXRvci5nZW5lcmF0ZUxpbmsodGhpcy5hcHAsIGZpbGUsIGhlYWRpbmcpO1xyXG5cdFx0XHRcdFx0Y29uc3QgdXJsT25seSA9IHRoaXMuaGVhZGluZ0xpbmtHZW5lcmF0b3IuZXh0cmFjdFVybChmdWxsTGluayk7XHJcblxyXG5cdFx0XHRcdFx0bWVudS5hZGRJdGVtKChpdGVtKSA9PiB7XHJcblx0XHRcdFx0XHRcdGl0ZW1cclxuXHRcdFx0XHRcdFx0XHQuc2V0VGl0bGUoJ0NvcHkgaGVhZGluZyBsaW5rJylcclxuXHRcdFx0XHRcdFx0XHQuc2V0SWNvbignbGluay0yJylcclxuXHRcdFx0XHRcdFx0XHQub25DbGljayhhc3luYyAoKSA9PiB7XHJcblx0XHRcdFx0XHRcdFx0XHRhd2FpdCBuYXZpZ2F0b3IuY2xpcGJvYXJkLndyaXRlVGV4dCh1cmxPbmx5KTtcclxuXHRcdFx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoJ0hlYWRpbmcgbGluayBjb3BpZWQgdG8gY2xpcGJvYXJkJyk7XHJcblx0XHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9KTtcclxuXHJcblx0XHRcdFx0XHRtZW51LmFkZEl0ZW0oKGl0ZW0pID0+IHtcclxuXHRcdFx0XHRcdFx0aXRlbVxyXG5cdFx0XHRcdFx0XHRcdC5zZXRUaXRsZSgnQ29weSBoZWFkaW5nIGxpbmsgd2l0aCB0ZXh0JylcclxuXHRcdFx0XHRcdFx0XHQuc2V0SWNvbignaGVhZGluZycpXHJcblx0XHRcdFx0XHRcdFx0Lm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xyXG5cdFx0XHRcdFx0XHRcdFx0YXdhaXQgbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQoZnVsbExpbmspO1xyXG5cdFx0XHRcdFx0XHRcdFx0bmV3IE5vdGljZSgnSGVhZGluZyBsaW5rIHdpdGggdGV4dCBjb3BpZWQgdG8gY2xpcGJvYXJkJyk7XHJcblx0XHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0pXHJcblx0XHQpO1xyXG5cdH1cclxuXHJcblx0cmVuYW1lQ29udGVudEJ5UGF0aChmaWxlUGF0aDogc3RyaW5nKTogdm9pZCB7XHJcblx0XHRyZW5hbWVDb250ZW50QnlQYXRoRnVuY3Rpb24odGhpcy5hcHAsIGZpbGVQYXRoLCB0aGlzLnNldHRpbmdzLCB0aGlzKTtcclxuXHR9XHJcblxyXG5cdHB1YmxpYyByZWdpc3RlclJpYmJvbkljb25zKCkge1xyXG5cdFx0aWYgKFBsYXRmb3JtLmlzTW9iaWxlKSB7XHJcblx0XHRcdGlmICh0aGlzLnRlcm1pbmFsUmliYm9uSWNvbikge1xyXG5cdFx0XHRcdHRyeSB7IGlmICh0aGlzLnRlcm1pbmFsUmliYm9uSWNvbi5wYXJlbnROb2RlKSB0aGlzLnRlcm1pbmFsUmliYm9uSWNvbi5yZW1vdmUoKTsgfSBjYXRjaCB7IC8qIElnbm9yZSAqLyB9XHJcblx0XHRcdFx0dGhpcy50ZXJtaW5hbFJpYmJvbkljb24gPSBudWxsO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICh0aGlzLmNvbmZpZ1JpYmJvbkljb24pIHtcclxuXHRcdFx0XHR0cnkgeyBpZiAodGhpcy5jb25maWdSaWJib25JY29uLnBhcmVudE5vZGUpIHRoaXMuY29uZmlnUmliYm9uSWNvbi5yZW1vdmUoKTsgfSBjYXRjaCB7IC8qIElnbm9yZSAqLyB9XHJcblx0XHRcdFx0dGhpcy5jb25maWdSaWJib25JY29uID0gbnVsbDtcclxuXHRcdFx0fVxyXG5cdFx0XHR0cnkge1xyXG5cdFx0XHRcdGNvbnN0IHRlcm1pbmFsSWNvbnMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2lkZS1kb2NrLXJpYmJvbi1hY3Rpb25bYXJpYS1sYWJlbD1cIk9wZW4gcHJvamVjdCB0ZXJtaW5hbFwiXScpO1xyXG5cdFx0XHRcdHRlcm1pbmFsSWNvbnMuZm9yRWFjaCgoaWNvbjogRWxlbWVudCkgPT4gaWNvbi5yZW1vdmUoKSk7XHJcblx0XHRcdFx0Y29uc3QgY29uZmlnSWNvbnMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCcuc2lkZS1kb2NrLXJpYmJvbi1hY3Rpb25bYXJpYS1sYWJlbD1cIkVkaXQgYXN0cm8gY29uZmlnXCJdJyk7XHJcblx0XHRcdFx0Y29uZmlnSWNvbnMuZm9yRWFjaCgoaWNvbjogRWxlbWVudCkgPT4gaWNvbi5yZW1vdmUoKSk7XHJcblx0XHRcdH0gY2F0Y2ggeyAvKiBJZ25vcmUgKi8gfVxyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgdGVybWluYWxTaG91bGRFeGlzdCA9IHRoaXMuc2V0dGluZ3MuZW5hYmxlVGVybWluYWxSaWJib25JY29uICYmIHRoaXMuc2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZDtcclxuXHRcdGNvbnN0IGNvbmZpZ1Nob3VsZEV4aXN0ID0gdGhpcy5zZXR0aW5ncy5lbmFibGVDb25maWdSaWJib25JY29uICYmIHRoaXMuc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kO1xyXG5cclxuXHRcdGlmICh0aGlzLnRlcm1pbmFsUmliYm9uSWNvbikge1xyXG5cdFx0XHR0cnkgeyBpZiAodGhpcy50ZXJtaW5hbFJpYmJvbkljb24ucGFyZW50Tm9kZSkgdGhpcy50ZXJtaW5hbFJpYmJvbkljb24ucmVtb3ZlKCk7IH0gY2F0Y2ggeyAvKiBJZ25vcmUgKi8gfVxyXG5cdFx0XHR0aGlzLnRlcm1pbmFsUmliYm9uSWNvbiA9IG51bGw7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKHRoaXMuY29uZmlnUmliYm9uSWNvbikge1xyXG5cdFx0XHR0cnkgeyBpZiAodGhpcy5jb25maWdSaWJib25JY29uLnBhcmVudE5vZGUpIHRoaXMuY29uZmlnUmliYm9uSWNvbi5yZW1vdmUoKTsgfSBjYXRjaCB7IC8qIElnbm9yZSAqLyB9XHJcblx0XHRcdHRoaXMuY29uZmlnUmliYm9uSWNvbiA9IG51bGw7XHJcblx0XHR9XHJcblxyXG5cdFx0dHJ5IHtcclxuXHRcdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnNpZGUtZG9jay1yaWJib24tYWN0aW9uW2FyaWEtbGFiZWw9XCJPcGVuIHByb2plY3QgdGVybWluYWxcIl0nKS5mb3JFYWNoKGVsID0+IGVsLnJlbW92ZSgpKTtcclxuXHRcdFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnNpZGUtZG9jay1yaWJib24tYWN0aW9uW2FyaWEtbGFiZWw9XCJFZGl0IGFzdHJvIGNvbmZpZ1wiXScpLmZvckVhY2goZWwgPT4gZWwucmVtb3ZlKCkpO1xyXG5cdFx0fSBjYXRjaCB7IC8qIElnbm9yZSAqLyB9XHJcblxyXG5cdFx0aWYgKHRlcm1pbmFsU2hvdWxkRXhpc3QpIHtcclxuXHRcdFx0dGhpcy50ZXJtaW5hbFJpYmJvbkljb24gPSB0aGlzLmFkZFJpYmJvbkljb24oJ3Rlcm1pbmFsLXNxdWFyZScsICdPcGVuIHByb2plY3QgdGVybWluYWwnLCAoKSA9PiB7XHJcblx0XHRcdFx0aWYgKCF0aGlzLnNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQpIHtcclxuXHRcdFx0XHRcdG5ldyBOb3RpY2UoXCJPcGVuIHRlcm1pbmFsIGNvbW1hbmQgaXMgZGlzYWJsZWQuXCIpO1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRvcGVuVGVybWluYWxJblByb2plY3RSb290KHRoaXMuYXBwLCB0aGlzLnNldHRpbmdzKTtcclxuXHRcdFx0fSk7XHJcblx0XHRcdGlmICh0aGlzLnRlcm1pbmFsUmliYm9uSWNvbikgdGhpcy50ZXJtaW5hbFJpYmJvbkljb24uc2V0QXR0cmlidXRlKCdkYXRhLWFzdHJvLWNvbXBvc2VyLXRlcm1pbmFsLXJpYmJvbicsICd0cnVlJyk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKGNvbmZpZ1Nob3VsZEV4aXN0KSB7XHJcblx0XHRcdHRoaXMuY29uZmlnUmliYm9uSWNvbiA9IHRoaXMuYWRkUmliYm9uSWNvbigncm9ja2V0JywgJ0VkaXQgYXN0cm8gY29uZmlnJywgYXN5bmMgKCkgPT4ge1xyXG5cdFx0XHRcdGlmICghdGhpcy5zZXR0aW5ncy5lbmFibGVPcGVuQ29uZmlnRmlsZUNvbW1hbmQpIHtcclxuXHRcdFx0XHRcdG5ldyBOb3RpY2UoXCJFZGl0IGNvbmZpZyBmaWxlIGNvbW1hbmQgaXMgZGlzYWJsZWQuXCIpO1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRhd2FpdCBvcGVuQ29uZmlnRmlsZSh0aGlzLmFwcCwgdGhpcy5zZXR0aW5ncyk7XHJcblx0XHRcdH0pO1xyXG5cdFx0XHRpZiAodGhpcy5jb25maWdSaWJib25JY29uKSB0aGlzLmNvbmZpZ1JpYmJvbkljb24uc2V0QXR0cmlidXRlKCdkYXRhLWFzdHJvLWNvbXBvc2VyLWNvbmZpZy1yaWJib24nLCAndHJ1ZScpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMudXBkYXRlUmliYm9uQ29udGV4dE1lbnVDU1MoKTtcclxuXHRcdHRoaXMuc2V0dXBSaWJib25Db250ZXh0TWVudU9ic2VydmVyKCk7XHJcblx0fVxyXG5cclxuXHRvbnVubG9hZCgpIHtcclxuXHRcdHRoaXMuZnJvbnRtYXR0ZXJTZXJ2aWNlPy5kZXN0cm95KCk7XHJcblx0XHRpZiAodGhpcy50ZXJtaW5hbFJpYmJvbkljb24pIHtcclxuXHRcdFx0dGhpcy50ZXJtaW5hbFJpYmJvbkljb24ucmVtb3ZlKCk7XHJcblx0XHRcdHRoaXMudGVybWluYWxSaWJib25JY29uID0gbnVsbDtcclxuXHRcdH1cclxuXHRcdGlmICh0aGlzLmNvbmZpZ1JpYmJvbkljb24pIHtcclxuXHRcdFx0dGhpcy5jb25maWdSaWJib25JY29uLnJlbW92ZSgpO1xyXG5cdFx0XHR0aGlzLmNvbmZpZ1JpYmJvbkljb24gPSBudWxsO1xyXG5cdFx0fVxyXG5cdFx0aWYgKHRoaXMucmliYm9uQ29udGV4dE1lbnVPYnNlcnZlcikge1xyXG5cdFx0XHR0aGlzLnJpYmJvbkNvbnRleHRNZW51T2JzZXJ2ZXIuZGlzY29ubmVjdCgpO1xyXG5cdFx0XHR0aGlzLnJpYmJvbkNvbnRleHRNZW51T2JzZXJ2ZXIgPSB1bmRlZmluZWQ7XHJcblx0XHR9XHJcblx0XHRkb2N1bWVudC5ib2R5LnJlbW92ZUNsYXNzKCdhc3Ryby1jb21wb3Nlci1oaWRlLXRlcm1pbmFsLWljb24nKTtcclxuXHRcdGRvY3VtZW50LmJvZHkucmVtb3ZlQ2xhc3MoJ2FzdHJvLWNvbXBvc2VyLWhpZGUtY29uZmlnLWljb24nKTtcclxuXHRcdGlmICh0aGlzLmhlbHBCdXR0b25PYnNlcnZlcikge1xyXG5cdFx0XHR0aGlzLmhlbHBCdXR0b25PYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcblx0XHRcdHRoaXMuaGVscEJ1dHRvbk9ic2VydmVyID0gdW5kZWZpbmVkO1xyXG5cdFx0fVxyXG5cdFx0aWYgKHRoaXMuY3VzdG9tSGVscEJ1dHRvbikge1xyXG5cdFx0XHR0aGlzLmN1c3RvbUhlbHBCdXR0b24ucmVtb3ZlKCk7XHJcblx0XHRcdHRoaXMuY3VzdG9tSGVscEJ1dHRvbiA9IHVuZGVmaW5lZDtcclxuXHRcdH1cclxuXHRcdHRoaXMuaGVscEJ1dHRvbkVsZW1lbnQgPSB1bmRlZmluZWQ7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIHNldHVwUmliYm9uQ29udGV4dE1lbnVIYW5kbGluZygpIHtcclxuXHRcdHRoaXMudXBkYXRlUmliYm9uQ29udGV4dE1lbnVDU1MoKTtcclxuXHRcdHRoaXMuc2V0dXBSaWJib25Db250ZXh0TWVudU9ic2VydmVyKCk7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIHVwZGF0ZVJpYmJvbkNvbnRleHRNZW51Q1NTKCkge1xyXG5cdFx0Y29uc3QgdGVybWluYWxTaG91bGRCZUhpZGRlbiA9ICF0aGlzLnNldHRpbmdzLmVuYWJsZVRlcm1pbmFsUmliYm9uSWNvbiB8fCAhdGhpcy5zZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kO1xyXG5cdFx0Y29uc3QgY29uZmlnU2hvdWxkQmVIaWRkZW4gPSAhdGhpcy5zZXR0aW5ncy5lbmFibGVDb25maWdSaWJib25JY29uIHx8ICF0aGlzLnNldHRpbmdzLmVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZDtcclxuXHJcblx0XHRpZiAodGVybWluYWxTaG91bGRCZUhpZGRlbikgZG9jdW1lbnQuYm9keS5hZGRDbGFzcygnYXN0cm8tY29tcG9zZXItaGlkZS10ZXJtaW5hbC1pY29uJyk7XHJcblx0XHRlbHNlIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2xhc3MoJ2FzdHJvLWNvbXBvc2VyLWhpZGUtdGVybWluYWwtaWNvbicpO1xyXG5cclxuXHRcdGlmIChjb25maWdTaG91bGRCZUhpZGRlbikgZG9jdW1lbnQuYm9keS5hZGRDbGFzcygnYXN0cm8tY29tcG9zZXItaGlkZS1jb25maWctaWNvbicpO1xyXG5cdFx0ZWxzZSBkb2N1bWVudC5ib2R5LnJlbW92ZUNsYXNzKCdhc3Ryby1jb21wb3Nlci1oaWRlLWNvbmZpZy1pY29uJyk7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIHNldHVwUmliYm9uQ29udGV4dE1lbnVPYnNlcnZlcigpIHtcclxuXHRcdGlmICh0aGlzLnJpYmJvbkNvbnRleHRNZW51T2JzZXJ2ZXIpIHRoaXMucmliYm9uQ29udGV4dE1lbnVPYnNlcnZlci5kaXNjb25uZWN0KCk7XHJcblxyXG5cdFx0Y29uc3QgdGVybWluYWxTaG91bGRCZUhpZGRlbiA9ICF0aGlzLnNldHRpbmdzLmVuYWJsZVRlcm1pbmFsUmliYm9uSWNvbiB8fCAhdGhpcy5zZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kO1xyXG5cdFx0Y29uc3QgY29uZmlnU2hvdWxkQmVIaWRkZW4gPSAhdGhpcy5zZXR0aW5ncy5lbmFibGVDb25maWdSaWJib25JY29uIHx8ICF0aGlzLnNldHRpbmdzLmVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZDtcclxuXHJcblx0XHRpZiAoIXRlcm1pbmFsU2hvdWxkQmVIaWRkZW4gJiYgIWNvbmZpZ1Nob3VsZEJlSGlkZGVuKSByZXR1cm47XHJcblxyXG5cdFx0dGhpcy5yaWJib25Db250ZXh0TWVudU9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoKG11dGF0aW9ucykgPT4ge1xyXG5cdFx0XHRmb3IgKGNvbnN0IG11dGF0aW9uIG9mIG11dGF0aW9ucykge1xyXG5cdFx0XHRcdGlmIChtdXRhdGlvbi5hZGRlZE5vZGVzLmxlbmd0aCA+IDApIHtcclxuXHRcdFx0XHRcdGZvciAoY29uc3Qgbm9kZSBvZiBBcnJheS5mcm9tKG11dGF0aW9uLmFkZGVkTm9kZXMpKSB7XHJcblx0XHRcdFx0XHRcdGlmIChub2RlIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQpIHtcclxuXHRcdFx0XHRcdFx0XHRpZiAobm9kZS5jbGFzc0xpc3QuY29udGFpbnMoJ21lbnUnKSB8fCBub2RlLnF1ZXJ5U2VsZWN0b3IoJy5tZW51JykpIHtcclxuXHRcdFx0XHRcdFx0XHRcdHRoaXMucmVtb3ZlUmliYm9uSWNvbnNGcm9tQ29udGV4dE1lbnUobm9kZSk7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHJcblx0XHR0aGlzLnJpYmJvbkNvbnRleHRNZW51T2JzZXJ2ZXIub2JzZXJ2ZShkb2N1bWVudC5ib2R5LCB7IGNoaWxkTGlzdDogdHJ1ZSwgc3VidHJlZTogdHJ1ZSB9KTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFN0YXJ0cyBhIHJvYnVzdCBtb25pdG9yIHRoYXQga2VlcHMgdGhlIGhlbHAgYnV0dG9uIGluIHN5bmMgd2l0aCBzZXR0aW5ncy5cclxuXHQgKi9cclxuXHRwcml2YXRlIHN0YXJ0SGVscEJ1dHRvbk1vbml0b3IoKSB7XHJcblx0XHRpZiAodGhpcy5oZWxwQnV0dG9uT2JzZXJ2ZXIpIHRoaXMuaGVscEJ1dHRvbk9ic2VydmVyLmRpc2Nvbm5lY3QoKTtcclxuXHJcblx0XHQvLyBJbW1lZGlhdGUgZmlyc3Qgc3luY1xyXG5cdFx0dGhpcy5zeW5jSGVscEJ1dHRvbigpO1xyXG5cclxuXHRcdGxldCB0aW1lcjogbnVtYmVyIHwgbnVsbCA9IG51bGw7XHJcblx0XHRsZXQgbXV0YXRpb25Db3VudCA9IDA7XHJcblxyXG5cdFx0dGhpcy5oZWxwQnV0dG9uT2JzZXJ2ZXIgPSBuZXcgTXV0YXRpb25PYnNlcnZlcigoKSA9PiB7XHJcblx0XHRcdG11dGF0aW9uQ291bnQrKztcclxuXHRcdFx0aWYgKHRpbWVyKSB3aW5kb3cuY2xlYXJUaW1lb3V0KHRpbWVyKTtcclxuXHJcblx0XHRcdC8vIEZvciB0aGUgZmlyc3QgZmV3IG11dGF0aW9ucyAoZHVyaW5nIHN0YXJ0dXApLCBiZSBzdXBlciBhZ2dyZXNzaXZlXHJcblx0XHRcdC8vIEFmdGVyIHRoYXQsIHVzZSBhIHNtYWxsIGRlYm91bmNlIHRvIHN0YXkgcGVyZm9ybWFudFxyXG5cdFx0XHRjb25zdCBkZWxheSA9IG11dGF0aW9uQ291bnQgPCAyMCA/IDAgOiAxMDA7XHJcblxyXG5cdFx0XHRpZiAoZGVsYXkgPT09IDApIHtcclxuXHRcdFx0XHR0aGlzLnN5bmNIZWxwQnV0dG9uKCk7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0dGltZXIgPSB3aW5kb3cuc2V0VGltZW91dCgoKSA9PiB0aGlzLnN5bmNIZWxwQnV0dG9uKCksIGRlbGF5KTtcclxuXHRcdFx0fVxyXG5cdFx0fSk7XHJcblxyXG5cdFx0Ly8gT2JzZXJ2ZSBib2R5IHdpdGggc3VidHJlZSBhbmQgYXR0cmlidXRlcyAoaW4gY2FzZSBpY29ucy9jbGFzc2VzIGNoYW5nZSlcclxuXHRcdHRoaXMuaGVscEJ1dHRvbk9ic2VydmVyLm9ic2VydmUoZG9jdW1lbnQuYm9keSwge1xyXG5cdFx0XHRjaGlsZExpc3Q6IHRydWUsXHJcblx0XHRcdHN1YnRyZWU6IHRydWUsXHJcblx0XHRcdGF0dHJpYnV0ZXM6IHRydWUsXHJcblx0XHRcdGF0dHJpYnV0ZUZpbHRlcjogWydjbGFzcycsICdzcmMnLCAnYXJpYS1sYWJlbCddXHJcblx0XHR9KTtcclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFN5bmNocm9uaXplcyB0aGUgaGVscCBidXR0b24gc3RhdGUgYmFzZWQgb24gc2V0dGluZ3MuXHJcblx0ICovXHJcblx0cHJpdmF0ZSBzeW5jSGVscEJ1dHRvbigpIHtcclxuXHRcdGNvbnN0IGVuYWJsZWQgPSB0aGlzLnNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudD8uZW5hYmxlZDtcclxuXHJcblx0XHQvLyAxLiBNYW5hZ2UgdGhlIENTUyBjbGFzcyBmb3IgaGlkaW5nIHRoZSBvcmlnaW5hbCBidXR0b25cclxuXHRcdGlmIChlbmFibGVkKSBkb2N1bWVudC5ib2R5LmFkZENsYXNzKCdhc3Ryby1jb21wb3Nlci1oaWRlLWhlbHAtYnV0dG9uJyk7XHJcblx0XHRlbHNlIGRvY3VtZW50LmJvZHkucmVtb3ZlQ2xhc3MoJ2FzdHJvLWNvbXBvc2VyLWhpZGUtaGVscC1idXR0b24nKTtcclxuXHJcblx0XHQvLyAyLiBDbGVhciBjdXN0b20gYnV0dG9uIGlmIGRpc2FibGVkXHJcblx0XHRpZiAoIWVuYWJsZWQpIHtcclxuXHRcdFx0aWYgKHRoaXMuY3VzdG9tSGVscEJ1dHRvbikge1xyXG5cdFx0XHRcdHRoaXMuY3VzdG9tSGVscEJ1dHRvbi5yZW1vdmUoKTtcclxuXHRcdFx0XHR0aGlzLmN1c3RvbUhlbHBCdXR0b24gPSB1bmRlZmluZWQ7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIDMuIExvb2sgZm9yIHRoZSBvcmlnaW5hbCBoZWxwIGJ1dHRvblxyXG5cdFx0Y29uc3Qgc2VsZWN0b3JzID0gW1xyXG5cdFx0XHQnLndvcmtzcGFjZS1kcmF3ZXItdmF1bHQtYWN0aW9ucyAuY2xpY2thYmxlLWljb24gc3ZnLmhlbHAnLFxyXG5cdFx0XHQnLndvcmtzcGFjZS1zaWRlZG9jay12YXVsdC1wcm9maWxlIC5jbGlja2FibGUtaWNvbiBzdmcuaGVscCcsXHJcblx0XHRcdCcud29ya3NwYWNlLWRyYXdlciAuY2xpY2thYmxlLWljb24gc3ZnLmhlbHAnLFxyXG5cdFx0XHQnLmNsaWNrYWJsZS1pY29uIHN2Zy5oZWxwJ1xyXG5cdFx0XTtcclxuXHJcblx0XHRsZXQgaGVscEJ1dHRvblN2ZzogU1ZHRWxlbWVudCB8IG51bGwgPSBudWxsO1xyXG5cdFx0Zm9yIChjb25zdCBzZWxlY3RvciBvZiBzZWxlY3RvcnMpIHtcclxuXHRcdFx0aGVscEJ1dHRvblN2ZyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3IpO1xyXG5cdFx0XHRpZiAoaGVscEJ1dHRvblN2ZykgYnJlYWs7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCFoZWxwQnV0dG9uU3ZnKSByZXR1cm47XHJcblx0XHRjb25zdCBvcmlnaW5hbEhlbHBCdXR0b24gPSBoZWxwQnV0dG9uU3ZnLnBhcmVudEVsZW1lbnQgYXMgSFRNTEVsZW1lbnQ7XHJcblx0XHRpZiAoIW9yaWdpbmFsSGVscEJ1dHRvbikgcmV0dXJuO1xyXG5cclxuXHRcdC8vIDQuIENoZWNrIGlmIHdlIGFscmVhZHkgaGF2ZSBhIHZhbGlkIGN1c3RvbSBidXR0b24gaW4gdGhlIHJpZ2h0IHBsYWNlXHJcblx0XHRjb25zdCBleGlzdGluZ1JlcGxhY2VtZW50ID0gb3JpZ2luYWxIZWxwQnV0dG9uLnBhcmVudEVsZW1lbnQ/LnF1ZXJ5U2VsZWN0b3IoJ1tkYXRhLWFzdHJvLWNvbXBvc2VyLWhlbHAtcmVwbGFjZW1lbnQ9XCJ0cnVlXCJdJyk7XHJcblx0XHRpZiAoZXhpc3RpbmdSZXBsYWNlbWVudCkge1xyXG5cdFx0XHR0aGlzLmN1c3RvbUhlbHBCdXR0b24gPSBleGlzdGluZ1JlcGxhY2VtZW50IGFzIEhUTUxFbGVtZW50O1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gNS4gQ3JlYXRlIGFuZCBpbmplY3QgdGhlIHJlcGxhY2VtZW50XHJcblx0XHRjb25zdCBjdXN0b21CdXR0b24gPSBvcmlnaW5hbEhlbHBCdXR0b24uY2xvbmVOb2RlKHRydWUpIGFzIEhUTUxFbGVtZW50O1xyXG5cdFx0Y3VzdG9tQnV0dG9uLmFkZENsYXNzKFwiYXN0cm8tY29tcG9zZXItaGVscC1yZXBsYWNlbWVudFwiKTtcclxuXHRcdGN1c3RvbUJ1dHRvbi5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtbGFiZWwnKTtcclxuXHRcdGN1c3RvbUJ1dHRvbi5zZXRBdHRyaWJ1dGUoJ2RhdGEtYXN0cm8tY29tcG9zZXItaGVscC1yZXBsYWNlbWVudCcsICd0cnVlJyk7XHJcblx0XHRjdXN0b21CdXR0b24ub25jbGljayA9IG51bGw7XHJcblxyXG5cdFx0Y29uc3QgaWNvbkNvbnRhaW5lciA9IGN1c3RvbUJ1dHRvbi5xdWVyeVNlbGVjdG9yKCdzdmcnKT8ucGFyZW50RWxlbWVudCB8fCBjdXN0b21CdXR0b247XHJcblx0XHR0cnkge1xyXG5cdFx0XHRpZiAoaWNvbkNvbnRhaW5lciBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSB7XHJcblx0XHRcdFx0c2V0SWNvbihpY29uQ29udGFpbmVyLCB0aGlzLnNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudCEuaWNvbklkKTtcclxuXHRcdFx0fVxyXG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcclxuXHRcdFx0Y29uc29sZS53YXJuKCdbQXN0cm8gQ29tcG9zZXJdIEVycm9yIHNldHRpbmcgcmVwbGFjZW1lbnQgaWNvbjonLCBlcnJvcik7XHJcblx0XHR9XHJcblxyXG5cdFx0Y3VzdG9tQnV0dG9uLmFkZEV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgKGV2dDogTW91c2VFdmVudCkgPT4ge1xyXG5cdFx0XHRldnQucHJldmVudERlZmF1bHQoKTtcclxuXHRcdFx0ZXZ0LnN0b3BQcm9wYWdhdGlvbigpO1xyXG5cclxuXHRcdFx0Y29uc3QgY29tbWFuZElkID0gdGhpcy5zZXR0aW5ncy5oZWxwQnV0dG9uUmVwbGFjZW1lbnQ/LmNvbW1hbmRJZDtcclxuXHRcdFx0aWYgKGNvbW1hbmRJZCkge1xyXG5cdFx0XHRcdGNvbnN0IGFwcFdpdGhDb21tYW5kcyA9IHRoaXMuYXBwIGFzIHVua25vd24gYXMgeyBjb21tYW5kcz86IHsgZXhlY3V0ZUNvbW1hbmRCeUlkPzogKGlkOiBzdHJpbmcpID0+IFByb21pc2U8dm9pZD4gfSB9O1xyXG5cdFx0XHRcdGlmIChhcHBXaXRoQ29tbWFuZHMuY29tbWFuZHM/LmV4ZWN1dGVDb21tYW5kQnlJZCkge1xyXG5cdFx0XHRcdFx0dm9pZCBhcHBXaXRoQ29tbWFuZHMuY29tbWFuZHMuZXhlY3V0ZUNvbW1hbmRCeUlkKGNvbW1hbmRJZCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9LCB0cnVlKTtcclxuXHJcblx0XHRvcmlnaW5hbEhlbHBCdXR0b24ucGFyZW50RWxlbWVudD8uaW5zZXJ0QmVmb3JlKGN1c3RvbUJ1dHRvbiwgb3JpZ2luYWxIZWxwQnV0dG9uKTtcclxuXHRcdHRoaXMuY3VzdG9tSGVscEJ1dHRvbiA9IGN1c3RvbUJ1dHRvbjtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgcmVzdG9yZUhlbHBCdXR0b24oKSB7XHJcblx0XHRkb2N1bWVudC5ib2R5LnJlbW92ZUNsYXNzKCdhc3Ryby1jb21wb3Nlci1oaWRlLWhlbHAtYnV0dG9uJyk7XHJcblx0XHRpZiAodGhpcy5jdXN0b21IZWxwQnV0dG9uKSB7XHJcblx0XHRcdHRoaXMuY3VzdG9tSGVscEJ1dHRvbi5yZW1vdmUoKTtcclxuXHRcdFx0dGhpcy5jdXN0b21IZWxwQnV0dG9uID0gdW5kZWZpbmVkO1xyXG5cdFx0fVxyXG5cdFx0dGhpcy5oZWxwQnV0dG9uRWxlbWVudCA9IHVuZGVmaW5lZDtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgcmVtb3ZlUmliYm9uSWNvbnNGcm9tQ29udGV4dE1lbnUobWVudUVsZW1lbnQ6IEhUTUxFbGVtZW50KSB7XHJcblx0XHRjb25zdCB0ZXJtaW5hbFNob3VsZEJlSGlkZGVuID0gIXRoaXMuc2V0dGluZ3MuZW5hYmxlVGVybWluYWxSaWJib25JY29uIHx8ICF0aGlzLnNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQ7XHJcblx0XHRjb25zdCBjb25maWdTaG91bGRCZUhpZGRlbiA9ICF0aGlzLnNldHRpbmdzLmVuYWJsZUNvbmZpZ1JpYmJvbkljb24gfHwgIXRoaXMuc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kO1xyXG5cclxuXHRcdGNvbnN0IG1lbnVJdGVtcyA9IG1lbnVFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJy5tZW51LWl0ZW0nKTtcclxuXHRcdGZvciAoY29uc3QgaXRlbSBvZiBBcnJheS5mcm9tKG1lbnVJdGVtcykpIHtcclxuXHRcdFx0Y29uc3Qgc3ZnID0gaXRlbS5xdWVyeVNlbGVjdG9yKCdzdmcnKTtcclxuXHRcdFx0aWYgKHN2Zykge1xyXG5cdFx0XHRcdGxldCBpY29uTmFtZSA9IHN2Zy5nZXRBdHRyaWJ1dGUoJ2RhdGEtbHVjaWRlJykgfHwgc3ZnLmdldEF0dHJpYnV0ZSgneG1sbnM6bHVjaWRlJykgfHxcclxuXHRcdFx0XHRcdHN2Zy5nZXRBdHRyaWJ1dGUoJ2RhdGEtaWNvbicpIHx8XHJcblx0XHRcdFx0XHQoc3ZnLmNsYXNzTGlzdC5jb250YWlucygnbHVjaWRlLXRlcm1pbmFsLXNxdWFyZScpID8gJ3Rlcm1pbmFsLXNxdWFyZScgOiBudWxsKSB8fFxyXG5cdFx0XHRcdFx0KHN2Zy5jbGFzc0xpc3QuY29udGFpbnMoJ2x1Y2lkZS1yb2NrZXQnKSA/ICdyb2NrZXQnIDogbnVsbCkgfHxcclxuXHRcdFx0XHRcdChzdmcuY2xhc3NMaXN0LmNvbnRhaW5zKCdsdWNpZGUtd3JlbmNoJykgPyAnd3JlbmNoJyA6IG51bGwpO1xyXG5cclxuXHRcdFx0XHRpZiAoaWNvbk5hbWUpIGljb25OYW1lID0gaWNvbk5hbWUucmVwbGFjZSgvXmx1Y2lkZS0vLCAnJyk7XHJcblxyXG5cdFx0XHRcdGlmICh0ZXJtaW5hbFNob3VsZEJlSGlkZGVuICYmIGljb25OYW1lID09PSAndGVybWluYWwtc3F1YXJlJykge1xyXG5cdFx0XHRcdFx0aWYgKGl0ZW0udGV4dENvbnRlbnQ/LnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoJ3Rlcm1pbmFsJykpIGl0ZW0ucmVtb3ZlKCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGlmIChjb25maWdTaG91bGRCZUhpZGRlbiAmJiAoaWNvbk5hbWUgPT09ICdyb2NrZXQnIHx8IGljb25OYW1lID09PSAnd3JlbmNoJykpIHtcclxuXHRcdFx0XHRcdGlmIChpdGVtLnRleHRDb250ZW50Py50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKCdjb25maWcnKSkgaXRlbS5yZW1vdmUoKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcbn1cclxuIiwgImltcG9ydCB7IFRGaWxlLCBQbHVnaW5TZXR0aW5nVGFiIH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB7XHJcblx0ZGVmYXVsdFRlbXBsYXRlOiBzdHJpbmc7IC8vIEtlcHQgdGVtcG9yYXJpbHkgZm9yIG1pZ3JhdGlvblxyXG5cdGF1dG9JbnNlcnRQcm9wZXJ0aWVzOiBib29sZWFuO1xyXG5cdGRhdGVGb3JtYXQ6IHN0cmluZztcclxuXHRlbmFibGVDb3B5SGVhZGluZ0xpbms6IGJvb2xlYW47XHJcblx0Y29weUhlYWRpbmdMaW5rRm9ybWF0OiBcIm9ic2lkaWFuXCIgfCBcImFzdHJvXCI7XHJcblx0YWRkVHJhaWxpbmdTbGFzaFRvTGlua3M6IGJvb2xlYW47XHJcblx0ZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZDogYm9vbGVhbjtcclxuXHR0ZXJtaW5hbFByb2plY3RSb290UGF0aDogc3RyaW5nO1xyXG5cdHRlcm1pbmFsQXBwbGljYXRpb25OYW1lOiBzdHJpbmc7XHJcblx0ZW5hYmxlVGVybWluYWxEZWJ1Z0xvZ2dpbmc6IGJvb2xlYW47XHJcblx0ZW5hYmxlVGVybWluYWxSaWJib25JY29uOiBib29sZWFuO1xyXG5cdGVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZDogYm9vbGVhbjtcclxuXHRjb25maWdGaWxlUGF0aDogc3RyaW5nO1xyXG5cdGVuYWJsZUNvbmZpZ1JpYmJvbkljb246IGJvb2xlYW47XHJcblx0Y29udGVudFR5cGVzOiBDb250ZW50VHlwZVtdO1xyXG5cdGhlbHBCdXR0b25SZXBsYWNlbWVudDogSGVscEJ1dHRvblJlcGxhY2VtZW50U2V0dGluZ3M7XHJcblx0bWlncmF0aW9uQ29tcGxldGVkOiBib29sZWFuO1xyXG5cdHNob3dNZHhGaWxlc0luRXhwbG9yZXI6IGJvb2xlYW47XHJcblx0cHJvY2Vzc0JhY2tncm91bmRGaWxlQ2hhbmdlczogYm9vbGVhbjtcclxuXHRzeW5jRHJhZnREYXRlOiBib29sZWFuO1xyXG5cdGRyYWZ0RGV0ZWN0aW9uTW9kZTogJ3Byb3BlcnR5JyB8ICd1bmRlcnNjb3JlLXByZWZpeCc7XHJcblx0ZHJhZnRQcm9wZXJ0eTogc3RyaW5nO1xyXG5cdGRyYWZ0TG9naWM6ICd0cnVlLWlzLWRyYWZ0JyB8ICdmYWxzZS1pcy1kcmFmdCc7XHJcblx0cHVibGlzaERhdGVGaWVsZDogc3RyaW5nO1xyXG5cdHJlbmFtZU9uVGl0bGVDbGljazogYm9vbGVhbjtcclxuXHQvLyBMZWdhY3kgZmllbGRzIChrZXB0IGZvciBtaWdyYXRpb24sIGlnbm9yZWQgYWZ0ZXIgbWlncmF0aW9uKVxyXG5cdGVuYWJsZVVuZGVyc2NvcmVQcmVmaXg/OiBib29sZWFuO1xyXG5cdHBvc3RzRm9sZGVyPzogc3RyaW5nO1xyXG5cdHBvc3RzTGlua0Jhc2VQYXRoPzogc3RyaW5nO1xyXG5cdGF1dG9tYXRlUG9zdENyZWF0aW9uPzogYm9vbGVhbjtcclxuXHRjcmVhdGlvbk1vZGU/OiBcImZpbGVcIiB8IFwiZm9sZGVyXCI7XHJcblx0aW5kZXhGaWxlTmFtZT86IHN0cmluZztcclxuXHRleGNsdWRlZERpcmVjdG9yaWVzPzogc3RyaW5nO1xyXG5cdG9ubHlBdXRvbWF0ZUluUG9zdHNGb2xkZXI/OiBib29sZWFuO1xyXG5cdGVuYWJsZVBhZ2VzPzogYm9vbGVhbjtcclxuXHRwYWdlc0ZvbGRlcj86IHN0cmluZztcclxuXHRwYWdlc0xpbmtCYXNlUGF0aD86IHN0cmluZztcclxuXHRwYWdlc0NyZWF0aW9uTW9kZT86IFwiZmlsZVwiIHwgXCJmb2xkZXJcIjtcclxuXHRwYWdlc0luZGV4RmlsZU5hbWU/OiBzdHJpbmc7XHJcblx0cGFnZVRlbXBsYXRlPzogc3RyaW5nO1xyXG5cdG9ubHlBdXRvbWF0ZUluUGFnZXNGb2xkZXI/OiBib29sZWFuO1xyXG5cdGN1c3RvbUNvbnRlbnRUeXBlcz86IENvbnRlbnRUeXBlW107IC8vIExlZ2FjeSBuYW1lXHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgSGVscEJ1dHRvblJlcGxhY2VtZW50U2V0dGluZ3Mge1xyXG5cdGVuYWJsZWQ6IGJvb2xlYW47XHJcblx0Y29tbWFuZElkOiBzdHJpbmc7XHJcblx0aWNvbklkOiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkRnJvbnRtYXR0ZXIge1xyXG5cdHByb3BlcnRpZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPjtcclxuXHRwcm9wZXJ0aWVzVGV4dDogc3RyaW5nO1xyXG5cdHByb3BlcnRpZXNFbmQ6IG51bWJlcjtcclxuXHRib2R5Q29udGVudDogc3RyaW5nO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFRlbXBsYXRlVmFsdWVzIHtcclxuXHRba2V5OiBzdHJpbmddOiBzdHJpbmdbXSB8IHN0cmluZztcclxufVxyXG5cclxuLy8gQ29udGVudFR5cGUgaXMgbm93IGp1c3QgYSBzdHJpbmcgSUQgLSBubyBkaXN0aW5jdGlvbiBiZXR3ZWVuIGJ1aWx0LWluIGFuZCBjdXN0b20gdHlwZXNcclxuZXhwb3J0IHR5cGUgQ29udGVudFR5cGVJZCA9IHN0cmluZztcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQ29udGVudFR5cGUge1xyXG5cdGlkOiBzdHJpbmc7XHJcblx0bmFtZTogc3RyaW5nO1xyXG5cdGZvbGRlcjogc3RyaW5nO1xyXG5cdGxpbmtCYXNlUGF0aDogc3RyaW5nO1xyXG5cdHRlbXBsYXRlOiBzdHJpbmc7XHJcblx0ZW5hYmxlZDogYm9vbGVhbjtcclxuXHRjcmVhdGlvbk1vZGU6IFwiZmlsZVwiIHwgXCJmb2xkZXJcIjtcclxuXHRpbmRleEZpbGVOYW1lOiBzdHJpbmc7XHJcblx0aWdub3JlU3ViZm9sZGVyczogYm9vbGVhbjtcclxuXHRlbmFibGVVbmRlcnNjb3JlUHJlZml4OiBib29sZWFuO1xyXG5cdHVzZU1keEV4dGVuc2lvbjogYm9vbGVhbjtcclxuXHRtb2RpZmllZERhdGVGaWVsZDogc3RyaW5nO1xyXG5cdGNvbGxhcHNlZD86IGJvb2xlYW47XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgRmlsZUNyZWF0aW9uT3B0aW9ucyB7XHJcblx0ZmlsZTogVEZpbGU7XHJcblx0dGl0bGU6IHN0cmluZztcclxuXHR0eXBlOiBDb250ZW50VHlwZUlkOyAvLyBDb250ZW50IHR5cGUgSUQgKHN0cmluZylcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBSZW5hbWVPcHRpb25zIHtcclxuXHRmaWxlOiBURmlsZTtcclxuXHR0aXRsZTogc3RyaW5nO1xyXG5cdHR5cGU6IENvbnRlbnRUeXBlSWQ7IC8vIENvbnRlbnQgdHlwZSBJRCAoc3RyaW5nKVxyXG59XHJcblxyXG5leHBvcnQgY29uc3QgS05PV05fQVJSQVlfS0VZUyA9IFsndGFncycsICdhbGlhc2VzJywgJ2Nzc2NsYXNzZXMnXSBhcyBjb25zdDtcclxuXHJcbmV4cG9ydCBjb25zdCBDT05TVEFOVFMgPSB7XHJcblx0REVCT1VOQ0VfTVM6IDUwMCxcclxuXHRTVEFUX01USU1FX1RIUkVTSE9MRDogNTAwMCxcclxuXHRFRElUT1JfU1RBQklMSVpFX0RFTEFZOiAxMDAsXHJcblx0RklMRV9FWFBMT1JFUl9SRVZFQUxfREVMQVk6IDIwMCxcclxufSBhcyBjb25zdDtcclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSB7XHJcblx0c2V0dGluZ3M6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncztcclxuXHRzYXZlU2V0dGluZ3MoKTogUHJvbWlzZTx2b2lkPjtcclxuXHRsb2FkU2V0dGluZ3MoKTogUHJvbWlzZTx2b2lkPjtcclxuXHRyZWdpc3RlckNyZWF0ZUV2ZW50KCk6IHZvaWQ7XHJcblx0cmVnaXN0ZXJFdmVudChldmVudFJlZjogYW55KTogdm9pZDtcclxuXHRyZWdpc3RlckV4dGVuc2lvbnMoZXh0ZW5zaW9uczogc3RyaW5nW10sIHZpZXdUeXBlOiBzdHJpbmcpOiB2b2lkO1xyXG5cdGhlYWRpbmdMaW5rR2VuZXJhdG9yOiBhbnk7XHJcblx0ZnJvbnRtYXR0ZXJTZXJ2aWNlOiBhbnk7XHJcblx0cGx1Z2luQ3JlYXRlZEZpbGVzOiBNYXA8c3RyaW5nLCBudW1iZXI+O1xyXG5cdGZpbGVPcHM6IGFueTtcclxuXHRzZXR0aW5nc1RhYj86IFBsdWdpblNldHRpbmdUYWI7XHJcblx0cmVnaXN0ZXJSaWJib25JY29ucz8oKTogdm9pZDtcclxuXHR1cGRhdGVIZWxwQnV0dG9uPygpOiBQcm9taXNlPHZvaWQ+O1xyXG59IiwgImltcG9ydCB7IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB9IGZyb20gXCIuL3R5cGVzXCI7XHJcblxyXG5leHBvcnQgdHlwZSB7IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB9IGZyb20gXCIuL3R5cGVzXCI7XHJcbmV4cG9ydCB7IENPTlNUQU5UUyB9IGZyb20gXCIuL3R5cGVzXCI7XHJcblxyXG5leHBvcnQgY29uc3QgREVGQVVMVF9TRVRUSU5HUzogQXN0cm9Db21wb3NlclNldHRpbmdzID0ge1xyXG5cdGRlZmF1bHRUZW1wbGF0ZTpcclxuXHRcdCctLS1cXG50aXRsZTogXCJ7e3RpdGxlfX1cIlxcbmRhdGU6IHt7ZGF0ZX19XFxudGFnczogW11cXG4tLS1cXG4nLFxyXG5cdGF1dG9JbnNlcnRQcm9wZXJ0aWVzOiB0cnVlLFxyXG5cdGRhdGVGb3JtYXQ6IFwiWVlZWS1NTS1ERFwiLFxyXG5cdGVuYWJsZUNvcHlIZWFkaW5nTGluazogdHJ1ZSxcclxuXHRjb3B5SGVhZGluZ0xpbmtGb3JtYXQ6IFwib2JzaWRpYW5cIixcclxuXHRhZGRUcmFpbGluZ1NsYXNoVG9MaW5rczogZmFsc2UsXHJcblx0ZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZDogZmFsc2UsXHJcblx0dGVybWluYWxQcm9qZWN0Um9vdFBhdGg6IFwiXCIsXHJcblx0dGVybWluYWxBcHBsaWNhdGlvbk5hbWU6IFwiXCIsXHJcblx0ZW5hYmxlVGVybWluYWxEZWJ1Z0xvZ2dpbmc6IGZhbHNlLFxyXG5cdGVuYWJsZVRlcm1pbmFsUmliYm9uSWNvbjogZmFsc2UsXHJcblx0ZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kOiBmYWxzZSxcclxuXHRjb25maWdGaWxlUGF0aDogXCJcIixcclxuXHRlbmFibGVDb25maWdSaWJib25JY29uOiBmYWxzZSxcclxuXHRjb250ZW50VHlwZXM6IFtdLFxyXG5cdG1pZ3JhdGlvbkNvbXBsZXRlZDogZmFsc2UsXHJcblx0aGVscEJ1dHRvblJlcGxhY2VtZW50OiB7XHJcblx0XHRlbmFibGVkOiBmYWxzZSxcclxuXHRcdGNvbW1hbmRJZDogJ2VkaXQtYXN0cm8tY29uZmlnJyxcclxuXHRcdGljb25JZDogJ3JvY2tldCcsXHJcblx0fSxcclxuXHRzaG93TWR4RmlsZXNJbkV4cGxvcmVyOiBmYWxzZSxcclxuXHRwcm9jZXNzQmFja2dyb3VuZEZpbGVDaGFuZ2VzOiB0cnVlLFxyXG5cdHN5bmNEcmFmdERhdGU6IGZhbHNlLFxyXG5cdGRyYWZ0RGV0ZWN0aW9uTW9kZTogXCJwcm9wZXJ0eVwiLFxyXG5cdGRyYWZ0UHJvcGVydHk6IFwiXCIsXHJcblx0ZHJhZnRMb2dpYzogXCJ0cnVlLWlzLWRyYWZ0XCIsXHJcblx0cHVibGlzaERhdGVGaWVsZDogXCJcIixcclxuXHRyZW5hbWVPblRpdGxlQ2xpY2s6IGZhbHNlLFxyXG59O1xyXG4iLCAiaW1wb3J0IHsgUGx1Z2luLCBFZGl0b3IsIE1hcmtkb3duVmlldywgVEZpbGUsIE5vdGljZSwgQXBwLCBNYXJrZG93bkZpbGVJbmZvLCBQbGF0Zm9ybSwgVEZvbGRlciB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgeyBBc3Ryb0NvbXBvc2VyU2V0dGluZ3MsIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UgfSBmcm9tIFwiLi4vdHlwZXNcIjtcclxuaW1wb3J0IHsgRmlsZU9wZXJhdGlvbnMgfSBmcm9tIFwiLi4vdXRpbHMvZmlsZS1vcGVyYXRpb25zXCI7XHJcbmltcG9ydCB7IFRlbXBsYXRlUGFyc2VyIH0gZnJvbSBcIi4uL3V0aWxzL3RlbXBsYXRlLXBhcnNpbmdcIjtcclxuaW1wb3J0IHsgTGlua0NvbnZlcnRlciB9IGZyb20gXCIuLi91dGlscy9saW5rLWNvbnZlcnNpb25cIjtcclxuaW1wb3J0IHsgVGl0bGVNb2RhbCB9IGZyb20gXCIuLi91aS90aXRsZS1tb2RhbFwiO1xyXG5pbXBvcnQgeyB0b0tlYmFiQ2FzZSB9IGZyb20gXCIuLi91dGlscy9zdHJpbmctdXRpbHNcIjtcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckNvbW1hbmRzKHBsdWdpbjogUGx1Z2luLCBzZXR0aW5nczogQXN0cm9Db21wb3NlclNldHRpbmdzKTogdm9pZCB7XHJcblx0Ly8gVGVybWluYWwgYW5kIGNvbmZpZyBjb21tYW5kcyBhcmUgZGVza3RvcC1vbmx5IC0gTkVWRVIgcmVnaXN0ZXIgb24gbW9iaWxlXHJcblx0Ly8gQ2hlY2sgUGxhdGZvcm0uaXNNb2JpbGUgLSBpZiB0cnVlLCB0aGVzZSBjb21tYW5kcyBtdXN0IE5FVkVSIGJlIHJlZ2lzdGVyZWRcclxuXHRjb25zdCBpc01vYmlsZSA9IFBsYXRmb3JtLmlzTW9iaWxlO1xyXG5cclxuXHQvLyBJZiBvbiBtb2JpbGUsIGFic29sdXRlbHkgZG8gbm90IHJlZ2lzdGVyIHRlcm1pbmFsL2NvbmZpZyBjb21tYW5kc1xyXG5cdC8vIFRoZXkgdXNlIE5vZGUuanMvRWxlY3Ryb24gQVBJcyB0aGF0IGRvbid0IGV4aXN0IG9uIG1vYmlsZVxyXG5cdGlmIChpc01vYmlsZSkge1xyXG5cdFx0Ly8gT24gbW9iaWxlLCBvbmx5IHJlZ2lzdGVyIHRoZSBzYWZlIGNvbW1hbmRzIHRoYXQgd29yayBvbiBtb2JpbGVcclxuXHRcdGNvbnN0IHBsdWdpbkludGVyZmFjZSA9IHBsdWdpbiBhcyB1bmtub3duIGFzIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2U7XHJcblx0XHRjb25zdCBmaWxlT3BzID0gbmV3IEZpbGVPcGVyYXRpb25zKHBsdWdpbi5hcHAsIHNldHRpbmdzLCBwbHVnaW5JbnRlcmZhY2UpO1xyXG5cdFx0Y29uc3QgbGlua0NvbnZlcnRlciA9IG5ldyBMaW5rQ29udmVydGVyKHNldHRpbmdzLCBwbHVnaW5JbnRlcmZhY2UpO1xyXG5cclxuXHRcdC8vIFJlZ2lzdGVyIG9ubHkgbW9iaWxlLXNhZmUgY29tbWFuZHNcclxuXHRcdHBsdWdpbi5hZGRDb21tYW5kKHtcclxuXHRcdFx0aWQ6IFwic3RhbmRhcmRpemUtcHJvcGVydGllc1wiLFxyXG5cdFx0XHRuYW1lOiBcIlN0YW5kYXJkaXplIHByb3BlcnRpZXNcIixcclxuXHRcdFx0aWNvbjogXCJmaWxlLWNoZWNrXCIsXHJcblx0XHRcdGVkaXRvckNhbGxiYWNrOiAoZWRpdG9yOiBFZGl0b3IsIGN0eDogTWFya2Rvd25WaWV3IHwgTWFya2Rvd25GaWxlSW5mbykgPT4ge1xyXG5cdFx0XHRcdGNvbnN0IGZpbGUgPSBjdHggaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgPyBjdHguZmlsZSA6IGN0eC5maWxlO1xyXG5cdFx0XHRcdGlmIChmaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcclxuXHRcdFx0XHRcdC8vIEdldCBmcmVzaCBzZXR0aW5ncyBmcm9tIHBsdWdpblxyXG5cdFx0XHRcdFx0Y29uc3QgY3VycmVudFNldHRpbmdzID0gcGx1Z2luSW50ZXJmYWNlLnNldHRpbmdzIHx8IHNldHRpbmdzO1xyXG5cdFx0XHRcdFx0dm9pZCBzdGFuZGFyZGl6ZVByb3BlcnRpZXMocGx1Z2luLmFwcCwgY3VycmVudFNldHRpbmdzLCBmaWxlLCBwbHVnaW5JbnRlcmZhY2UsIGVkaXRvcik7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9LFxyXG5cdFx0fSk7XHJcblxyXG5cdFx0cGx1Z2luLmFkZENvbW1hbmQoe1xyXG5cdFx0XHRpZDogXCJjb252ZXJ0LXdpa2lsaW5rcy1hc3Ryb1wiLFxyXG5cdFx0XHRuYW1lOiBcIkNvbnZlcnQgaW50ZXJuYWwgbGlua3MgZm9yIGFzdHJvXCIsXHJcblx0XHRcdGljb246IFwibGluay0yXCIsXHJcblx0XHRcdGVkaXRvckNhbGxiYWNrOiAoZWRpdG9yOiBFZGl0b3IsIGN0eDogTWFya2Rvd25WaWV3IHwgTWFya2Rvd25GaWxlSW5mbykgPT4ge1xyXG5cdFx0XHRcdGNvbnN0IGZpbGUgPSBjdHggaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgPyBjdHguZmlsZSA6IGN0eC5maWxlO1xyXG5cdFx0XHRcdGlmIChmaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcclxuXHRcdFx0XHRcdGxpbmtDb252ZXJ0ZXIuY29udmVydFdpa2lsaW5rc0ZvckFzdHJvKGVkaXRvciwgZmlsZSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9LFxyXG5cdFx0fSk7XHJcblxyXG5cdFx0Ly8gSGVscGVyIGZ1bmN0aW9uIGZvciByZW5hbWUgY29tbWFuZCAobW9iaWxlIHZlcnNpb24pXHJcblx0XHQvLyBVc2VzIHRoZSBzYW1lIGxvZ2ljIGFzIEZpbGVPcGVyYXRpb25zLmRldGVybWluZVR5cGUoKSB0byBlbnN1cmUgY29uc2lzdGVuY3lcclxuXHRcdGZ1bmN0aW9uIGhhc01hdGNoaW5nQ29udGVudFR5cGUoZmlsZTogVEZpbGUsIHNldHRpbmdzOiBBc3Ryb0NvbXBvc2VyU2V0dGluZ3MpOiBib29sZWFuIHtcclxuXHRcdFx0Y29uc3QgdHlwZSA9IGZpbGVPcHMuZGV0ZXJtaW5lVHlwZShmaWxlKTtcclxuXHRcdFx0Ly8gSWYgZGV0ZXJtaW5lVHlwZSByZXR1cm5zIFwibm90ZVwiLCBpdCBtZWFucyBubyBjb250ZW50IHR5cGUgbWF0Y2hlZFxyXG5cdFx0XHRpZiAodHlwZSA9PT0gXCJub3RlXCIpIHtcclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdH1cclxuXHRcdFx0Ly8gQ2hlY2sgaWYgdGhlIG1hdGNoZWQgY29udGVudCB0eXBlIGlzIGVuYWJsZWRcclxuXHRcdFx0Y29uc3QgY29udGVudFR5cGUgPSBmaWxlT3BzLmdldENvbnRlbnRUeXBlKHR5cGUpO1xyXG5cdFx0XHRyZXR1cm4gY29udGVudFR5cGUgIT09IG51bGwgJiYgY29udGVudFR5cGUuZW5hYmxlZDtcclxuXHRcdH1cclxuXHJcblx0XHRwbHVnaW4uYWRkQ29tbWFuZCh7XHJcblx0XHRcdGlkOiBcInJlbmFtZS1jb250ZW50XCIsXHJcblx0XHRcdG5hbWU6IFwiUmVuYW1lIGN1cnJlbnQgY29udGVudFwiLFxyXG5cdFx0XHRpY29uOiBcInBlbmNpbFwiLFxyXG5cdFx0XHRlZGl0b3JDYWxsYmFjazogKGVkaXRvcjogRWRpdG9yLCBjdHg6IE1hcmtkb3duVmlldyB8IE1hcmtkb3duRmlsZUluZm8pID0+IHtcclxuXHRcdFx0XHRjb25zdCBmaWxlID0gY3R4IGluc3RhbmNlb2YgTWFya2Rvd25WaWV3ID8gY3R4LmZpbGUgOiBjdHguZmlsZTtcclxuXHRcdFx0XHRpZiAoZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSB7XHJcblx0XHRcdFx0XHRpZiAoIWhhc01hdGNoaW5nQ29udGVudFR5cGUoZmlsZSwgc2V0dGluZ3MpKSB7XHJcblx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoXCJDYW5ub3QgcmVuYW1lOiB0aGlzIGZpbGUgaXMgbm90IHBhcnQgb2YgYSBjb25maWd1cmVkIGNvbnRlbnQgdHlwZSBmb2xkZXIuXCIpO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0Y29uc3QgdHlwZSA9IGZpbGVPcHMuZGV0ZXJtaW5lVHlwZShmaWxlKTtcclxuXHRcdFx0XHRcdGNvbnN0IGNhY2hlID0gcGx1Z2luLmFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZShmaWxlKTtcclxuXHRcdFx0XHRcdGNvbnN0IHRpdGxlS2V5ID0gZmlsZU9wcy5nZXRUaXRsZUtleSh0eXBlKTtcclxuXHJcblx0XHRcdFx0XHRpZiAoIWNhY2hlPy5mcm9udG1hdHRlciB8fCAhKHRpdGxlS2V5IGluIGNhY2hlLmZyb250bWF0dGVyKSkge1xyXG5cdFx0XHRcdFx0XHRuZXcgTm90aWNlKGBDYW5ub3QgcmVuYW1lOiBObyAke3RpdGxlS2V5fSBmb3VuZCBpbiBwcm9wZXJ0aWVzYCk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRuZXcgVGl0bGVNb2RhbChwbHVnaW4uYXBwLCBmaWxlLCBwbHVnaW4gYXMgdW5rbm93biBhcyBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlLCB0eXBlLCB0cnVlKS5vcGVuKCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9LFxyXG5cdFx0fSk7XHJcblxyXG5cdFx0Ly8gRE8gTk9UIHJlZ2lzdGVyIHRlcm1pbmFsIG9yIGNvbmZpZyBjb21tYW5kcyBvbiBtb2JpbGUgLSByZXR1cm4gZWFybHlcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblxyXG5cdC8vIERlc2t0b3A6IHJlZ2lzdGVyIGFsbCBjb21tYW5kcyBpbmNsdWRpbmcgdGVybWluYWwgYW5kIGNvbmZpZ1xyXG5cdGNvbnN0IHBsdWdpbkludGVyZmFjZSA9IHBsdWdpbiBhcyB1bmtub3duIGFzIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2U7XHJcblxyXG5cclxuXHQvLyBIZWxwZXIgZnVuY3Rpb24gdG8gY2hlY2sgaWYgYSBmaWxlIG1hdGNoZXMgYW55IGNvbmZpZ3VyZWQgY29udGVudCB0eXBlXHJcblx0Ly8gVXNlcyB0aGUgc2FtZSBsb2dpYyBhcyBGaWxlT3BlcmF0aW9ucy5kZXRlcm1pbmVUeXBlKCkgdG8gZW5zdXJlIGNvbnNpc3RlbmN5XHJcblx0Ly8gR2V0cyBmcmVzaCBzZXR0aW5ncyBmcm9tIHBsdWdpbiB0byBlbnN1cmUgd2UgY2hlY2sgYWdhaW5zdCBjdXJyZW50IGNvbnRlbnQgdHlwZXNcclxuXHRmdW5jdGlvbiBoYXNNYXRjaGluZ0NvbnRlbnRUeXBlKGZpbGU6IFRGaWxlLCBzZXR0aW5nczogQXN0cm9Db21wb3NlclNldHRpbmdzKTogYm9vbGVhbiB7XHJcblx0XHQvLyBHZXQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gaWYgYXZhaWxhYmxlXHJcblx0XHRjb25zdCBjdXJyZW50U2V0dGluZ3MgPSAocGx1Z2luIGFzIHVua25vd24gYXMgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSk/LnNldHRpbmdzIHx8IHNldHRpbmdzO1xyXG5cdFx0Ly8gQ3JlYXRlIGEgdGVtcG9yYXJ5IEZpbGVPcGVyYXRpb25zIHdpdGggZnJlc2ggc2V0dGluZ3NcclxuXHRcdGNvbnN0IHRlbXBGaWxlT3BzID0gbmV3IEZpbGVPcGVyYXRpb25zKHBsdWdpbi5hcHAsIGN1cnJlbnRTZXR0aW5ncywgcGx1Z2luIGFzIHVua25vd24gYXMgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSk7XHJcblx0XHRjb25zdCB0eXBlID0gdGVtcEZpbGVPcHMuZGV0ZXJtaW5lVHlwZShmaWxlKTtcclxuXHRcdC8vIElmIGRldGVybWluZVR5cGUgcmV0dXJucyBcIm5vdGVcIiwgaXQgbWVhbnMgbm8gY29udGVudCB0eXBlIG1hdGNoZWRcclxuXHRcdGlmICh0eXBlID09PSBcIm5vdGVcIikge1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblx0XHQvLyBDaGVjayBpZiB0aGUgbWF0Y2hlZCBjb250ZW50IHR5cGUgaXMgZW5hYmxlZFxyXG5cdFx0Y29uc3QgY29udGVudFR5cGUgPSB0ZW1wRmlsZU9wcy5nZXRDb250ZW50VHlwZSh0eXBlKTtcclxuXHRcdHJldHVybiBjb250ZW50VHlwZSAhPT0gbnVsbCAmJiBjb250ZW50VHlwZS5lbmFibGVkO1xyXG5cdH1cclxuXHJcblx0Ly8gU3RhbmRhcmRpemUgUHJvcGVydGllcyBjb21tYW5kXHJcblx0cGx1Z2luLmFkZENvbW1hbmQoe1xyXG5cdFx0aWQ6IFwic3RhbmRhcmRpemUtcHJvcGVydGllc1wiLFxyXG5cdFx0bmFtZTogXCJTdGFuZGFyZGl6ZSBwcm9wZXJ0aWVzXCIsXHJcblx0XHRpY29uOiBcImZpbGUtY2hlY2tcIixcclxuXHRcdGVkaXRvckNhbGxiYWNrOiAoZWRpdG9yOiBFZGl0b3IsIGN0eDogTWFya2Rvd25WaWV3IHwgTWFya2Rvd25GaWxlSW5mbykgPT4ge1xyXG5cdFx0XHRjb25zdCBmaWxlID0gY3R4IGluc3RhbmNlb2YgTWFya2Rvd25WaWV3ID8gY3R4LmZpbGUgOiBjdHguZmlsZTtcclxuXHRcdFx0aWYgKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkge1xyXG5cdFx0XHRcdHZvaWQgc3RhbmRhcmRpemVQcm9wZXJ0aWVzKHBsdWdpbi5hcHAsIHNldHRpbmdzLCBmaWxlLCBwbHVnaW4gYXMgdW5rbm93biBhcyBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlLCBlZGl0b3IpO1xyXG5cdFx0XHR9XHJcblx0XHR9LFxyXG5cdH0pO1xyXG5cclxuXHQvLyBDb252ZXJ0IFdpa2lsaW5rcyBjb21tYW5kXHJcblx0cGx1Z2luLmFkZENvbW1hbmQoe1xyXG5cdFx0aWQ6IFwiY29udmVydC13aWtpbGlua3MtYXN0cm9cIixcclxuXHRcdG5hbWU6IFwiQ29udmVydCBpbnRlcm5hbCBsaW5rcyBmb3IgYXN0cm9cIixcclxuXHRcdGljb246IFwibGluay0yXCIsXHJcblx0XHRlZGl0b3JDYWxsYmFjazogKGVkaXRvcjogRWRpdG9yLCBjdHg6IE1hcmtkb3duVmlldyB8IE1hcmtkb3duRmlsZUluZm8pID0+IHtcclxuXHRcdFx0Y29uc3QgZmlsZSA9IGN0eCBpbnN0YW5jZW9mIE1hcmtkb3duVmlldyA/IGN0eC5maWxlIDogY3R4LmZpbGU7XHJcblx0XHRcdGlmIChmaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcclxuXHRcdFx0XHQvLyBHZXQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gYW5kIGNyZWF0ZSBMaW5rQ29udmVydGVyIHdpdGggaXRcclxuXHRcdFx0XHRjb25zdCBjdXJyZW50U2V0dGluZ3MgPSBwbHVnaW5JbnRlcmZhY2Uuc2V0dGluZ3MgfHwgc2V0dGluZ3M7XHJcblx0XHRcdFx0Y29uc3QgY3VycmVudExpbmtDb252ZXJ0ZXIgPSBuZXcgTGlua0NvbnZlcnRlcihjdXJyZW50U2V0dGluZ3MsIHBsdWdpbkludGVyZmFjZSk7XHJcblx0XHRcdFx0Y3VycmVudExpbmtDb252ZXJ0ZXIuY29udmVydFdpa2lsaW5rc0ZvckFzdHJvKGVkaXRvciwgZmlsZSk7XHJcblx0XHRcdH1cclxuXHRcdH0sXHJcblx0fSk7XHJcblxyXG5cdC8vIFJlbmFtZSBDb250ZW50IGNvbW1hbmRcclxuXHRwbHVnaW4uYWRkQ29tbWFuZCh7XHJcblx0XHRpZDogXCJyZW5hbWUtY29udGVudFwiLFxyXG5cdFx0bmFtZTogXCJSZW5hbWUgY3VycmVudCBjb250ZW50XCIsXHJcblx0XHRpY29uOiBcInBlbmNpbFwiLFxyXG5cdFx0ZWRpdG9yQ2FsbGJhY2s6IChlZGl0b3I6IEVkaXRvciwgY3R4OiBNYXJrZG93blZpZXcgfCBNYXJrZG93bkZpbGVJbmZvKSA9PiB7XHJcblx0XHRcdGNvbnN0IGZpbGUgPSBjdHggaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgPyBjdHguZmlsZSA6IGN0eC5maWxlO1xyXG5cdFx0XHRpZiAoZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSB7XHJcblx0XHRcdFx0Ly8gR2V0IGZyZXNoIHNldHRpbmdzIGZyb20gcGx1Z2luXHJcblx0XHRcdFx0Y29uc3QgY3VycmVudFNldHRpbmdzID0gcGx1Z2luSW50ZXJmYWNlLnNldHRpbmdzIHx8IHNldHRpbmdzO1xyXG5cdFx0XHRcdC8vIENyZWF0ZSBGaWxlT3BlcmF0aW9ucyB3aXRoIGZyZXNoIHNldHRpbmdzXHJcblx0XHRcdFx0Y29uc3QgY3VycmVudEZpbGVPcHMgPSBuZXcgRmlsZU9wZXJhdGlvbnMocGx1Z2luLmFwcCwgY3VycmVudFNldHRpbmdzLCBwbHVnaW5JbnRlcmZhY2UpO1xyXG5cclxuXHRcdFx0XHQvLyBDaGVjayBpZiB0aGlzIGZpbGUgbWF0Y2hlcyBhbnkgY29uZmlndXJlZCBjb250ZW50IHR5cGVcclxuXHRcdFx0XHRpZiAoIWhhc01hdGNoaW5nQ29udGVudFR5cGUoZmlsZSwgY3VycmVudFNldHRpbmdzKSkge1xyXG5cdFx0XHRcdFx0bmV3IE5vdGljZShcIkNhbm5vdCByZW5hbWU6IHRoaXMgZmlsZSBpcyBub3QgcGFydCBvZiBhIGNvbmZpZ3VyZWQgY29udGVudCB0eXBlIGZvbGRlci5cIik7XHJcblx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBEZXRlcm1pbmUgY29udGVudCB0eXBlIGZyb20gZm9sZGVyIHN0cnVjdHVyZVxyXG5cdFx0XHRcdGNvbnN0IHR5cGUgPSBjdXJyZW50RmlsZU9wcy5kZXRlcm1pbmVUeXBlKGZpbGUpO1xyXG5cclxuXHRcdFx0XHQvLyBBbHdheXMgb3BlbiB0aGUgbW9kYWwgLSBpdCB3aWxsIGhhbmRsZSBmaWxlcyB3aXRob3V0IGZyb250bWF0dGVyIG9yIHRpdGxlIGtleVxyXG5cdFx0XHRcdC8vIElmIHRoZXJlJ3Mgbm8gdGl0bGUgaW4gZnJvbnRtYXR0ZXIsIHRoZSBtb2RhbCB3aWxsIHVzZSB0aGUgZmlsZW5hbWUgYXMgZmFsbGJhY2tcclxuXHRcdFx0XHQvLyBhbmQgdGhlIHJlbmFtZSB3aWxsIHByb2NlZWQgd2l0aCBrZWJhYi1jYXNlIHZlcnNpb24gb2Ygd2hhdCB1c2VyIHR5cGVzXHJcblx0XHRcdFx0bmV3IFRpdGxlTW9kYWwocGx1Z2luLmFwcCwgZmlsZSwgcGx1Z2luSW50ZXJmYWNlLCB0eXBlLCB0cnVlKS5vcGVuKCk7XHJcblx0XHRcdH1cclxuXHRcdH0sXHJcblx0fSk7XHJcblxyXG5cdC8vIE9wZW4gVGVybWluYWwgY29tbWFuZCAoZGVza3RvcCBvbmx5IC0gbm90IGF2YWlsYWJsZSBvbiBtb2JpbGUpXHJcblx0aWYgKCFpc01vYmlsZSkge1xyXG5cdFx0cGx1Z2luLmFkZENvbW1hbmQoe1xyXG5cdFx0XHRpZDogXCJvcGVuLXByb2plY3QtdGVybWluYWxcIixcclxuXHRcdFx0bmFtZTogXCJPcGVuIHByb2plY3QgdGVybWluYWxcIixcclxuXHRcdFx0aWNvbjogXCJ0ZXJtaW5hbC1zcXVhcmVcIixcclxuXHRcdFx0Y2FsbGJhY2s6ICgpID0+IHtcclxuXHRcdFx0XHRjb25zdCBjdXJyZW50U2V0dGluZ3MgPSAocGx1Z2luIGFzIHVua25vd24gYXMgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSkuc2V0dGluZ3M7XHJcblx0XHRcdFx0aWYgKCFjdXJyZW50U2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZCkge1xyXG5cdFx0XHRcdFx0bmV3IE5vdGljZShcIk9wZW4gdGVybWluYWwgY29tbWFuZCBpcyBkaXNhYmxlZC4gRW5hYmxlIGl0IGluIHNldHRpbmdzIHRvIHVzZSB0aGlzIGNvbW1hbmQuXCIpO1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRvcGVuVGVybWluYWxJblByb2plY3RSb290KHBsdWdpbi5hcHAsIGN1cnJlbnRTZXR0aW5ncyk7XHJcblx0XHRcdH0sXHJcblx0XHR9KTtcclxuXHR9XHJcblxyXG5cdC8vIEVkaXQgQ29uZmlnIEZpbGUgY29tbWFuZCAoZGVza3RvcCBvbmx5IC0gbm90IGF2YWlsYWJsZSBvbiBtb2JpbGUpXHJcblx0aWYgKCFpc01vYmlsZSkge1xyXG5cdFx0cGx1Z2luLmFkZENvbW1hbmQoe1xyXG5cdFx0XHRpZDogXCJlZGl0LWFzdHJvLWNvbmZpZ1wiLFxyXG5cdFx0XHRuYW1lOiBcIkVkaXQgYXN0cm8gY29uZmlnXCIsXHJcblx0XHRcdGljb246IFwicm9ja2V0XCIsXHJcblx0XHRcdGNhbGxiYWNrOiBhc3luYyAoKSA9PiB7XHJcblx0XHRcdFx0Y29uc3QgY3VycmVudFNldHRpbmdzID0gKHBsdWdpbiBhcyB1bmtub3duIGFzIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UpLnNldHRpbmdzO1xyXG5cdFx0XHRcdGlmICghY3VycmVudFNldHRpbmdzLmVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZCkge1xyXG5cdFx0XHRcdFx0bmV3IE5vdGljZShcIkVkaXQgY29uZmlnIGZpbGUgY29tbWFuZCBpcyBkaXNhYmxlZC4gRW5hYmxlIGl0IGluIHNldHRpbmdzIHRvIHVzZSB0aGlzIGNvbW1hbmQuXCIpO1xyXG5cdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRhd2FpdCBvcGVuQ29uZmlnRmlsZShwbHVnaW4uYXBwLCBjdXJyZW50U2V0dGluZ3MpO1xyXG5cdFx0XHR9LFxyXG5cdFx0fSk7XHJcblx0fVxyXG59XHJcblxyXG5hc3luYyBmdW5jdGlvbiBzdGFuZGFyZGl6ZVByb3BlcnRpZXMoYXBwOiBBcHAsIHNldHRpbmdzOiBBc3Ryb0NvbXBvc2VyU2V0dGluZ3MsIGZpbGU6IFRGaWxlLCBwbHVnaW4/OiBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlLCBlZGl0b3I/OiBFZGl0b3IpOiBQcm9taXNlPHZvaWQ+IHtcclxuXHQvLyBHZXQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gaWYgYXZhaWxhYmxlXHJcblx0Y29uc3QgY3VycmVudFNldHRpbmdzID0gcGx1Z2luPy5zZXR0aW5ncyB8fCBzZXR0aW5ncztcclxuXHRjb25zdCB0ZW1wbGF0ZVBhcnNlciA9IG5ldyBUZW1wbGF0ZVBhcnNlcihhcHAsIGN1cnJlbnRTZXR0aW5ncyk7XHJcblx0Y29uc3QgZmlsZU9wcyA9IG5ldyBGaWxlT3BlcmF0aW9ucyhhcHAsIGN1cnJlbnRTZXR0aW5ncywgcGx1Z2luKTtcclxuXHJcblx0Ly8gUHJlc2VydmUgY3Vyc29yIHBvc2l0aW9uIGlmIGVkaXRvciBpcyBwcm92aWRlZFxyXG5cdGxldCBjdXJzb3JQb3NpdGlvbjogeyBsaW5lOiBudW1iZXI7IGNoOiBudW1iZXIgfSB8IG51bGwgPSBudWxsO1xyXG5cdGxldCBvcmlnaW5hbENvbnRlbnQgPSBcIlwiO1xyXG5cdGlmIChlZGl0b3IpIHtcclxuXHRcdGNvbnN0IGN1cnNvciA9IGVkaXRvci5nZXRDdXJzb3IoKTtcclxuXHRcdGN1cnNvclBvc2l0aW9uID0geyBsaW5lOiBjdXJzb3IubGluZSwgY2g6IGN1cnNvci5jaCB9O1xyXG5cdFx0b3JpZ2luYWxDb250ZW50ID0gZWRpdG9yLmdldFZhbHVlKCk7XHJcblx0fVxyXG5cclxuXHQvLyBEZXRlcm1pbmUgY29udGVudCB0eXBlIHVzaW5nIHRoZSBleGlzdGluZyBsb2dpY1xyXG5cdGNvbnN0IHR5cGUgPSBmaWxlT3BzLmRldGVybWluZVR5cGUoZmlsZSk7XHJcblxyXG5cdC8vIENoZWNrIGlmIHRoaXMgZmlsZSBoYXMgYSB2YWxpZCBjb250ZW50IHR5cGUgKG5vdCBqdXN0IFwibm90ZVwiKVxyXG5cdGlmICh0eXBlID09PSBcIm5vdGVcIikge1xyXG5cdFx0bmV3IE5vdGljZShcIk5vIHByb3BlcnRpZXMgdGVtcGxhdGUgc3BlY2lmaWVkIGZvciB0aGlzIGNvbnRlbnQuIFRoaXMgZmlsZSBkb2Vzbid0IG1hdGNoIGFueSBjb25maWd1cmVkIGNvbnRlbnQgdHlwZSBmb2xkZXJzLlwiKTtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblxyXG5cdGxldCB0ZW1wbGF0ZVN0cmluZzogc3RyaW5nO1xyXG5cclxuXHQvLyBEZXRlcm1pbmUgdGVtcGxhdGUgYmFzZWQgb24gY29udGVudCB0eXBlXHJcblx0aWYgKHR5cGUgPT09IFwibm90ZVwiKSB7XHJcblx0XHRuZXcgTm90aWNlKFwiTm8gcHJvcGVydGllcyB0ZW1wbGF0ZSBzcGVjaWZpZWQgZm9yIHRoaXMgY29udGVudC4gVGhpcyBmaWxlIGRvZXNuJ3QgbWF0Y2ggYW55IGNvbmZpZ3VyZWQgY29udGVudCB0eXBlIGZvbGRlcnMuXCIpO1xyXG5cdFx0cmV0dXJuO1xyXG5cdH1cclxuXHJcblx0Y29uc3QgY29udGVudFR5cGUgPSBmaWxlT3BzLmdldENvbnRlbnRUeXBlKHR5cGUpO1xyXG5cdGlmICghY29udGVudFR5cGUpIHtcclxuXHRcdG5ldyBOb3RpY2UoXCJDb250ZW50IHR5cGUgbm90IGZvdW5kLlwiKTtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblxyXG5cdHRlbXBsYXRlU3RyaW5nID0gY29udGVudFR5cGUudGVtcGxhdGU7XHJcblxyXG5cdC8vIFdhaXQgYnJpZWZseSB0byBhbGxvdyBlZGl0b3Igc3RhdGUgdG8gc3RhYmlsaXplXHJcblx0YXdhaXQgbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIDEwMCkpO1xyXG5cclxuXHQvLyBSZS1yZWFkIGNvbnRlbnQgdG8gZW5zdXJlIGxhdGVzdCBzdGF0ZSBhZnRlciBlZGl0b3IgY2hhbmdlc1xyXG5cdGNvbnN0IGNvbnRlbnQgPSBhd2FpdCBhcHAudmF1bHQucmVhZChmaWxlKTtcclxuXHRjb25zdCB0aXRsZSA9IGZpbGUuYmFzZW5hbWUucmVwbGFjZSgvXl8vLCBcIlwiKTtcclxuXHJcblx0Y29uc3QgcGFyc2VkID0gdGVtcGxhdGVQYXJzZXIucGFyc2VGcm9udG1hdHRlcihjb250ZW50KTtcclxuXHRjb25zdCB7IHRlbXBsYXRlUHJvcHMsIHRlbXBsYXRlVmFsdWVzIH0gPSB0ZW1wbGF0ZVBhcnNlci5wYXJzZVRlbXBsYXRlKHRlbXBsYXRlU3RyaW5nLCB0aXRsZSk7XHJcblxyXG5cdC8vIE1lcmdlIHRlbXBsYXRlIHByb3BlcnRpZXMgd2l0aCBleGlzdGluZyBvbmVzLCBwcmVzZXJ2aW5nIGFsbCBleGlzdGluZ1xyXG5cdGNvbnN0IGZpbmFsUHJvcHM6IFJlY29yZDxzdHJpbmcsIHN0cmluZ1tdPiA9IHsgLi4ucGFyc2VkLnByb3BlcnRpZXMgfTtcclxuXHRjb25zdCBhcnJheUtleXMgPSBuZXcgU2V0PHN0cmluZz4oKTsgLy8gVHJhY2sgd2hpY2gga2V5cyBhcmUgYXJyYXlzXHJcblxyXG5cdC8vIEdlbmVyYXRlIHNsdWcgZnJvbSB0aXRsZSBmb3Igc2x1ZyBwcm9wZXJ0eSBhdXRvLXBvcHVsYXRpb25cclxuXHRjb25zdCBzbHVnID0gdG9LZWJhYkNhc2UodGl0bGUpO1xyXG5cclxuXHRmb3IgKGNvbnN0IGtleSBvZiB0ZW1wbGF0ZVByb3BzKSB7XHJcblx0XHRpZiAoIShrZXkgaW4gcGFyc2VkLnByb3BlcnRpZXMpKSB7XHJcblx0XHRcdC8vIFByb3BlcnR5IGRvZXNuJ3QgZXhpc3QsIGFkZCBpdCBmcm9tIHRlbXBsYXRlXHJcblx0XHRcdGNvbnN0IHRlbXBsYXRlVmFsdWUgPSB0ZW1wbGF0ZVZhbHVlc1trZXldO1xyXG5cdFx0XHRpZiAoQXJyYXkuaXNBcnJheSh0ZW1wbGF0ZVZhbHVlKSkge1xyXG5cdFx0XHRcdGZpbmFsUHJvcHNba2V5XSA9IHRlbXBsYXRlVmFsdWU7XHJcblx0XHRcdFx0YXJyYXlLZXlzLmFkZChrZXkpOyAvLyBNYXJrIGFzIGFycmF5XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0ZmluYWxQcm9wc1trZXldID0gW3RlbXBsYXRlVmFsdWUgfHwgXCJcIl07XHJcblx0XHRcdH1cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdC8vIFByb3BlcnR5IGV4aXN0cywgY2hlY2sgaWYgaXQncyBhbiBhcnJheSB0eXBlXHJcblx0XHRcdGNvbnN0IHRlbXBsYXRlVmFsdWUgPSB0ZW1wbGF0ZVZhbHVlc1trZXldO1xyXG5cdFx0XHRjb25zdCBpc0FycmF5VmFsdWUgPSBBcnJheS5pc0FycmF5KHRlbXBsYXRlVmFsdWUpO1xyXG5cclxuXHRcdFx0aWYgKGlzQXJyYXlWYWx1ZSkge1xyXG5cdFx0XHRcdC8vIFRoaXMgaXMgYW4gYXJyYXkgcHJvcGVydHkgLSBwcmVzZXJ2ZSBleGlzdGluZyB2YWx1ZXMgYW5kIG1lcmdlIHdpdGggdGVtcGxhdGVcclxuXHRcdFx0XHRjb25zdCBleGlzdGluZ0l0ZW1zID0gcGFyc2VkLnByb3BlcnRpZXNba2V5XSB8fCBbXTtcclxuXHRcdFx0XHRjb25zdCBuZXdJdGVtcyA9IHRlbXBsYXRlVmFsdWUuZmlsdGVyKGl0ZW0gPT4gIWV4aXN0aW5nSXRlbXMuaW5jbHVkZXMoaXRlbSkpO1xyXG5cdFx0XHRcdGZpbmFsUHJvcHNba2V5XSA9IFsuLi5leGlzdGluZ0l0ZW1zLCAuLi5uZXdJdGVtc107XHJcblx0XHRcdFx0YXJyYXlLZXlzLmFkZChrZXkpOyAvLyBNYXJrIGFzIGFycmF5XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0Ly8gRm9yIG5vbi1hcnJheSB2YWx1ZXMsIGNoZWNrIGlmIGl0J3Mgc2x1ZyBhbmQgbmVlZHMgYXV0by1wb3B1bGF0aW9uXHJcblx0XHRcdFx0aWYgKGtleSA9PT0gXCJzbHVnXCIpIHtcclxuXHRcdFx0XHRcdGNvbnN0IGV4aXN0aW5nU2x1ZyA9IHBhcnNlZC5wcm9wZXJ0aWVzW2tleV1bMF0gfHwgXCJcIjtcclxuXHRcdFx0XHRcdC8vIE9ubHkgYXV0by1wb3B1bGF0ZSBpZiBzbHVnIGlzIGVtcHR5IG9yIG1pc3NpbmdcclxuXHRcdFx0XHRcdGlmICghZXhpc3RpbmdTbHVnIHx8IGV4aXN0aW5nU2x1Zy50cmltKCkgPT09IFwiXCIpIHtcclxuXHRcdFx0XHRcdFx0ZmluYWxQcm9wc1trZXldID0gW3NsdWddO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0Ly8gSWYgc2x1ZyBoYXMgYSB2YWx1ZSwgcHJlc2VydmUgaXQgKGRvbid0IG92ZXJ3cml0ZSlcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0Ly8gRm9yIG90aGVyIG5vbi1hcnJheSB2YWx1ZXMsIGtlZXAgZXhpc3RpbmcgdmFsdWUgKGRvbid0IG92ZXJ3cml0ZSlcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly8gQWxzbyBjaGVjayBpZiBzbHVnIHByb3BlcnR5IGV4aXN0cyBpbiBmcm9udG1hdHRlciBidXQgaXMgZW1wdHkgKGV2ZW4gaWYgbm90IGluIHRlbXBsYXRlKVxyXG5cdC8vIE9ubHkgYXV0by1wb3B1bGF0ZSBpZiB0ZW1wbGF0ZSBoYXMge3tzbHVnfX0gcGxhY2Vob2xkZXJcclxuXHRpZiAoXCJzbHVnXCIgaW4gcGFyc2VkLnByb3BlcnRpZXMgJiYgdGVtcGxhdGVTdHJpbmcuaW5jbHVkZXMoXCJ7e3NsdWd9fVwiKSkge1xyXG5cdFx0Y29uc3QgZXhpc3RpbmdTbHVnID0gcGFyc2VkLnByb3BlcnRpZXNbXCJzbHVnXCJdWzBdIHx8IFwiXCI7XHJcblx0XHRpZiAoIWV4aXN0aW5nU2x1ZyB8fCBleGlzdGluZ1NsdWcudHJpbSgpID09PSBcIlwiKSB7XHJcblx0XHRcdC8vIFNsdWcgZXhpc3RzIGJ1dCBpcyBlbXB0eSwgYW5kIHRlbXBsYXRlIGhhcyB7e3NsdWd9fSAtIGF1dG8tcG9wdWxhdGUgaXRcclxuXHRcdFx0ZmluYWxQcm9wc1tcInNsdWdcIl0gPSBbc2x1Z107XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvLyBBbHNvIGFkZCBhbnkgZXhpc3RpbmcgYXJyYXkga2V5cyB0aGF0IHdlcmVuJ3QgaW4gdGhlIHRlbXBsYXRlXHJcblx0Zm9yIChjb25zdCBrZXkgaW4gcGFyc2VkLnByb3BlcnRpZXMpIHtcclxuXHRcdGlmIChwYXJzZWQucHJvcGVydGllc1trZXldLmxlbmd0aCA+IDEpIHtcclxuXHRcdFx0YXJyYXlLZXlzLmFkZChrZXkpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Y29uc3QgbmV3Q29udGVudCA9IHRlbXBsYXRlUGFyc2VyLmJ1aWxkRnJvbnRtYXR0ZXJDb250ZW50KGZpbmFsUHJvcHMsIGFycmF5S2V5cykgKyBwYXJzZWQuYm9keUNvbnRlbnQ7XHJcblxyXG5cdGF3YWl0IGFwcC52YXVsdC5tb2RpZnkoZmlsZSwgbmV3Q29udGVudCk7XHJcblxyXG5cdC8vIFJlc3RvcmUgY3Vyc29yIHBvc2l0aW9uIGlmIGVkaXRvciB3YXMgcHJvdmlkZWQgYW5kIGZpbGUgaXMgc3RpbGwgb3BlblxyXG5cdGlmIChlZGl0b3IgJiYgY3Vyc29yUG9zaXRpb24pIHtcclxuXHRcdC8vIFdhaXQgZm9yIE9ic2lkaWFuIHRvIHJlbG9hZCB0aGUgZmlsZSBpbiB0aGUgZWRpdG9yXHJcblx0XHRhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgNTApKTtcclxuXHJcblx0XHQvLyBUcnkgdG8gZ2V0IHRoZSBhY3RpdmUgZWRpdG9yIGZvciB0aGlzIGZpbGVcclxuXHRcdGNvbnN0IGFjdGl2ZVZpZXcgPSBhcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUoTWFya2Rvd25WaWV3KTtcclxuXHRcdGlmIChhY3RpdmVWaWV3ICYmIGFjdGl2ZVZpZXcuZmlsZSA9PT0gZmlsZSAmJiBhY3RpdmVWaWV3LmVkaXRvcikge1xyXG5cdFx0XHRjb25zdCBhY3RpdmVFZGl0b3IgPSBhY3RpdmVWaWV3LmVkaXRvcjtcclxuXHRcdFx0Y29uc3QgbmV3TGluZUNvdW50ID0gbmV3Q29udGVudC5zcGxpdCgnXFxuJykubGVuZ3RoO1xyXG5cdFx0XHRjb25zdCBvcmlnaW5hbExpbmVDb3VudCA9IG9yaWdpbmFsQ29udGVudC5zcGxpdCgnXFxuJykubGVuZ3RoO1xyXG5cclxuXHRcdFx0Ly8gQ2FsY3VsYXRlIG5ldyBjdXJzb3IgcG9zaXRpb25cclxuXHRcdFx0bGV0IG5ld0xpbmUgPSBjdXJzb3JQb3NpdGlvbi5saW5lO1xyXG5cdFx0XHRsZXQgbmV3Q2ggPSBjdXJzb3JQb3NpdGlvbi5jaDtcclxuXHJcblx0XHRcdC8vIEFkanVzdCBmb3IgY29udGVudCBjaGFuZ2VzXHJcblx0XHRcdGlmIChuZXdMaW5lQ291bnQgIT09IG9yaWdpbmFsTGluZUNvdW50KSB7XHJcblx0XHRcdFx0Ly8gSWYgbGluZXMgd2VyZSBhZGRlZC9yZW1vdmVkLCBhZGp1c3QgbGluZSBudW1iZXJcclxuXHRcdFx0XHRpZiAobmV3TGluZSA+PSBuZXdMaW5lQ291bnQpIHtcclxuXHRcdFx0XHRcdG5ld0xpbmUgPSBNYXRoLm1heCgwLCBuZXdMaW5lQ291bnQgLSAxKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIEFkanVzdCBjb2x1bW4gcG9zaXRpb24gaWYgbGluZSBsZW5ndGggY2hhbmdlZFxyXG5cdFx0XHRjb25zdCBuZXdMaW5lTGVuZ3RoID0gbmV3Q29udGVudC5zcGxpdCgnXFxuJylbbmV3TGluZV0/Lmxlbmd0aCB8fCAwO1xyXG5cdFx0XHRpZiAobmV3Q2ggPiBuZXdMaW5lTGVuZ3RoKSB7XHJcblx0XHRcdFx0bmV3Q2ggPSBNYXRoLm1heCgwLCBuZXdMaW5lTGVuZ3RoKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gUmVzdG9yZSBjdXJzb3IgcG9zaXRpb25cclxuXHRcdFx0YWN0aXZlRWRpdG9yLnNldEN1cnNvcih7IGxpbmU6IG5ld0xpbmUsIGNoOiBuZXdDaCB9KTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdG5ldyBOb3RpY2UoXCJQcm9wZXJ0aWVzIHN0YW5kYXJkaXplZCB1c2luZyB0ZW1wbGF0ZS5cIik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZW5hbWUgYSBmaWxlIGJ5IHBhdGggKGZvciBwcm9ncmFtbWF0aWMgdXNlLCBlLmcuLCBmcm9tIG90aGVyIHBsdWdpbnMpXHJcbiAqIFRoaXMgYWxsb3dzIHRoZSByZW5hbWUgbW9kYWwgdG8gYXBwZWFyIHdpdGhvdXQgb3BlbmluZyB0aGUgZmlsZSBmaXJzdFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJlbmFtZUNvbnRlbnRCeVBhdGgoXHJcblx0YXBwOiBBcHAsXHJcblx0ZmlsZVBhdGg6IHN0cmluZyxcclxuXHRzZXR0aW5nczogQXN0cm9Db21wb3NlclNldHRpbmdzLFxyXG5cdHBsdWdpbjogQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZVxyXG4pOiB2b2lkIHtcclxuXHRjb25zdCBmaWxlID0gYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChmaWxlUGF0aCk7XHJcblx0aWYgKCEoZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSkge1xyXG5cdFx0bmV3IE5vdGljZShgRmlsZSBub3QgZm91bmQ6ICR7ZmlsZVBhdGh9YCk7XHJcblx0XHRyZXR1cm47XHJcblx0fVxyXG5cclxuXHRjb25zdCBmaWxlT3BzID0gbmV3IEZpbGVPcGVyYXRpb25zKGFwcCwgc2V0dGluZ3MsIHBsdWdpbik7XHJcblxyXG5cdC8vIEhlbHBlciBmdW5jdGlvbiB0byBjaGVjayBpZiBmaWxlIG1hdGNoZXMgY29udGVudCB0eXBlXHJcblx0Ly8gVXNlcyB0aGUgc2FtZSBsb2dpYyBhcyBGaWxlT3BlcmF0aW9ucy5kZXRlcm1pbmVUeXBlKCkgdG8gZW5zdXJlIGNvbnNpc3RlbmN5XHJcblx0ZnVuY3Rpb24gaGFzTWF0Y2hpbmdDb250ZW50VHlwZShmaWxlOiBURmlsZSwgc2V0dGluZ3M6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyk6IGJvb2xlYW4ge1xyXG5cdFx0Y29uc3QgdHlwZSA9IGZpbGVPcHMuZGV0ZXJtaW5lVHlwZShmaWxlKTtcclxuXHRcdC8vIElmIGRldGVybWluZVR5cGUgcmV0dXJucyBcIm5vdGVcIiwgaXQgbWVhbnMgbm8gY29udGVudCB0eXBlIG1hdGNoZWRcclxuXHRcdGlmICh0eXBlID09PSBcIm5vdGVcIikge1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblx0XHQvLyBDaGVjayBpZiB0aGUgbWF0Y2hlZCBjb250ZW50IHR5cGUgaXMgZW5hYmxlZFxyXG5cdFx0Y29uc3QgY29udGVudFR5cGUgPSBmaWxlT3BzLmdldENvbnRlbnRUeXBlKHR5cGUpO1xyXG5cdFx0cmV0dXJuIGNvbnRlbnRUeXBlICE9PSBudWxsICYmIGNvbnRlbnRUeXBlLmVuYWJsZWQ7XHJcblx0fVxyXG5cclxuXHRpZiAoIWhhc01hdGNoaW5nQ29udGVudFR5cGUoZmlsZSwgc2V0dGluZ3MpKSB7XHJcblx0XHRuZXcgTm90aWNlKFwiQ2Fubm90IHJlbmFtZTogdGhpcyBmaWxlIGlzIG5vdCBwYXJ0IG9mIGEgY29uZmlndXJlZCBjb250ZW50IHR5cGUgZm9sZGVyLlwiKTtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblxyXG5cdGNvbnN0IHR5cGUgPSBmaWxlT3BzLmRldGVybWluZVR5cGUoZmlsZSk7XHJcblxyXG5cdC8vIEFsd2F5cyBvcGVuIHRoZSBtb2RhbCAtIGl0IHdpbGwgaGFuZGxlIGZpbGVzIHdpdGhvdXQgZnJvbnRtYXR0ZXIgb3IgdGl0bGUga2V5XHJcblx0Ly8gSWYgdGhlcmUncyBubyB0aXRsZSBpbiBmcm9udG1hdHRlciwgdGhlIG1vZGFsIHdpbGwgdXNlIHRoZSBmaWxlbmFtZSBhcyBmYWxsYmFja1xyXG5cdC8vIGFuZCB0aGUgcmVuYW1lIHdpbGwgcHJvY2VlZCB3aXRoIGtlYmFiLWNhc2UgdmVyc2lvbiBvZiB3aGF0IHVzZXIgdHlwZXNcclxuXHRuZXcgVGl0bGVNb2RhbChhcHAsIGZpbGUsIHBsdWdpbiwgdHlwZSwgdHJ1ZSkub3BlbigpO1xyXG59XHJcblxyXG4vKipcclxuICogUmVnaXN0ZXIgY29tbWFuZHMgZm9yIGVhY2ggZW5hYmxlZCBjb250ZW50IHR5cGVcclxuICogRWFjaCBjb21tYW5kIGNyZWF0ZXMgYSBuZXcgZmlsZSBpbiB0aGUgY29udGVudCB0eXBlJ3MgZm9sZGVyIGFuZCBvcGVucyB0aGUgVGl0bGVNb2RhbFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHJlZ2lzdGVyQ29udGVudFR5cGVDb21tYW5kcyhwbHVnaW46IFBsdWdpbiwgc2V0dGluZ3M6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyk6IHZvaWQge1xyXG5cdGNvbnN0IHBsdWdpbkludGVyZmFjZSA9IHBsdWdpbiBhcyB1bmtub3duIGFzIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2U7XHJcblx0Y29uc3QgY29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xyXG5cclxuXHQvLyBSZWdpc3RlciBhIGNvbW1hbmQgZm9yIGVhY2ggZW5hYmxlZCBjb250ZW50IHR5cGVcclxuXHRmb3IgKGNvbnN0IGNvbnRlbnRUeXBlIG9mIGNvbnRlbnRUeXBlcykge1xyXG5cdFx0aWYgKCFjb250ZW50VHlwZS5lbmFibGVkKSB7XHJcblx0XHRcdGNvbnRpbnVlOyAvLyBTa2lwIGRpc2FibGVkIGNvbnRlbnQgdHlwZXNcclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBjb21tYW5kSWQgPSBgY3JlYXRlLWNvbnRlbnQtdHlwZS0ke2NvbnRlbnRUeXBlLmlkfWA7XHJcblx0XHRjb25zdCBjb21tYW5kTmFtZSA9IGBDcmVhdGUgbmV3IGNvbnRlbnQgdHlwZTogJHtjb250ZW50VHlwZS5uYW1lfWA7XHJcblxyXG5cdFx0cGx1Z2luLmFkZENvbW1hbmQoe1xyXG5cdFx0XHRpZDogY29tbWFuZElkLFxyXG5cdFx0XHRuYW1lOiBjb21tYW5kTmFtZSxcclxuXHRcdFx0Y2FsbGJhY2s6IGFzeW5jICgpID0+IHtcclxuXHRcdFx0XHQvLyBEZXRlcm1pbmUgdGFyZ2V0IGZvbGRlciBmcm9tIGNvbnRlbnQgdHlwZSAob3IgdmF1bHQgcm9vdCBpZiBibGFuaylcclxuXHRcdFx0XHRsZXQgdGFyZ2V0Rm9sZGVyID0gY29udGVudFR5cGUuZm9sZGVyIHx8IFwiXCI7XHJcblxyXG5cdFx0XHRcdC8vIENyZWF0ZSBmb2xkZXIgaWYgaXQgZG9lc24ndCBleGlzdCBhbmQgaXMgc3BlY2lmaWVkXHJcblx0XHRcdFx0aWYgKHRhcmdldEZvbGRlciAmJiB0YXJnZXRGb2xkZXIudHJpbSgpICE9PSBcIlwiKSB7XHJcblx0XHRcdFx0XHRjb25zdCBmb2xkZXIgPSBwbHVnaW4uYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aCh0YXJnZXRGb2xkZXIpO1xyXG5cdFx0XHRcdFx0aWYgKCEoZm9sZGVyIGluc3RhbmNlb2YgVEZvbGRlcikpIHtcclxuXHRcdFx0XHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRcdFx0XHRhd2FpdCBwbHVnaW4uYXBwLnZhdWx0LmNyZWF0ZUZvbGRlcih0YXJnZXRGb2xkZXIpO1xyXG5cdFx0XHRcdFx0XHR9IGNhdGNoIChlcnJvcikge1xyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcclxuXHRcdFx0XHRcdFx0XHRuZXcgTm90aWNlKGBGYWlsZWQgdG8gY3JlYXRlIGZvbGRlcjogJHtlcnJvck1lc3NhZ2V9YCk7XHJcblx0XHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBDcmVhdGUgYSB0ZW1wb3JhcnkgZmlsZSBpbiB0aGUgdGFyZ2V0IGZvbGRlclxyXG5cdFx0XHRcdGNvbnN0IHRlbXBGaWxlTmFtZSA9IFwiVW50aXRsZWQubWRcIjtcclxuXHRcdFx0XHRjb25zdCBmaWxlUGF0aCA9IHRhcmdldEZvbGRlciA/IGAke3RhcmdldEZvbGRlcn0vJHt0ZW1wRmlsZU5hbWV9YCA6IHRlbXBGaWxlTmFtZTtcclxuXHJcblx0XHRcdFx0Ly8gQ2hlY2sgaWYgZmlsZSBhbHJlYWR5IGV4aXN0cyAodW5saWtlbHkgYnV0IHBvc3NpYmxlKVxyXG5cdFx0XHRcdGNvbnN0IGV4aXN0aW5nRmlsZSA9IHBsdWdpbi5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKGZpbGVQYXRoKTtcclxuXHRcdFx0XHRpZiAoZXhpc3RpbmdGaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcclxuXHRcdFx0XHRcdC8vIElmIGZpbGUgZXhpc3RzLCB1c2UgaXQgZGlyZWN0bHlcclxuXHRcdFx0XHRcdG5ldyBUaXRsZU1vZGFsKHBsdWdpbi5hcHAsIGV4aXN0aW5nRmlsZSwgcGx1Z2luSW50ZXJmYWNlLCBjb250ZW50VHlwZS5pZCwgZmFsc2UsIHRydWUpLm9wZW4oKTtcclxuXHRcdFx0XHRcdHJldHVybjtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIE1hcmsgdGhhdCB0aGlzIGZpbGUgd2lsbCBiZSBjcmVhdGVkIGJ5IHRoZSBwbHVnaW5cclxuXHRcdFx0XHQvLyBUaGlzIHByZXZlbnRzIHRoZSBjcmVhdGUgZXZlbnQgZnJvbSB0cmlnZ2VyaW5nIGFub3RoZXIgbW9kYWxcclxuXHRcdFx0XHRpZiAocGx1Z2luSW50ZXJmYWNlICYmICdwbHVnaW5DcmVhdGVkRmlsZXMnIGluIHBsdWdpbkludGVyZmFjZSkge1xyXG5cdFx0XHRcdFx0cGx1Z2luSW50ZXJmYWNlLnBsdWdpbkNyZWF0ZWRGaWxlcy5zZXQoZmlsZVBhdGgsIERhdGUubm93KCkpO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRcdC8vIENyZWF0ZSB0aGUgdGVtcG9yYXJ5IGZpbGVcclxuXHRcdFx0XHRcdGNvbnN0IHRlbXBGaWxlID0gYXdhaXQgcGx1Z2luLmFwcC52YXVsdC5jcmVhdGUoZmlsZVBhdGgsIFwiXCIpO1xyXG5cclxuXHRcdFx0XHRcdC8vIE9wZW4gdGhlIFRpdGxlTW9kYWwgd2l0aCB0aGUgZmlsZSwgY29udGVudCB0eXBlIElELCBhbmQgaXNOZXdOb3RlIGZsYWdcclxuXHRcdFx0XHRcdG5ldyBUaXRsZU1vZGFsKHBsdWdpbi5hcHAsIHRlbXBGaWxlLCBwbHVnaW5JbnRlcmZhY2UsIGNvbnRlbnRUeXBlLmlkLCBmYWxzZSwgdHJ1ZSkub3BlbigpO1xyXG5cdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XHJcblx0XHRcdFx0XHRjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XHJcblx0XHRcdFx0XHRuZXcgTm90aWNlKGBGYWlsZWQgdG8gY3JlYXRlIGZpbGU6ICR7ZXJyb3JNZXNzYWdlfWApO1xyXG5cclxuXHRcdFx0XHRcdC8vIENsZWFuIHVwIHRoZSB0cmFja2luZyBpZiBmaWxlIGNyZWF0aW9uIGZhaWxlZFxyXG5cdFx0XHRcdFx0aWYgKHBsdWdpbkludGVyZmFjZSAmJiAncGx1Z2luQ3JlYXRlZEZpbGVzJyBpbiBwbHVnaW5JbnRlcmZhY2UpIHtcclxuXHRcdFx0XHRcdFx0cGx1Z2luSW50ZXJmYWNlLnBsdWdpbkNyZWF0ZWRGaWxlcy5kZWxldGUoZmlsZVBhdGgpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSxcclxuXHRcdH0pO1xyXG5cdH1cclxufVxyXG5cclxuLyoqXHJcbiAqIERlYnVnIGxvZ2dlciBmb3IgdGVybWluYWwgY29tbWFuZHNcclxuICovXHJcbmNvbnN0IHRlcm1pbmFsTG9nZ2VyID0ge1xyXG5cdGVuYWJsZWQ6IGZhbHNlLFxyXG5cdHNldEVuYWJsZWQodmFsdWU6IGJvb2xlYW4pIHtcclxuXHRcdHRoaXMuZW5hYmxlZCA9IHZhbHVlO1xyXG5cdH0sXHJcblx0bG9nKC4uLmFyZ3M6IHVua25vd25bXSkge1xyXG5cdFx0aWYgKHRoaXMuZW5hYmxlZCkge1xyXG5cdFx0XHRjb25zb2xlLmRlYnVnKFwiW2FzdHJvLWNvbXBvc2VyOnRlcm1pbmFsXVwiLCAuLi5hcmdzKTtcclxuXHRcdH1cclxuXHR9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGRlZmF1bHQgdGVybWluYWwgYXBwbGljYXRpb24gbmFtZSBiYXNlZCBvbiBwbGF0Zm9ybVxyXG4gKi9cclxuZnVuY3Rpb24gZ2V0RGVmYXVsdFRlcm1pbmFsQXBwKCk6IHN0cmluZyB7XHJcblx0aWYgKCFQbGF0Zm9ybS5pc0Rlc2t0b3BBcHApIHtcclxuXHRcdHJldHVybiBcIlwiO1xyXG5cdH1cclxuXHRpZiAoUGxhdGZvcm0uaXNNYWNPUykge1xyXG5cdFx0cmV0dXJuIFwiVGVybWluYWxcIjtcclxuXHR9XHJcblx0aWYgKFBsYXRmb3JtLmlzV2luKSB7XHJcblx0XHR0cnkge1xyXG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5vZGVqcy1tb2R1bGVzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzLCBuby11bmRlZiAtLSBSZXF1aXJlZCBmb3IgT1MgcmVsZWFzZSBkZXRlY3Rpb24gb24gZGVza3RvcFxyXG5cdFx0XHRjb25zdCBvcyA9IHJlcXVpcmUoJ29zJykgYXMgeyByZWxlYXNlOiAoKSA9PiBzdHJpbmcgfTtcclxuXHRcdFx0Y29uc3QgcmVsZWFzZSA9IG9zLnJlbGVhc2UoKTtcclxuXHRcdFx0Ly8gV2luZG93cyAxMSBidWlsZCBudW1iZXJzIHN0YXJ0IGF0IDIyMDAwXHJcblx0XHRcdGNvbnN0IG1ham9yVmVyc2lvbiA9IHBhcnNlSW50KHJlbGVhc2Uuc3BsaXQoJy4nKVswXSk7XHJcblx0XHRcdGNvbnN0IGJ1aWxkTnVtYmVyID0gcGFyc2VJbnQocmVsZWFzZS5zcGxpdCgnLicpWzJdKTtcclxuXHJcblx0XHRcdGlmIChtYWpvclZlcnNpb24gPiAxMCB8fCAobWFqb3JWZXJzaW9uID09PSAxMCAmJiBidWlsZE51bWJlciA+PSAyMjAwMCkpIHtcclxuXHRcdFx0XHRyZXR1cm4gXCJ3dC5leGVcIjtcclxuXHRcdFx0fVxyXG5cdFx0fSBjYXRjaCB7XHJcblx0XHRcdC8vIEZhbGxiYWNrIHRvIGNtZC5leGUgaWYgT1MgZGV0ZWN0aW9uIGZhaWxzXHJcblx0XHR9XHJcblx0XHRyZXR1cm4gXCJjbWQuZXhlXCI7XHJcblx0fVxyXG5cdGlmIChQbGF0Zm9ybS5pc0xpbnV4KSB7XHJcblx0XHRyZXR1cm4gXCJnbm9tZS10ZXJtaW5hbFwiO1xyXG5cdH1cclxuXHRyZXR1cm4gXCJcIjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplIHRlcm1pbmFsIGFwcGxpY2F0aW9uIG5hbWUgKHRyaW0gd2hpdGVzcGFjZSlcclxuICovXHJcbmZ1bmN0aW9uIHNhbml0aXplVGVybWluYWxBcHAodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XHJcblx0cmV0dXJuIHZhbHVlLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEVzY2FwZSBkb3VibGUgcXVvdGVzIGluIGEgc3RyaW5nXHJcbiAqL1xyXG5mdW5jdGlvbiBlc2NhcGVEb3VibGVRdW90ZXModmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XHJcblx0cmV0dXJuIHZhbHVlLnJlcGxhY2UoL1wiL2csICdcXFxcXCInKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE9wZW4gdGVybWluYWwgaW4gcHJvamVjdCByb290IGRpcmVjdG9yeVxyXG4gKiBFeHBvcnRlZCBmb3IgdXNlIGJ5IHJpYmJvbiBpY29uc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG9wZW5UZXJtaW5hbEluUHJvamVjdFJvb3QoYXBwOiBBcHAsIHNldHRpbmdzOiBBc3Ryb0NvbXBvc2VyU2V0dGluZ3MpOiB2b2lkIHtcclxuXHQvLyBVcGRhdGUgbG9nZ2VyIHN0YXRlXHJcblx0dGVybWluYWxMb2dnZXIuc2V0RW5hYmxlZChzZXR0aW5ncy5lbmFibGVUZXJtaW5hbERlYnVnTG9nZ2luZyk7XHJcblxyXG5cdHRyeSB7XHJcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5vZGVqcy1tb2R1bGVzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzLCBuby11bmRlZiAtLSBjaGlsZF9wcm9jZXNzIGlzIHJlcXVpcmVkIGZvciB0ZXJtaW5hbCBjb21tYW5kcyBvbiBkZXNrdG9wXHJcblx0XHRjb25zdCB7IGV4ZWMgfSA9IHJlcXVpcmUoJ2NoaWxkX3Byb2Nlc3MnKSBhcyB7IGV4ZWM6IChjb21tYW5kOiBzdHJpbmcsIGNhbGxiYWNrOiAoZXJyb3I6IHsgbWVzc2FnZT86IHN0cmluZyB9IHwgbnVsbCkgPT4gdm9pZCkgPT4gdm9pZCB9O1xyXG5cdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1ub2RlanMtbW9kdWxlcywgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cywgbm8tdW5kZWYgLS0gcGF0aCBpcyByZXF1aXJlZCBmb3IgcmVzb2x2aW5nIHBhdGhzIG9uIGRlc2t0b3BcclxuXHRcdGNvbnN0IHBhdGggPSByZXF1aXJlKCdwYXRoJykgYXMgeyByZXNvbHZlOiAoLi4uYXJnczogc3RyaW5nW10pID0+IHN0cmluZyB9O1xyXG5cdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1ub2RlanMtbW9kdWxlcywgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cywgbm8tdW5kZWYgLS0gZnMgaXMgcmVxdWlyZWQgZm9yIHZlcmlmeWluZyBwYXRocyBvbiBkZXNrdG9wXHJcblx0XHRjb25zdCBmcyA9IHJlcXVpcmUoJ2ZzJykgYXMgeyBleGlzdHNTeW5jOiAocGF0aDogc3RyaW5nKSA9PiBib29sZWFuIH07XHJcblxyXG5cdFx0Ly8gR2V0IHRoZSBhY3R1YWwgdmF1bHQgcGF0aCBzdHJpbmcgZnJvbSB0aGUgYWRhcHRlclxyXG5cdFx0Y29uc3QgYWRhcHRlciA9IGFwcC52YXVsdC5hZGFwdGVyIGFzIHVua25vd24gYXMgeyBiYXNlUGF0aD86IHN0cmluZzsgcGF0aD86IHN0cmluZyB9O1xyXG5cdFx0Y29uc3QgdmF1bHRQYXRoID0gYWRhcHRlci5iYXNlUGF0aCB8fCBhZGFwdGVyLnBhdGg7XHJcblx0XHRjb25zdCB2YXVsdFBhdGhTdHJpbmcgPSB0eXBlb2YgdmF1bHRQYXRoID09PSAnc3RyaW5nJyA/IHZhdWx0UGF0aCA6IFN0cmluZyh2YXVsdFBhdGgpO1xyXG5cclxuXHRcdC8vIFJlc29sdmUgcHJvamVjdCByb290IHBhdGhcclxuXHRcdGxldCBwcm9qZWN0UGF0aDogc3RyaW5nO1xyXG5cdFx0aWYgKHNldHRpbmdzLnRlcm1pbmFsUHJvamVjdFJvb3RQYXRoICYmIHNldHRpbmdzLnRlcm1pbmFsUHJvamVjdFJvb3RQYXRoLnRyaW0oKSkge1xyXG5cdFx0XHQvLyBVc2UgY3VzdG9tIHBhdGggcmVsYXRpdmUgdG8gdmF1bHRcclxuXHRcdFx0cHJvamVjdFBhdGggPSBwYXRoLnJlc29sdmUodmF1bHRQYXRoU3RyaW5nLCBzZXR0aW5ncy50ZXJtaW5hbFByb2plY3RSb290UGF0aCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQvLyBEZWZhdWx0OiB2YXVsdCBmb2xkZXIgaXRzZWxmXHJcblx0XHRcdHByb2plY3RQYXRoID0gdmF1bHRQYXRoU3RyaW5nO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFZlcmlmeSB0aGUgcGF0aCBleGlzdHNcclxuXHRcdGlmICghZnMuZXhpc3RzU3luYyhwcm9qZWN0UGF0aCkpIHtcclxuXHRcdFx0bmV3IE5vdGljZShgUHJvamVjdCByb290IGRpcmVjdG9yeSBub3QgZm91bmQgYXQ6ICR7cHJvamVjdFBhdGh9YCk7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBHZXQgdGVybWluYWwgYXBwbGljYXRpb24gbmFtZSAodXNlIGNvbmZpZ3VyZWQgb3IgZGVmYXVsdClcclxuXHRcdGNvbnN0IGNvbmZpZ3VyZWRBcHAgPSBzYW5pdGl6ZVRlcm1pbmFsQXBwKHNldHRpbmdzLnRlcm1pbmFsQXBwbGljYXRpb25OYW1lIHx8IFwiXCIpO1xyXG5cdFx0Y29uc3QgdGVybWluYWxBcHAgPSBjb25maWd1cmVkQXBwIHx8IGdldERlZmF1bHRUZXJtaW5hbEFwcCgpO1xyXG5cclxuXHRcdC8vIFdhcm4gaWYgdGVybWluYWwgYXBwIG5hbWUgaXMgZW1wdHkgKGJ1dCBzdGlsbCB0cnkgdG8gdXNlIGRlZmF1bHRzKVxyXG5cdFx0aWYgKCFjb25maWd1cmVkQXBwICYmICF0ZXJtaW5hbEFwcCkge1xyXG5cdFx0XHRuZXcgTm90aWNlKFwiVGVybWluYWwgYXBwbGljYXRpb24gbmFtZSBpcyBlbXB0eS4gUGxlYXNlIGNvbmZpZ3VyZSBpdCBpbiBzZXR0aW5ncy5cIik7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWYgLS0gcHJvY2VzcyBpcyBhIGdsb2JhbCBpbiB0aGUgRWxlY3Ryb24gcmVuZGVyZXIgcHJvY2Vzc1xyXG5cdFx0Y29uc3QgcGxhdGZvcm0gPSBwcm9jZXNzLnBsYXRmb3JtO1xyXG5cdFx0dGVybWluYWxMb2dnZXIubG9nKFwiT3BlbmluZyB0ZXJtaW5hbFwiLCB7IHBsYXRmb3JtLCB0ZXJtaW5hbEFwcCwgcHJvamVjdFBhdGggfSk7XHJcblxyXG5cdFx0aWYgKHBsYXRmb3JtID09PSAnd2luMzInKSB7XHJcblx0XHRcdC8vIFdpbmRvd3M6IFVzZSBzdGFydCBjb21tYW5kIHdpdGggY29uZmlndXJhYmxlIHRlcm1pbmFsXHJcblx0XHRcdGNvbnN0IGVzY2FwZWRQYXRoID0gcHJvamVjdFBhdGgucmVwbGFjZSgvXCIvZywgJ1wiJyk7XHJcblx0XHRcdGNvbnN0IGxvd2VyQXBwID0gdGVybWluYWxBcHAudG9Mb3dlckNhc2UoKTtcclxuXHJcblx0XHRcdGlmIChsb3dlckFwcCA9PT0gXCJ3dC5leGVcIiB8fCBsb3dlckFwcCA9PT0gXCJ3dFwiIHx8IGxvd2VyQXBwID09PSBcIndpbmRvd3MgdGVybWluYWxcIikge1xyXG5cdFx0XHRcdC8vIFdpbmRvd3MgVGVybWluYWxcclxuXHRcdFx0XHRleGVjKCd3aGVyZSB3dCcsIChlcnJvcjogeyBtZXNzYWdlPzogc3RyaW5nIH0gfCBudWxsKSA9PiB7XHJcblx0XHRcdFx0XHRpZiAoIWVycm9yKSB7XHJcblx0XHRcdFx0XHRcdGNvbnN0IGNvbW1hbmQgPSBgc3RhcnQgXCJcIiB3dC5leGUgLWQgXCIke2VzY2FwZWRQYXRofVwiYDtcclxuXHRcdFx0XHRcdFx0dGVybWluYWxMb2dnZXIubG9nKFwiV2luZG93cyBsYXVuY2ggKHd0KVwiLCB7IGNvbW1hbmQsIHByb2plY3RQYXRoIH0pO1xyXG5cdFx0XHRcdFx0XHRleGVjKGNvbW1hbmQsIChleGVjRXJyb3I6IHsgbWVzc2FnZT86IHN0cmluZyB9IHwgbnVsbCkgPT4ge1xyXG5cdFx0XHRcdFx0XHRcdGlmIChleGVjRXJyb3IpIHtcclxuXHRcdFx0XHRcdFx0XHRcdHRlcm1pbmFsTG9nZ2VyLmxvZyhcIldpbmRvd3MgVGVybWluYWwgZmFpbGVkLCBmYWxsaW5nIGJhY2sgdG8gY21kXCIsIHsgZXJyb3I6IGV4ZWNFcnJvci5tZXNzYWdlIH0pO1xyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gRmFsbGJhY2sgdG8gY21kXHJcblx0XHRcdFx0XHRcdFx0XHRjb25zdCBmYWxsYmFja0NvbW1hbmQgPSBgc3RhcnQgXCJcIiBjbWQuZXhlIC9LIFwiY2QgL2QgXCIke2VzY2FwZWRQYXRofVwiXCJgO1xyXG5cdFx0XHRcdFx0XHRcdFx0ZXhlYyhmYWxsYmFja0NvbW1hbmQsIChjbWRFcnJvcjogeyBtZXNzYWdlPzogc3RyaW5nIH0gfCBudWxsKSA9PiB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdGlmIChjbWRFcnJvcikge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgdGVybWluYWw6ICR7Y21kRXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcid9YCk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHQvLyBXaW5kb3dzIFRlcm1pbmFsIG5vdCBmb3VuZCwgZmFsbGJhY2sgdG8gY21kXHJcblx0XHRcdFx0XHRcdHRlcm1pbmFsTG9nZ2VyLmxvZyhcIldpbmRvd3MgVGVybWluYWwgbm90IGZvdW5kLCB1c2luZyBjbWRcIiwge30pO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBmYWxsYmFja0NvbW1hbmQgPSBgc3RhcnQgXCJcIiBjbWQuZXhlIC9LIFwiY2QgL2QgXCIke2VzY2FwZWRQYXRofVwiXCJgO1xyXG5cdFx0XHRcdFx0XHRleGVjKGZhbGxiYWNrQ29tbWFuZCwgKGNtZEVycm9yOiB7IG1lc3NhZ2U/OiBzdHJpbmcgfSB8IG51bGwpID0+IHtcclxuXHRcdFx0XHRcdFx0XHRpZiAoY21kRXJyb3IpIHtcclxuXHRcdFx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgdGVybWluYWw6ICR7Y21kRXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcid9YCk7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fSBlbHNlIGlmIChsb3dlckFwcCA9PT0gXCJwb3dlcnNoZWxsXCIgfHwgbG93ZXJBcHAgPT09IFwicG93ZXJzaGVsbC5leGVcIikge1xyXG5cdFx0XHRcdC8vIFBvd2VyU2hlbGxcclxuXHRcdFx0XHRjb25zdCBlc2NhcGVkUGF0aEZvclBTID0gcHJvamVjdFBhdGgucmVwbGFjZSgvJy9nLCBcIicnXCIpO1xyXG5cdFx0XHRcdGNvbnN0IGNvbW1hbmQgPSBgc3RhcnQgXCJcIiBwb3dlcnNoZWxsIC1Ob0V4aXQgLUNvbW1hbmQgXCJTZXQtTG9jYXRpb24gJyR7ZXNjYXBlZFBhdGhGb3JQU30nO1wiYDtcclxuXHRcdFx0XHR0ZXJtaW5hbExvZ2dlci5sb2coXCJXaW5kb3dzIGxhdW5jaCAocG93ZXJzaGVsbClcIiwgeyBjb21tYW5kLCBwcm9qZWN0UGF0aCB9KTtcclxuXHRcdFx0XHRleGVjKGNvbW1hbmQsIChlcnJvcjogeyBtZXNzYWdlPzogc3RyaW5nIH0gfCBudWxsKSA9PiB7XHJcblx0XHRcdFx0XHRpZiAoZXJyb3IpIHtcclxuXHRcdFx0XHRcdFx0bmV3IE5vdGljZShgRXJyb3Igb3BlbmluZyB0ZXJtaW5hbDogJHtlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJ31gKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fSBlbHNlIGlmIChsb3dlckFwcCA9PT0gXCJjbWQuZXhlXCIgfHwgbG93ZXJBcHAgPT09IFwiY21kXCIpIHtcclxuXHRcdFx0XHQvLyBDb21tYW5kIFByb21wdFxyXG5cdFx0XHRcdGNvbnN0IGNvbW1hbmQgPSBgc3RhcnQgXCJcIiBjbWQuZXhlIC9LIFwiY2QgL2QgXCIke2VzY2FwZWRQYXRofVwiXCJgO1xyXG5cdFx0XHRcdHRlcm1pbmFsTG9nZ2VyLmxvZyhcIldpbmRvd3MgbGF1bmNoIChjbWQpXCIsIHsgY29tbWFuZCwgcHJvamVjdFBhdGggfSk7XHJcblx0XHRcdFx0ZXhlYyhjb21tYW5kLCAoZXJyb3I6IHsgbWVzc2FnZT86IHN0cmluZyB9IHwgbnVsbCkgPT4ge1xyXG5cdFx0XHRcdFx0aWYgKGVycm9yKSB7XHJcblx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgdGVybWluYWw6ICR7ZXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcid9YCk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fSk7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0Ly8gR2VuZXJpYyB0ZXJtaW5hbCAtIHRyeSB0byBsYXVuY2ggaXQgZGlyZWN0bHlcclxuXHRcdFx0XHRjb25zdCBjb21tYW5kID0gYHN0YXJ0IFwiXCIgXCIke3Rlcm1pbmFsQXBwfVwiYDtcclxuXHRcdFx0XHR0ZXJtaW5hbExvZ2dlci5sb2coXCJXaW5kb3dzIGxhdW5jaCAoZ2VuZXJpYylcIiwgeyBjb21tYW5kLCB0ZXJtaW5hbEFwcCwgcHJvamVjdFBhdGggfSk7XHJcblx0XHRcdFx0ZXhlYyhjb21tYW5kLCAoZXJyb3I6IHsgbWVzc2FnZT86IHN0cmluZyB9IHwgbnVsbCkgPT4ge1xyXG5cdFx0XHRcdFx0aWYgKGVycm9yKSB7XHJcblx0XHRcdFx0XHRcdC8vIEZhbGxiYWNrIHRvIGNtZCBpZiBnZW5lcmljIGxhdW5jaCBmYWlsc1xyXG5cdFx0XHRcdFx0XHR0ZXJtaW5hbExvZ2dlci5sb2coXCJHZW5lcmljIHRlcm1pbmFsIGZhaWxlZCwgZmFsbGluZyBiYWNrIHRvIGNtZFwiLCB7IGVycm9yOiBlcnJvci5tZXNzYWdlIH0pO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBmYWxsYmFja0NvbW1hbmQgPSBgc3RhcnQgXCJcIiBjbWQuZXhlIC9LIFwiY2QgL2QgXCIke2VzY2FwZWRQYXRofVwiXCJgO1xyXG5cdFx0XHRcdFx0XHRleGVjKGZhbGxiYWNrQ29tbWFuZCwgKGNtZEVycm9yOiB7IG1lc3NhZ2U/OiBzdHJpbmcgfSB8IG51bGwpID0+IHtcclxuXHRcdFx0XHRcdFx0XHRpZiAoY21kRXJyb3IpIHtcclxuXHRcdFx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgdGVybWluYWw6ICR7Y21kRXJyb3IubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcid9YCk7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fVxyXG5cdFx0fSBlbHNlIGlmIChwbGF0Zm9ybSA9PT0gJ2RhcndpbicpIHtcclxuXHRcdFx0Ly8gbWFjT1M6IFVzZSBvcGVuIC1hIChzaW1wbGVyIHRoYW4gb3Nhc2NyaXB0KVxyXG5cdFx0XHRjb25zdCBlc2NhcGVkQXBwID0gZXNjYXBlRG91YmxlUXVvdGVzKHRlcm1pbmFsQXBwKTtcclxuXHRcdFx0Y29uc3QgZXNjYXBlZFBhdGggPSBlc2NhcGVEb3VibGVRdW90ZXMocHJvamVjdFBhdGgpO1xyXG5cdFx0XHRjb25zdCBjb21tYW5kID0gYG9wZW4gLW5hIFwiJHtlc2NhcGVkQXBwfVwiIFwiJHtlc2NhcGVkUGF0aH1cImA7XHJcblx0XHRcdHRlcm1pbmFsTG9nZ2VyLmxvZyhcIm1hY09TIGxhdW5jaFwiLCB7IGNvbW1hbmQsIHRlcm1pbmFsQXBwLCBwcm9qZWN0UGF0aCB9KTtcclxuXHRcdFx0ZXhlYyhjb21tYW5kLCAoZXJyb3I6IHsgbWVzc2FnZT86IHN0cmluZyB9IHwgbnVsbCkgPT4ge1xyXG5cdFx0XHRcdGlmIChlcnJvcikge1xyXG5cdFx0XHRcdFx0bmV3IE5vdGljZShgRXJyb3Igb3BlbmluZyB0ZXJtaW5hbDogJHtlcnJvci5tZXNzYWdlIHx8ICdVbmtub3duIGVycm9yJ31gKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0pO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0Ly8gTGludXg6IFRyeSBjb25maWd1cmFibGUgdGVybWluYWwgd2l0aCBmYWxsYmFjayBjaGFpblxyXG5cdFx0XHRjb25zdCB0ZXJtaW5hbHMgPSB0ZXJtaW5hbEFwcCA/IFt0ZXJtaW5hbEFwcF0gOiBbXCJnbm9tZS10ZXJtaW5hbFwiLCBcImtvbnNvbGVcIiwgXCJ4dGVybVwiXTtcclxuXHRcdFx0Y29uc3QgcHJvamVjdFBhdGhFc2NhcGVkID0gcHJvamVjdFBhdGgucmVwbGFjZSgvXCIvZywgJ1xcXFxcIicpO1xyXG5cclxuXHRcdFx0Ly8gVHJ5IGVhY2ggdGVybWluYWwgdW50aWwgb25lIHdvcmtzXHJcblx0XHRcdGNvbnN0IHRyeVRlcm1pbmFsID0gKGluZGV4OiBudW1iZXIpID0+IHtcclxuXHRcdFx0XHRpZiAoaW5kZXggPj0gdGVybWluYWxzLmxlbmd0aCkge1xyXG5cdFx0XHRcdFx0bmV3IE5vdGljZSgnTm8gc3VwcG9ydGVkIHRlcm1pbmFsIGZvdW5kLiBQbGVhc2UgaW5zdGFsbCBhIHRlcm1pbmFsIGFwcGxpY2F0aW9uIG9yIGNvbmZpZ3VyZSBvbmUgaW4gc2V0dGluZ3MuJyk7XHJcblx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBjdXJyZW50VGVybWluYWwgPSB0ZXJtaW5hbHNbaW5kZXhdO1xyXG5cdFx0XHRcdGNvbnN0IHRlcm1pbmFsTmFtZSA9IGN1cnJlbnRUZXJtaW5hbC5zcGxpdCgnICcpWzBdO1xyXG5cclxuXHRcdFx0XHQvLyBDaGVjayBpZiB0ZXJtaW5hbCBleGlzdHNcclxuXHRcdFx0XHRleGVjKGB3aGljaCAke3Rlcm1pbmFsTmFtZX1gLCAoZXJyb3I6IHsgbWVzc2FnZT86IHN0cmluZyB9IHwgbnVsbCkgPT4ge1xyXG5cdFx0XHRcdFx0aWYgKCFlcnJvcikge1xyXG5cdFx0XHRcdFx0XHQvLyBUZXJtaW5hbCBmb3VuZCwgdHJ5IHRvIGxhdW5jaCBpdFxyXG5cdFx0XHRcdFx0XHRsZXQgY29tbWFuZDogc3RyaW5nO1xyXG5cdFx0XHRcdFx0XHRpZiAoY3VycmVudFRlcm1pbmFsLmluY2x1ZGVzKFwiZ25vbWUtdGVybWluYWxcIikpIHtcclxuXHRcdFx0XHRcdFx0XHRjb21tYW5kID0gYGdub21lLXRlcm1pbmFsIC0td29ya2luZy1kaXJlY3Rvcnk9XCIke3Byb2plY3RQYXRoRXNjYXBlZH1cImA7XHJcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoY3VycmVudFRlcm1pbmFsLmluY2x1ZGVzKFwia29uc29sZVwiKSkge1xyXG5cdFx0XHRcdFx0XHRcdGNvbW1hbmQgPSBga29uc29sZSAtLXdvcmtkaXIgXCIke3Byb2plY3RQYXRoRXNjYXBlZH1cImA7XHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdFx0Ly8gR2VuZXJpYyB0ZXJtaW5hbFxyXG5cdFx0XHRcdFx0XHRcdGNvbW1hbmQgPSBgJHtjdXJyZW50VGVybWluYWx9IC1lIFwiY2QgXFxcXFwiJHtwcm9qZWN0UGF0aEVzY2FwZWR9XFxcXFwiICYmIGJhc2hcImA7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0dGVybWluYWxMb2dnZXIubG9nKFwiTGludXggbGF1bmNoXCIsIHsgY29tbWFuZCwgdGVybWluYWw6IGN1cnJlbnRUZXJtaW5hbCwgcHJvamVjdFBhdGggfSk7XHJcblx0XHRcdFx0XHRcdGV4ZWMoY29tbWFuZCwgKGV4ZWNFcnJvcjogeyBtZXNzYWdlPzogc3RyaW5nIH0gfCBudWxsKSA9PiB7XHJcblx0XHRcdFx0XHRcdFx0aWYgKGV4ZWNFcnJvciAmJiBpbmRleCA8IHRlcm1pbmFscy5sZW5ndGggLSAxKSB7XHJcblx0XHRcdFx0XHRcdFx0XHR0ZXJtaW5hbExvZ2dlci5sb2coXCJUZXJtaW5hbCBsYXVuY2ggZmFpbGVkLCB0cnlpbmcgbmV4dFwiLCB7IHRlcm1pbmFsOiBjdXJyZW50VGVybWluYWwsIGVycm9yOiBleGVjRXJyb3IubWVzc2FnZSB9KTtcclxuXHRcdFx0XHRcdFx0XHRcdHRyeVRlcm1pbmFsKGluZGV4ICsgMSk7XHJcblx0XHRcdFx0XHRcdFx0fSBlbHNlIGlmIChleGVjRXJyb3IpIHtcclxuXHRcdFx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgdGVybWluYWw6ICR7ZXhlY0Vycm9yLm1lc3NhZ2UgfHwgJ1Vua25vd24gZXJyb3InfWApO1xyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHQvLyBUZXJtaW5hbCBub3QgZm91bmQsIHRyeSBuZXh0XHJcblx0XHRcdFx0XHRcdHRlcm1pbmFsTG9nZ2VyLmxvZyhcIlRlcm1pbmFsIG5vdCBmb3VuZCwgdHJ5aW5nIG5leHRcIiwgeyB0ZXJtaW5hbDogY3VycmVudFRlcm1pbmFsIH0pO1xyXG5cdFx0XHRcdFx0XHR0cnlUZXJtaW5hbChpbmRleCArIDEpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0dHJ5VGVybWluYWwoMCk7XHJcblx0XHR9XHJcblx0fSBjYXRjaCAoZXJyb3IpIHtcclxuXHRcdHRlcm1pbmFsTG9nZ2VyLmxvZyhcIlVuZXhwZWN0ZWQgZXJyb3JcIiwgeyBlcnJvciB9KTtcclxuXHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgdGVybWluYWw6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xyXG5cdH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE9wZW4gY29uZmlnIGZpbGUgaW4gZGVmYXVsdCBlZGl0b3JcclxuICogRXhwb3J0ZWQgZm9yIHVzZSBieSByaWJib24gaWNvbnNcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBvcGVuQ29uZmlnRmlsZShhcHA6IEFwcCwgc2V0dGluZ3M6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyk6IFByb21pc2U8dm9pZD4ge1xyXG5cdHRyeSB7XHJcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5vZGVqcy1tb2R1bGVzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzLCBuby11bmRlZiAtLSBmcyBpcyByZXF1aXJlZCBmb3IgdmVyaWZ5aW5nIGNvbmZpZyBmaWxlIGV4aXN0cyBvbiBkZXNrdG9wXHJcblx0XHRjb25zdCBmcyA9IHJlcXVpcmUoJ2ZzJykgYXMgeyBleGlzdHNTeW5jOiAocGF0aDogc3RyaW5nKSA9PiBib29sZWFuIH07XHJcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5vZGVqcy1tb2R1bGVzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzLCBuby11bmRlZiAtLSBwYXRoIGlzIHJlcXVpcmVkIGZvciByZXNvbHZpbmcgcGF0aHMgb24gZGVza3RvcFxyXG5cdFx0Y29uc3QgcGF0aCA9IHJlcXVpcmUoJ3BhdGgnKSBhcyB7IHJlc29sdmU6ICguLi5hcmdzOiBzdHJpbmdbXSkgPT4gc3RyaW5nIH07XHJcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0cywgbm8tdW5kZWYgLS0gZWxlY3Ryb24gc2hlbGwgaXMgcmVxdWlyZWQgdG8gb3BlbiBmaWxlcyBpbiBkZWZhdWx0IGVkaXRvclxyXG5cdFx0Y29uc3QgeyBzaGVsbCB9ID0gcmVxdWlyZSgnZWxlY3Ryb24nKSBhcyB7IHNoZWxsOiB7IG9wZW5QYXRoOiAocGF0aDogc3RyaW5nKSA9PiBQcm9taXNlPHN0cmluZz4gfSB9O1xyXG5cclxuXHRcdC8vIEdldCB0aGUgYWN0dWFsIHZhdWx0IHBhdGggc3RyaW5nIGZyb20gdGhlIGFkYXB0ZXJcclxuXHRcdGNvbnN0IGFkYXB0ZXIgPSBhcHAudmF1bHQuYWRhcHRlciBhcyB1bmtub3duIGFzIHsgYmFzZVBhdGg/OiBzdHJpbmc7IHBhdGg/OiBzdHJpbmcgfTtcclxuXHRcdGNvbnN0IHZhdWx0UGF0aCA9IGFkYXB0ZXIuYmFzZVBhdGggfHwgYWRhcHRlci5wYXRoO1xyXG5cdFx0Y29uc3QgdmF1bHRQYXRoU3RyaW5nID0gdHlwZW9mIHZhdWx0UGF0aCA9PT0gJ3N0cmluZycgPyB2YXVsdFBhdGggOiBTdHJpbmcodmF1bHRQYXRoKTtcclxuXHJcblx0XHQvLyBSZXNvbHZlIGNvbmZpZyBmaWxlIHBhdGhcclxuXHRcdGlmICghc2V0dGluZ3MuY29uZmlnRmlsZVBhdGggfHwgIXNldHRpbmdzLmNvbmZpZ0ZpbGVQYXRoLnRyaW0oKSkge1xyXG5cdFx0XHRuZXcgTm90aWNlKFwiUGxlYXNlIHNwZWNpZnkgYSBjb25maWcgZmlsZSBwYXRoIGluIHNldHRpbmdzLlwiKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIFVzZSBjdXN0b20gcGF0aCByZWxhdGl2ZSB0byB2YXVsdFxyXG5cdFx0Y29uc3QgY29uZmlnUGF0aCA9IHBhdGgucmVzb2x2ZSh2YXVsdFBhdGhTdHJpbmcsIHNldHRpbmdzLmNvbmZpZ0ZpbGVQYXRoKTtcclxuXHJcblx0XHQvLyBDaGVjayBpZiBmaWxlIGV4aXN0c1xyXG5cdFx0aWYgKCFmcy5leGlzdHNTeW5jKGNvbmZpZ1BhdGgpKSB7XHJcblx0XHRcdG5ldyBOb3RpY2UoYENvbmZpZyBmaWxlIG5vdCBmb3VuZCBhdDogJHtjb25maWdQYXRofWApO1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gVXNlIEVsZWN0cm9uJ3Mgc2hlbGwgdG8gb3BlbiB0aGUgZmlsZSB3aXRoIHRoZSBkZWZhdWx0IGVkaXRvclxyXG5cdFx0YXdhaXQgc2hlbGwub3BlblBhdGgoY29uZmlnUGF0aCk7XHJcblx0fSBjYXRjaCAoZXJyb3IpIHtcclxuXHRcdG5ldyBOb3RpY2UoYEVycm9yIG9wZW5pbmcgY29uZmlnIGZpbGU6ICR7ZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpfWApO1xyXG5cdH1cclxufSIsICJpbXBvcnQgeyBBcHAsIFRGaWxlLCBURm9sZGVyLCBOb3RpY2UgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCB7IEFzdHJvQ29tcG9zZXJTZXR0aW5ncywgRmlsZUNyZWF0aW9uT3B0aW9ucywgUmVuYW1lT3B0aW9ucywgQ29udGVudFR5cGUsIENvbnRlbnRUeXBlSWQsIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IG1hdGNoZXNGb2xkZXJQYXR0ZXJuLCBzb3J0QnlQYXR0ZXJuU3BlY2lmaWNpdHkgfSBmcm9tIFwiLi9wYXRoLW1hdGNoaW5nXCI7XG5pbXBvcnQgeyB0b0tlYmFiQ2FzZSB9IGZyb20gXCIuL3N0cmluZy11dGlsc1wiO1xuXG5leHBvcnQgY2xhc3MgRmlsZU9wZXJhdGlvbnMge1xuXHRjb25zdHJ1Y3Rvcihwcml2YXRlIGFwcDogQXBwLCBwcml2YXRlIHNldHRpbmdzOiBBc3Ryb0NvbXBvc2VyU2V0dGluZ3MsIHByaXZhdGUgcGx1Z2luPzogQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSkgeyB9XG5cblx0Ly8gR2V0IGZyZXNoIHNldHRpbmdzIGZyb20gcGx1Z2luIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIHVzZSBzdG9yZWQgc2V0dGluZ3Ncblx0cHJpdmF0ZSBnZXRTZXR0aW5ncygpOiBBc3Ryb0NvbXBvc2VyU2V0dGluZ3Mge1xuXHRcdC8vIEFsd2F5cyBwcmVmZXIgcGx1Z2luIHNldHRpbmdzICh0aGV5J3JlIGtlcHQgdXAgdG8gZGF0ZSlcblx0XHRpZiAodGhpcy5wbHVnaW4/LnNldHRpbmdzKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLnNldHRpbmdzO1xuXHR9XG5cblx0Z2VuZXJhdGVGaWxlbmFtZSh0aXRsZTogc3RyaW5nLCBlbmFibGVVbmRlcnNjb3JlUHJlZml4OiBib29sZWFuID0gZmFsc2UpOiBzdHJpbmcge1xuXHRcdGNvbnN0IGtlYmFiVGl0bGUgPSB0b0tlYmFiQ2FzZSh0aXRsZSk7XG5cdFx0Ly8gSWYga2ViYWIgY2FzZSByZXN1bHRzIGluIGVtcHR5IHN0cmluZywgdXNlIGEgZmFsbGJhY2tcblx0XHRjb25zdCBzYWZlS2ViYWJUaXRsZSA9IGtlYmFiVGl0bGUgfHwgXCJ1bnRpdGxlZFwiO1xuXHRcdGNvbnN0IHByZWZpeCA9IGVuYWJsZVVuZGVyc2NvcmVQcmVmaXggPyBcIl9cIiA6IFwiXCI7XG5cdFx0cmV0dXJuIGAke3ByZWZpeH0ke3NhZmVLZWJhYlRpdGxlfWA7XG5cdH1cblxuXHRkZXRlcm1pbmVUeXBlKGZpbGU6IFRGaWxlKTogQ29udGVudFR5cGVJZCB7XG5cdFx0Y29uc3QgZmlsZVBhdGggPSBmaWxlLnBhdGg7XG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLmdldFNldHRpbmdzKCk7XG5cblx0XHQvLyBDaGVjayBhbGwgY29udGVudCB0eXBlcywgc29ydGVkIGJ5IHBhdHRlcm4gc3BlY2lmaWNpdHkgKG1vcmUgc3BlY2lmaWMgZmlyc3QpXG5cdFx0Y29uc3QgY29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdGNvbnN0IHNvcnRlZFR5cGVzID0gc29ydEJ5UGF0dGVyblNwZWNpZmljaXR5KGNvbnRlbnRUeXBlcyk7XG5cblx0XHRmb3IgKGNvbnN0IGNvbnRlbnRUeXBlIG9mIHNvcnRlZFR5cGVzKSB7XG5cdFx0XHRpZiAoIWNvbnRlbnRUeXBlLmVuYWJsZWQpIGNvbnRpbnVlO1xuXG5cdFx0XHQvLyBIYW5kbGUgYmxhbmsgZm9sZGVyIChyb290KSAtIG1hdGNoZXMgZmlsZXMgaW4gdmF1bHQgcm9vdCBvbmx5XG5cdFx0XHRpZiAoIWNvbnRlbnRUeXBlLmZvbGRlciB8fCBjb250ZW50VHlwZS5mb2xkZXIudHJpbSgpID09PSBcIlwiKSB7XG5cdFx0XHRcdGlmICghZmlsZVBhdGguaW5jbHVkZXMoXCIvXCIpIHx8IGZpbGVQYXRoLnNwbGl0KFwiL1wiKS5sZW5ndGggPT09IDEpIHtcblx0XHRcdFx0XHRyZXR1cm4gY29udGVudFR5cGUuaWQ7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAobWF0Y2hlc0ZvbGRlclBhdHRlcm4oZmlsZVBhdGgsIGNvbnRlbnRUeXBlLmZvbGRlcikpIHtcblx0XHRcdFx0Ly8gQ2hlY2sgaWdub3JlU3ViZm9sZGVycyBpZiBmb2xkZXIgaXMgc3BlY2lmaWVkXG5cdFx0XHRcdGlmIChjb250ZW50VHlwZS5pZ25vcmVTdWJmb2xkZXJzKSB7XG5cdFx0XHRcdFx0Y29uc3QgcGF0aFNlZ21lbnRzID0gZmlsZVBhdGguc3BsaXQoXCIvXCIpO1xuXHRcdFx0XHRcdGNvbnN0IHBhdGhEZXB0aCA9IHBhdGhTZWdtZW50cy5sZW5ndGg7XG5cdFx0XHRcdFx0Y29uc3QgcGF0dGVyblNlZ21lbnRzID0gY29udGVudFR5cGUuZm9sZGVyLnNwbGl0KFwiL1wiKTtcblx0XHRcdFx0XHRjb25zdCBleHBlY3RlZERlcHRoID0gcGF0dGVyblNlZ21lbnRzLmxlbmd0aDtcblxuXHRcdFx0XHRcdGlmIChjb250ZW50VHlwZS5jcmVhdGlvbk1vZGUgPT09IFwiZm9sZGVyXCIpIHtcblx0XHRcdFx0XHRcdC8vIEZvciBmb2xkZXItYmFzZWQgY3JlYXRpb24sIGZpbGVzIGFyZSBvbmUgbGV2ZWwgZGVlcGVyIChlLmcuLCB0ZXN0L215LWZpbGUvaW5kZXgubWQpXG5cdFx0XHRcdFx0XHQvLyBTbyB3ZSBuZWVkIHRvIGFsbG93IG9uZSBleHRyYSBsZXZlbCBiZXlvbmQgdGhlIHBhdHRlcm4gZGVwdGhcblx0XHRcdFx0XHRcdGNvbnN0IGZvbGRlckRlcHRoID0gcGF0aERlcHRoIC0gMTsgLy8gU3VidHJhY3QgMSBmb3IgdGhlIGluZGV4Lm1kIGZpbGVcblx0XHRcdFx0XHRcdGlmIChmb2xkZXJEZXB0aCA9PT0gZXhwZWN0ZWREZXB0aCB8fCBmb2xkZXJEZXB0aCA9PT0gZXhwZWN0ZWREZXB0aCArIDEpIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGNvbnRlbnRUeXBlLmlkO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHQvLyBGb3IgZmlsZS1iYXNlZCBjcmVhdGlvbiwgZmlsZXMgYXJlIGF0IHRoZSBzYW1lIGRlcHRoIGFzIHRoZSBwYXR0ZXJuXG5cdFx0XHRcdFx0XHRpZiAocGF0aERlcHRoID09PSBleHBlY3RlZERlcHRoKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBjb250ZW50VHlwZS5pZDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIGNvbnRlbnRUeXBlLmlkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gSWYgbm8gY29udGVudCB0eXBlIG1hdGNoZXMsIHJldHVybiBcIm5vdGVcIiBhcyBmYWxsYmFja1xuXHRcdHJldHVybiBcIm5vdGVcIjtcblx0fVxuXG5cdGdldENvbnRlbnRUeXBlKHR5cGVJZDogQ29udGVudFR5cGVJZCk6IENvbnRlbnRUeXBlIHwgbnVsbCB7XG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLmdldFNldHRpbmdzKCk7XG5cdFx0Y29uc3QgY29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdHJldHVybiBjb250ZW50VHlwZXMuZmluZChjdCA9PiBjdC5pZCA9PT0gdHlwZUlkKSB8fCBudWxsO1xuXHR9XG5cblx0LyoqXG5cdCAqIEhlbHBlciB0byBnZXQgY29udGVudCB0eXBlIGZvciBhIGdpdmVuIGZpbGUgcGF0aFxuXHQgKi9cblx0Z2V0Q29udGVudFR5cGVCeVBhdGgoZmlsZVBhdGg6IHN0cmluZyk6IENvbnRlbnRUeXBlIHwgbnVsbCB7XG5cdFx0Ly8gQ3JlYXRlIGEgZHVtbXkgVEZpbGUgZm9yIGRldGVybWluZVR5cGVcblx0XHRjb25zdCBkdW1teUZpbGUgPSB7IHBhdGg6IGZpbGVQYXRoIH0gYXMgVEZpbGU7XG5cdFx0Y29uc3QgdHlwZUlkID0gdGhpcy5kZXRlcm1pbmVUeXBlKGR1bW15RmlsZSk7XG5cdFx0aWYgKHR5cGVJZCA9PT0gXCJub3RlXCIpIHJldHVybiBudWxsO1xuXHRcdHJldHVybiB0aGlzLmdldENvbnRlbnRUeXBlKHR5cGVJZCk7XG5cdH1cblxuXHRnZXRUaXRsZUtleSh0eXBlOiBDb250ZW50VHlwZUlkKTogc3RyaW5nIHtcblx0XHQvLyBGb3IgZ2VuZXJpYyBub3RlcywgYWx3YXlzIHVzZSBcInRpdGxlXCJcblx0XHRpZiAodHlwZSA9PT0gXCJub3RlXCIpIHJldHVybiBcInRpdGxlXCI7XG5cblx0XHRjb25zdCBjb250ZW50VHlwZSA9IHRoaXMuZ2V0Q29udGVudFR5cGUodHlwZSk7XG5cdFx0aWYgKCFjb250ZW50VHlwZSkgcmV0dXJuIFwidGl0bGVcIjtcblxuXHRcdGNvbnN0IHRlbXBsYXRlID0gY29udGVudFR5cGUudGVtcGxhdGU7XG5cdFx0Y29uc3QgbGluZXMgPSB0ZW1wbGF0ZS5zcGxpdChcIlxcblwiKTtcblx0XHRsZXQgaW5Qcm9wZXJ0aWVzID0gZmFsc2U7XG5cdFx0Zm9yIChjb25zdCBsaW5lIG9mIGxpbmVzKSB7XG5cdFx0XHRjb25zdCB0cmltbWVkID0gbGluZS50cmltKCk7XG5cdFx0XHRpZiAodHJpbW1lZCA9PT0gXCItLS1cIikge1xuXHRcdFx0XHRpblByb3BlcnRpZXMgPSAhaW5Qcm9wZXJ0aWVzO1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblx0XHRcdGlmIChpblByb3BlcnRpZXMpIHtcblx0XHRcdFx0Y29uc3QgbWF0Y2ggPSB0cmltbWVkLm1hdGNoKC9eKFxcdyspOlxccyooLispJC8pO1xuXHRcdFx0XHRpZiAobWF0Y2gpIHtcblx0XHRcdFx0XHRjb25zdCBrZXkgPSBtYXRjaFsxXTtcblx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IG1hdGNoWzJdO1xuXHRcdFx0XHRcdGlmICh2YWx1ZS5pbmNsdWRlcyhcInt7dGl0bGV9fVwiKSkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGtleTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIFwidGl0bGVcIjtcblx0fVxuXG5cdGFzeW5jIGNyZWF0ZUZpbGUob3B0aW9uczogRmlsZUNyZWF0aW9uT3B0aW9ucyk6IFByb21pc2U8VEZpbGUgfCBudWxsPiB7XG5cdFx0Y29uc3QgeyBmaWxlLCB0aXRsZSwgdHlwZSB9ID0gb3B0aW9ucztcblxuXHRcdGlmICghdGl0bGUpIHtcblx0XHRcdG5ldyBOb3RpY2UoYFRpdGxlIGlzIHJlcXVpcmVkIHRvIGNyZWF0ZSBhICR7dHlwZX0uYCk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cblx0XHQvLyBHZXQgY29udGVudCB0eXBlIHNldHRpbmdzXG5cdFx0Y29uc3QgY29udGVudFR5cGUgPSB0aGlzLmdldENvbnRlbnRUeXBlKHR5cGUpO1xuXHRcdGlmICghY29udGVudFR5cGUgJiYgdHlwZSAhPT0gXCJub3RlXCIpIHtcblx0XHRcdG5ldyBOb3RpY2UoYENvbnRlbnQgdHlwZSAke3R5cGV9IG5vdCBmb3VuZC5gKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdGNvbnN0IGtlYmFiVGl0bGUgPSB0b0tlYmFiQ2FzZSh0aXRsZSk7XG5cdFx0Y29uc3QgZW5hYmxlVW5kZXJzY29yZVByZWZpeCA9IGNvbnRlbnRUeXBlPy5lbmFibGVVbmRlcnNjb3JlUHJlZml4IHx8IGZhbHNlO1xuXHRcdGNvbnN0IHByZWZpeCA9IGVuYWJsZVVuZGVyc2NvcmVQcmVmaXggPyBcIl9cIiA6IFwiXCI7XG5cblx0XHRsZXQgdGFyZ2V0Rm9sZGVyID0gXCJcIjtcblx0XHRpZiAodHlwZSA9PT0gXCJub3RlXCIpIHtcblx0XHRcdC8vIEZvciBnZW5lcmljIG5vdGVzLCBrZWVwIHRoZW0gaW4gdGhlaXIgY3VycmVudCBsb2NhdGlvblxuXHRcdFx0dGFyZ2V0Rm9sZGVyID0gXCJcIjtcblx0XHR9IGVsc2UgaWYgKGNvbnRlbnRUeXBlKSB7XG5cdFx0XHQvLyBHZXQgdGhlIGRpcmVjdG9yeSB3aGVyZSB0aGUgdXNlciBjcmVhdGVkIHRoZSBmaWxlXG5cdFx0XHRjb25zdCBvcmlnaW5hbERpciA9IGZpbGUucGFyZW50Py5wYXRoIHx8IFwiXCI7XG5cblx0XHRcdC8vIFJlc3BlY3QgdGhlIHVzZXIncyBjaG9zZW4gbG9jYXRpb24gKHN1YmZvbGRlcilcblx0XHRcdC8vIE9ubHkgdXNlIHRoZSBjb25maWd1cmVkIGZvbGRlciBpZiB0aGUgdXNlciBjcmVhdGVkIHRoZSBmaWxlIGluIHRoZSB2YXVsdCByb290XG5cdFx0XHRpZiAob3JpZ2luYWxEaXIgPT09IFwiXCIgfHwgb3JpZ2luYWxEaXIgPT09IFwiL1wiKSB7XG5cdFx0XHRcdHRhcmdldEZvbGRlciA9IGNvbnRlbnRUeXBlLmZvbGRlciB8fCBcIlwiO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGFyZ2V0Rm9sZGVyID0gb3JpZ2luYWxEaXI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHRhcmdldEZvbGRlcikge1xuXHRcdFx0Y29uc3QgZm9sZGVyID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKHRhcmdldEZvbGRlcik7XG5cdFx0XHRpZiAoIShmb2xkZXIgaW5zdGFuY2VvZiBURm9sZGVyKSkge1xuXHRcdFx0XHRhd2FpdCB0aGlzLmFwcC52YXVsdC5jcmVhdGVGb2xkZXIodGFyZ2V0Rm9sZGVyKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRjb25zdCBjcmVhdGlvbk1vZGUgPSBjb250ZW50VHlwZT8uY3JlYXRpb25Nb2RlIHx8IFwiZmlsZVwiO1xuXHRcdGlmIChjcmVhdGlvbk1vZGUgPT09IFwiZm9sZGVyXCIpIHtcblx0XHRcdHJldHVybiB0aGlzLmNyZWF0ZUZvbGRlclN0cnVjdHVyZShmaWxlLCBrZWJhYlRpdGxlLCBwcmVmaXgsIHRhcmdldEZvbGRlciwgdHlwZSwgY29udGVudFR5cGUpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5jcmVhdGVGaWxlU3RydWN0dXJlKGZpbGUsIGtlYmFiVGl0bGUsIHByZWZpeCwgdGFyZ2V0Rm9sZGVyLCBjb250ZW50VHlwZSk7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBhc3luYyBjcmVhdGVGb2xkZXJTdHJ1Y3R1cmUoZmlsZTogVEZpbGUsIGtlYmFiVGl0bGU6IHN0cmluZywgcHJlZml4OiBzdHJpbmcsIHRhcmdldEZvbGRlcjogc3RyaW5nLCB0eXBlOiBDb250ZW50VHlwZUlkLCBjb250ZW50VHlwZTogQ29udGVudFR5cGUgfCBudWxsKTogUHJvbWlzZTxURmlsZSB8IG51bGw+IHtcblx0XHRjb25zdCBmb2xkZXJOYW1lID0gYCR7cHJlZml4fSR7a2ViYWJUaXRsZX1gO1xuXHRcdGxldCBmb2xkZXJQYXRoOiBzdHJpbmc7XG5cblx0XHRpZiAodGFyZ2V0Rm9sZGVyKSB7XG5cdFx0XHQvLyBNb3ZlIHRvIHRhcmdldCBmb2xkZXJcblx0XHRcdGZvbGRlclBhdGggPSBgJHt0YXJnZXRGb2xkZXJ9LyR7Zm9sZGVyTmFtZX1gO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBLZWVwIGluIGN1cnJlbnQgbG9jYXRpb25cblx0XHRcdGNvbnN0IGN1cnJlbnREaXIgPSBmaWxlLnBhcmVudCA/IGZpbGUucGFyZW50LnBhdGggOiBcIlwiO1xuXHRcdFx0aWYgKGN1cnJlbnREaXIgJiYgY3VycmVudERpciAhPT0gXCIvXCIpIHtcblx0XHRcdFx0Zm9sZGVyUGF0aCA9IGAke2N1cnJlbnREaXJ9LyR7Zm9sZGVyTmFtZX1gO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gRmlsZSBpcyBpbiB2YXVsdCByb290LCBqdXN0IHVzZSBmb2xkZXIgbmFtZVxuXHRcdFx0XHRmb2xkZXJQYXRoID0gZm9sZGVyTmFtZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0cnkge1xuXHRcdFx0Y29uc3QgZm9sZGVyID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKGZvbGRlclBhdGgpO1xuXHRcdFx0aWYgKCEoZm9sZGVyIGluc3RhbmNlb2YgVEZvbGRlcikpIHtcblx0XHRcdFx0YXdhaXQgdGhpcy5hcHAudmF1bHQuY3JlYXRlRm9sZGVyKGZvbGRlclBhdGgpO1xuXHRcdFx0fVxuXHRcdH0gY2F0Y2gge1xuXHRcdFx0Ly8gRm9sZGVyIG1pZ2h0IGFscmVhZHkgZXhpc3QsIHByb2NlZWRcblx0XHR9XG5cblx0XHRjb25zdCBpbmRleEZpbGVOYW1lID0gY29udGVudFR5cGU/LmluZGV4RmlsZU5hbWUgfHwgXCJpbmRleFwiO1xuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGNvbnRlbnRUeXBlPy51c2VNZHhFeHRlbnNpb24gPyBcIi5tZHhcIiA6IFwiLm1kXCI7XG5cdFx0Y29uc3QgZmlsZU5hbWUgPSBgJHtpbmRleEZpbGVOYW1lfSR7ZXh0ZW5zaW9ufWA7XG5cdFx0Y29uc3QgbmV3UGF0aCA9IGAke2ZvbGRlclBhdGh9LyR7ZmlsZU5hbWV9YDtcblxuXHRcdGNvbnN0IGV4aXN0aW5nRmlsZSA9IHRoaXMuYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChuZXdQYXRoKTtcblx0XHRpZiAoZXhpc3RpbmdGaWxlIGluc3RhbmNlb2YgVEZpbGUpIHtcblx0XHRcdG5ldyBOb3RpY2UoYEZpbGUgYWxyZWFkeSBleGlzdHMgYXQgJHtuZXdQYXRofS5gKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdC8vIFRyYWNrIHRoYXQgdGhpcyBmaWxlIHdpbGwgYmUgY3JlYXRlZCBieSB0aGUgcGx1Z2luIEJFRk9SRSByZW5hbWluZ1xuXHRcdC8vIFRoaXMgcHJldmVudHMgdGhlIGNyZWF0ZSBldmVudCBmcm9tIHRyaWdnZXJpbmcgYW5vdGhlciBtb2RhbFxuXHRcdGlmICh0aGlzLnBsdWdpbikge1xuXHRcdFx0dGhpcy5wbHVnaW4ucGx1Z2luQ3JlYXRlZEZpbGVzLnNldChuZXdQYXRoLCBEYXRlLm5vdygpKTtcblx0XHR9XG5cblx0XHR0cnkge1xuXHRcdFx0YXdhaXQgdGhpcy5hcHAuZmlsZU1hbmFnZXIucmVuYW1lRmlsZShmaWxlLCBuZXdQYXRoKTtcblx0XHRcdGNvbnN0IG5ld0ZpbGUgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgobmV3UGF0aCk7XG5cdFx0XHRpZiAoIShuZXdGaWxlIGluc3RhbmNlb2YgVEZpbGUpKSB7XG5cdFx0XHRcdHJldHVybiBudWxsO1xuXHRcdFx0fVxuXG5cdFx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdFx0Y29uc3QgZmlsZUV4cGxvcmVyID0gdGhpcy5hcHAud29ya3NwYWNlLmdldExlYXZlc09mVHlwZShcImZpbGUtZXhwbG9yZXJcIilbMF07XG5cdFx0XHRcdGlmIChmaWxlRXhwbG9yZXIgJiYgZmlsZUV4cGxvcmVyLnZpZXcpIHtcblx0XHRcdFx0XHRjb25zdCB2aWV3ID0gZmlsZUV4cGxvcmVyLnZpZXc7XG5cdFx0XHRcdFx0aWYgKHZpZXcgJiYgdHlwZW9mIHZpZXcgPT09ICdvYmplY3QnICYmICd0cmVlJyBpbiB2aWV3KSB7XG5cdFx0XHRcdFx0XHRjb25zdCBmaWxlVHJlZSA9ICh2aWV3IGFzIHsgdHJlZT86IHsgcmV2ZWFsRmlsZT86IChmaWxlOiBURmlsZSkgPT4gdm9pZCB9IH0pLnRyZWU7XG5cdFx0XHRcdFx0XHRpZiAoZmlsZVRyZWUgJiYgbmV3RmlsZSBpbnN0YW5jZW9mIFRGaWxlICYmIHR5cGVvZiBmaWxlVHJlZS5yZXZlYWxGaWxlID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdFx0XHRcdGZpbGVUcmVlLnJldmVhbEZpbGUobmV3RmlsZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9LCAyMDApO1xuXG5cdFx0XHRjb25zdCBsZWFmID0gdGhpcy5hcHAud29ya3NwYWNlLmdldExlYWYoZmFsc2UpO1xuXHRcdFx0YXdhaXQgbGVhZi5vcGVuRmlsZShuZXdGaWxlKTtcblxuXHRcdFx0Ly8gUG9zaXRpb24gY3Vyc29yIGF0IHRoZSBlbmQgb2YgY29udGVudCBhZnRlciBlZGl0b3IgaXMgcmVhZHlcblx0XHRcdGNvbnN0IHBvc2l0aW9uQ3Vyc29yID0gKCkgPT4ge1xuXHRcdFx0XHRjb25zdCB2aWV3ID0gbGVhZi52aWV3O1xuXHRcdFx0XHRpZiAodmlldyAmJiAnZWRpdG9yJyBpbiB2aWV3KSB7XG5cdFx0XHRcdFx0Y29uc3QgZWRpdG9yID0gKHZpZXcgYXMgeyBlZGl0b3I/OiB7IHNldEN1cnNvcjogKHBvczogeyBsaW5lOiBudW1iZXI7IGNoOiBudW1iZXIgfSkgPT4gdm9pZDsgZ2V0VmFsdWU6ICgpID0+IHN0cmluZzsgZm9jdXM6ICgpID0+IHZvaWQgfSB9KS5lZGl0b3I7XG5cdFx0XHRcdFx0aWYgKGVkaXRvcikge1xuXHRcdFx0XHRcdFx0Y29uc3QgY29udGVudCA9IGVkaXRvci5nZXRWYWx1ZSgpO1xuXHRcdFx0XHRcdFx0aWYgKGNvbnRlbnQpIHtcblx0XHRcdFx0XHRcdFx0Y29uc3QgbGluZXMgPSBjb250ZW50LnNwbGl0KCdcXG4nKTtcblx0XHRcdFx0XHRcdFx0Y29uc3QgbGFzdExpbmUgPSBsaW5lcy5sZW5ndGggLSAxO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBsYXN0TGluZUxlbmd0aCA9IGxpbmVzW2xhc3RMaW5lXT8ubGVuZ3RoIHx8IDA7XG5cdFx0XHRcdFx0XHRcdGVkaXRvci5zZXRDdXJzb3IoeyBsaW5lOiBsYXN0TGluZSwgY2g6IGxhc3RMaW5lTGVuZ3RoIH0pO1xuXHRcdFx0XHRcdFx0XHRlZGl0b3IuZm9jdXMoKTtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH07XG5cblx0XHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRpZiAoIXBvc2l0aW9uQ3Vyc29yKCkpIHtcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCgpID0+IHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uQ3Vyc29yKCk7XG5cdFx0XHRcdFx0fSwgMjAwKTtcblx0XHRcdFx0fVxuXHRcdFx0fSwgMTAwKTtcblxuXHRcdFx0cmV0dXJuIG5ld0ZpbGU7XG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcblx0XHRcdGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcblx0XHRcdG5ldyBOb3RpY2UoYEZhaWxlZCB0byBjcmVhdGUgZm9sZGVyIHN0cnVjdHVyZTogJHtlcnJvck1lc3NhZ2V9LmApO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXHR9XG5cblx0cHJpdmF0ZSBhc3luYyBjcmVhdGVGaWxlU3RydWN0dXJlKGZpbGU6IFRGaWxlLCBrZWJhYlRpdGxlOiBzdHJpbmcsIHByZWZpeDogc3RyaW5nLCB0YXJnZXRGb2xkZXI6IHN0cmluZywgY29udGVudFR5cGU6IENvbnRlbnRUeXBlIHwgbnVsbCk6IFByb21pc2U8VEZpbGUgfCBudWxsPiB7XG5cdFx0Y29uc3QgZXh0ZW5zaW9uID0gY29udGVudFR5cGU/LnVzZU1keEV4dGVuc2lvbiA/IFwiLm1keFwiIDogXCIubWRcIjtcblx0XHRjb25zdCBuZXdOYW1lID0gYCR7cHJlZml4fSR7a2ViYWJUaXRsZX0ke2V4dGVuc2lvbn1gO1xuXHRcdGxldCBuZXdQYXRoOiBzdHJpbmc7XG5cblx0XHRpZiAodGFyZ2V0Rm9sZGVyKSB7XG5cdFx0XHQvLyBNb3ZlIHRvIHRhcmdldCBmb2xkZXJcblx0XHRcdG5ld1BhdGggPSBgJHt0YXJnZXRGb2xkZXJ9LyR7bmV3TmFtZX1gO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBLZWVwIGluIGN1cnJlbnQgbG9jYXRpb24sIGp1c3QgcmVuYW1lIHRoZSBmaWxlXG5cdFx0XHRjb25zdCBjdXJyZW50RGlyID0gZmlsZS5wYXJlbnQgPyBmaWxlLnBhcmVudC5wYXRoIDogXCJcIjtcblx0XHRcdGlmIChjdXJyZW50RGlyICYmIGN1cnJlbnREaXIgIT09IFwiL1wiKSB7XG5cdFx0XHRcdG5ld1BhdGggPSBgJHtjdXJyZW50RGlyfS8ke25ld05hbWV9YDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIEZpbGUgaXMgaW4gdmF1bHQgcm9vdCwganVzdCB1c2UgbmV3IG5hbWVcblx0XHRcdFx0bmV3UGF0aCA9IG5ld05hbWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Y29uc3QgZXhpc3RpbmdGaWxlID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKG5ld1BhdGgpO1xuXHRcdGlmIChleGlzdGluZ0ZpbGUgaW5zdGFuY2VvZiBURmlsZSAmJiBleGlzdGluZ0ZpbGUgIT09IGZpbGUpIHtcblx0XHRcdG5ldyBOb3RpY2UoYEZpbGUgd2l0aCBuYW1lIFwiJHtuZXdOYW1lfVwiIGFscmVhZHkgZXhpc3RzLmApO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXG5cdFx0Ly8gVHJhY2sgdGhhdCB0aGlzIGZpbGUgd2lsbCBiZSBjcmVhdGVkIGJ5IHRoZSBwbHVnaW4gQkVGT1JFIHJlbmFtaW5nXG5cdFx0Ly8gVGhpcyBwcmV2ZW50cyB0aGUgY3JlYXRlIGV2ZW50IGZyb20gdHJpZ2dlcmluZyBhbm90aGVyIG1vZGFsXG5cdFx0aWYgKHRoaXMucGx1Z2luKSB7XG5cdFx0XHR0aGlzLnBsdWdpbi5wbHVnaW5DcmVhdGVkRmlsZXMuc2V0KG5ld1BhdGgsIERhdGUubm93KCkpO1xuXHRcdH1cblxuXHRcdHRyeSB7XG5cdFx0XHQvLyBVc2UgZmlsZU1hbmFnZXIucmVuYW1lRmlsZSgpIHdoaWNoIHJlc3BlY3RzIHVzZXIgc2V0dGluZ3MgYW5kIGhhbmRsZXMgYWxsIGxpbmsgZm9ybWF0c1xuXHRcdFx0YXdhaXQgdGhpcy5hcHAuZmlsZU1hbmFnZXIucmVuYW1lRmlsZShmaWxlLCBuZXdQYXRoKTtcblxuXHRcdFx0Y29uc3QgbmV3RmlsZSA9IHRoaXMuYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChuZXdQYXRoKTtcblx0XHRcdGlmICghKG5ld0ZpbGUgaW5zdGFuY2VvZiBURmlsZSkpIHtcblx0XHRcdFx0bmV3IE5vdGljZShcIkZhaWxlZCB0byBsb2NhdGUgcmVuYW1lZCBmaWxlLlwiKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGxlYWYgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0TGVhZihmYWxzZSk7XG5cdFx0XHRhd2FpdCBsZWFmLm9wZW5GaWxlKG5ld0ZpbGUpO1xuXG5cdFx0XHQvLyBQb3NpdGlvbiBjdXJzb3IgYXQgdGhlIGVuZCBvZiBjb250ZW50IGFmdGVyIGVkaXRvciBpcyByZWFkeVxuXHRcdFx0Y29uc3QgcG9zaXRpb25DdXJzb3IgPSAoKSA9PiB7XG5cdFx0XHRcdGNvbnN0IHZpZXcgPSBsZWFmLnZpZXc7XG5cdFx0XHRcdGlmICh2aWV3ICYmICdlZGl0b3InIGluIHZpZXcpIHtcblx0XHRcdFx0XHRjb25zdCBlZGl0b3IgPSAodmlldyBhcyB7IGVkaXRvcj86IHsgc2V0Q3Vyc29yOiAocG9zOiB7IGxpbmU6IG51bWJlcjsgY2g6IG51bWJlciB9KSA9PiB2b2lkOyBnZXRWYWx1ZTogKCkgPT4gc3RyaW5nOyBmb2N1czogKCkgPT4gdm9pZCB9IH0pLmVkaXRvcjtcblx0XHRcdFx0XHRpZiAoZWRpdG9yKSB7XG5cdFx0XHRcdFx0XHRjb25zdCBjb250ZW50ID0gZWRpdG9yLmdldFZhbHVlKCk7XG5cdFx0XHRcdFx0XHRpZiAoY29udGVudCkge1xuXHRcdFx0XHRcdFx0XHRjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBsYXN0TGluZSA9IGxpbmVzLmxlbmd0aCAtIDE7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IGxhc3RMaW5lTGVuZ3RoID0gbGluZXNbbGFzdExpbmVdPy5sZW5ndGggfHwgMDtcblx0XHRcdFx0XHRcdFx0ZWRpdG9yLnNldEN1cnNvcih7IGxpbmU6IGxhc3RMaW5lLCBjaDogbGFzdExpbmVMZW5ndGggfSk7XG5cdFx0XHRcdFx0XHRcdGVkaXRvci5mb2N1cygpO1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fTtcblxuXHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRcdGlmICghcG9zaXRpb25DdXJzb3IoKSkge1xuXHRcdFx0XHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRcdFx0cG9zaXRpb25DdXJzb3IoKTtcblx0XHRcdFx0XHR9LCAyMDApO1xuXHRcdFx0XHR9XG5cdFx0XHR9LCAxMDApO1xuXG5cdFx0XHRyZXR1cm4gbmV3RmlsZTtcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0Y29uc3QgZXJyb3JNZXNzYWdlID0gZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yLm1lc3NhZ2UgOiBTdHJpbmcoZXJyb3IpO1xuXHRcdFx0bmV3IE5vdGljZShgRmFpbGVkIHRvIHJlbmFtZSBmaWxlOiAke2Vycm9yTWVzc2FnZX0uYCk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cdH1cblxuXG5cdGFzeW5jIHJlbmFtZUZpbGUob3B0aW9uczogUmVuYW1lT3B0aW9ucyk6IFByb21pc2U8VEZpbGUgfCBudWxsPiB7XG5cdFx0Y29uc3QgeyBmaWxlLCB0aXRsZSwgdHlwZSB9ID0gb3B0aW9ucztcblxuXHRcdGlmICghdGl0bGUpIHtcblx0XHRcdG5ldyBOb3RpY2UoYFRpdGxlIGlzIHJlcXVpcmVkIHRvIHJlbmFtZSB0aGUgY29udGVudC5gKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdGNvbnN0IGNvbnRlbnRUeXBlID0gdGhpcy5nZXRDb250ZW50VHlwZSh0eXBlKTtcblx0XHRpZiAoIWNvbnRlbnRUeXBlICYmIHR5cGUgIT09IFwibm90ZVwiKSB7XG5cdFx0XHRuZXcgTm90aWNlKGBDb250ZW50IHR5cGUgJHt0eXBlfSBub3QgZm91bmQuYCk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cblx0XHRjb25zdCBrZWJhYlRpdGxlID0gdG9LZWJhYkNhc2UodGl0bGUpO1xuXHRcdGNvbnN0IHByZWZpeCA9IFwiXCI7XG5cblx0XHRjb25zdCBjcmVhdGlvbk1vZGUgPSBjb250ZW50VHlwZT8uY3JlYXRpb25Nb2RlIHx8IFwiZmlsZVwiO1xuXHRcdGlmIChjcmVhdGlvbk1vZGUgPT09IFwiZm9sZGVyXCIpIHtcblx0XHRcdHJldHVybiB0aGlzLnJlbmFtZUZvbGRlclN0cnVjdHVyZShmaWxlLCBrZWJhYlRpdGxlLCBwcmVmaXgsIHR5cGUsIGNvbnRlbnRUeXBlKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIHRoaXMucmVuYW1lRmlsZVN0cnVjdHVyZShmaWxlLCBrZWJhYlRpdGxlLCBwcmVmaXgsIGNvbnRlbnRUeXBlKTtcblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIGFzeW5jIHJlbmFtZUZvbGRlclN0cnVjdHVyZShmaWxlOiBURmlsZSwga2ViYWJUaXRsZTogc3RyaW5nLCBwcmVmaXg6IHN0cmluZywgdHlwZTogQ29udGVudFR5cGVJZCwgY29udGVudFR5cGU6IENvbnRlbnRUeXBlIHwgbnVsbCk6IFByb21pc2U8VEZpbGUgfCBudWxsPiB7XG5cdFx0Ly8gU21hcnQgZGV0ZWN0aW9uOiB0cmVhdCBhcyBpbmRleCBpZiBmaWxlbmFtZSBtYXRjaGVzIHRoZSBpbmRleCBmaWxlIG5hbWVcblx0XHQvLyBEZWZhdWx0IHRvIFwiaW5kZXhcIiB3aGVuIGluZGV4RmlsZU5hbWUgaXMgYmxhbmtcblx0XHRjb25zdCBpbmRleEZpbGVOYW1lID0gY29udGVudFR5cGU/LmluZGV4RmlsZU5hbWUgfHwgXCJpbmRleFwiO1xuXHRcdGNvbnN0IGlzSW5kZXggPSBmaWxlLmJhc2VuYW1lID09PSBpbmRleEZpbGVOYW1lO1xuXHRcdGlmIChpc0luZGV4KSB7XG5cdFx0XHRpZiAoIWZpbGUucGFyZW50KSB7XG5cdFx0XHRcdG5ldyBOb3RpY2UoXCJDYW5ub3QgcmVuYW1lOiBmaWxlIGhhcyBubyBwYXJlbnQgZm9sZGVyLlwiKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cdFx0XHRwcmVmaXggPSBmaWxlLnBhcmVudC5uYW1lLnN0YXJ0c1dpdGgoXCJfXCIpID8gXCJfXCIgOiBcIlwiO1xuXHRcdFx0Y29uc3QgbmV3Rm9sZGVyTmFtZSA9IGAke3ByZWZpeH0ke2tlYmFiVGl0bGV9YDtcblx0XHRcdGNvbnN0IHBhcmVudEZvbGRlciA9IGZpbGUucGFyZW50LnBhcmVudDtcblx0XHRcdGlmICghcGFyZW50Rm9sZGVyKSB7XG5cdFx0XHRcdG5ldyBOb3RpY2UoXCJDYW5ub3QgcmVuYW1lOiBwYXJlbnQgZm9sZGVyIGhhcyBubyBwYXJlbnQuXCIpO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblx0XHRcdC8vIEZpeCBwYXRoIGNvbnN0cnVjdGlvbiB0byBhdm9pZCBkb3VibGUgc2xhc2hlc1xuXHRcdFx0bGV0IG5ld0ZvbGRlclBhdGg6IHN0cmluZztcblx0XHRcdGlmIChwYXJlbnRGb2xkZXIucGF0aCA9PT0gXCJcIiB8fCBwYXJlbnRGb2xkZXIucGF0aCA9PT0gXCIvXCIpIHtcblx0XHRcdFx0Ly8gUGFyZW50IGlzIHZhdWx0IHJvb3Rcblx0XHRcdFx0bmV3Rm9sZGVyUGF0aCA9IG5ld0ZvbGRlck5hbWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBQYXJlbnQgaXMgaW4gYSBzdWJmb2xkZXJcblx0XHRcdFx0bmV3Rm9sZGVyUGF0aCA9IGAke3BhcmVudEZvbGRlci5wYXRofS8ke25ld0ZvbGRlck5hbWV9YDtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZXhpc3RpbmdGb2xkZXIgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgobmV3Rm9sZGVyUGF0aCk7XG5cdFx0XHRpZiAoZXhpc3RpbmdGb2xkZXIgaW5zdGFuY2VvZiBURm9sZGVyKSB7XG5cdFx0XHRcdG5ldyBOb3RpY2UoYEZvbGRlciBhbHJlYWR5IGV4aXN0cyBhdCAke25ld0ZvbGRlclBhdGh9LmApO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YXdhaXQgdGhpcy5hcHAuZmlsZU1hbmFnZXIucmVuYW1lRmlsZShmaWxlLnBhcmVudCwgbmV3Rm9sZGVyUGF0aCk7XG5cdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0XHRjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG5cdFx0XHRcdG5ldyBOb3RpY2UoYEZhaWxlZCB0byByZW5hbWUgZm9sZGVyOiAke2Vycm9yTWVzc2FnZX0uYCk7XG5cdFx0XHRcdHJldHVybiBudWxsO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBuZXdGaWxlUGF0aCA9IGAke25ld0ZvbGRlclBhdGh9LyR7ZmlsZS5uYW1lfWA7XG5cdFx0XHRjb25zdCBuZXdGaWxlID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKG5ld0ZpbGVQYXRoKTtcblx0XHRcdGlmICghKG5ld0ZpbGUgaW5zdGFuY2VvZiBURmlsZSkpIHtcblx0XHRcdFx0bmV3IE5vdGljZShcIkZhaWxlZCB0byBsb2NhdGUgcmVuYW1lZCBmaWxlLlwiKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cblxuXHRcdFx0cmV0dXJuIG5ld0ZpbGU7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGlmICghZmlsZS5wYXJlbnQpIHtcblx0XHRcdFx0bmV3IE5vdGljZShcIkNhbm5vdCByZW5hbWU6IGZpbGUgaGFzIG5vIHBhcmVudCBmb2xkZXIuXCIpO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblx0XHRcdHByZWZpeCA9IGZpbGUuYmFzZW5hbWUuc3RhcnRzV2l0aChcIl9cIikgPyBcIl9cIiA6IFwiXCI7XG5cdFx0XHQvLyBQcmVzZXJ2ZSB0aGUgb3JpZ2luYWwgZmlsZSBleHRlbnNpb25cblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGZpbGUuZXh0ZW5zaW9uO1xuXHRcdFx0Y29uc3QgbmV3TmFtZSA9IGAke3ByZWZpeH0ke2tlYmFiVGl0bGV9LiR7ZXh0ZW5zaW9ufWA7XG5cdFx0XHRjb25zdCBuZXdQYXRoID0gYCR7ZmlsZS5wYXJlbnQucGF0aH0vJHtuZXdOYW1lfWA7XG5cblx0XHRcdGNvbnN0IGV4aXN0aW5nRmlsZSA9IHRoaXMuYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChuZXdQYXRoKTtcblx0XHRcdGlmIChleGlzdGluZ0ZpbGUgaW5zdGFuY2VvZiBURmlsZSAmJiBleGlzdGluZ0ZpbGUgIT09IGZpbGUpIHtcblx0XHRcdFx0bmV3IE5vdGljZShgRmlsZSBhbHJlYWR5IGV4aXN0cyBhdCAke25ld1BhdGh9LmApO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gVXNlIGZpbGVNYW5hZ2VyLnJlbmFtZUZpbGUoKSB3aGljaCBhdXRvbWF0aWNhbGx5IHVwZGF0ZXMgbGlua3Ncblx0XHRcdGF3YWl0IHRoaXMuYXBwLmZpbGVNYW5hZ2VyLnJlbmFtZUZpbGUoZmlsZSwgbmV3UGF0aCk7XG5cdFx0XHRjb25zdCBuZXdGaWxlID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKG5ld1BhdGgpO1xuXHRcdFx0aWYgKCEobmV3RmlsZSBpbnN0YW5jZW9mIFRGaWxlKSkge1xuXHRcdFx0XHRuZXcgTm90aWNlKFwiRmFpbGVkIHRvIGxvY2F0ZSByZW5hbWVkIGZpbGUuXCIpO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblxuXG5cdFx0XHRyZXR1cm4gbmV3RmlsZTtcblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIGFzeW5jIHJlbmFtZUZpbGVTdHJ1Y3R1cmUoZmlsZTogVEZpbGUsIGtlYmFiVGl0bGU6IHN0cmluZywgcHJlZml4OiBzdHJpbmcsIGNvbnRlbnRUeXBlOiBDb250ZW50VHlwZSB8IG51bGwpOiBQcm9taXNlPFRGaWxlIHwgbnVsbD4ge1xuXHRcdGlmICghZmlsZS5wYXJlbnQpIHtcblx0XHRcdG5ldyBOb3RpY2UoXCJDYW5ub3QgcmVuYW1lOiBmaWxlIGhhcyBubyBwYXJlbnQgZm9sZGVyLlwiKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdC8vIENoZWNrIGlmIHRoaXMgaXMgYW4gaW5kZXggZmlsZSAtIGlmIHNvLCByZW5hbWUgdGhlIHBhcmVudCBmb2xkZXIgaW5zdGVhZFxuXHRcdC8vIFNtYXJ0IGRldGVjdGlvbjogb25seSB0cmVhdCBhcyBpbmRleCBpZiBpbmRleEZpbGVOYW1lIGlzIHNwZWNpZmllZCBhbmQgbWF0Y2hlc1xuXHRcdGNvbnN0IGluZGV4RmlsZU5hbWUgPSBjb250ZW50VHlwZT8uaW5kZXhGaWxlTmFtZSB8fCBcIlwiO1xuXHRcdGNvbnN0IGlzSW5kZXggPSBpbmRleEZpbGVOYW1lICYmXG5cdFx0XHRpbmRleEZpbGVOYW1lLnRyaW0oKSAhPT0gXCJcIiAmJlxuXHRcdFx0ZmlsZS5iYXNlbmFtZSA9PT0gaW5kZXhGaWxlTmFtZTtcblxuXHRcdGlmIChpc0luZGV4KSB7XG5cdFx0XHRwcmVmaXggPSBmaWxlLnBhcmVudC5uYW1lLnN0YXJ0c1dpdGgoXCJfXCIpID8gXCJfXCIgOiBcIlwiO1xuXHRcdFx0Y29uc3QgbmV3Rm9sZGVyTmFtZSA9IGAke3ByZWZpeH0ke2tlYmFiVGl0bGV9YDtcblx0XHRcdGNvbnN0IHBhcmVudEZvbGRlciA9IGZpbGUucGFyZW50LnBhcmVudDtcblx0XHRcdGlmICghcGFyZW50Rm9sZGVyKSB7XG5cdFx0XHRcdG5ldyBOb3RpY2UoXCJDYW5ub3QgcmVuYW1lOiBwYXJlbnQgZm9sZGVyIGhhcyBubyBwYXJlbnQuXCIpO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblx0XHRcdC8vIEZpeCBwYXRoIGNvbnN0cnVjdGlvbiB0byBhdm9pZCBkb3VibGUgc2xhc2hlc1xuXHRcdFx0bGV0IG5ld0ZvbGRlclBhdGg6IHN0cmluZztcblx0XHRcdGlmIChwYXJlbnRGb2xkZXIucGF0aCA9PT0gXCJcIiB8fCBwYXJlbnRGb2xkZXIucGF0aCA9PT0gXCIvXCIpIHtcblx0XHRcdFx0Ly8gUGFyZW50IGlzIHZhdWx0IHJvb3Rcblx0XHRcdFx0bmV3Rm9sZGVyUGF0aCA9IG5ld0ZvbGRlck5hbWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBQYXJlbnQgaXMgaW4gYSBzdWJmb2xkZXJcblx0XHRcdFx0bmV3Rm9sZGVyUGF0aCA9IGAke3BhcmVudEZvbGRlci5wYXRofS8ke25ld0ZvbGRlck5hbWV9YDtcblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZXhpc3RpbmdGb2xkZXIgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgobmV3Rm9sZGVyUGF0aCk7XG5cdFx0XHRpZiAoZXhpc3RpbmdGb2xkZXIgaW5zdGFuY2VvZiBURm9sZGVyKSB7XG5cdFx0XHRcdG5ldyBOb3RpY2UoYEZvbGRlciBhbHJlYWR5IGV4aXN0cyBhdCAke25ld0ZvbGRlclBhdGh9LmApO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBuZXcgZmlsZSBwYXRoIGJlZm9yZSByZW5hbWluZ1xuXHRcdFx0Y29uc3QgbmV3RmlsZVBhdGggPSBgJHtuZXdGb2xkZXJQYXRofS8ke2ZpbGUubmFtZX1gO1xuXG5cdFx0XHQvLyBUcmFjayB0aGF0IHRoaXMgZmlsZSB3aWxsIGJlIGNyZWF0ZWQgYnkgdGhlIHBsdWdpbiBCRUZPUkUgcmVuYW1pbmdcblx0XHRcdC8vIFRoaXMgcHJldmVudHMgdGhlIGNyZWF0ZSBldmVudCBmcm9tIHRyaWdnZXJpbmcgYW5vdGhlciBtb2RhbFxuXHRcdFx0aWYgKHRoaXMucGx1Z2luKSB7XG5cdFx0XHRcdHRoaXMucGx1Z2luLnBsdWdpbkNyZWF0ZWRGaWxlcy5zZXQobmV3RmlsZVBhdGgsIERhdGUubm93KCkpO1xuXHRcdFx0fVxuXG5cdFx0XHR0cnkge1xuXHRcdFx0XHRhd2FpdCB0aGlzLmFwcC5maWxlTWFuYWdlci5yZW5hbWVGaWxlKGZpbGUucGFyZW50LCBuZXdGb2xkZXJQYXRoKTtcblx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoJ0ZpbGVPcGVyYXRpb25zOiBGb2xkZXIgcmVuYW1lIGZhaWxlZDonLCBlcnJvcik7XG5cdFx0XHRcdGNvbnN0IGVycm9yTWVzc2FnZSA9IGVycm9yIGluc3RhbmNlb2YgRXJyb3IgPyBlcnJvci5tZXNzYWdlIDogU3RyaW5nKGVycm9yKTtcblx0XHRcdFx0bmV3IE5vdGljZShgRmFpbGVkIHRvIHJlbmFtZSBmb2xkZXI6ICR7ZXJyb3JNZXNzYWdlfS5gKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IG5ld0ZpbGUgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgobmV3RmlsZVBhdGgpO1xuXHRcdFx0aWYgKCEobmV3RmlsZSBpbnN0YW5jZW9mIFRGaWxlKSkge1xuXHRcdFx0XHRuZXcgTm90aWNlKFwiRmFpbGVkIHRvIGxvY2F0ZSByZW5hbWVkIGZpbGUuXCIpO1xuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG5ld0ZpbGU7XG5cdFx0fVxuXG5cdFx0Ly8gRm9yIG5vbi1pbmRleCBmaWxlcywgcmVuYW1lIHRoZSBmaWxlIGl0c2VsZlxuXHRcdHByZWZpeCA9IGZpbGUuYmFzZW5hbWUuc3RhcnRzV2l0aChcIl9cIikgPyBcIl9cIiA6IFwiXCI7XG5cdFx0Ly8gUHJlc2VydmUgdGhlIG9yaWdpbmFsIGZpbGUgZXh0ZW5zaW9uXG5cdFx0Y29uc3QgZXh0ZW5zaW9uID0gZmlsZS5leHRlbnNpb247XG5cdFx0Y29uc3QgbmV3TmFtZSA9IGAke3ByZWZpeH0ke2tlYmFiVGl0bGV9LiR7ZXh0ZW5zaW9ufWA7XG5cblx0XHQvLyBGaXggcGF0aCBjb25zdHJ1Y3Rpb24gdG8gYXZvaWQgZG91YmxlIHNsYXNoZXNcblx0XHRsZXQgbmV3UGF0aDogc3RyaW5nO1xuXHRcdGlmIChmaWxlLnBhcmVudC5wYXRoID09PSBcIlwiIHx8IGZpbGUucGFyZW50LnBhdGggPT09IFwiL1wiKSB7XG5cdFx0XHQvLyBGaWxlIGlzIGluIHZhdWx0IHJvb3Rcblx0XHRcdG5ld1BhdGggPSBuZXdOYW1lO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBGaWxlIGlzIGluIGEgc3ViZm9sZGVyXG5cdFx0XHRuZXdQYXRoID0gYCR7ZmlsZS5wYXJlbnQucGF0aH0vJHtuZXdOYW1lfWA7XG5cdFx0fVxuXG5cdFx0Y29uc3QgZXhpc3RpbmdGaWxlID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKG5ld1BhdGgpO1xuXHRcdGlmIChleGlzdGluZ0ZpbGUgaW5zdGFuY2VvZiBURmlsZSAmJiBleGlzdGluZ0ZpbGUgIT09IGZpbGUpIHtcblx0XHRcdG5ldyBOb3RpY2UoYEZpbGUgYWxyZWFkeSBleGlzdHMgYXQgJHtuZXdQYXRofS5gKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdC8vIFRyYWNrIHRoYXQgdGhpcyBmaWxlIHdpbGwgYmUgY3JlYXRlZCBieSB0aGUgcGx1Z2luIEJFRk9SRSByZW5hbWluZ1xuXHRcdC8vIFRoaXMgcHJldmVudHMgdGhlIGNyZWF0ZSBldmVudCBmcm9tIHRyaWdnZXJpbmcgYW5vdGhlciBtb2RhbFxuXHRcdGlmICh0aGlzLnBsdWdpbikge1xuXHRcdFx0dGhpcy5wbHVnaW4ucGx1Z2luQ3JlYXRlZEZpbGVzLnNldChuZXdQYXRoLCBEYXRlLm5vdygpKTtcblx0XHR9XG5cblx0XHR0cnkge1xuXHRcdFx0YXdhaXQgdGhpcy5hcHAuZmlsZU1hbmFnZXIucmVuYW1lRmlsZShmaWxlLCBuZXdQYXRoKTtcblx0XHR9IGNhdGNoIChlcnJvcikge1xuXHRcdFx0Y29uc29sZS5lcnJvcignRmlsZU9wZXJhdGlvbnM6IEZpbGUgcmVuYW1lIGZhaWxlZDonLCBlcnJvcik7XG5cdFx0XHRjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XG5cdFx0XHRuZXcgTm90aWNlKGBGYWlsZWQgdG8gcmVuYW1lIGZpbGU6ICR7ZXJyb3JNZXNzYWdlfS5gKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdGNvbnN0IG5ld0ZpbGUgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgobmV3UGF0aCk7XG5cdFx0aWYgKCEobmV3RmlsZSBpbnN0YW5jZW9mIFRGaWxlKSkge1xuXHRcdFx0bmV3IE5vdGljZShcIkZhaWxlZCB0byBsb2NhdGUgcmVuYW1lZCBmaWxlLlwiKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdHJldHVybiBuZXdGaWxlO1xuXHR9XG59XG4iLCAiLyoqXHJcbiAqIFV0aWxpdHkgZnVuY3Rpb25zIGZvciBtYXRjaGluZyBmaWxlIHBhdGhzIGFnYWluc3QgZm9sZGVyIHBhdHRlcm5zIHdpdGggd2lsZGNhcmQgc3VwcG9ydC5cclxuICogXHJcbiAqIFdpbGRjYXJkIHBhdHRlcm5zOlxyXG4gKiAtIGBkb2NzYCBtYXRjaGVzIGBkb2NzL2AgYW5kIGFueXRoaW5nIHVuZGVyIGl0XHJcbiAqIC0gYGRvY3Mve2FzdGVyaXNrfWAgbWF0Y2hlcyBgZG9jcy9hbnl0aGluZy9gIGFuZCBhbnl0aGluZyB1bmRlciBpdCAob25lIGxldmVsIGRlZXApXHJcbiAqIC0gYGRvY3Mve2FzdGVyaXNrfS97YXN0ZXJpc2t9YCBtYXRjaGVzIGBkb2NzL2FueXRoaW5nL2FueXRoaW5nL2AgYW5kIGFueXRoaW5nIHVuZGVyIGl0ICh0d28gbGV2ZWxzIGRlZXApXHJcbiAqIC0gZXRjLlxyXG4gKiBcclxuICogTm90ZToge2FzdGVyaXNrfSByZXByZXNlbnRzIHRoZSB3aWxkY2FyZCBjaGFyYWN0ZXIgKlxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBmaWxlIHBhdGggbWF0Y2hlcyBhIGZvbGRlciBwYXR0ZXJuIChzdXBwb3J0cyB3aWxkY2FyZHMpXHJcbiAqIEBwYXJhbSBmaWxlUGF0aCBUaGUgZmlsZSBwYXRoIHRvIGNoZWNrIChlLmcuLCBcImRvY3MvZXhhbXBsZS1hL2dldHRpbmctc3RhcnRlZC5tZFwiKVxyXG4gKiBAcGFyYW0gZm9sZGVyUGF0dGVybiBUaGUgZm9sZGVyIHBhdHRlcm4gLSB1c2UgYXN0ZXJpc2sgZm9yIHdpbGRjYXJkcyAoZS5nLiwgXCJkb2NzXCIsIFwiZG9jcy9hc3Rlcmlza1wiLCBcImRvY3MvYXN0ZXJpc2svYXN0ZXJpc2tcIilcclxuICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgZmlsZSBwYXRoIG1hdGNoZXMgdGhlIHBhdHRlcm5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXRjaGVzRm9sZGVyUGF0dGVybihmaWxlUGF0aDogc3RyaW5nLCBmb2xkZXJQYXR0ZXJuOiBzdHJpbmcpOiBib29sZWFuIHtcclxuXHQvLyBOb3JtYWxpemUgZm9yIGNhc2UtaW5zZW5zaXRpdmUgbWF0Y2hpbmdcclxuXHRjb25zdCBub3JtYWxpemVkRmlsZVBhdGggPSBmaWxlUGF0aC50b0xvd2VyQ2FzZSgpO1xyXG5cdGNvbnN0IG5vcm1hbGl6ZWRQYXR0ZXJuID0gZm9sZGVyUGF0dGVybi50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL15cXC98XFwvJC9nLCBcIlwiKTtcclxuXHJcblx0Ly8gSGFuZGxlIGVtcHR5IGZvbGRlciBwYXR0ZXJuIChyb290IGZvbGRlcikgLSBtYXRjaGVzIGZpbGVzIGluIHZhdWx0IHJvb3Qgb25seVxyXG5cdGlmICghbm9ybWFsaXplZFBhdHRlcm4gfHwgbm9ybWFsaXplZFBhdHRlcm4udHJpbSgpID09PSBcIlwiKSB7XHJcblx0XHRyZXR1cm4gIW5vcm1hbGl6ZWRGaWxlUGF0aC5pbmNsdWRlcyhcIi9cIikgfHwgKG5vcm1hbGl6ZWRGaWxlUGF0aC5zcGxpdChcIi9cIikubGVuZ3RoID09PSAxKTtcclxuXHR9XHJcblxyXG5cdC8vIElmIHBhdHRlcm4gZG9lc24ndCBjb250YWluIHdpbGRjYXJkcywgdXNlIHNpbXBsZSBwcmVmaXggbWF0Y2hpbmdcclxuXHRpZiAoIW5vcm1hbGl6ZWRQYXR0ZXJuLmluY2x1ZGVzKFwiKlwiKSkge1xyXG5cdFx0cmV0dXJuIG5vcm1hbGl6ZWRGaWxlUGF0aCA9PT0gbm9ybWFsaXplZFBhdHRlcm4gfHwgbm9ybWFsaXplZEZpbGVQYXRoLnN0YXJ0c1dpdGgobm9ybWFsaXplZFBhdHRlcm4gKyBcIi9cIik7XHJcblx0fVxyXG5cclxuXHQvLyBDb252ZXJ0IHdpbGRjYXJkIHBhdHRlcm4gdG8gcmVnZXhcclxuXHQvLyBFc2NhcGUgc3BlY2lhbCByZWdleCBjaGFyYWN0ZXJzIGV4Y2VwdCAqXHJcblx0Y29uc3QgZXNjYXBlZFBhdHRlcm4gPSBub3JtYWxpemVkUGF0dGVyblxyXG5cdFx0LnJlcGxhY2UoL1suKz9eJHt9KCl8W1xcXVxcXFxdL2csIFwiXFxcXCQmXCIpXHJcblx0XHQucmVwbGFjZSgvXFwqL2csIFwiW14vXStcIik7IC8vIFdpbGRjYXJkIG1hdGNoZXMgYW55IHBhdGggc2VnbWVudCAobm9uLXNsYXNoIGNoYXJhY3RlcnMpXHJcblxyXG5cdC8vIENyZWF0ZSByZWdleCB0aGF0IG1hdGNoZXMgdGhlIHBhdHRlcm4gYW5kIGFueXRoaW5nIGFmdGVyIGl0XHJcblx0Y29uc3QgcmVnZXhQYXR0ZXJuID0gYF4ke2VzY2FwZWRQYXR0ZXJufSg/Oi98JClgO1xyXG5cdGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cChyZWdleFBhdHRlcm4pO1xyXG5cdHJldHVybiByZWdleC50ZXN0KG5vcm1hbGl6ZWRGaWxlUGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBkZXB0aCBvZiBhIGZvbGRlciBwYXR0ZXJuIChudW1iZXIgb2Ygc2VnbWVudHMpXHJcbiAqIFVzZWQgZm9yIHByaW9yaXRpemluZyBtb3JlIHNwZWNpZmljIHBhdHRlcm5zXHJcbiAqIEJsYW5rL3Jvb3QgZm9sZGVyIGhhcyBkZXB0aCAwIChsZWFzdCBzcGVjaWZpYylcclxuICogQHBhcmFtIGZvbGRlclBhdHRlcm4gVGhlIGZvbGRlciBwYXR0ZXJuXHJcbiAqIEByZXR1cm5zIFRoZSBudW1iZXIgb2YgcGF0aCBzZWdtZW50cyBpbiB0aGUgcGF0dGVybiAoMCBmb3Igcm9vdC9ibGFuaylcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQYXR0ZXJuRGVwdGgoZm9sZGVyUGF0dGVybjogc3RyaW5nKTogbnVtYmVyIHtcclxuXHRpZiAoIWZvbGRlclBhdHRlcm4gfHwgZm9sZGVyUGF0dGVybi50cmltKCkgPT09IFwiXCIpIHJldHVybiAwO1xyXG5cdHJldHVybiBmb2xkZXJQYXR0ZXJuLnNwbGl0KFwiL1wiKS5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTb3J0cyBjb250ZW50IHR5cGVzIGJ5IHBhdHRlcm4gc3BlY2lmaWNpdHkgKG1vcmUgc3BlY2lmaWMgcGF0dGVybnMgZmlyc3QpXHJcbiAqIFRoaXMgZW5zdXJlcyB0aGF0IG1vcmUgc3BlY2lmaWMgcGF0dGVybnMgYXJlIGNoZWNrZWQgYmVmb3JlIGxlc3Mgc3BlY2lmaWMgb25lc1xyXG4gKiBCbGFuay9yb290IGZvbGRlciBwYXR0ZXJucyAoZGVwdGggMCkgYXJlIHNvcnRlZCBsYXN0IChsZWFzdCBzcGVjaWZpYylcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzb3J0QnlQYXR0ZXJuU3BlY2lmaWNpdHk8VCBleHRlbmRzIHsgZm9sZGVyOiBzdHJpbmcgfT4odHlwZXM6IFRbXSk6IFRbXSB7XHJcblx0cmV0dXJuIFsuLi50eXBlc10uc29ydCgoYSwgYikgPT4ge1xyXG5cdFx0Y29uc3QgZGVwdGhBID0gZ2V0UGF0dGVybkRlcHRoKGEuZm9sZGVyKTtcclxuXHRcdGNvbnN0IGRlcHRoQiA9IGdldFBhdHRlcm5EZXB0aChiLmZvbGRlcik7XHJcblx0XHQvLyBNb3JlIHNwZWNpZmljIChkZWVwZXIpIHBhdHRlcm5zIGZpcnN0XHJcblx0XHQvLyBCbGFuayBwYXR0ZXJucyAoZGVwdGggMCkgd2lsbCBiZSBzb3J0ZWQgbGFzdFxyXG5cdFx0cmV0dXJuIGRlcHRoQiAtIGRlcHRoQTtcclxuXHR9KTtcclxufVxyXG5cclxuIiwgIi8qKlxyXG4gKiBDb252ZXJ0cyBhIHN0cmluZyB0byBrZWJhYi1jYXNlLlxyXG4gKiBAcGFyYW0gc3RyIFRoZSBzdHJpbmcgdG8gY29udmVydFxyXG4gKiBAcmV0dXJucyBLZWJhYi1jYXNlIHN0cmluZ1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRvS2ViYWJDYXNlKHN0cjogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHJldHVybiBzdHJcclxuICAgICAgICAucmVwbGFjZSgvKFthLXowLTldKShbQS1aXSkvZywgJyQxLSQyJylcclxuICAgICAgICAucmVwbGFjZSgvKFtBLVpdKShbQS1aXVthLXpdKS9nLCAnJDEtJDIkMycpXHJcbiAgICAgICAgLnRvTG93ZXJDYXNlKClcclxuICAgICAgICAucmVwbGFjZSgvW15hLXowLTlcXHMtXS9nLCBcIlwiKVxyXG4gICAgICAgIC50cmltKClcclxuICAgICAgICAucmVwbGFjZSgvXFxzKy9nLCBcIi1cIilcclxuICAgICAgICAucmVwbGFjZSgvLSsvZywgXCItXCIpXHJcbiAgICAgICAgLnJlcGxhY2UoL14tfC0kL2csIFwiXCIpO1xyXG59XHJcbiIsICJpbXBvcnQgeyBBcHAsIFRGaWxlLCBOb3RpY2UgfSBmcm9tIFwib2JzaWRpYW5cIjtcclxuaW1wb3J0IHsgQXN0cm9Db21wb3NlclNldHRpbmdzLCBQYXJzZWRGcm9udG1hdHRlciwgVGVtcGxhdGVWYWx1ZXMsIEtOT1dOX0FSUkFZX0tFWVMsIENvbnRlbnRUeXBlSWQsIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UgfSBmcm9tIFwiLi4vdHlwZXNcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZVBhcnNlciB7XHJcblx0Y29uc3RydWN0b3IocHJpdmF0ZSBhcHA6IEFwcCwgcHJpdmF0ZSBzZXR0aW5nczogQXN0cm9Db21wb3NlclNldHRpbmdzLCBwcml2YXRlIHBsdWdpbj86IEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UpIHsgfVxyXG5cclxuXHQvLyBHZXQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gaWYgYXZhaWxhYmxlLCBvdGhlcndpc2UgdXNlIHN0b3JlZCBzZXR0aW5nc1xyXG5cdHByaXZhdGUgZ2V0U2V0dGluZ3MoKTogQXN0cm9Db21wb3NlclNldHRpbmdzIHtcclxuXHRcdC8vIEFsd2F5cyBwcmVmZXIgcGx1Z2luIHNldHRpbmdzICh0aGV5J3JlIGtlcHQgdXAgdG8gZGF0ZSlcclxuXHRcdGlmICh0aGlzLnBsdWdpbj8uc2V0dGluZ3MpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMucGx1Z2luLnNldHRpbmdzO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0dGluZ3M7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBDb252ZXJ0IGEgc3RyaW5nIHRvIGtlYmFiLWNhc2UgZm9yIHNsdWcgZ2VuZXJhdGlvblxyXG5cdCAqL1xyXG5cdHByaXZhdGUgdG9LZWJhYkNhc2Uoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xyXG5cdFx0cmV0dXJuIHN0clxyXG5cdFx0XHQudG9Mb3dlckNhc2UoKVxyXG5cdFx0XHQucmVwbGFjZSgvW15hLXowLTlcXHMtXS9nLCBcIlwiKVxyXG5cdFx0XHQudHJpbSgpXHJcblx0XHRcdC5yZXBsYWNlKC9cXHMrL2csIFwiLVwiKVxyXG5cdFx0XHQucmVwbGFjZSgvLSsvZywgXCItXCIpXHJcblx0XHRcdC5yZXBsYWNlKC9eLXwtJC9nLCBcIlwiKTtcclxuXHR9XHJcblxyXG5cdHBhcnNlRnJvbnRtYXR0ZXIoY29udGVudDogc3RyaW5nKTogUGFyc2VkRnJvbnRtYXR0ZXIge1xyXG5cdFx0bGV0IHByb3BlcnRpZXNFbmQgPSAwO1xyXG5cdFx0bGV0IHByb3BlcnRpZXNUZXh0ID0gXCJcIjtcclxuXHRcdGNvbnN0IGV4aXN0aW5nUHJvcGVydGllczogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+ID0ge307XHJcblxyXG5cdFx0Ly8gUGFyc2UgZXhpc3RpbmcgcHJvcGVydGllcyB3aXRoIGZhbGxiYWNrIGZvciBtaXNzaW5nIHNlY29uZCAtLS1cclxuXHRcdGlmIChjb250ZW50LnN0YXJ0c1dpdGgoXCItLS1cIikpIHtcclxuXHRcdFx0cHJvcGVydGllc0VuZCA9IGNvbnRlbnQuaW5kZXhPZihcIlxcbi0tLVwiLCAzKTtcclxuXHRcdFx0aWYgKHByb3BlcnRpZXNFbmQgPT09IC0xKSB7XHJcblx0XHRcdFx0cHJvcGVydGllc0VuZCA9IGNvbnRlbnQubGVuZ3RoOyAvLyBUcmVhdCBlbnRpcmUgY29udGVudCBhcyBwcm9wZXJ0aWVzIGlmIG5vIHNlY29uZCAtLS1cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRwcm9wZXJ0aWVzRW5kICs9IDQ7IC8vIE1vdmUgcGFzdCB0aGUgc2Vjb25kIC0tLVxyXG5cdFx0XHR9XHJcblx0XHRcdHByb3BlcnRpZXNUZXh0ID0gY29udGVudC5zbGljZSg0LCBwcm9wZXJ0aWVzRW5kIC0gNCkudHJpbSgpO1xyXG5cclxuXHRcdFx0dHJ5IHtcclxuXHRcdFx0XHRsZXQgY3VycmVudEtleTogc3RyaW5nIHwgbnVsbCA9IG51bGw7XHJcblx0XHRcdFx0Y29uc3QgYXJyYXlLZXlzID0gbmV3IFNldDxzdHJpbmc+KCk7IC8vIFRyYWNrIHdoaWNoIGtleXMgYXJlIGFycmF5c1xyXG5cclxuXHRcdFx0XHRwcm9wZXJ0aWVzVGV4dC5zcGxpdChcIlxcblwiKS5mb3JFYWNoKChsaW5lKSA9PiB7XHJcblx0XHRcdFx0XHRjb25zdCB0cmltbWVkTGluZSA9IGxpbmUudHJpbSgpO1xyXG5cclxuXHRcdFx0XHRcdC8vIE1hdGNoIHByb3BlcnR5IGxpbmVzIC0gbW9yZSBmbGV4aWJsZSByZWdleCB0byBoYW5kbGUgdmFyaW91cyBwcm9wZXJ0eSBuYW1lc1xyXG5cdFx0XHRcdFx0Y29uc3QgbWF0Y2ggPSB0cmltbWVkTGluZS5tYXRjaCgvXihbYS16QS1aX11bYS16QS1aMC05Xy1dKik6XFxzKiguKikkLyk7XHJcblx0XHRcdFx0XHRpZiAobWF0Y2gpIHtcclxuXHRcdFx0XHRcdFx0Y29uc3QgWywga2V5LCB2YWx1ZV0gPSBtYXRjaDtcclxuXHRcdFx0XHRcdFx0Y3VycmVudEtleSA9IGtleTtcclxuXHRcdFx0XHRcdFx0Y29uc3QgdHJpbW1lZFZhbHVlID0gdmFsdWUgPyB2YWx1ZS50cmltKCkgOiBcIlwiO1xyXG5cclxuXHRcdFx0XHRcdFx0Ly8gQ2hlY2sgZm9yIGJyYWNrZXQtc3ludGF4IGFycmF5czogW2l0ZW1dIG9yIFtcIml0ZW0xXCIsIFwiaXRlbTJcIl0gb3IgW2l0ZW0xLCBpdGVtMl1cclxuXHRcdFx0XHRcdFx0Y29uc3QgYnJhY2tldEFycmF5TWF0Y2ggPSB0cmltbWVkVmFsdWUubWF0Y2goL15cXFsoLiopXFxdJC8pO1xyXG5cdFx0XHRcdFx0XHRpZiAoYnJhY2tldEFycmF5TWF0Y2gpIHtcclxuXHRcdFx0XHRcdFx0XHQvLyBUaGlzIGlzIGEgYnJhY2tldC1mb3JtYXQgYXJyYXlcclxuXHRcdFx0XHRcdFx0XHRjb25zdCBhcnJheUNvbnRlbnQgPSBicmFja2V0QXJyYXlNYXRjaFsxXS50cmltKCk7XHJcblx0XHRcdFx0XHRcdFx0ZXhpc3RpbmdQcm9wZXJ0aWVzW2tleV0gPSBbXTtcclxuXHRcdFx0XHRcdFx0XHRhcnJheUtleXMuYWRkKGtleSk7IC8vIE1hcmsgdGhpcyBrZXkgYXMgYW4gYXJyYXlcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKGFycmF5Q29udGVudCkge1xyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gUGFyc2UgYXJyYXkgaXRlbXMgLSBoYW5kbGUgYm90aCBxdW90ZWQgYW5kIHVucXVvdGVkIHZhbHVlc1xyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gU3BsaXQgYnkgY29tbWEsIGJ1dCByZXNwZWN0IHF1b3Rlc1xyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgaXRlbXM6IHN0cmluZ1tdID0gW107XHJcblx0XHRcdFx0XHRcdFx0XHRsZXQgY3VycmVudEl0ZW0gPSBcIlwiO1xyXG5cdFx0XHRcdFx0XHRcdFx0bGV0IGluUXVvdGVzID0gZmFsc2U7XHJcblx0XHRcdFx0XHRcdFx0XHRsZXQgcXVvdGVDaGFyID0gJyc7XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheUNvbnRlbnQubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgY2hhciA9IGFycmF5Q29udGVudFtpXTtcclxuXHJcblx0XHRcdFx0XHRcdFx0XHRcdGlmICghaW5RdW90ZXMgJiYgKGNoYXIgPT09ICdcIicgfHwgY2hhciA9PT0gXCInXCIpKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0aW5RdW90ZXMgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHF1b3RlQ2hhciA9IGNoYXI7XHJcblx0XHRcdFx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoaW5RdW90ZXMgJiYgY2hhciA9PT0gcXVvdGVDaGFyKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gQ2hlY2sgaWYgaXQncyBlc2NhcGVkXHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKGkgPiAwICYmIGFycmF5Q29udGVudFtpIC0gMV0gPT09ICdcXFxcJykge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Y3VycmVudEl0ZW0gKz0gY2hhcjtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aW5RdW90ZXMgPSBmYWxzZTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHF1b3RlQ2hhciA9ICcnO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIGlmICghaW5RdW90ZXMgJiYgY2hhciA9PT0gJywnKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gRW5kIG9mIGN1cnJlbnQgaXRlbVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IHRyaW1tZWRJdGVtID0gY3VycmVudEl0ZW0udHJpbSgpO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmICh0cmltbWVkSXRlbSkge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gUmVtb3ZlIHN1cnJvdW5kaW5nIHF1b3RlcyBpZiBwcmVzZW50XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb25zdCB1bnF1b3RlZCA9IHRyaW1tZWRJdGVtLnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgJycpO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aXRlbXMucHVzaCh1bnF1b3RlZCk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGN1cnJlbnRJdGVtID0gXCJcIjtcclxuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRjdXJyZW50SXRlbSArPSBjaGFyO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdFx0Ly8gQWRkIHRoZSBsYXN0IGl0ZW1cclxuXHRcdFx0XHRcdFx0XHRcdGlmIChjdXJyZW50SXRlbS50cmltKCkpIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgdHJpbW1lZEl0ZW0gPSBjdXJyZW50SXRlbS50cmltKCk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IHVucXVvdGVkID0gdHJpbW1lZEl0ZW0ucmVwbGFjZSgvXltcIiddfFtcIiddJC9nLCAnJyk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdGl0ZW1zLnB1c2godW5xdW90ZWQpO1xyXG5cdFx0XHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGV4aXN0aW5nUHJvcGVydGllc1trZXldID0gaXRlbXM7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRcdC8vIE5vdCBhIGJyYWNrZXQgYXJyYXksIGNoZWNrIGZvciBvdGhlciBhcnJheSBmb3JtYXRzXHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgaXNLbm93bkFycmF5S2V5ID0gS05PV05fQVJSQVlfS0VZUy5pbmNsdWRlcyhrZXkgYXMgdHlwZW9mIEtOT1dOX0FSUkFZX0tFWVNbbnVtYmVyXSk7XHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgaXNFbXB0eUFycmF5ID0gIXRyaW1tZWRWYWx1ZSB8fCB0cmltbWVkVmFsdWUgPT09IFwiXCI7XHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgaXNBcnJheVByb3BlcnR5ID0gaXNLbm93bkFycmF5S2V5IHx8IGlzRW1wdHlBcnJheTtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKGlzQXJyYXlQcm9wZXJ0eSkge1xyXG5cdFx0XHRcdFx0XHRcdFx0ZXhpc3RpbmdQcm9wZXJ0aWVzW2tleV0gPSBbXTtcclxuXHRcdFx0XHRcdFx0XHRcdGFycmF5S2V5cy5hZGQoa2V5KTsgLy8gTWFyayB0aGlzIGtleSBhcyBhbiBhcnJheVxyXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdFx0XHQvLyBTdHJpcCBzdXJyb3VuZGluZyBxdW90ZXMgZnJvbSBzdHJpbmcgdmFsdWVzXHJcblx0XHRcdFx0XHRcdFx0XHRjb25zdCB1bnF1b3RlZFZhbHVlID0gdHJpbW1lZFZhbHVlLnJlcGxhY2UoL15bXCInXXxbXCInXSQvZywgJycpO1xyXG5cdFx0XHRcdFx0XHRcdFx0ZXhpc3RpbmdQcm9wZXJ0aWVzW2tleV0gPSBbdW5xdW90ZWRWYWx1ZV07XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9IGVsc2UgaWYgKGN1cnJlbnRLZXkgJiYgdHJpbW1lZExpbmUuc3RhcnRzV2l0aChcIi0gXCIpKSB7XHJcblx0XHRcdFx0XHRcdC8vIENoZWNrIGlmIGN1cnJlbnQga2V5IGlzIGFuIGFycmF5IHByb3BlcnR5XHJcblx0XHRcdFx0XHRcdGNvbnN0IGlzQXJyYXlQcm9wZXJ0eSA9IGFycmF5S2V5cy5oYXMoY3VycmVudEtleSk7XHJcblxyXG5cdFx0XHRcdFx0XHRpZiAoaXNBcnJheVByb3BlcnR5KSB7XHJcblx0XHRcdFx0XHRcdFx0Y29uc3QgaXRlbSA9IHRyaW1tZWRMaW5lLnJlcGxhY2UoL14tXFxzKi8sIFwiXCIpO1xyXG5cdFx0XHRcdFx0XHRcdGlmIChpdGVtKSBleGlzdGluZ1Byb3BlcnRpZXNbY3VycmVudEtleV0ucHVzaChpdGVtKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmICh0cmltbWVkTGluZSAmJiAhdHJpbW1lZExpbmUuc3RhcnRzV2l0aChcIi0gXCIpICYmICF0cmltbWVkTGluZS5zdGFydHNXaXRoKFwiI1wiKSkge1xyXG5cdFx0XHRcdFx0XHQvLyBIYW5kbGUgdW5yZWNvZ25pemVkIHByb3BlcnRpZXMgdGhhdCBkb24ndCBtYXRjaCB0aGUgc3RhbmRhcmQgZm9ybWF0XHJcblx0XHRcdFx0XHRcdC8vIFRoaXMgaXMgYSBmYWxsYmFjayB0byBwcmVzZXJ2ZSBwcm9wZXJ0aWVzIHRoYXQgbWlnaHQgaGF2ZSBzcGVjaWFsIGZvcm1hdHRpbmdcclxuXHRcdFx0XHRcdFx0Y29uc3Qga2V5TWF0Y2ggPSB0cmltbWVkTGluZS5tYXRjaCgvXihbXjpdKyk6XFxzKiguKikkLyk7XHJcblx0XHRcdFx0XHRcdGlmIChrZXlNYXRjaCkge1xyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IFssIGtleSwgdmFsdWVdID0ga2V5TWF0Y2g7XHJcblx0XHRcdFx0XHRcdFx0aWYgKCFleGlzdGluZ1Byb3BlcnRpZXNba2V5XSkge1xyXG5cdFx0XHRcdFx0XHRcdFx0ZXhpc3RpbmdQcm9wZXJ0aWVzW2tleV0gPSBbdmFsdWUgPyB2YWx1ZS50cmltKCkgOiBcIlwiXTtcclxuXHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0XHQvLyBQcmVzZXJ2ZSBhcnJheSBrZXlzIGlmIHRoZXkgZXhpc3Qgd2l0aG91dCB2YWx1ZXNcclxuXHRcdFx0XHRLTk9XTl9BUlJBWV9LRVlTLmZvckVhY2goa2V5ID0+IHtcclxuXHRcdFx0XHRcdGlmIChwcm9wZXJ0aWVzVGV4dC5pbmNsdWRlcyhrZXkgKyAnOicpICYmICFleGlzdGluZ1Byb3BlcnRpZXNba2V5XSkge1xyXG5cdFx0XHRcdFx0XHRleGlzdGluZ1Byb3BlcnRpZXNba2V5XSA9IFtdO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHR9IGNhdGNoIHtcclxuXHRcdFx0XHQvLyBGYWxsYmFjayB0byB0ZW1wbGF0ZSBpZiBwYXJzaW5nIGZhaWxzXHJcblx0XHRcdFx0bmV3IE5vdGljZShcIkZhbGxpbmcgYmFjayB0byB0ZW1wbGF0ZSBkdWUgdG8gcGFyc2luZyBlcnJvci5cIik7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCBib2R5Q29udGVudCA9IGNvbnRlbnQuc2xpY2UocHJvcGVydGllc0VuZCk7XHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHRwcm9wZXJ0aWVzOiBleGlzdGluZ1Byb3BlcnRpZXMsXHJcblx0XHRcdHByb3BlcnRpZXNUZXh0LFxyXG5cdFx0XHRwcm9wZXJ0aWVzRW5kLFxyXG5cdFx0XHRib2R5Q29udGVudFxyXG5cdFx0fTtcclxuXHR9XHJcblxyXG5cdHBhcnNlVGVtcGxhdGUodGVtcGxhdGVTdHJpbmc6IHN0cmluZywgdGl0bGU6IHN0cmluZyk6IHsgdGVtcGxhdGVQcm9wczogc3RyaW5nW107IHRlbXBsYXRlVmFsdWVzOiBUZW1wbGF0ZVZhbHVlcyB9IHtcclxuXHRcdGNvbnN0IHRlbXBsYXRlTGluZXMgPSB0ZW1wbGF0ZVN0cmluZy5zcGxpdChcIlxcblwiKTtcclxuXHRcdGNvbnN0IHRlbXBsYXRlUHJvcHM6IHN0cmluZ1tdID0gW107XHJcblx0XHRjb25zdCB0ZW1wbGF0ZVZhbHVlczogVGVtcGxhdGVWYWx1ZXMgPSB7fTtcclxuXHRcdGxldCBpblByb3BlcnRpZXMgPSBmYWxzZTtcclxuXHJcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRlbXBsYXRlTGluZXMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0Y29uc3QgbGluZSA9IHRlbXBsYXRlTGluZXNbaV0udHJpbSgpO1xyXG5cdFx0XHRpZiAobGluZSA9PT0gXCItLS1cIikge1xyXG5cdFx0XHRcdGluUHJvcGVydGllcyA9ICFpblByb3BlcnRpZXM7XHJcblx0XHRcdFx0aWYgKCFpblByb3BlcnRpZXMpIHtcclxuXHRcdFx0XHRcdGJyZWFrOyAvLyBTdG9wIGF0IHNlY29uZCAtLS0gdG8gZXhjbHVkZSBwb3N0LXByb3BlcnR5IGNvbnRlbnRcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKGluUHJvcGVydGllcykge1xyXG5cdFx0XHRcdGNvbnN0IG1hdGNoID0gbGluZS5tYXRjaCgvXihcXHcrKTpcXHMqKC4qKSQvKTtcclxuXHRcdFx0XHRpZiAobWF0Y2gpIHtcclxuXHRcdFx0XHRcdGNvbnN0IFssIGtleSwgdmFsdWVdID0gbWF0Y2g7XHJcblx0XHRcdFx0XHR0ZW1wbGF0ZVByb3BzLnB1c2goa2V5KTtcclxuXHJcblx0XHRcdFx0XHQvLyBDaGVjayBpZiB0aGlzIGlzIGFuIGFycmF5IHByb3BlcnR5IChrbm93biBhcnJheSBrZXlzIG9yIFlBTUwgbGlzdCBmb3JtYXQpXHJcblx0XHRcdFx0XHRjb25zdCBpc0tub3duQXJyYXlLZXkgPSBLTk9XTl9BUlJBWV9LRVlTLmluY2x1ZGVzKGtleSBhcyB0eXBlb2YgS05PV05fQVJSQVlfS0VZU1tudW1iZXJdKTtcclxuXHRcdFx0XHRcdC8vIENoZWNrIGlmIGl0J3MgYSBZQU1MIGxpc3QgZm9ybWF0IChubyB2YWx1ZSBhZnRlciBjb2xvbiwgZW1wdHkgYnJhY2tldHMsIG9yIGVtcHR5IHZhbHVlIG1lYW5zIGl0J3MgYW4gYXJyYXkpXHJcblx0XHRcdFx0XHRjb25zdCBpc0VtcHR5QXJyYXkgPSAhdmFsdWUgfHwgdmFsdWUudHJpbSgpID09PSBcIlwiIHx8IHZhbHVlLnRyaW0oKSA9PT0gXCJbXVwiO1xyXG5cdFx0XHRcdFx0Y29uc3QgaXNBcnJheVByb3BlcnR5ID0gaXNLbm93bkFycmF5S2V5IHx8IGlzRW1wdHlBcnJheTtcclxuXHJcblx0XHRcdFx0XHRpZiAoaXNBcnJheVByb3BlcnR5KSB7XHJcblx0XHRcdFx0XHRcdC8vIEhhbmRsZSBhcnJheSBwcm9wZXJ0aWVzXHJcblx0XHRcdFx0XHRcdGlmICh2YWx1ZSAmJiB2YWx1ZS5zdGFydHNXaXRoKFwiW1wiKSkge1xyXG5cdFx0XHRcdFx0XHRcdC8vIEhhbmRsZSBicmFja2V0IGZvcm1hdDogW1wiaXRlbTFcIiwgXCJpdGVtMlwiXVxyXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGl0ZW1zID0gdmFsdWVcclxuXHRcdFx0XHRcdFx0XHRcdC5yZXBsYWNlKC9bW1xcXV0vZywgXCJcIilcclxuXHRcdFx0XHRcdFx0XHRcdC5zcGxpdChcIixcIilcclxuXHRcdFx0XHRcdFx0XHRcdC5tYXAodCA9PiB0LnRyaW0oKSlcclxuXHRcdFx0XHRcdFx0XHRcdC5maWx0ZXIodCA9PiB0KTtcclxuXHRcdFx0XHRcdFx0XHR0ZW1wbGF0ZVZhbHVlc1trZXldID0gaXRlbXM7XHJcblx0XHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdFx0Ly8gSGFuZGxlIFlBTUwgbGlzdCBmb3JtYXQ6IGVtcHR5IG9yIHdpdGggLSBpdGVtc1xyXG5cdFx0XHRcdFx0XHRcdHRlbXBsYXRlVmFsdWVzW2tleV0gPSBbXTtcclxuXHRcdFx0XHRcdFx0XHQvLyBMb29rIGFoZWFkIGZvciBpdGVtIGxpc3RcclxuXHRcdFx0XHRcdFx0XHRmb3IgKGxldCBqID0gaSArIDE7IGogPCB0ZW1wbGF0ZUxpbmVzLmxlbmd0aDsgaisrKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRjb25zdCBuZXh0TGluZSA9IHRlbXBsYXRlTGluZXNbal0udHJpbSgpO1xyXG5cdFx0XHRcdFx0XHRcdFx0aWYgKG5leHRMaW5lLnN0YXJ0c1dpdGgoXCItIFwiKSkge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBpdGVtID0gbmV4dExpbmUucmVwbGFjZSgvXi1cXHMqLywgXCJcIikudHJpbSgpO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoaXRlbSkge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IGFycmF5VmFsdWUgPSB0ZW1wbGF0ZVZhbHVlc1trZXldO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmIChBcnJheS5pc0FycmF5KGFycmF5VmFsdWUpKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRhcnJheVZhbHVlLnB1c2goaXRlbSk7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0XHR9IGVsc2UgaWYgKG5leHRMaW5lID09PSBcIi0tLVwiIHx8IChuZXh0TGluZSAmJiAhbmV4dExpbmUuc3RhcnRzV2l0aChcIi0gXCIpICYmIG5leHRMaW5lLmluY2x1ZGVzKFwiOlwiKSkpIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gU3RvcCBhdCBuZXh0IHByb3BlcnR5IG9yIGVuZCBvZiBwcm9wZXJ0aWVzIHNlY3Rpb25cclxuXHRcdFx0XHRcdFx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHQvLyBUaGlzIGlzIGEgc3RyaW5nIHByb3BlcnR5LCBub3QgYW4gYXJyYXlcclxuXHRcdFx0XHRcdFx0Y29uc3Qgc2x1ZyA9IHRoaXMudG9LZWJhYkNhc2UodGl0bGUpO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMuZ2V0U2V0dGluZ3MoKTtcclxuXHRcdFx0XHRcdFx0Y29uc3Qgc3RyaW5nVmFsdWUgPSAodmFsdWUgfHwgXCJcIilcclxuXHRcdFx0XHRcdFx0XHQucmVwbGFjZSgvXFx7XFx7dGl0bGVcXH1cXH0vZywgdGl0bGUpXHJcblx0XHRcdFx0XHRcdFx0LnJlcGxhY2UoL1xce1xce2RhdGVcXH1cXH0vZywgd2luZG93Lm1vbWVudChuZXcgRGF0ZSgpKS5mb3JtYXQoc2V0dGluZ3MuZGF0ZUZvcm1hdCkpXHJcblx0XHRcdFx0XHRcdFx0LnJlcGxhY2UoL1xce1xce3NsdWdcXH1cXH0vZywgc2x1Zyk7XHJcblx0XHRcdFx0XHRcdC8vIFN0b3JlIGFzIGEgc2luZ2xlIHN0cmluZyB2YWx1ZSwgbm90IGluIGFuIGFycmF5XHJcblx0XHRcdFx0XHRcdHRlbXBsYXRlVmFsdWVzW2tleV0gPSBzdHJpbmdWYWx1ZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4geyB0ZW1wbGF0ZVByb3BzLCB0ZW1wbGF0ZVZhbHVlcyB9O1xyXG5cdH1cclxuXHJcblx0YnVpbGRGcm9udG1hdHRlckNvbnRlbnQoZmluYWxQcm9wczogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+LCBhcnJheUtleXM/OiBTZXQ8c3RyaW5nPik6IHN0cmluZyB7XHJcblx0XHRsZXQgbmV3Q29udGVudCA9IFwiLS0tXFxuXCI7XHJcblx0XHRmb3IgKGNvbnN0IGtleSBpbiBmaW5hbFByb3BzKSB7XHJcblx0XHRcdC8vIENoZWNrIGlmIHRoaXMgaXMgYW4gYXJyYXkgcHJvcGVydHlcclxuXHRcdFx0Y29uc3QgaXNBcnJheVByb3BlcnR5ID0gS05PV05fQVJSQVlfS0VZUy5pbmNsdWRlcyhrZXkgYXMgdHlwZW9mIEtOT1dOX0FSUkFZX0tFWVNbbnVtYmVyXSkgfHxcclxuXHRcdFx0XHQoYXJyYXlLZXlzICYmIGFycmF5S2V5cy5oYXMoa2V5KSk7XHJcblxyXG5cdFx0XHRpZiAoaXNBcnJheVByb3BlcnR5KSB7XHJcblx0XHRcdFx0bmV3Q29udGVudCArPSBgJHtrZXl9OlxcbmA7XHJcblx0XHRcdFx0aWYgKGZpbmFsUHJvcHNba2V5XS5sZW5ndGggPiAwKSB7XHJcblx0XHRcdFx0XHRmaW5hbFByb3BzW2tleV0uZm9yRWFjaChpdGVtID0+IHtcclxuXHRcdFx0XHRcdFx0bmV3Q29udGVudCArPSBgICAtICR7aXRlbX1cXG5gO1xyXG5cdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdG5ld0NvbnRlbnQgKz0gYCR7a2V5fTogJHtmaW5hbFByb3BzW2tleV1bMF0gfHwgXCJcIn1cXG5gO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRuZXdDb250ZW50ICs9IFwiLS0tXCI7XHJcblx0XHRyZXR1cm4gbmV3Q29udGVudDtcclxuXHR9XHJcblxyXG5cdGFzeW5jIHVwZGF0ZVRpdGxlSW5Gcm9udG1hdHRlcihmaWxlOiBURmlsZSwgbmV3VGl0bGU6IHN0cmluZywgdHlwZTogQ29udGVudFR5cGVJZCk6IFByb21pc2U8dm9pZD4ge1xyXG5cdFx0Ly8gQ2hlY2sgaWYgdGVtcGxhdGUgaGFzIHt7dGl0bGV9fSAtIGlmIG5vdCwgZG9uJ3QgdXBkYXRlIGZyb250bWF0dGVyIGF0IGFsbFxyXG5cdFx0Y29uc3QgdGl0bGVLZXkgPSB0aGlzLmdldFRpdGxlS2V5KHR5cGUpO1xyXG5cdFx0Y29uc3QgaGFzVGl0bGVJblRlbXBsYXRlID0gdGhpcy50ZW1wbGF0ZUhhc1RpdGxlKHR5cGUpO1xyXG5cclxuXHRcdC8vIElmIHRlbXBsYXRlIGRvZXNuJ3QgaGF2ZSB7e3RpdGxlfX0sIGRvbid0IG1vZGlmeSBmcm9udG1hdHRlclxyXG5cdFx0aWYgKCFoYXNUaXRsZUluVGVtcGxhdGUpIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IGNvbnRlbnQgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkKGZpbGUpO1xyXG5cdFx0bGV0IHByb3BlcnRpZXNFbmQgPSAwO1xyXG5cdFx0bGV0IHByb3BlcnRpZXNUZXh0ID0gXCJcIjtcclxuXHRcdGxldCBoYXNGcm9udG1hdHRlciA9IGZhbHNlO1xyXG5cclxuXHRcdGlmIChjb250ZW50LnN0YXJ0c1dpdGgoXCItLS1cIikpIHtcclxuXHRcdFx0aGFzRnJvbnRtYXR0ZXIgPSB0cnVlO1xyXG5cdFx0XHRwcm9wZXJ0aWVzRW5kID0gY29udGVudC5pbmRleE9mKFwiXFxuLS0tXCIsIDMpO1xyXG5cdFx0XHRpZiAocHJvcGVydGllc0VuZCA9PT0gLTEpIHtcclxuXHRcdFx0XHRwcm9wZXJ0aWVzRW5kID0gY29udGVudC5sZW5ndGg7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0cHJvcGVydGllc0VuZCArPSA0O1xyXG5cdFx0XHR9XHJcblx0XHRcdHByb3BlcnRpZXNUZXh0ID0gY29udGVudC5zbGljZSg0LCBwcm9wZXJ0aWVzRW5kIC0gNCkudHJpbSgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGNvbnN0IHByb3BPcmRlcjogc3RyaW5nW10gPSBbXTtcclxuXHRcdGNvbnN0IGV4aXN0aW5nOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmcgfCBzdHJpbmdbXT4gPSB7fTtcclxuXHRcdGxldCBjdXJyZW50S2V5OiBzdHJpbmcgfCBudWxsID0gbnVsbDtcclxuXHRcdGxldCB0aXRsZUtleVBvc2l0aW9uID0gLTE7IC8vIFRyYWNrIHRoZSBvcmlnaW5hbCBwb3NpdGlvbiBvZiB0aGUgdGl0bGUga2V5XHJcblxyXG5cdFx0Y29uc3QgYXJyYXlLZXlzID0gbmV3IFNldDxzdHJpbmc+KCk7IC8vIFRyYWNrIHdoaWNoIGtleXMgYXJlIGFycmF5c1xyXG5cclxuXHRcdHByb3BlcnRpZXNUZXh0LnNwbGl0KFwiXFxuXCIpLmZvckVhY2goKGxpbmUsIGluZGV4KSA9PiB7XHJcblx0XHRcdGNvbnN0IHRyaW1tZWRMaW5lID0gbGluZS50cmltKCk7XHJcblxyXG5cdFx0XHQvLyBNYXRjaCBwcm9wZXJ0eSBsaW5lcyAtIG1vcmUgZmxleGlibGUgcmVnZXggdG8gaGFuZGxlIHZhcmlvdXMgcHJvcGVydHkgbmFtZXNcclxuXHRcdFx0Y29uc3QgbWF0Y2ggPSB0cmltbWVkTGluZS5tYXRjaCgvXihbYS16QS1aX11bYS16QS1aMC05Xy1dKik6XFxzKiguKikkLyk7XHJcblx0XHRcdGlmIChtYXRjaCkge1xyXG5cdFx0XHRcdGNvbnN0IFssIGtleSwgdmFsdWVdID0gbWF0Y2g7XHJcblx0XHRcdFx0cHJvcE9yZGVyLnB1c2goa2V5KTtcclxuXHRcdFx0XHRjdXJyZW50S2V5ID0ga2V5O1xyXG5cclxuXHRcdFx0XHQvLyBUcmFjayB0aGUgb3JpZ2luYWwgcG9zaXRpb24gb2YgdGhlIHRpdGxlIGtleVxyXG5cdFx0XHRcdGlmIChrZXkgPT09IHRpdGxlS2V5KSB7XHJcblx0XHRcdFx0XHR0aXRsZUtleVBvc2l0aW9uID0gaW5kZXg7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb25zdCBpc0tub3duQXJyYXlLZXkgPSBLTk9XTl9BUlJBWV9LRVlTLmluY2x1ZGVzKGtleSBhcyB0eXBlb2YgS05PV05fQVJSQVlfS0VZU1tudW1iZXJdKTtcclxuXHRcdFx0XHRjb25zdCBpc0VtcHR5QXJyYXkgPSAhdmFsdWUgfHwgdmFsdWUudHJpbSgpID09PSBcIlwiIHx8IHZhbHVlLnRyaW0oKSA9PT0gXCJbXVwiO1xyXG5cdFx0XHRcdGNvbnN0IGlzQXJyYXlQcm9wZXJ0eSA9IGlzS25vd25BcnJheUtleSB8fCBpc0VtcHR5QXJyYXk7XHJcblxyXG5cdFx0XHRcdGlmIChpc0FycmF5UHJvcGVydHkpIHtcclxuXHRcdFx0XHRcdGV4aXN0aW5nW2tleV0gPSBbXTtcclxuXHRcdFx0XHRcdGFycmF5S2V5cy5hZGQoa2V5KTsgLy8gTWFyayB0aGlzIGtleSBhcyBhbiBhcnJheVxyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRleGlzdGluZ1trZXldID0gdmFsdWUgPyB2YWx1ZS50cmltKCkgOiBcIlwiO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBlbHNlIGlmIChjdXJyZW50S2V5ICYmIGFycmF5S2V5cy5oYXMoY3VycmVudEtleSkgJiYgdHJpbW1lZExpbmUuc3RhcnRzV2l0aChcIi0gXCIpKSB7XHJcblx0XHRcdFx0Ly8gSGFuZGxlIGFycmF5IGl0ZW1zXHJcblx0XHRcdFx0Y29uc3QgaXRlbSA9IHRyaW1tZWRMaW5lLnJlcGxhY2UoL14tXFxzKi8sIFwiXCIpO1xyXG5cdFx0XHRcdGlmIChpdGVtKSAoZXhpc3RpbmdbY3VycmVudEtleV0gYXMgc3RyaW5nW10pLnB1c2goaXRlbSk7XHJcblx0XHRcdH0gZWxzZSBpZiAodHJpbW1lZExpbmUgJiYgIXRyaW1tZWRMaW5lLnN0YXJ0c1dpdGgoXCItIFwiKSAmJiAhdHJpbW1lZExpbmUuc3RhcnRzV2l0aChcIiNcIikpIHtcclxuXHRcdFx0XHQvLyBIYW5kbGUgdW5yZWNvZ25pemVkIHByb3BlcnRpZXMgdGhhdCBkb24ndCBtYXRjaCB0aGUgc3RhbmRhcmQgZm9ybWF0XHJcblx0XHRcdFx0Ly8gVGhpcyBpcyBhIGZhbGxiYWNrIHRvIHByZXNlcnZlIHByb3BlcnRpZXMgdGhhdCBtaWdodCBoYXZlIHNwZWNpYWwgZm9ybWF0dGluZ1xyXG5cdFx0XHRcdGNvbnN0IGtleU1hdGNoID0gdHJpbW1lZExpbmUubWF0Y2goL14oW146XSspOlxccyooLiopJC8pO1xyXG5cdFx0XHRcdGlmIChrZXlNYXRjaCkge1xyXG5cdFx0XHRcdFx0Y29uc3QgWywga2V5LCB2YWx1ZV0gPSBrZXlNYXRjaDtcclxuXHRcdFx0XHRcdGlmICghcHJvcE9yZGVyLmluY2x1ZGVzKGtleSkpIHtcclxuXHRcdFx0XHRcdFx0cHJvcE9yZGVyLnB1c2goa2V5KTtcclxuXHRcdFx0XHRcdFx0ZXhpc3Rpbmdba2V5XSA9IHZhbHVlID8gdmFsdWUudHJpbSgpIDogXCJcIjtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH0pO1xyXG5cclxuXHRcdC8vIFByb3Blcmx5IGVzY2FwZSBZQU1MIHN0cmluZyB2YWx1ZXNcclxuXHRcdC8vIFlBTUwgc3RyaW5ncyB3aXRoIHF1b3RlcyBuZWVkIHRvIGJlIHdyYXBwZWQgaW4gc2luZ2xlIHF1b3RlcyBvciBlc2NhcGVkIHByb3Blcmx5XHJcblx0XHRsZXQgdGl0bGVWYWw6IHN0cmluZztcclxuXHRcdGlmIChuZXdUaXRsZS5pbmNsdWRlcygnXCInKSB8fCBuZXdUaXRsZS5pbmNsdWRlcyhcIidcIikgfHwgbmV3VGl0bGUuaW5jbHVkZXMoJ1xcbicpIHx8IG5ld1RpdGxlLmluY2x1ZGVzKCdcXFxcJykpIHtcclxuXHRcdFx0Ly8gRm9yIHN0cmluZ3Mgd2l0aCBxdW90ZXMsIG5ld2xpbmVzLCBvciBiYWNrc2xhc2hlcywgdXNlIHNpbmdsZSBxdW90ZXMgYW5kIGVzY2FwZSBzaW5nbGUgcXVvdGVzXHJcblx0XHRcdHRpdGxlVmFsID0gYCcke25ld1RpdGxlLnJlcGxhY2UoLycvZywgXCInJ1wiKX0nYDtcclxuXHRcdH0gZWxzZSBpZiAobmV3VGl0bGUuaW5jbHVkZXMoXCIgXCIpIHx8IG5ld1RpdGxlLmluY2x1ZGVzKFwiOlwiKSB8fCBuZXdUaXRsZS5pbmNsdWRlcyhcIiNcIikgfHwgbmV3VGl0bGUuaW5jbHVkZXMoXCJAXCIpKSB7XHJcblx0XHRcdC8vIEZvciBzdHJpbmdzIHdpdGggc3BhY2VzIG9yIHNwZWNpYWwgWUFNTCBjaGFyYWN0ZXJzLCB3cmFwIGluIGRvdWJsZSBxdW90ZXMgYW5kIGVzY2FwZSBkb3VibGUgcXVvdGVzXHJcblx0XHRcdHRpdGxlVmFsID0gYFwiJHtuZXdUaXRsZS5yZXBsYWNlKC9cIi9nLCAnXFxcXFwiJyl9XCJgO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0Ly8gRm9yIHNpbXBsZSBzdHJpbmdzLCBubyBxdW90ZXMgbmVlZGVkXHJcblx0XHRcdHRpdGxlVmFsID0gbmV3VGl0bGU7XHJcblx0XHR9XHJcblx0XHRleGlzdGluZ1t0aXRsZUtleV0gPSB0aXRsZVZhbDtcclxuXHJcblx0XHQvLyBBbHNvIHVwZGF0ZSBzbHVnIGlmIGl0IGV4aXN0cyBpbiBmcm9udG1hdHRlclxyXG5cdFx0aWYgKFwic2x1Z1wiIGluIGV4aXN0aW5nKSB7XHJcblx0XHRcdGNvbnN0IG5ld1NsdWcgPSB0aGlzLnRvS2ViYWJDYXNlKG5ld1RpdGxlKTtcclxuXHRcdFx0ZXhpc3RpbmdbXCJzbHVnXCJdID0gbmV3U2x1ZztcclxuXHRcdH1cclxuXHJcblx0XHQvLyBJZiB0aXRsZSBrZXkgd2FzIGZvdW5kIGluIG9yaWdpbmFsIHByb3BlcnRpZXMsIHByZXNlcnZlIGl0cyBwb3NpdGlvblxyXG5cdFx0Ly8gT3RoZXJ3aXNlLCBhZGQgaXQgYXQgdGhlIGVuZFxyXG5cdFx0aWYgKHRpdGxlS2V5UG9zaXRpb24gPT09IC0xKSB7XHJcblx0XHRcdC8vIFRpdGxlIGtleSBub3QgZm91bmQgaW4gb3JpZ2luYWwgcHJvcGVydGllcywgYWRkIGl0IGF0IHRoZSBlbmRcclxuXHRcdFx0cHJvcE9yZGVyLnB1c2godGl0bGVLZXkpO1xyXG5cdFx0fVxyXG5cdFx0Ly8gSWYgdGl0bGVLZXlQb3NpdGlvbiA+PSAwLCB0aGUgdGl0bGUga2V5IGlzIGFscmVhZHkgaW4gcHJvcE9yZGVyIGF0IHRoZSBjb3JyZWN0IHBvc2l0aW9uXHJcblxyXG5cdFx0Ly8gT25seSBjcmVhdGUvdXBkYXRlIGZyb250bWF0dGVyIGlmIGl0IGFscmVhZHkgZXhpc3RzXHJcblx0XHQvLyBEb24ndCBjcmVhdGUgZnJvbnRtYXR0ZXIgZnJvbSBzY3JhdGNoIGlmIGZpbGUgaGFkIG5vbmVcclxuXHRcdGlmICghaGFzRnJvbnRtYXR0ZXIpIHtcclxuXHRcdFx0Ly8gRmlsZSBoYWQgbm8gZnJvbnRtYXR0ZXIgLSBkb24ndCBjcmVhdGUgaXQsIGp1c3QgcmV0dXJuXHJcblx0XHRcdC8vIFRoZSByZW5hbWUgYWxyZWFkeSBoYXBwZW5lZCwgd2UganVzdCBkb24ndCB1cGRhdGUgZnJvbnRtYXR0ZXJcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEJ1aWxkIG5ldyBjb250ZW50IHdpdGggZnJvbnRtYXR0ZXJcclxuXHRcdGxldCBuZXdDb250ZW50ID0gXCItLS1cXG5cIjtcclxuXHRcdGZvciAoY29uc3Qga2V5IG9mIHByb3BPcmRlcikge1xyXG5cdFx0XHRjb25zdCB2YWwgPSBleGlzdGluZ1trZXldO1xyXG5cdFx0XHRpZiAoQXJyYXkuaXNBcnJheSh2YWwpKSB7XHJcblx0XHRcdFx0bmV3Q29udGVudCArPSBgJHtrZXl9OlxcbmA7XHJcblx0XHRcdFx0aWYgKHZhbC5sZW5ndGggPiAwKSB7XHJcblx0XHRcdFx0XHR2YWwuZm9yRWFjaCgoaXRlbTogc3RyaW5nKSA9PiB7XHJcblx0XHRcdFx0XHRcdG5ld0NvbnRlbnQgKz0gYCAgLSAke2l0ZW19XFxuYDtcclxuXHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRuZXdDb250ZW50ICs9IGAke2tleX06ICR7dmFsIHx8IFwiXCJ9XFxuYDtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0bmV3Q29udGVudCArPSBcIi0tLVxcblwiO1xyXG5cclxuXHRcdC8vIEdldCBib2R5IGNvbnRlbnQgKGZyb250bWF0dGVyIGFscmVhZHkgZXhpc3RlZCwgc28gd2Uga25vdyBwcm9wZXJ0aWVzRW5kIGlzIHNldClcclxuXHRcdGNvbnN0IGJvZHlDb250ZW50ID0gY29udGVudC5zbGljZShwcm9wZXJ0aWVzRW5kKTtcclxuXHRcdG5ld0NvbnRlbnQgKz0gYm9keUNvbnRlbnQ7XHJcblxyXG5cdFx0YXdhaXQgdGhpcy5hcHAudmF1bHQubW9kaWZ5KGZpbGUsIG5ld0NvbnRlbnQpO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSBnZXRUaXRsZUtleSh0eXBlOiBDb250ZW50VHlwZUlkKTogc3RyaW5nIHtcclxuXHRcdGlmICh0eXBlID09PSBcIm5vdGVcIikgcmV0dXJuIFwidGl0bGVcIjtcclxuXHJcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMuZ2V0U2V0dGluZ3MoKTtcclxuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcclxuXHRcdGNvbnN0IGNvbnRlbnRUeXBlID0gY29udGVudFR5cGVzLmZpbmQoY3QgPT4gY3QuaWQgPT09IHR5cGUpO1xyXG5cdFx0aWYgKCFjb250ZW50VHlwZSkgcmV0dXJuIFwidGl0bGVcIjtcclxuXHJcblx0XHRjb25zdCB0ZW1wbGF0ZSA9IGNvbnRlbnRUeXBlLnRlbXBsYXRlO1xyXG5cdFx0Y29uc3QgbGluZXMgPSB0ZW1wbGF0ZS5zcGxpdChcIlxcblwiKTtcclxuXHRcdGxldCBpblByb3BlcnRpZXMgPSBmYWxzZTtcclxuXHRcdGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xyXG5cdFx0XHRjb25zdCB0cmltbWVkID0gbGluZS50cmltKCk7XHJcblx0XHRcdGlmICh0cmltbWVkID09PSBcIi0tLVwiKSB7XHJcblx0XHRcdFx0aW5Qcm9wZXJ0aWVzID0gIWluUHJvcGVydGllcztcclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAoaW5Qcm9wZXJ0aWVzKSB7XHJcblx0XHRcdFx0Y29uc3QgbWF0Y2ggPSB0cmltbWVkLm1hdGNoKC9eKFxcdyspOlxccyooLispJC8pO1xyXG5cdFx0XHRcdGlmIChtYXRjaCkge1xyXG5cdFx0XHRcdFx0Y29uc3Qga2V5ID0gbWF0Y2hbMV07XHJcblx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IG1hdGNoWzJdO1xyXG5cdFx0XHRcdFx0aWYgKHZhbHVlLmluY2x1ZGVzKFwie3t0aXRsZX19XCIpKSB7XHJcblx0XHRcdFx0XHRcdHJldHVybiBrZXk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gXCJ0aXRsZVwiO1xyXG5cdH1cclxuXHJcblx0Ly8gQ2hlY2sgaWYgdGhlIHRlbXBsYXRlIGZvciB0aGlzIGNvbnRlbnQgdHlwZSBoYXMge3t0aXRsZX19XHJcblx0cHJpdmF0ZSB0ZW1wbGF0ZUhhc1RpdGxlKHR5cGU6IENvbnRlbnRUeXBlSWQpOiBib29sZWFuIHtcclxuXHRcdGlmICh0eXBlID09PSBcIm5vdGVcIikgcmV0dXJuIHRydWU7IC8vIE5vdGVzIGFsd2F5cyBoYXZlIHRpdGxlXHJcblxyXG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLmdldFNldHRpbmdzKCk7XHJcblx0XHRjb25zdCBjb250ZW50VHlwZXMgPSBzZXR0aW5ncy5jb250ZW50VHlwZXMgfHwgW107XHJcblx0XHRjb25zdCBjb250ZW50VHlwZSA9IGNvbnRlbnRUeXBlcy5maW5kKGN0ID0+IGN0LmlkID09PSB0eXBlKTtcclxuXHRcdGlmICghY29udGVudFR5cGUpIHJldHVybiB0cnVlOyAvLyBEZWZhdWx0IHRvIHRydWUgZm9yIHNhZmV0eVxyXG5cclxuXHRcdGNvbnN0IHRlbXBsYXRlID0gY29udGVudFR5cGUudGVtcGxhdGU7XHJcblx0XHRyZXR1cm4gdGVtcGxhdGUuaW5jbHVkZXMoXCJ7e3RpdGxlfX1cIik7XHJcblx0fVxyXG59XHJcbiIsICJpbXBvcnQgeyBFZGl0b3IsIFRGaWxlLCBOb3RpY2UgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCB7IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB9IGZyb20gXCIuLi90eXBlc1wiO1xuXG5pbXBvcnQgeyBtYXRjaGVzRm9sZGVyUGF0dGVybiwgc29ydEJ5UGF0dGVyblNwZWNpZmljaXR5IH0gZnJvbSBcIi4vcGF0aC1tYXRjaGluZ1wiO1xuaW1wb3J0IHsgdG9LZWJhYkNhc2UgfSBmcm9tIFwiLi9zdHJpbmctdXRpbHNcIjtcblxuZXhwb3J0IGNsYXNzIExpbmtDb252ZXJ0ZXIge1xuXHRjb25zdHJ1Y3Rvcihwcml2YXRlIHNldHRpbmdzOiBBc3Ryb0NvbXBvc2VyU2V0dGluZ3MsIHByaXZhdGUgcGx1Z2luPzogeyBzZXR0aW5ncz86IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB9KSB7IH1cblxuXHQvLyBHZXQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gaWYgYXZhaWxhYmxlLCBvdGhlcndpc2UgdXNlIHN0b3JlZCBzZXR0aW5nc1xuXHRwcml2YXRlIGdldFNldHRpbmdzKCk6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB7XG5cdFx0Ly8gQWx3YXlzIHByZWZlciBwbHVnaW4gc2V0dGluZ3MgKHRoZXkncmUga2VwdCB1cCB0byBkYXRlKVxuXHRcdGlmICh0aGlzLnBsdWdpbj8uc2V0dGluZ3MpIHtcblx0XHRcdHJldHVybiB0aGlzLnBsdWdpbi5zZXR0aW5ncztcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuc2V0dGluZ3M7XG5cdH1cblxuXHQvLyBMb2NhbCB0b0tlYmFiQ2FzZSByZW1vdmVkLCB1c2luZyBpbXBvcnRlZCBvbmUgaW5zdGVhZFxuXG5cdGdldEFzdHJvVXJsRnJvbUludGVybmFsTGluayhsaW5rOiBzdHJpbmcpOiBzdHJpbmcge1xuXHRcdGNvbnN0IGhhc2hJbmRleCA9IGxpbmsuaW5kZXhPZignIycpO1xuXHRcdGxldCBwYXRoID0gaGFzaEluZGV4ID49IDAgPyBsaW5rLnNsaWNlKDAsIGhhc2hJbmRleCkgOiBsaW5rO1xuXHRcdGNvbnN0IGFuY2hvciA9IGhhc2hJbmRleCA+PSAwID8gbGluay5zbGljZShoYXNoSW5kZXgpIDogJyc7XG5cblx0XHQvLyBVUkwgZGVjb2RlIHRoZSBwYXRoIHRvIGhhbmRsZSBlbmNvZGVkIGNoYXJhY3RlcnMgbGlrZSAlMjBcblx0XHRwYXRoID0gZGVjb2RlVVJJQ29tcG9uZW50KHBhdGgpO1xuXHRcdHBhdGggPSBwYXRoLnJlcGxhY2UoL1xcLihtZHxtZHgpJC8sIFwiXCIpO1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIGNvbnRlbnQgdHlwZSBhbmQgYXBwcm9wcmlhdGUgYmFzZSBwYXRoIHVzaW5nIHBhdHRlcm4gc3BlY2lmaWNpdHlcblx0XHQvLyBTdXBwb3J0IGJvdGggLm1kIGFuZCAubWR4IGV4dGVuc2lvbnNcblx0XHRjb25zdCBmaWxlRXh0ZW5zaW9uID0gbGluay5lbmRzV2l0aCgnLm1keCcpID8gJy5tZHgnIDogJy5tZCc7XG5cdFx0Y29uc3QgY29udGVudFR5cGVJbmZvID0gdGhpcy5nZXRDb250ZW50VHlwZUZvclBhdGgocGF0aCArIGZpbGVFeHRlbnNpb24pO1xuXHRcdGxldCBiYXNlUGF0aCA9IGNvbnRlbnRUeXBlSW5mby5iYXNlUGF0aCB8fCBcIlwiO1xuXHRcdGxldCBjb250ZW50Rm9sZGVyID0gY29udGVudFR5cGVJbmZvLmNvbnRlbnRGb2xkZXIgfHwgXCJcIjtcblx0XHRsZXQgaW5kZXhGaWxlTmFtZSA9IGNvbnRlbnRUeXBlSW5mby5pbmRleEZpbGVOYW1lIHx8IFwiXCI7XG5cblxuXHRcdC8vIFN0cmlwIGNvbnRlbnQgZm9sZGVyIGlmIHByZXNlbnRcblx0XHRpZiAoY29udGVudEZvbGRlcikge1xuXHRcdFx0cGF0aCA9IHBhdGguc2xpY2UoY29udGVudEZvbGRlci5sZW5ndGggKyAxKTtcblx0XHR9XG5cblx0XHRsZXQgYWRkVHJhaWxpbmdTbGFzaCA9IGZhbHNlO1xuXG5cdFx0Ly8gU21hcnQgZGV0ZWN0aW9uOiBpZiB0aGUgZmlsZW5hbWUgbWF0Y2hlcyB0aGUgaW5kZXggZmlsZSBuYW1lIChyZWdhcmRsZXNzIG9mIGNyZWF0aW9uIG1vZGUpLFxuXHRcdC8vIHRyZWF0IGl0IGFzIGZvbGRlci1iYXNlZCBsb2dpY1xuXHRcdC8vIE5vdGU6IFdlIG9ubHkgc2V0IGFkZFRyYWlsaW5nU2xhc2ggaGVyZTsgdGhlIGZpbmFsIGNoZWNrIHdpbGwgcHJldmVudCBpdCBpZiB0aGVyZSdzIGFuIGFuY2hvclxuXHRcdGNvbnN0IHBhcnRzID0gcGF0aC5zcGxpdCgnLycpO1xuXHRcdGNvbnN0IGxhc3RQYXJ0ID0gcGFydHNbcGFydHMubGVuZ3RoIC0gMV07XG5cblx0XHQvLyBDaGVjayBpZiB0aGUgbGFzdCBwYXJ0IG1hdGNoZXMgdGhlIHNwZWNpZmllZCBpbmRleCBmaWxlIG5hbWVcblx0XHRpZiAoaW5kZXhGaWxlTmFtZSAmJiBpbmRleEZpbGVOYW1lLnRyaW0oKSAhPT0gXCJcIiAmJiBsYXN0UGFydCA9PT0gaW5kZXhGaWxlTmFtZSkge1xuXHRcdFx0cGFydHMucG9wKCk7XG5cdFx0XHRwYXRoID0gcGFydHMuam9pbignLycpO1xuXHRcdFx0YWRkVHJhaWxpbmdTbGFzaCA9IHRydWU7XG5cdFx0fVxuXHRcdC8vIENoZWNrIGlmIHRoZSBsYXN0IHBhcnQgbWF0Y2hlcyB0aGUgZGVmYXVsdCBcImluZGV4XCIgKHdoZW4gbm8gaW5kZXhGaWxlTmFtZSBpcyBzcGVjaWZpZWQpXG5cdFx0ZWxzZSBpZiAoKCFpbmRleEZpbGVOYW1lIHx8IGluZGV4RmlsZU5hbWUudHJpbSgpID09PSBcIlwiKSAmJiBsYXN0UGFydCA9PT0gXCJpbmRleFwiKSB7XG5cdFx0XHRwYXJ0cy5wb3AoKTtcblx0XHRcdHBhdGggPSBwYXJ0cy5qb2luKCcvJyk7XG5cdFx0XHRhZGRUcmFpbGluZ1NsYXNoID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRjb25zdCBzbHVnUGFydHMgPSBwYXRoLnNwbGl0KCcvJykubWFwKHBhcnQgPT4gdG9LZWJhYkNhc2UocGFydCkpO1xuXHRcdGNvbnN0IHNsdWcgPSBzbHVnUGFydHMuam9pbignLycpO1xuXG5cdFx0Ly8gRm9ybWF0IGJhc2UgcGF0aFxuXHRcdGlmIChiYXNlUGF0aCkge1xuXHRcdFx0Ly8gQWRkIGxlYWRpbmcgc2xhc2ggaWYgbm90IHByZXNlbnQgdG8gbWFrZSBpdCBhYnNvbHV0ZSBmcm9tIHJvb3Rcblx0XHRcdGlmICghYmFzZVBhdGguc3RhcnRzV2l0aChcIi9cIikpIHtcblx0XHRcdFx0YmFzZVBhdGggPSBcIi9cIiArIGJhc2VQYXRoO1xuXHRcdFx0fVxuXHRcdFx0Ly8gQWRkIHRyYWlsaW5nIHNsYXNoIGlmIG5vdCBwcmVzZW50XG5cdFx0XHRpZiAoIWJhc2VQYXRoLmVuZHNXaXRoKFwiL1wiKSkge1xuXHRcdFx0XHRiYXNlUGF0aCArPSBcIi9cIjtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gV2hlbiBubyBiYXNlIHBhdGggaXMgc3BlY2lmaWVkLCBhZGQgbGVhZGluZyBzbGFzaCB0byBtYWtlIGl0IGFic29sdXRlIGZyb20gcm9vdFxuXHRcdFx0YmFzZVBhdGggPSBcIi9cIjtcblx0XHR9XG5cblx0XHQvLyBEZXRlcm1pbmUgaWYgd2Ugc2hvdWxkIGFkZCB0cmFpbGluZyBzbGFzaFxuXHRcdC8vIENSSVRJQ0FMOiBOZXZlciBhZGQgdHJhaWxpbmcgc2xhc2ggYmVmb3JlIGFuIGFuY2hvciAoZS5nLiwgL2Fib3V0I2hlYWRpbmcgbm90IC9hYm91dC8jaGVhZGluZylcblx0XHQvLyBUaGlzIGlzIGVzcGVjaWFsbHkgaW1wb3J0YW50IGZvciBhbmNob3IgbGlua3MgZnJvbSBjb3B5IGhlYWRpbmcgVVJMIGZ1bmN0aW9uYWxpdHlcblx0XHQvLyBBbmNob3IgbGlua3Mgc2hvdWxkIE5FVkVSIGhhdmUgdHJhaWxpbmcgc2xhc2hlcywgcmVnYXJkbGVzcyBvZiBzZXR0aW5nc1xuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5nZXRTZXR0aW5ncygpO1xuXHRcdGNvbnN0IHNob3VsZEFkZFRyYWlsaW5nU2xhc2ggPSAoc2V0dGluZ3MuYWRkVHJhaWxpbmdTbGFzaFRvTGlua3MgfHwgYWRkVHJhaWxpbmdTbGFzaCkgJiYgIWFuY2hvcjtcblxuXHRcdHJldHVybiBgJHtiYXNlUGF0aH0ke3NsdWd9JHtzaG91bGRBZGRUcmFpbGluZ1NsYXNoID8gJy8nIDogJyd9JHthbmNob3J9YDtcblx0fVxuXG5cdHByaXZhdGUgZ2V0QXN0cm9VcmxGcm9tSW50ZXJuYWxMaW5rV2l0aENvbnRleHQobGluazogc3RyaW5nLCBjdXJyZW50RmlsZVBhdGg6IHN0cmluZywgY3VycmVudEZpbGVDb250ZW50VHlwZTogeyBiYXNlUGF0aDogc3RyaW5nOyBjcmVhdGlvbk1vZGU6IFwiZmlsZVwiIHwgXCJmb2xkZXJcIjsgaW5kZXhGaWxlTmFtZTogc3RyaW5nOyBjb250ZW50Rm9sZGVyOiBzdHJpbmcgfSk6IHN0cmluZyB7XG5cblx0XHRjb25zdCBoYXNoSW5kZXggPSBsaW5rLmluZGV4T2YoJyMnKTtcblx0XHRsZXQgcGF0aCA9IGhhc2hJbmRleCA+PSAwID8gbGluay5zbGljZSgwLCBoYXNoSW5kZXgpIDogbGluaztcblx0XHRjb25zdCBhbmNob3IgPSBoYXNoSW5kZXggPj0gMCA/IGxpbmsuc2xpY2UoaGFzaEluZGV4KSA6ICcnO1xuXG5cdFx0Ly8gVVJMIGRlY29kZSB0aGUgcGF0aCB0byBoYW5kbGUgZW5jb2RlZCBjaGFyYWN0ZXJzIGxpa2UgJTIwXG5cdFx0cGF0aCA9IGRlY29kZVVSSUNvbXBvbmVudChwYXRoKTtcblx0XHRwYXRoID0gcGF0aC5yZXBsYWNlKC9cXC4obWR8bWR4KSQvLCBcIlwiKTtcblxuXG5cdFx0Ly8gRGV0ZXJtaW5lIGNvbnRlbnQgdHlwZSBhbmQgYXBwcm9wcmlhdGUgYmFzZSBwYXRoXG5cdFx0bGV0IGJhc2VQYXRoID0gXCJcIjtcblx0XHRsZXQgY29udGVudEZvbGRlciA9IFwiXCI7XG5cdFx0bGV0IGluZGV4RmlsZU5hbWUgPSBcIlwiO1xuXG5cdFx0Ly8gVXNlIHRoZSBzYW1lIGxvZ2ljIGFzIGdldENvbnRlbnRUeXBlRm9yUGF0aCBidXQgZm9yIHRoZSB0YXJnZXQgbGlua1xuXHRcdC8vIFN1cHBvcnQgYm90aCAubWQgYW5kIC5tZHggZXh0ZW5zaW9ucyAtIHRyeSAubWR4IGZpcnN0IGlmIGxpbmsgc3VnZ2VzdHMgaXRcblx0XHRjb25zdCBmaWxlRXh0ZW5zaW9uID0gbGluay5lbmRzV2l0aCgnLm1keCcpID8gJy5tZHgnIDogJy5tZCc7XG5cdFx0Y29uc3QgdGFyZ2V0Q29udGVudFR5cGUgPSB0aGlzLmdldENvbnRlbnRUeXBlRm9yUGF0aChwYXRoICsgZmlsZUV4dGVuc2lvbik7XG5cblx0XHQvLyBJZiB0YXJnZXQgbGluayBkb2Vzbid0IGhhdmUgYSBjbGVhciBjb250ZW50IHR5cGUgKG5vIGZvbGRlciBwYXRoKSwgdXNlIGN1cnJlbnQgZmlsZSdzIGNvbnRlbnQgdHlwZVxuXHRcdGlmICghdGFyZ2V0Q29udGVudFR5cGUuYmFzZVBhdGggJiYgY3VycmVudEZpbGVDb250ZW50VHlwZS5iYXNlUGF0aCkge1xuXHRcdFx0YmFzZVBhdGggPSBjdXJyZW50RmlsZUNvbnRlbnRUeXBlLmJhc2VQYXRoO1xuXHRcdFx0aW5kZXhGaWxlTmFtZSA9IGN1cnJlbnRGaWxlQ29udGVudFR5cGUuaW5kZXhGaWxlTmFtZTtcblx0XHRcdGNvbnRlbnRGb2xkZXIgPSBjdXJyZW50RmlsZUNvbnRlbnRUeXBlLmNvbnRlbnRGb2xkZXI7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGJhc2VQYXRoID0gdGFyZ2V0Q29udGVudFR5cGUuYmFzZVBhdGg7XG5cdFx0XHRpbmRleEZpbGVOYW1lID0gdGFyZ2V0Q29udGVudFR5cGUuaW5kZXhGaWxlTmFtZTtcblx0XHRcdGNvbnRlbnRGb2xkZXIgPSB0YXJnZXRDb250ZW50VHlwZS5jb250ZW50Rm9sZGVyO1xuXHRcdH1cblxuXHRcdC8vIFN0cmlwIGNvbnRlbnQgZm9sZGVyIGlmIHByZXNlbnRcblx0XHRpZiAoY29udGVudEZvbGRlcikge1xuXHRcdFx0cGF0aCA9IHBhdGguc2xpY2UoY29udGVudEZvbGRlci5sZW5ndGggKyAxKTtcblx0XHR9XG5cblx0XHRsZXQgYWRkVHJhaWxpbmdTbGFzaCA9IGZhbHNlO1xuXG5cdFx0Ly8gU21hcnQgZGV0ZWN0aW9uOiBpZiB0aGUgZmlsZW5hbWUgbWF0Y2hlcyB0aGUgaW5kZXggZmlsZSBuYW1lIChyZWdhcmRsZXNzIG9mIGNyZWF0aW9uIG1vZGUpLFxuXHRcdC8vIHRyZWF0IGl0IGFzIGZvbGRlci1iYXNlZCBsb2dpY1xuXHRcdC8vIE5vdGU6IFdlIG9ubHkgc2V0IGFkZFRyYWlsaW5nU2xhc2ggaGVyZTsgdGhlIGZpbmFsIGNoZWNrIHdpbGwgcHJldmVudCBpdCBpZiB0aGVyZSdzIGFuIGFuY2hvclxuXHRcdGNvbnN0IHBhcnRzID0gcGF0aC5zcGxpdCgnLycpO1xuXHRcdGNvbnN0IGxhc3RQYXJ0ID0gcGFydHNbcGFydHMubGVuZ3RoIC0gMV07XG5cblx0XHQvLyBDaGVjayBpZiB0aGUgbGFzdCBwYXJ0IG1hdGNoZXMgdGhlIHNwZWNpZmllZCBpbmRleCBmaWxlIG5hbWVcblx0XHRpZiAoaW5kZXhGaWxlTmFtZSAmJiBpbmRleEZpbGVOYW1lLnRyaW0oKSAhPT0gXCJcIiAmJiBsYXN0UGFydCA9PT0gaW5kZXhGaWxlTmFtZSkge1xuXHRcdFx0cGFydHMucG9wKCk7XG5cdFx0XHRwYXRoID0gcGFydHMuam9pbignLycpO1xuXHRcdFx0YWRkVHJhaWxpbmdTbGFzaCA9IHRydWU7XG5cdFx0fVxuXHRcdC8vIENoZWNrIGlmIHRoZSBsYXN0IHBhcnQgbWF0Y2hlcyB0aGUgZGVmYXVsdCBcImluZGV4XCIgKHdoZW4gbm8gaW5kZXhGaWxlTmFtZSBpcyBzcGVjaWZpZWQpXG5cdFx0ZWxzZSBpZiAoKCFpbmRleEZpbGVOYW1lIHx8IGluZGV4RmlsZU5hbWUudHJpbSgpID09PSBcIlwiKSAmJiBsYXN0UGFydCA9PT0gXCJpbmRleFwiKSB7XG5cdFx0XHRwYXJ0cy5wb3AoKTtcblx0XHRcdHBhdGggPSBwYXJ0cy5qb2luKCcvJyk7XG5cdFx0XHRhZGRUcmFpbGluZ1NsYXNoID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRjb25zdCBzbHVnUGFydHMgPSBwYXRoLnNwbGl0KCcvJykubWFwKHBhcnQgPT4gdG9LZWJhYkNhc2UocGFydCkpO1xuXHRcdGNvbnN0IHNsdWcgPSBzbHVnUGFydHMuam9pbignLycpO1xuXG5cdFx0Ly8gRm9ybWF0IGJhc2UgcGF0aFxuXHRcdGlmIChiYXNlUGF0aCkge1xuXHRcdFx0Ly8gQWRkIGxlYWRpbmcgc2xhc2ggaWYgbm90IHByZXNlbnQgdG8gbWFrZSBpdCBhYnNvbHV0ZSBmcm9tIHJvb3Rcblx0XHRcdGlmICghYmFzZVBhdGguc3RhcnRzV2l0aChcIi9cIikpIHtcblx0XHRcdFx0YmFzZVBhdGggPSBcIi9cIiArIGJhc2VQYXRoO1xuXHRcdFx0fVxuXHRcdFx0Ly8gQWRkIHRyYWlsaW5nIHNsYXNoIGlmIG5vdCBwcmVzZW50XG5cdFx0XHRpZiAoIWJhc2VQYXRoLmVuZHNXaXRoKFwiL1wiKSkge1xuXHRcdFx0XHRiYXNlUGF0aCArPSBcIi9cIjtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gV2hlbiBubyBiYXNlIHBhdGggaXMgc3BlY2lmaWVkLCBhZGQgbGVhZGluZyBzbGFzaCB0byBtYWtlIGl0IGFic29sdXRlIGZyb20gcm9vdFxuXHRcdFx0YmFzZVBhdGggPSBcIi9cIjtcblx0XHR9XG5cblx0XHQvLyBEZXRlcm1pbmUgaWYgd2Ugc2hvdWxkIGFkZCB0cmFpbGluZyBzbGFzaFxuXHRcdC8vIENSSVRJQ0FMOiBOZXZlciBhZGQgdHJhaWxpbmcgc2xhc2ggYmVmb3JlIGFuIGFuY2hvciAoZS5nLiwgL2Fib3V0I2hlYWRpbmcgbm90IC9hYm91dC8jaGVhZGluZylcblx0XHQvLyBUaGlzIGlzIGVzcGVjaWFsbHkgaW1wb3J0YW50IGZvciBhbmNob3IgbGlua3MgZnJvbSBjb3B5IGhlYWRpbmcgVVJMIGZ1bmN0aW9uYWxpdHlcblx0XHQvLyBBbmNob3IgbGlua3Mgc2hvdWxkIE5FVkVSIGhhdmUgdHJhaWxpbmcgc2xhc2hlcywgcmVnYXJkbGVzcyBvZiBzZXR0aW5nc1xuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5nZXRTZXR0aW5ncygpO1xuXHRcdGNvbnN0IHNob3VsZEFkZFRyYWlsaW5nU2xhc2ggPSAoc2V0dGluZ3MuYWRkVHJhaWxpbmdTbGFzaFRvTGlua3MgfHwgYWRkVHJhaWxpbmdTbGFzaCkgJiYgIWFuY2hvcjtcblxuXHRcdHJldHVybiBgJHtiYXNlUGF0aH0ke3NsdWd9JHtzaG91bGRBZGRUcmFpbGluZ1NsYXNoID8gJy8nIDogJyd9JHthbmNob3J9YDtcblx0fVxuXG5cdHByaXZhdGUgaXNJbkNvbmZpZ3VyZWRDb250ZW50RGlyZWN0b3J5KGZpbGVQYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcblx0XHQvLyBDaGVjayBhbGwgY29udGVudCB0eXBlcywgc29ydGVkIGJ5IHBhdHRlcm4gc3BlY2lmaWNpdHkgKG1vcmUgc3BlY2lmaWMgZmlyc3QpXG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLmdldFNldHRpbmdzKCk7XG5cdFx0Y29uc3QgY29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdGNvbnN0IHNvcnRlZFR5cGVzID0gc29ydEJ5UGF0dGVyblNwZWNpZmljaXR5KGNvbnRlbnRUeXBlcyk7XG5cblx0XHRmb3IgKGNvbnN0IGNvbnRlbnRUeXBlIG9mIHNvcnRlZFR5cGVzKSB7XG5cdFx0XHRpZiAoIWNvbnRlbnRUeXBlLmVuYWJsZWQpIGNvbnRpbnVlO1xuXG5cdFx0XHQvLyBIYW5kbGUgYmxhbmsgZm9sZGVyIChyb290KSAtIG1hdGNoZXMgZmlsZXMgaW4gdmF1bHQgcm9vdCBvbmx5XG5cdFx0XHRpZiAoIWNvbnRlbnRUeXBlLmZvbGRlciB8fCBjb250ZW50VHlwZS5mb2xkZXIudHJpbSgpID09PSBcIlwiKSB7XG5cdFx0XHRcdGlmICghZmlsZVBhdGguaW5jbHVkZXMoXCIvXCIpIHx8IGZpbGVQYXRoLnNwbGl0KFwiL1wiKS5sZW5ndGggPT09IDEpIHtcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmIChtYXRjaGVzRm9sZGVyUGF0dGVybihmaWxlUGF0aCwgY29udGVudFR5cGUuZm9sZGVyKSkge1xuXHRcdFx0XHQvLyBDaGVjayBpZ25vcmVTdWJmb2xkZXJzIGlmIGZvbGRlciBpcyBzcGVjaWZpZWRcblx0XHRcdFx0aWYgKGNvbnRlbnRUeXBlLmlnbm9yZVN1YmZvbGRlcnMpIHtcblx0XHRcdFx0XHRjb25zdCBwYXRoU2VnbWVudHMgPSBmaWxlUGF0aC5zcGxpdChcIi9cIik7XG5cdFx0XHRcdFx0Y29uc3QgcGF0aERlcHRoID0gcGF0aFNlZ21lbnRzLmxlbmd0aDtcblx0XHRcdFx0XHRjb25zdCBwYXR0ZXJuU2VnbWVudHMgPSBjb250ZW50VHlwZS5mb2xkZXIuc3BsaXQoXCIvXCIpO1xuXHRcdFx0XHRcdGNvbnN0IGV4cGVjdGVkRGVwdGggPSBwYXR0ZXJuU2VnbWVudHMubGVuZ3RoO1xuXG5cdFx0XHRcdFx0aWYgKGNvbnRlbnRUeXBlLmNyZWF0aW9uTW9kZSA9PT0gXCJmb2xkZXJcIikge1xuXHRcdFx0XHRcdFx0Ly8gRm9yIGZvbGRlci1iYXNlZCBjcmVhdGlvbiwgZmlsZXMgYXJlIG9uZSBsZXZlbCBkZWVwZXIgKGUuZy4sIHRlc3QvbXktZmlsZS9pbmRleC5tZClcblx0XHRcdFx0XHRcdC8vIFNvIHdlIG5lZWQgdG8gYWxsb3cgb25lIGV4dHJhIGxldmVsIGJleW9uZCB0aGUgcGF0dGVybiBkZXB0aFxuXHRcdFx0XHRcdFx0Y29uc3QgZm9sZGVyRGVwdGggPSBwYXRoRGVwdGggLSAxOyAvLyBTdWJ0cmFjdCAxIGZvciB0aGUgaW5kZXgubWQgZmlsZVxuXHRcdFx0XHRcdFx0aWYgKGZvbGRlckRlcHRoID09PSBleHBlY3RlZERlcHRoIHx8IGZvbGRlckRlcHRoID09PSBleHBlY3RlZERlcHRoICsgMSkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Ly8gRm9yIGZpbGUtYmFzZWQgY3JlYXRpb24sIGZpbGVzIGFyZSBhdCB0aGUgc2FtZSBkZXB0aCBhcyB0aGUgcGF0dGVyblxuXHRcdFx0XHRcdFx0aWYgKHBhdGhEZXB0aCA9PT0gZXhwZWN0ZWREZXB0aCkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRwcml2YXRlIGdldENvbnRlbnRUeXBlRm9yUGF0aChmaWxlUGF0aDogc3RyaW5nKTogeyBiYXNlUGF0aDogc3RyaW5nOyBjcmVhdGlvbk1vZGU6IFwiZmlsZVwiIHwgXCJmb2xkZXJcIjsgaW5kZXhGaWxlTmFtZTogc3RyaW5nOyBjb250ZW50Rm9sZGVyOiBzdHJpbmcgfSB7XG5cdFx0Ly8gQ2hlY2sgYWxsIGNvbnRlbnQgdHlwZXMsIHNvcnRlZCBieSBwYXR0ZXJuIHNwZWNpZmljaXR5IChtb3JlIHNwZWNpZmljIGZpcnN0KVxuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5nZXRTZXR0aW5ncygpO1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBzb3J0ZWRUeXBlcyA9IHNvcnRCeVBhdHRlcm5TcGVjaWZpY2l0eShjb250ZW50VHlwZXMpO1xuXG5cdFx0Zm9yIChjb25zdCBjb250ZW50VHlwZSBvZiBzb3J0ZWRUeXBlcykge1xuXHRcdFx0aWYgKCFjb250ZW50VHlwZS5lbmFibGVkKSBjb250aW51ZTtcblxuXHRcdFx0Ly8gSGFuZGxlIGJsYW5rIGZvbGRlciAocm9vdCkgLSBtYXRjaGVzIGZpbGVzIGluIHZhdWx0IHJvb3Qgb25seVxuXHRcdFx0aWYgKCFjb250ZW50VHlwZS5mb2xkZXIgfHwgY29udGVudFR5cGUuZm9sZGVyLnRyaW0oKSA9PT0gXCJcIikge1xuXHRcdFx0XHRpZiAoIWZpbGVQYXRoLmluY2x1ZGVzKFwiL1wiKSB8fCBmaWxlUGF0aC5zcGxpdChcIi9cIikubGVuZ3RoID09PSAxKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdGJhc2VQYXRoOiBjb250ZW50VHlwZS5saW5rQmFzZVBhdGggfHwgXCJcIixcblx0XHRcdFx0XHRcdGNyZWF0aW9uTW9kZTogY29udGVudFR5cGUuY3JlYXRpb25Nb2RlLFxuXHRcdFx0XHRcdFx0aW5kZXhGaWxlTmFtZTogY29udGVudFR5cGUuaW5kZXhGaWxlTmFtZSB8fCBcIlwiLFxuXHRcdFx0XHRcdFx0Y29udGVudEZvbGRlcjogXCJcIlxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAobWF0Y2hlc0ZvbGRlclBhdHRlcm4oZmlsZVBhdGgsIGNvbnRlbnRUeXBlLmZvbGRlcikpIHtcblx0XHRcdFx0Ly8gQ2hlY2sgaWdub3JlU3ViZm9sZGVycyBpZiBmb2xkZXIgaXMgc3BlY2lmaWVkXG5cdFx0XHRcdGlmIChjb250ZW50VHlwZS5pZ25vcmVTdWJmb2xkZXJzKSB7XG5cdFx0XHRcdFx0Y29uc3QgcGF0aFNlZ21lbnRzID0gZmlsZVBhdGguc3BsaXQoXCIvXCIpO1xuXHRcdFx0XHRcdGNvbnN0IHBhdGhEZXB0aCA9IHBhdGhTZWdtZW50cy5sZW5ndGg7XG5cdFx0XHRcdFx0Y29uc3QgcGF0dGVyblNlZ21lbnRzID0gY29udGVudFR5cGUuZm9sZGVyLnNwbGl0KFwiL1wiKTtcblx0XHRcdFx0XHRjb25zdCBleHBlY3RlZERlcHRoID0gcGF0dGVyblNlZ21lbnRzLmxlbmd0aDtcblxuXHRcdFx0XHRcdGlmIChjb250ZW50VHlwZS5jcmVhdGlvbk1vZGUgPT09IFwiZm9sZGVyXCIpIHtcblx0XHRcdFx0XHRcdC8vIEZvciBmb2xkZXItYmFzZWQgY3JlYXRpb24sIGZpbGVzIGFyZSBvbmUgbGV2ZWwgZGVlcGVyIChlLmcuLCB0ZXN0L215LWZpbGUvaW5kZXgubWQpXG5cdFx0XHRcdFx0XHQvLyBTbyB3ZSBuZWVkIHRvIGFsbG93IG9uZSBleHRyYSBsZXZlbCBiZXlvbmQgdGhlIHBhdHRlcm4gZGVwdGhcblx0XHRcdFx0XHRcdGNvbnN0IGZvbGRlckRlcHRoID0gcGF0aERlcHRoIC0gMTsgLy8gU3VidHJhY3QgMSBmb3IgdGhlIGluZGV4Lm1kIGZpbGVcblx0XHRcdFx0XHRcdGlmIChmb2xkZXJEZXB0aCA9PT0gZXhwZWN0ZWREZXB0aCB8fCBmb2xkZXJEZXB0aCA9PT0gZXhwZWN0ZWREZXB0aCArIDEpIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdFx0XHRiYXNlUGF0aDogY29udGVudFR5cGUubGlua0Jhc2VQYXRoIHx8IFwiXCIsXG5cdFx0XHRcdFx0XHRcdFx0Y3JlYXRpb25Nb2RlOiBjb250ZW50VHlwZS5jcmVhdGlvbk1vZGUsXG5cdFx0XHRcdFx0XHRcdFx0aW5kZXhGaWxlTmFtZTogY29udGVudFR5cGUuaW5kZXhGaWxlTmFtZSB8fCBcIlwiLFxuXHRcdFx0XHRcdFx0XHRcdGNvbnRlbnRGb2xkZXI6IGNvbnRlbnRUeXBlLmZvbGRlclxuXHRcdFx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHQvLyBGb3IgZmlsZS1iYXNlZCBjcmVhdGlvbiwgZmlsZXMgYXJlIGF0IHRoZSBzYW1lIGRlcHRoIGFzIHRoZSBwYXR0ZXJuXG5cdFx0XHRcdFx0XHRpZiAocGF0aERlcHRoID09PSBleHBlY3RlZERlcHRoKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XHRcdFx0YmFzZVBhdGg6IGNvbnRlbnRUeXBlLmxpbmtCYXNlUGF0aCB8fCBcIlwiLFxuXHRcdFx0XHRcdFx0XHRcdGNyZWF0aW9uTW9kZTogY29udGVudFR5cGUuY3JlYXRpb25Nb2RlLFxuXHRcdFx0XHRcdFx0XHRcdGluZGV4RmlsZU5hbWU6IGNvbnRlbnRUeXBlLmluZGV4RmlsZU5hbWUgfHwgXCJcIixcblx0XHRcdFx0XHRcdFx0XHRjb250ZW50Rm9sZGVyOiBjb250ZW50VHlwZS5mb2xkZXJcblx0XHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdGJhc2VQYXRoOiBjb250ZW50VHlwZS5saW5rQmFzZVBhdGggfHwgXCJcIixcblx0XHRcdFx0XHRcdGNyZWF0aW9uTW9kZTogY29udGVudFR5cGUuY3JlYXRpb25Nb2RlLFxuXHRcdFx0XHRcdFx0aW5kZXhGaWxlTmFtZTogY29udGVudFR5cGUuaW5kZXhGaWxlTmFtZSB8fCBcIlwiLFxuXHRcdFx0XHRcdFx0Y29udGVudEZvbGRlcjogY29udGVudFR5cGUuZm9sZGVyXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIERlZmF1bHQgZmFsbGJhY2tcblx0XHRyZXR1cm4ge1xuXHRcdFx0YmFzZVBhdGg6IFwiXCIsXG5cdFx0XHRjcmVhdGlvbk1vZGU6IFwiZmlsZVwiLFxuXHRcdFx0aW5kZXhGaWxlTmFtZTogXCJcIixcblx0XHRcdGNvbnRlbnRGb2xkZXI6IFwiXCJcblx0XHR9O1xuXHR9XG5cblx0Y29udmVydFdpa2lsaW5rc0ZvckFzdHJvKGVkaXRvcjogRWRpdG9yLCBmaWxlOiBURmlsZSB8IG51bGwpOiB2b2lkIHtcblx0XHRpZiAoIShmaWxlIGluc3RhbmNlb2YgVEZpbGUpKSB7XG5cdFx0XHRuZXcgTm90aWNlKFwiTm8gYWN0aXZlIGZpbGUuXCIpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIFByZXNlcnZlIGN1cnNvciBwb3NpdGlvbiBiZWZvcmUgbW9kaWZ5aW5nIGNvbnRlbnRcblx0XHRjb25zdCBjdXJzb3IgPSBlZGl0b3IuZ2V0Q3Vyc29yKCk7XG5cdFx0Y29uc3Qgb3JpZ2luYWxMaW5lID0gY3Vyc29yLmxpbmU7XG5cdFx0Y29uc3Qgb3JpZ2luYWxDaCA9IGN1cnNvci5jaDtcblx0XHRjb25zdCBvcmlnaW5hbENvbnRlbnQgPSBlZGl0b3IuZ2V0VmFsdWUoKTtcblx0XHRjb25zdCBvcmlnaW5hbExpbmVDb3VudCA9IG9yaWdpbmFsQ29udGVudC5zcGxpdCgnXFxuJykubGVuZ3RoO1xuXHRcdGNvbnN0IG9yaWdpbmFsTGluZUxlbmd0aCA9IG9yaWdpbmFsQ29udGVudC5zcGxpdCgnXFxuJylbb3JpZ2luYWxMaW5lXT8ubGVuZ3RoIHx8IDA7XG5cblx0XHRjb25zdCBjb250ZW50ID0gZWRpdG9yLmdldFZhbHVlKCk7XG5cdFx0bGV0IG5ld0NvbnRlbnQgPSBjb250ZW50O1xuXHRcdGxldCBjb252ZXJ0ZWRDb3VudCA9IDA7XG5cdFx0bGV0IHNraXBwZWRDb3VudCA9IDA7XG5cdFx0Y29uc3Qgc2tpcHBlZExpbmtzOiBzdHJpbmdbXSA9IFtdO1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIHRoZSBjdXJyZW50IGZpbGUncyBjb250ZW50IHR5cGUgZm9yIHJlbGF0aXZlIGxpbmtzXG5cdFx0Y29uc3QgY3VycmVudEZpbGVDb250ZW50VHlwZSA9IHRoaXMuZ2V0Q29udGVudFR5cGVGb3JQYXRoKGZpbGUucGF0aCk7XG5cblx0XHQvLyBEZWZpbmUgY29tbW9uIGltYWdlIGV4dGVuc2lvbnNcblx0XHRjb25zdCBpbWFnZUV4dGVuc2lvbnMgPSAvXFwuKHBuZ3xqcGd8anBlZ3xnaWZ8c3ZnKSQvaTtcblxuXHRcdC8vIEhlbHBlciBmdW5jdGlvbiB0byBjaGVjayBpZiBhIGxpbmsgY2FuIGJlIHJlbGlhYmx5IGNvbnZlcnRlZFxuXHRcdGNvbnN0IGNhbkNvbnZlcnRMaW5rID0gKGxpbmtUZXh0OiBzdHJpbmcpOiBib29sZWFuID0+IHtcblx0XHRcdC8vIERvbid0IGNvbnZlcnQgaWYgaXQncyBhbiBpbWFnZVxuXHRcdFx0aWYgKGltYWdlRXh0ZW5zaW9ucy50ZXN0KGxpbmtUZXh0KSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdC8vIERvbid0IGNvbnZlcnQgZXh0ZXJuYWwgbGlua3Ncblx0XHRcdGlmIChsaW5rVGV4dC5tYXRjaCgvXmh0dHBzPzpcXC9cXC8vKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdC8vIERvbid0IGNvbnZlcnQgaWYgaXQncyBub3QgYSAubWQgb3IgLm1keCBmaWxlIGFuZCBkb2Vzbid0IGxvb2sgbGlrZSBhIHZhbGlkIGludGVybmFsIGxpbmtcblx0XHRcdGlmICghbGlua1RleHQuaW5jbHVkZXMoJy5tZCcpICYmICFsaW5rVGV4dC5pbmNsdWRlcygnLm1keCcpICYmICFsaW5rVGV4dC5tYXRjaCgvXlthLXpBLVowLTlfLV0rKFxcL1thLXpBLVowLTlfLV0rKSokLykpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDaGVjayBpZiB0aGUgdGFyZ2V0IGZpbGUgaXMgaW4gYW55IGNvbmZpZ3VyZWQgY29udGVudCBkaXJlY3Rvcnlcblx0XHRcdC8vIFN1cHBvcnQgYm90aCAubWQgYW5kIC5tZHggZXh0ZW5zaW9uc1xuXHRcdFx0bGV0IHRhcmdldFBhdGg6IHN0cmluZztcblx0XHRcdGlmIChsaW5rVGV4dC5lbmRzV2l0aCgnLm1kJykgfHwgbGlua1RleHQuZW5kc1dpdGgoJy5tZHgnKSkge1xuXHRcdFx0XHR0YXJnZXRQYXRoID0gbGlua1RleHQ7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBEZWZhdWx0IHRvIC5tZCBpZiBubyBleHRlbnNpb24gc3BlY2lmaWVkXG5cdFx0XHRcdHRhcmdldFBhdGggPSBsaW5rVGV4dCArICcubWQnO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDaGVjayBpZiBpdCdzIGluIGEgY29uZmlndXJlZCBjb250ZW50IGRpcmVjdG9yeVxuXHRcdFx0Y29uc3QgaXNJbkNvbmZpZ3VyZWREaXJlY3RvcnkgPSB0aGlzLmlzSW5Db25maWd1cmVkQ29udGVudERpcmVjdG9yeSh0YXJnZXRQYXRoKTtcblxuXHRcdFx0Ly8gQWxzbyBjaGVjayBpZiBpdCdzIGEgc2ltcGxlIGZpbGVuYW1lIChubyBwYXRoKSBhbmQgY3VycmVudCBmaWxlIGhhcyBhIGNvbnRlbnQgdHlwZVxuXHRcdFx0Y29uc3QgaXNTaW1wbGVGaWxlbmFtZSA9ICF0YXJnZXRQYXRoLmluY2x1ZGVzKCcvJyk7XG5cdFx0XHRjb25zdCBoYXNDdXJyZW50Q29udGVudFR5cGUgPSBjdXJyZW50RmlsZUNvbnRlbnRUeXBlLmJhc2VQYXRoICE9PSBcIlwiIHx8IGN1cnJlbnRGaWxlQ29udGVudFR5cGUuY3JlYXRpb25Nb2RlICE9PSBcImZpbGVcIiB8fCBjdXJyZW50RmlsZUNvbnRlbnRUeXBlLmluZGV4RmlsZU5hbWUgIT09IFwiXCI7XG5cblx0XHRcdHJldHVybiBpc0luQ29uZmlndXJlZERpcmVjdG9yeSB8fCAoaXNTaW1wbGVGaWxlbmFtZSAmJiBoYXNDdXJyZW50Q29udGVudFR5cGUpO1xuXHRcdH07XG5cblx0XHQvLyBIYW5kbGUgcmVndWxhciBXaWtpbGlua3MgKG5vbi1pbWFnZSlcblx0XHRuZXdDb250ZW50ID0gbmV3Q29udGVudC5yZXBsYWNlKFxuXHRcdFx0L1xcW1xcWyhbXlxcXXxdKykoXFx8KFteXFxdXSspKT9cXF1cXF0vZyxcblx0XHRcdChtYXRjaDogc3RyaW5nLCBsaW5rVGV4dDogc3RyaW5nLCBfcGlwZTogc3RyaW5nIHwgdW5kZWZpbmVkLCBkaXNwbGF5VGV4dDogc3RyaW5nIHwgdW5kZWZpbmVkKSA9PiB7XG5cdFx0XHRcdC8vIENoZWNrIGlmIGl0J3MgYW4gaW1hZ2UgV2lraWxpbmtcblx0XHRcdFx0aWYgKGltYWdlRXh0ZW5zaW9ucy50ZXN0KGxpbmtUZXh0KSkge1xuXHRcdFx0XHRcdHNraXBwZWRDb3VudCsrO1xuXHRcdFx0XHRcdHNraXBwZWRMaW5rcy5wdXNoKGxpbmtUZXh0KTtcblx0XHRcdFx0XHRyZXR1cm4gbWF0Y2g7IC8vIElnbm9yZSBhbmQgcmV0dXJuIG9yaWdpbmFsIGltYWdlIFdpa2lsaW5rXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBDaGVjayBpZiB3ZSBjYW4gcmVsaWFibHkgY29udmVydCB0aGlzIGxpbmtcblx0XHRcdFx0aWYgKCFjYW5Db252ZXJ0TGluayhsaW5rVGV4dCkpIHtcblx0XHRcdFx0XHRza2lwcGVkQ291bnQrKztcblx0XHRcdFx0XHRza2lwcGVkTGlua3MucHVzaChsaW5rVGV4dCk7XG5cdFx0XHRcdFx0cmV0dXJuIG1hdGNoOyAvLyBSZXR1cm4gb3JpZ2luYWwgaWYgd2UgY2FuJ3QgY29udmVydCByZWxpYWJseVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgZGlzcGxheSA9IGRpc3BsYXlUZXh0IHx8IGxpbmtUZXh0LnJlcGxhY2UoL1xcLihtZHxtZHgpJC8sIFwiXCIpO1xuXG5cdFx0XHRcdC8vIEZvciByZWxhdGl2ZSBsaW5rcyAobm8gZm9sZGVyIHBhdGgpLCB1c2UgY3VycmVudCBmaWxlJ3MgY29udGVudCB0eXBlXG5cdFx0XHRcdGNvbnN0IHVybCA9IHRoaXMuZ2V0QXN0cm9VcmxGcm9tSW50ZXJuYWxMaW5rV2l0aENvbnRleHQobGlua1RleHQsIGZpbGUucGF0aCwgY3VycmVudEZpbGVDb250ZW50VHlwZSk7XG5cblx0XHRcdFx0Y29udmVydGVkQ291bnQrKztcblx0XHRcdFx0cmV0dXJuIGBbJHtkaXNwbGF5fV0oJHt1cmx9KWA7XG5cdFx0XHR9XG5cdFx0KTtcblxuXHRcdC8vIEhhbmRsZSBzdGFuZGFyZCBNYXJrZG93biBsaW5rcyAobm9uLWltYWdlLCBub24tZXh0ZXJuYWwpXG5cdFx0Ly8gT25seSBwcm9jZXNzIGxpbmtzIHRoYXQgY29udGFpbiAubWQgb3IgLm1keCB0byBhdm9pZCBwcm9jZXNzaW5nIGFscmVhZHktY29udmVydGVkIGxpbmtzXG5cdFx0bmV3Q29udGVudCA9IG5ld0NvbnRlbnQucmVwbGFjZShcblx0XHRcdC9cXFsoW15cXF1dKylcXF1cXCgoW14pXStcXC4obWR8bWR4KVteKV0qKVxcKS9nLFxuXHRcdFx0KG1hdGNoOiBzdHJpbmcsIGRpc3BsYXlUZXh0OiBzdHJpbmcsIGxpbms6IHN0cmluZykgPT4ge1xuXHRcdFx0XHQvLyBDaGVjayBpZiBpdCdzIGFuIGltYWdlIGxpbmsgb3IgZXh0ZXJuYWwgbGlua1xuXHRcdFx0XHRpZiAobGluay5tYXRjaCgvXmh0dHBzPzpcXC9cXC8vKSB8fCBpbWFnZUV4dGVuc2lvbnMudGVzdChsaW5rKSkge1xuXHRcdFx0XHRcdHNraXBwZWRDb3VudCsrO1xuXHRcdFx0XHRcdHNraXBwZWRMaW5rcy5wdXNoKGxpbmspO1xuXHRcdFx0XHRcdHJldHVybiBtYXRjaDsgLy8gSWdub3JlIGV4dGVybmFsIG9yIGltYWdlIGxpbmtzXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBDaGVjayBpZiB3ZSBjYW4gcmVsaWFibHkgY29udmVydCB0aGlzIGxpbmtcblx0XHRcdFx0aWYgKCFjYW5Db252ZXJ0TGluayhsaW5rKSkge1xuXHRcdFx0XHRcdHNraXBwZWRDb3VudCsrO1xuXHRcdFx0XHRcdHNraXBwZWRMaW5rcy5wdXNoKGxpbmspO1xuXHRcdFx0XHRcdHJldHVybiBtYXRjaDsgLy8gUmV0dXJuIG9yaWdpbmFsIGlmIHdlIGNhbid0IGNvbnZlcnQgcmVsaWFibHlcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbnN0IHVybCA9IHRoaXMuZ2V0QXN0cm9VcmxGcm9tSW50ZXJuYWxMaW5rV2l0aENvbnRleHQobGluaywgZmlsZS5wYXRoLCBjdXJyZW50RmlsZUNvbnRlbnRUeXBlKTtcblxuXHRcdFx0XHRjb252ZXJ0ZWRDb3VudCsrO1xuXHRcdFx0XHRyZXR1cm4gYFske2Rpc3BsYXlUZXh0fV0oJHt1cmx9KWA7XG5cdFx0XHR9XG5cdFx0KTtcblxuXHRcdC8vIEhhbmRsZSBpbWFnZSBsaW5rcyBpbiBNYXJrZG93biBmb3JtYXQgKGUuZy4sICFbSW1hZ2VdKG1vdW50YWlucy5wbmcpKVxuXHRcdG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoXG5cdFx0XHQvIVxcWyguKj8pXFxdXFwoKFteKV0rKVxcKS9nLFxuXHRcdFx0KG1hdGNoOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0c2tpcHBlZENvdW50Kys7XG5cdFx0XHRcdHJldHVybiBtYXRjaDsgLy8gSWdub3JlIGFsbCBpbWFnZSBsaW5rc1xuXHRcdFx0fVxuXHRcdCk7XG5cblx0XHQvLyBIYW5kbGUge3tlbWJlZH19IHN5bnRheFxuXHRcdG5ld0NvbnRlbnQgPSBuZXdDb250ZW50LnJlcGxhY2UoL1xce1xceyhbXn1dKylcXH1cXH0vZywgKG1hdGNoOiBzdHJpbmcsIGZpbGVOYW1lOiBzdHJpbmcpID0+IHtcblx0XHRcdGlmIChpbWFnZUV4dGVuc2lvbnMudGVzdChmaWxlTmFtZSkpIHtcblx0XHRcdFx0c2tpcHBlZENvdW50Kys7XG5cdFx0XHRcdHNraXBwZWRMaW5rcy5wdXNoKGZpbGVOYW1lKTtcblx0XHRcdFx0cmV0dXJuIG1hdGNoOyAvLyBJZ25vcmUgZW1iZWRkZWQgaW1hZ2VzXG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGlmIHdlIGNhbiByZWxpYWJseSBjb252ZXJ0IHRoaXMgbGlua1xuXHRcdFx0aWYgKCFjYW5Db252ZXJ0TGluayhmaWxlTmFtZSkpIHtcblx0XHRcdFx0c2tpcHBlZENvdW50Kys7XG5cdFx0XHRcdHNraXBwZWRMaW5rcy5wdXNoKGZpbGVOYW1lKTtcblx0XHRcdFx0cmV0dXJuIG1hdGNoOyAvLyBSZXR1cm4gb3JpZ2luYWwgaWYgd2UgY2FuJ3QgY29udmVydCByZWxpYWJseVxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCB1cmwgPSB0aGlzLmdldEFzdHJvVXJsRnJvbUludGVybmFsTGlua1dpdGhDb250ZXh0KGZpbGVOYW1lLCBmaWxlLnBhdGgsIGN1cnJlbnRGaWxlQ29udGVudFR5cGUpO1xuXG5cdFx0XHRjb252ZXJ0ZWRDb3VudCsrO1xuXHRcdFx0cmV0dXJuIGBbRW1iZWRkZWQ6ICR7ZmlsZU5hbWV9XSgke3VybH0pYDtcblx0XHR9KTtcblxuXHRcdGVkaXRvci5zZXRWYWx1ZShuZXdDb250ZW50KTtcblxuXHRcdC8vIFJlc3RvcmUgY3Vyc29yIHBvc2l0aW9uLCBhZGp1c3RpbmcgZm9yIGNvbnRlbnQgY2hhbmdlc1xuXHRcdGNvbnN0IG5ld0xpbmVDb3VudCA9IG5ld0NvbnRlbnQuc3BsaXQoJ1xcbicpLmxlbmd0aDtcblx0XHRjb25zdCBuZXdMaW5lTGVuZ3RoID0gbmV3Q29udGVudC5zcGxpdCgnXFxuJylbb3JpZ2luYWxMaW5lXT8ubGVuZ3RoIHx8IDA7XG5cblx0XHQvLyBDYWxjdWxhdGUgbmV3IGN1cnNvciBwb3NpdGlvblxuXHRcdGxldCBuZXdMaW5lID0gb3JpZ2luYWxMaW5lO1xuXHRcdGxldCBuZXdDaCA9IG9yaWdpbmFsQ2g7XG5cblx0XHQvLyBJZiBjb250ZW50IGxlbmd0aCBjaGFuZ2VkLCBhZGp1c3QgY3Vyc29yIHBvc2l0aW9uXG5cdFx0aWYgKG5ld0xpbmVDb3VudCAhPT0gb3JpZ2luYWxMaW5lQ291bnQpIHtcblx0XHRcdC8vIElmIGxpbmVzIHdlcmUgYWRkZWQvcmVtb3ZlZCBiZWZvcmUgY3Vyc29yLCBhZGp1c3QgbGluZSBudW1iZXJcblx0XHRcdC8vIEZvciBzaW1wbGljaXR5LCBrZWVwIHNhbWUgbGluZSBpZiBpdCBzdGlsbCBleGlzdHMsIG90aGVyd2lzZSBjbGFtcCB0byBlbmRcblx0XHRcdGlmIChuZXdMaW5lID49IG5ld0xpbmVDb3VudCkge1xuXHRcdFx0XHRuZXdMaW5lID0gTWF0aC5tYXgoMCwgbmV3TGluZUNvdW50IC0gMSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gQWRqdXN0IGNvbHVtbiBwb3NpdGlvbiBpZiBsaW5lIGxlbmd0aCBjaGFuZ2VkXG5cdFx0aWYgKG5ld0xpbmVMZW5ndGggIT09IG9yaWdpbmFsTGluZUxlbmd0aCkge1xuXHRcdFx0Ly8gSWYgbGluZSBnb3Qgc2hvcnRlciwgY2xhbXAgdG8gZW5kIG9mIGxpbmVcblx0XHRcdGlmIChuZXdDaCA+IG5ld0xpbmVMZW5ndGgpIHtcblx0XHRcdFx0bmV3Q2ggPSBNYXRoLm1heCgwLCBuZXdMaW5lTGVuZ3RoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBSZXN0b3JlIGN1cnNvciBwb3NpdGlvblxuXHRcdGVkaXRvci5zZXRDdXJzb3IoeyBsaW5lOiBuZXdMaW5lLCBjaDogbmV3Q2ggfSk7XG5cblx0XHQvLyBTaG93IGFwcHJvcHJpYXRlIG5vdGljZSBiYXNlZCBvbiByZXN1bHRzXG5cdFx0aWYgKGNvbnZlcnRlZENvdW50ID4gMCAmJiBza2lwcGVkQ291bnQgPT09IDApIHtcblx0XHRcdG5ldyBOb3RpY2UoYENvbnZlcnRlZCAke2NvbnZlcnRlZENvdW50fSBpbnRlcm5hbCBsaW5rJHtjb252ZXJ0ZWRDb3VudCA+IDEgPyAncycgOiAnJ30gZm9yIEFzdHJvLmApO1xuXHRcdH0gZWxzZSBpZiAoY29udmVydGVkQ291bnQgPiAwICYmIHNraXBwZWRDb3VudCA+IDApIHtcblx0XHRcdG5ldyBOb3RpY2UoYENvbnZlcnRlZCAke2NvbnZlcnRlZENvdW50fSBsaW5rJHtjb252ZXJ0ZWRDb3VudCA+IDEgPyAncycgOiAnJ30gZm9yIEFzdHJvLiBTa2lwcGVkICR7c2tpcHBlZENvdW50fSBsaW5rJHtza2lwcGVkQ291bnQgPiAxID8gJ3MnIDogJyd9IG91dHNpZGUgY29uZmlndXJlZCBjb250ZW50IGRpcmVjdG9yaWVzLmApO1xuXHRcdH0gZWxzZSBpZiAoc2tpcHBlZENvdW50ID4gMCkge1xuXHRcdFx0bmV3IE5vdGljZShgTm8gbGlua3MgY29udmVydGVkLiBBbGwgJHtza2lwcGVkQ291bnR9IGxpbmske3NraXBwZWRDb3VudCA+IDEgPyAncycgOiAnJ30gYXJlIG91dHNpZGUgY29uZmlndXJlZCBjb250ZW50IGRpcmVjdG9yaWVzIG9yIGFyZSBpbWFnZXMvZXh0ZXJuYWwgbGlua3MuYCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG5ldyBOb3RpY2UoXCJObyBpbnRlcm5hbCBsaW5rcyBmb3VuZCB0byBjb252ZXJ0LlwiKTtcblx0XHR9XG5cdH1cbn1cbiIsICJpbXBvcnQgeyBBcHAsIE1vZGFsLCBURmlsZSwgTm90aWNlLCBQbGF0Zm9ybSwgTWFya2Rvd25WaWV3IH0gZnJvbSBcIm9ic2lkaWFuXCI7XHJcbmltcG9ydCB7IEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2UsIENvbnRlbnRUeXBlSWQgfSBmcm9tIFwiLi4vdHlwZXNcIjtcclxuaW1wb3J0IHsgRmlsZU9wZXJhdGlvbnMgfSBmcm9tIFwiLi4vdXRpbHMvZmlsZS1vcGVyYXRpb25zXCI7XHJcbmltcG9ydCB7IFRlbXBsYXRlUGFyc2VyIH0gZnJvbSBcIi4uL3V0aWxzL3RlbXBsYXRlLXBhcnNpbmdcIjtcclxuaW1wb3J0IHsgdG9LZWJhYkNhc2UgfSBmcm9tIFwiLi4vdXRpbHMvc3RyaW5nLXV0aWxzXCI7XHJcblxyXG5leHBvcnQgY2xhc3MgVGl0bGVNb2RhbCBleHRlbmRzIE1vZGFsIHtcclxuXHRmaWxlOiBURmlsZSB8IG51bGw7XHJcblx0cGx1Z2luOiBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlO1xyXG5cdHR5cGU6IENvbnRlbnRUeXBlSWQ7XHJcblx0aXNSZW5hbWU6IGJvb2xlYW47XHJcblx0aXNOZXdOb3RlOiBib29sZWFuO1xyXG5cdHRpdGxlSW5wdXQhOiBIVE1MSW5wdXRFbGVtZW50O1xyXG5cdHByaXZhdGUgZmlsZU9wczogRmlsZU9wZXJhdGlvbnM7XHJcblx0cHJpdmF0ZSB0ZW1wbGF0ZVBhcnNlcjogVGVtcGxhdGVQYXJzZXI7XHJcblxyXG5cdGNvbnN0cnVjdG9yKGFwcDogQXBwLCBmaWxlOiBURmlsZSB8IG51bGwsIHBsdWdpbjogQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSwgdHlwZTogQ29udGVudFR5cGVJZCwgaXNSZW5hbWUgPSBmYWxzZSwgaXNOZXdOb3RlID0gZmFsc2UpIHtcclxuXHRcdHN1cGVyKGFwcCk7XHJcblx0XHR0aGlzLmZpbGUgPSBmaWxlO1xyXG5cdFx0dGhpcy5wbHVnaW4gPSBwbHVnaW47XHJcblx0XHR0aGlzLnR5cGUgPSB0eXBlO1xyXG5cdFx0dGhpcy5pc1JlbmFtZSA9IGlzUmVuYW1lO1xyXG5cdFx0dGhpcy5pc05ld05vdGUgPSBpc05ld05vdGU7XHJcblxyXG5cdFx0Ly8gSW5pdGlhbGl6ZSB1dGlsaXRpZXMgd2l0aCBjdXJyZW50IHNldHRpbmdzXHJcblx0XHQvLyBGaWxlT3BlcmF0aW9ucyB3aWxsIGdldCBmcmVzaCBzZXR0aW5ncyBmcm9tIHBsdWdpbiBkeW5hbWljYWxseVxyXG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSBwbHVnaW4uc2V0dGluZ3M7XHJcblx0XHR0aGlzLmZpbGVPcHMgPSBuZXcgRmlsZU9wZXJhdGlvbnMoYXBwLCBzZXR0aW5ncywgcGx1Z2luKTtcclxuXHRcdHRoaXMudGVtcGxhdGVQYXJzZXIgPSBuZXcgVGVtcGxhdGVQYXJzZXIoYXBwLCBzZXR0aW5ncyk7XHJcblx0fVxyXG5cclxuXHRhc3luYyBnZXRDdXJyZW50VGl0bGVBc3luYygpOiBQcm9taXNlPHN0cmluZz4ge1xyXG5cdFx0aWYgKCF0aGlzLmZpbGUpIHtcclxuXHRcdFx0cmV0dXJuIFwiXCI7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUmVhZCB0aGUgZmlsZSBjb250ZW50IGRpcmVjdGx5IHRvIGVuc3VyZSB3ZSBoYXZlIHRoZSBsYXRlc3QgdGl0bGVcclxuXHRcdHRyeSB7XHJcblx0XHRcdGNvbnN0IGNvbnRlbnQgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkKHRoaXMuZmlsZSk7XHJcblx0XHRcdGNvbnN0IHRpdGxlS2V5ID0gdGhpcy5maWxlT3BzLmdldFRpdGxlS2V5KHRoaXMudHlwZSk7XHJcblx0XHRcdGNvbnN0IHsgcHJvcGVydGllcyB9ID0gdGhpcy50ZW1wbGF0ZVBhcnNlci5wYXJzZUZyb250bWF0dGVyKGNvbnRlbnQpO1xyXG5cclxuXHRcdFx0aWYgKHRpdGxlS2V5IGluIHByb3BlcnRpZXMpIHtcclxuXHRcdFx0XHRjb25zdCB0aXRsZVZhbHVlID0gcHJvcGVydGllc1t0aXRsZUtleV07XHJcblx0XHRcdFx0aWYgKEFycmF5LmlzQXJyYXkodGl0bGVWYWx1ZSkgJiYgdGl0bGVWYWx1ZS5sZW5ndGggPiAwKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gU3RyaW5nKHRpdGxlVmFsdWVbMF0pO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRpZiAodGl0bGVWYWx1ZSAhPT0gbnVsbCAmJiB0aXRsZVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0XHRcdHJldHVybiBTdHJpbmcodGl0bGVWYWx1ZSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9IGNhdGNoIChlcnJvcikge1xyXG5cdFx0XHRjb25zb2xlLmVycm9yKFwiRXJyb3IgcmVhZGluZyBmaWxlIGZvciB0aXRsZTpcIiwgZXJyb3IpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEZhbGwgYmFjayB0byBmaWxlbmFtZS1iYXNlZCB0aXRsZVxyXG5cdFx0cmV0dXJuIHRoaXMuZ2V0RmFsbGJhY2tUaXRsZSgpO1xyXG5cdH1cclxuXHJcblx0Z2V0Q3VycmVudFRpdGxlKCk6IHN0cmluZyB7XHJcblx0XHRpZiAoIXRoaXMuZmlsZSkge1xyXG5cdFx0XHRyZXR1cm4gXCJcIjtcclxuXHRcdH1cclxuXHJcblx0XHRjb25zdCB0aXRsZUtleSA9IHRoaXMuZmlsZU9wcy5nZXRUaXRsZUtleSh0aGlzLnR5cGUpO1xyXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLmFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZSh0aGlzLmZpbGUpO1xyXG5cclxuXHRcdGlmIChjYWNoZT8uZnJvbnRtYXR0ZXIgJiYgdGl0bGVLZXkgaW4gY2FjaGUuZnJvbnRtYXR0ZXIpIHtcclxuXHRcdFx0Y29uc3QgdGl0bGVWYWx1ZSA9IGNhY2hlLmZyb250bWF0dGVyW3RpdGxlS2V5XSBhcyB1bmtub3duO1xyXG5cdFx0XHRpZiAodHlwZW9mIHRpdGxlVmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcblx0XHRcdFx0cmV0dXJuIHRpdGxlVmFsdWU7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKEFycmF5LmlzQXJyYXkodGl0bGVWYWx1ZSkgJiYgdGl0bGVWYWx1ZS5sZW5ndGggPiAwKSB7XHJcblx0XHRcdFx0Y29uc3QgZmlyc3RWYWx1ZSA9IHRpdGxlVmFsdWVbMF0gYXMgdW5rbm93bjtcclxuXHRcdFx0XHRpZiAodHlwZW9mIGZpcnN0VmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcblx0XHRcdFx0XHRyZXR1cm4gZmlyc3RWYWx1ZTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYgKGZpcnN0VmFsdWUgIT0gbnVsbCkge1xyXG5cdFx0XHRcdFx0aWYgKHR5cGVvZiBmaXJzdFZhbHVlID09PSAnbnVtYmVyJyB8fCB0eXBlb2YgZmlyc3RWYWx1ZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcblx0XHRcdFx0XHRcdHJldHVybiBTdHJpbmcoZmlyc3RWYWx1ZSk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRpZiAodHlwZW9mIGZpcnN0VmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcblx0XHRcdFx0XHRcdHJldHVybiBmaXJzdFZhbHVlO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAodGl0bGVWYWx1ZSA9PSBudWxsKSB7XHJcblx0XHRcdFx0cmV0dXJuICcnO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmICh0eXBlb2YgdGl0bGVWYWx1ZSA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHRpdGxlVmFsdWUgPT09ICdib29sZWFuJykge1xyXG5cdFx0XHRcdHJldHVybiBTdHJpbmcodGl0bGVWYWx1ZSk7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKHR5cGVvZiB0aXRsZVZhbHVlID09PSAnc3RyaW5nJykge1xyXG5cdFx0XHRcdHJldHVybiB0aXRsZVZhbHVlO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiAnJztcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzLmdldEZhbGxiYWNrVGl0bGUoKTtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgZ2V0RmFsbGJhY2tUaXRsZSgpOiBzdHJpbmcge1xyXG5cdFx0aWYgKCF0aGlzLmZpbGUpIHtcclxuXHRcdFx0cmV0dXJuIFwiXCI7XHJcblx0XHR9XHJcblxyXG5cdFx0bGV0IGJhc2VuYW1lID0gdGhpcy5maWxlLmJhc2VuYW1lO1xyXG5cdFx0aWYgKHRoaXMuZmlsZS5wYXJlbnQgJiYgdGhpcy50eXBlICE9PSBcIm5vdGVcIikge1xyXG5cdFx0XHRjb25zdCBjb250ZW50VHlwZSA9IHRoaXMuZmlsZU9wcy5nZXRDb250ZW50VHlwZSh0aGlzLnR5cGUpO1xyXG5cdFx0XHRjb25zdCBpbmRleEZpbGVOYW1lID0gY29udGVudFR5cGU/LmluZGV4RmlsZU5hbWUgfHwgXCJcIjtcclxuXHRcdFx0aWYgKGluZGV4RmlsZU5hbWUudHJpbSgpICE9PSBcIlwiICYmIGJhc2VuYW1lID09PSBpbmRleEZpbGVOYW1lKSB7XHJcblx0XHRcdFx0YmFzZW5hbWUgPSB0aGlzLmZpbGUucGFyZW50Lm5hbWU7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdGlmIChiYXNlbmFtZS5zdGFydHNXaXRoKFwiX1wiKSkge1xyXG5cdFx0XHRiYXNlbmFtZSA9IGJhc2VuYW1lLnNsaWNlKDEpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGJhc2VuYW1lLnJlcGxhY2UoLy0vZywgXCIgXCIpLnNwbGl0KFwiIFwiKS5tYXAod29yZCA9PiB3b3JkLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgd29yZC5zbGljZSgxKSkuam9pbihcIiBcIik7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBFeHRyYWN0cyBhIHN1Z2dlc3RlZCB0aXRsZSBmcm9tIHRoZSBmaWxlIGJhc2VuYW1lIGZvciBuZXdseSBjcmVhdGVkIGZpbGVzLlxyXG5cdCAqIFRoaXMgaXMgdXNlZCB3aGVuIGEgZmlsZSBpcyBjcmVhdGVkIGZyb20gYSBsaW5rIChlLmcuLCBbW3NFZnNsZWlmXV0pLlxyXG5cdCAqIFByZXNlcnZlcyB0aGUgb3JpZ2luYWwgdGV4dCBhcyBtdWNoIGFzIHBvc3NpYmxlLlxyXG5cdCAqL1xyXG5cdGdldFN1Z2dlc3RlZFRpdGxlRnJvbUJhc2VuYW1lKCk6IHN0cmluZyB7XHJcblx0XHRpZiAoIXRoaXMuZmlsZSkge1xyXG5cdFx0XHRyZXR1cm4gXCJcIjtcclxuXHRcdH1cclxuXHJcblx0XHRsZXQgYmFzZW5hbWUgPSB0aGlzLmZpbGUuYmFzZW5hbWU7XHJcblxyXG5cdFx0Ly8gSGFuZGxlIGluZGV4IGZpbGUgbmFtZXMgLSB1c2UgcGFyZW50IGZvbGRlciBuYW1lIGluc3RlYWRcclxuXHRcdGlmICh0aGlzLmZpbGUucGFyZW50ICYmIHRoaXMudHlwZSAhPT0gXCJub3RlXCIpIHtcclxuXHRcdFx0Y29uc3QgY29udGVudFR5cGUgPSB0aGlzLmZpbGVPcHMuZ2V0Q29udGVudFR5cGUodGhpcy50eXBlKTtcclxuXHRcdFx0Y29uc3QgaW5kZXhGaWxlTmFtZSA9IGNvbnRlbnRUeXBlPy5pbmRleEZpbGVOYW1lIHx8IFwiXCI7XHJcblx0XHRcdGlmIChpbmRleEZpbGVOYW1lLnRyaW0oKSAhPT0gXCJcIiAmJiBiYXNlbmFtZSA9PT0gaW5kZXhGaWxlTmFtZSkge1xyXG5cdFx0XHRcdGJhc2VuYW1lID0gdGhpcy5maWxlLnBhcmVudC5uYW1lO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gUmVtb3ZlIGxlYWRpbmcgdW5kZXJzY29yZSBpZiBwcmVzZW50XHJcblx0XHRpZiAoYmFzZW5hbWUuc3RhcnRzV2l0aChcIl9cIikpIHtcclxuXHRcdFx0YmFzZW5hbWUgPSBiYXNlbmFtZS5zbGljZSgxKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBSZXR1cm4gdGhlIGJhc2VuYW1lIGFzLWlzIHRvIHByZXNlcnZlIHVzZXIncyBvcmlnaW5hbCBpbnB1dFxyXG5cdFx0Ly8gKGUuZy4sIFwic0Vmc2xlaWZcIiBzdGF5cyBhcyBcInNFZnNsZWlmXCIpXHJcblx0XHRyZXR1cm4gYmFzZW5hbWU7XHJcblx0fVxyXG5cclxuXHRvbk9wZW4oKSB7XHJcblx0XHRjb25zdCB7IGNvbnRlbnRFbCB9ID0gdGhpcztcclxuXHRcdGNvbnRlbnRFbC5lbXB0eSgpO1xyXG5cclxuXHRcdC8vIEFkZCBtb2JpbGUtZnJpZW5kbHkgcG9zaXRpb25pbmcgY2xhc3MgLSBjaGVjayBib3RoIHdpZHRoIGFuZCBwbGF0Zm9ybVxyXG5cdFx0Y29uc3QgaXNNb2JpbGUgPSB3aW5kb3cuaW5uZXJXaWR0aCA8PSA3NjggfHwgUGxhdGZvcm0uaXNNb2JpbGU7XHJcblx0XHRpZiAoaXNNb2JpbGUpIHtcclxuXHRcdFx0dGhpcy5tb2RhbEVsLmFkZENsYXNzKCdhc3Ryby1jb21wb3Nlci1tb2JpbGUtbW9kYWwnKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5pc1JlbmFtZSkge1xyXG5cdFx0XHRjb25zdCB0eXBlTmFtZSA9IHRoaXMuZ2V0VHlwZURpc3BsYXlOYW1lKCk7XHJcblxyXG5cdFx0XHRpZiAodGhpcy50eXBlID09PSBcIm5vdGVcIikge1xyXG5cdFx0XHRcdC8vIEZvciBnZW5lcmljIG5vdGVzIG91dHNpZGUgb2YgYW55IGtub3duIGNvbnRlbnQgdHlwZVxyXG5cdFx0XHRcdGNvbnRlbnRFbC5jcmVhdGVFbChcImgyXCIsIHsgdGV4dDogXCJSZW5hbWUgY29udGVudFwiIH0pO1xyXG5cdFx0XHRcdGNvbnRlbnRFbC5jcmVhdGVFbChcInBcIiwgeyB0ZXh0OiBcIkVudGVyIGEgdGl0bGUgZm9yIHRoaXMgY29udGVudDpcIiB9KTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRjb250ZW50RWwuY3JlYXRlRWwoXCJoMlwiLCB7IHRleHQ6IGBSZW5hbWUgJHt0eXBlTmFtZX0gY29udGVudGAgfSk7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwicFwiLCB7IHRleHQ6IGBFbnRlciBuZXcgdGl0bGUgZm9yIHlvdXIgJHt0eXBlTmFtZX0gY29udGVudDpgIH0pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLnRpdGxlSW5wdXQgPSBjb250ZW50RWwuY3JlYXRlRWwoXCJpbnB1dFwiLCB7XHJcblx0XHRcdFx0dHlwZTogXCJ0ZXh0XCIsXHJcblx0XHRcdFx0cGxhY2Vob2xkZXI6IFwiTmV3IFRpdGxlXCIsXHJcblx0XHRcdFx0Y2xzOiBcImFzdHJvLWNvbXBvc2VyLXRpdGxlLWlucHV0XCJcclxuXHRcdFx0fSk7XHJcblxyXG5cdFx0XHQvLyBBc3luYyBsb2FkIHRoZSBjdXJyZW50IHRpdGxlIGZyb20gZmlsZVxyXG5cdFx0XHR2b2lkIHRoaXMuZ2V0Q3VycmVudFRpdGxlQXN5bmMoKS50aGVuKHRpdGxlID0+IHtcclxuXHRcdFx0XHR0aGlzLnRpdGxlSW5wdXQudmFsdWUgPSB0aXRsZTtcclxuXHRcdFx0fSk7XHJcblx0XHR9IGVsc2UgaWYgKHRoaXMuaXNOZXdOb3RlKSB7XHJcblx0XHRcdGNvbnN0IHR5cGVOYW1lID0gdGhpcy5nZXRUeXBlRGlzcGxheU5hbWUoKTtcclxuXHJcblx0XHRcdGlmICh0aGlzLnR5cGUgPT09IFwibm90ZVwiKSB7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwiaDJcIiwgeyB0ZXh0OiBcIk5ldyBjb250ZW50XCIgfSk7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwicFwiLCB7IHRleHQ6IFwiRW50ZXIgYSB0aXRsZSBmb3IgdGhpcyBjb250ZW50OlwiIH0pO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGNvbnRlbnRFbC5jcmVhdGVFbChcImgyXCIsIHsgdGV4dDogYENyZWF0ZSBuZXcgJHt0eXBlTmFtZX0gY29udGVudGAgfSk7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwicFwiLCB7IHRleHQ6IGBFbnRlciBhIHRpdGxlIGZvciB5b3VyIG5ldyAke3R5cGVOYW1lfSBjb250ZW50OmAgfSk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMudGl0bGVJbnB1dCA9IGNvbnRlbnRFbC5jcmVhdGVFbChcImlucHV0XCIsIHtcclxuXHRcdFx0XHR0eXBlOiBcInRleHRcIixcclxuXHRcdFx0XHRwbGFjZWhvbGRlcjogXCJOZXcgVGl0bGVcIixcclxuXHRcdFx0XHRjbHM6IFwiYXN0cm8tY29tcG9zZXItdGl0bGUtaW5wdXRcIlxyXG5cdFx0XHR9KTtcclxuXHRcdFx0Ly8gTGVhdmUgaW5wdXQgZW1wdHkgZm9yIG5ldyBub3RlcyAtIHVzZXIgY2FuIHR5cGUgZGlyZWN0bHlcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGNvbnN0IHR5cGVOYW1lID0gdGhpcy5nZXRUeXBlRGlzcGxheU5hbWUoKTtcclxuXHJcblx0XHRcdGlmICh0aGlzLnR5cGUgPT09IFwibm90ZVwiKSB7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwiaDJcIiwgeyB0ZXh0OiBcIk5ldyBjb250ZW50XCIgfSk7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwicFwiLCB7IHRleHQ6IFwiRW50ZXIgYSB0aXRsZSBmb3IgdGhpcyBjb250ZW50OlwiIH0pO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGNvbnRlbnRFbC5jcmVhdGVFbChcImgyXCIsIHsgdGV4dDogYENyZWF0ZSBuZXcgJHt0eXBlTmFtZX0gY29udGVudGAgfSk7XHJcblx0XHRcdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwicFwiLCB7IHRleHQ6IGBFbnRlciBhIHRpdGxlIGZvciB5b3VyIG5ldyAke3R5cGVOYW1lfSBjb250ZW50OmAgfSk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMudGl0bGVJbnB1dCA9IGNvbnRlbnRFbC5jcmVhdGVFbChcImlucHV0XCIsIHtcclxuXHRcdFx0XHR0eXBlOiBcInRleHRcIixcclxuXHRcdFx0XHRwbGFjZWhvbGRlcjogXCJOZXcgVGl0bGVcIixcclxuXHRcdFx0XHRjbHM6IFwiYXN0cm8tY29tcG9zZXItdGl0bGUtaW5wdXRcIlxyXG5cdFx0XHR9KTtcclxuXHRcdFx0Ly8gUHJlLXBvcHVsYXRlIHdpdGggc3VnZ2VzdGVkIHRpdGxlIGZyb20gYmFzZW5hbWUgaWYgYXZhaWxhYmxlXHJcblx0XHRcdC8vIFRoaXMgaGFuZGxlcyBmaWxlcyBjcmVhdGVkIGZyb20gbGlua3MgKGUuZy4sIFtbc0Vmc2xlaWZdXSlcclxuXHRcdFx0aWYgKHRoaXMuZmlsZSkge1xyXG5cdFx0XHRcdGNvbnN0IHN1Z2dlc3RlZFRpdGxlID0gdGhpcy5nZXRTdWdnZXN0ZWRUaXRsZUZyb21CYXNlbmFtZSgpO1xyXG5cdFx0XHRcdGlmIChzdWdnZXN0ZWRUaXRsZSkge1xyXG5cdFx0XHRcdFx0dGhpcy50aXRsZUlucHV0LnZhbHVlID0gc3VnZ2VzdGVkVGl0bGU7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHR0aGlzLnRpdGxlSW5wdXQuZm9jdXMoKTtcclxuXHRcdC8vIEZvciBuZXcgbm90ZXMsIGVuc3VyZSBjdXJzb3IgaXMgYXQgdGhlIHN0YXJ0IChwb3NpdGlvbiAwKVxyXG5cdFx0aWYgKHRoaXMuaXNOZXdOb3RlKSB7XHJcblx0XHRcdHNldFRpbWVvdXQoKCkgPT4ge1xyXG5cdFx0XHRcdHRoaXMudGl0bGVJbnB1dC5zZXRTZWxlY3Rpb25SYW5nZSgwLCAwKTtcclxuXHRcdFx0fSwgMCk7XHJcblx0XHR9XHJcblxyXG5cdFx0Y29uc3QgYnV0dG9uQ29udGFpbmVyID0gY29udGVudEVsLmNyZWF0ZURpdih7IGNsczogXCJhc3Ryby1jb21wb3Nlci1idXR0b24tY29udGFpbmVyXCIgfSk7XHJcblxyXG5cdFx0Y29uc3QgY2FuY2VsQnV0dG9uID0gYnV0dG9uQ29udGFpbmVyLmNyZWF0ZUVsKFwiYnV0dG9uXCIsIHsgdGV4dDogXCJDYW5jZWxcIiwgY2xzOiBcImFzdHJvLWNvbXBvc2VyLWNhbmNlbC1idXR0b25cIiB9KTtcclxuXHRcdGNhbmNlbEJ1dHRvbi5vbmNsaWNrID0gKCkgPT4gdGhpcy5jbG9zZSgpO1xyXG5cclxuXHRcdGNvbnN0IHN1Ym1pdEJ1dHRvbiA9IGJ1dHRvbkNvbnRhaW5lci5jcmVhdGVFbChcImJ1dHRvblwiLCB7IHRleHQ6IHRoaXMuaXNSZW5hbWUgPyBcIlJlbmFtZVwiIDogXCJDcmVhdGVcIiwgY2xzOiBbXCJhc3Ryby1jb21wb3Nlci1jcmVhdGUtYnV0dG9uXCIsIFwibW9kLWN0YVwiXSB9KTtcclxuXHRcdHN1Ym1pdEJ1dHRvbi5vbmNsaWNrID0gKCkgPT4gdGhpcy5zdWJtaXQoKTtcclxuXHJcblx0XHR0aGlzLnRpdGxlSW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImtleXByZXNzXCIsIChlKSA9PiB7XHJcblx0XHRcdGlmIChlLmtleSA9PT0gXCJFbnRlclwiKSB2b2lkIHRoaXMuc3VibWl0KCk7XHJcblx0XHR9KTtcclxuXHR9XHJcblxyXG5cdGFzeW5jIHN1Ym1pdCgpIHtcclxuXHRcdGNvbnN0IHRpdGxlID0gdGhpcy50aXRsZUlucHV0LnZhbHVlLnRyaW0oKTtcclxuXHJcblx0XHRpZiAoIXRpdGxlKSB7XHJcblx0XHRcdG5ldyBOb3RpY2UoXCJQbGVhc2UgZW50ZXIgYSB0aXRsZS5cIik7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHR0cnkge1xyXG5cdFx0XHRsZXQgbmV3RmlsZTogVEZpbGUgfCBudWxsID0gbnVsbDtcclxuXHRcdFx0aWYgKHRoaXMuaXNSZW5hbWUpIHtcclxuXHRcdFx0XHRuZXdGaWxlID0gYXdhaXQgdGhpcy5maWxlT3BzLnJlbmFtZUZpbGUoeyBmaWxlOiB0aGlzLmZpbGUhLCB0aXRsZSwgdHlwZTogdGhpcy50eXBlIH0pO1xyXG5cclxuXHRcdFx0XHRpZiAobmV3RmlsZSkge1xyXG5cdFx0XHRcdFx0YXdhaXQgdGhpcy50ZW1wbGF0ZVBhcnNlci51cGRhdGVUaXRsZUluRnJvbnRtYXR0ZXIobmV3RmlsZSwgdGl0bGUsIHRoaXMudHlwZSk7XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdC8vIHJlbmFtZUZpbGUgYWxyZWFkeSBzaG93ZWQgYW4gZXJyb3Igbm90aWNlLCBjbG9zZSBtb2RhbCBhbmQgcmV0dXJuXHJcblx0XHRcdFx0XHR0aGlzLmNsb3NlKCk7XHJcblx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9IGVsc2UgaWYgKHRoaXMuaXNOZXdOb3RlKSB7XHJcblx0XHRcdFx0Ly8gUHJvY2VzcyB0aGUgXCJVbnRpdGxlZFwiIGZpbGUgLSByZW5hbWUgaXQgYW5kIGFkZCBwcm9wZXJ0aWVzXHJcblx0XHRcdFx0Ly8gVGhpcyByZXNwZWN0cyBjcmVhdGlvbk1vZGUgKGZvbGRlciB2cyBmaWxlKSBhbmQgZG9lc24ndCByZXF1aXJlIGRlbGV0aW9uXHJcblx0XHRcdFx0aWYgKHRoaXMuZmlsZSkge1xyXG5cdFx0XHRcdFx0bmV3RmlsZSA9IGF3YWl0IHRoaXMuZmlsZU9wcy5jcmVhdGVGaWxlKHsgZmlsZTogdGhpcy5maWxlLCB0aXRsZSwgdHlwZTogdGhpcy50eXBlIH0pO1xyXG5cdFx0XHRcdFx0Ly8gQWx3YXlzIGluc2VydCBwcm9wZXJ0aWVzIHdoZW4gYXV0b0luc2VydFByb3BlcnRpZXMgaXMgZW5hYmxlZFxyXG5cdFx0XHRcdFx0Y29uc3Qgc2hvdWxkSW5zZXJ0UHJvcGVydGllcyA9IHRoaXMucGx1Z2luLnNldHRpbmdzLmF1dG9JbnNlcnRQcm9wZXJ0aWVzO1xyXG5cclxuXHRcdFx0XHRcdGlmIChuZXdGaWxlICYmIHNob3VsZEluc2VydFByb3BlcnRpZXMpIHtcclxuXHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5hZGRQcm9wZXJ0aWVzVG9GaWxlKG5ld0ZpbGUsIHRpdGxlLCB0aGlzLnR5cGUpO1xyXG5cdFx0XHRcdFx0XHQvLyBQb3NpdGlvbiBjdXJzb3IgYXQgZW5kIGFmdGVyIHByb3BlcnRpZXMgYXJlIGFkZGVkXHJcblx0XHRcdFx0XHRcdHRoaXMucG9zaXRpb25DdXJzb3JBdEVuZChuZXdGaWxlKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0gZWxzZSBpZiAodGhpcy5maWxlKSB7XHJcblx0XHRcdFx0Ly8gV2UgaGF2ZSBhbiBleGlzdGluZyBmaWxlLCBwcm9jZXNzIGl0XHJcblx0XHRcdFx0bmV3RmlsZSA9IGF3YWl0IHRoaXMuZmlsZU9wcy5jcmVhdGVGaWxlKHsgZmlsZTogdGhpcy5maWxlLCB0aXRsZSwgdHlwZTogdGhpcy50eXBlIH0pO1xyXG5cdFx0XHRcdC8vIEFsd2F5cyBpbnNlcnQgcHJvcGVydGllcyB3aGVuIGF1dG9JbnNlcnRQcm9wZXJ0aWVzIGlzIGVuYWJsZWRcclxuXHRcdFx0XHRjb25zdCBzaG91bGRJbnNlcnRQcm9wZXJ0aWVzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3MuYXV0b0luc2VydFByb3BlcnRpZXM7XHJcblxyXG5cdFx0XHRcdGlmIChuZXdGaWxlICYmIHNob3VsZEluc2VydFByb3BlcnRpZXMpIHtcclxuXHRcdFx0XHRcdGF3YWl0IHRoaXMuYWRkUHJvcGVydGllc1RvRmlsZShuZXdGaWxlLCB0aXRsZSwgdGhpcy50eXBlKTtcclxuXHRcdFx0XHRcdC8vIFBvc2l0aW9uIGN1cnNvciBhdCBlbmQgYWZ0ZXIgcHJvcGVydGllcyBhcmUgYWRkZWRcclxuXHRcdFx0XHRcdHRoaXMucG9zaXRpb25DdXJzb3JBdEVuZChuZXdGaWxlKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0Ly8gRmFsbGJhY2sgLSBjcmVhdGUgbmV3IGZpbGVcclxuXHRcdFx0XHRuZXdGaWxlID0gYXdhaXQgdGhpcy5jcmVhdGVOZXdGaWxlKHRpdGxlKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCFuZXdGaWxlKSB7XHJcblx0XHRcdFx0bmV3IE5vdGljZShgRmFpbGVkIHRvICR7dGhpcy5pc1JlbmFtZSA/IFwicmVuYW1lXCIgOiBcImNyZWF0ZVwifSAke3RoaXMudHlwZX0uYCk7XHJcblx0XHRcdFx0dGhpcy5jbG9zZSgpO1xyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0fVxyXG5cdFx0fSBjYXRjaCAoZXJyb3IpIHtcclxuXHRcdFx0Y29uc29sZS5lcnJvcignVGl0bGVNb2RhbDogRXJyb3IgZHVyaW5nIHByb2Nlc3M6JywgZXJyb3IpO1xyXG5cdFx0XHRjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XHJcblx0XHRcdG5ldyBOb3RpY2UoYEVycm9yICR7dGhpcy5pc1JlbmFtZSA/IFwicmVuYW1pbmdcIiA6IFwiY3JlYXRpbmdcIn0gJHt0aGlzLnR5cGV9OiAke2Vycm9yTWVzc2FnZX0uYCk7XHJcblx0XHRcdHRoaXMuY2xvc2UoKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuY2xvc2UoKTtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgZ2V0VHlwZURpc3BsYXlOYW1lKCk6IHN0cmluZyB7XHJcblx0XHRpZiAodGhpcy50eXBlID09PSBcIm5vdGVcIikge1xyXG5cdFx0XHRyZXR1cm4gXCJDb250ZW50XCI7XHJcblx0XHR9XHJcblx0XHRjb25zdCBjb250ZW50VHlwZSA9IHRoaXMuZmlsZU9wcy5nZXRDb250ZW50VHlwZSh0aGlzLnR5cGUpO1xyXG5cdFx0cmV0dXJuIGNvbnRlbnRUeXBlID8gY29udGVudFR5cGUubmFtZSA6IFwiQ29udGVudFwiO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSBhc3luYyBjcmVhdGVOZXdGaWxlKHRpdGxlOiBzdHJpbmcpOiBQcm9taXNlPFRGaWxlIHwgbnVsbD4ge1xyXG5cdFx0Ly8gRGV0ZXJtaW5lIHRoZSBhcHByb3ByaWF0ZSBmb2xkZXIgYmFzZWQgb24gd2hlcmUgdGhlIHVzZXIgY3JlYXRlZCB0aGUgZmlsZVxyXG5cdFx0bGV0IHRhcmdldEZvbGRlcjogc3RyaW5nO1xyXG5cclxuXHRcdC8vIEdldCB0aGUgZGlyZWN0b3J5IHdoZXJlIHRoZSB1c2VyIGNyZWF0ZWQgdGhlIGZpbGVcclxuXHRcdGNvbnN0IG9yaWdpbmFsRGlyID0gdGhpcy5maWxlPy5wYXJlbnQ/LnBhdGggfHwgXCJcIjtcclxuXHJcblx0XHRpZiAodGhpcy50eXBlICE9PSBcIm5vdGVcIikge1xyXG5cdFx0XHRjb25zdCBjb250ZW50VHlwZSA9IHRoaXMuZmlsZU9wcy5nZXRDb250ZW50VHlwZSh0aGlzLnR5cGUpO1xyXG5cdFx0XHQvLyBGb3IgY29udGVudCB0eXBlcywgcmVzcGVjdCB0aGUgdXNlcidzIGNob3NlbiBsb2NhdGlvbiAoc3ViZm9sZGVyKVxyXG5cdFx0XHQvLyBPbmx5IHVzZSB0aGUgY29uZmlndXJlZCBmb2xkZXIgaWYgdGhlIHVzZXIgY3JlYXRlZCB0aGUgZmlsZSBpbiB0aGUgdmF1bHQgcm9vdFxyXG5cdFx0XHRpZiAob3JpZ2luYWxEaXIgPT09IFwiXCIgfHwgb3JpZ2luYWxEaXIgPT09IFwiL1wiKSB7XHJcblx0XHRcdFx0dGFyZ2V0Rm9sZGVyID0gY29udGVudFR5cGU/LmZvbGRlciB8fCBcIlwiO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRhcmdldEZvbGRlciA9IG9yaWdpbmFsRGlyO1xyXG5cdFx0XHR9XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQvLyBGb3Igbm90ZXMsIHVzZSB0aGUgb3JpZ2luYWwgZGlyZWN0b3J5XHJcblx0XHRcdHRhcmdldEZvbGRlciA9IG9yaWdpbmFsRGlyO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIENyZWF0ZSB0aGUgZmlsZW5hbWUgZnJvbSB0aGUgdGl0bGVcclxuXHRcdGNvbnN0IGZpbGVuYW1lID0gdGhpcy5maWxlT3BzLmdlbmVyYXRlRmlsZW5hbWUodGl0bGUpO1xyXG5cdFx0Y29uc3QgY29udGVudFR5cGUgPSB0aGlzLmZpbGVPcHMuZ2V0Q29udGVudFR5cGUodGhpcy50eXBlKTtcclxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGNvbnRlbnRUeXBlPy51c2VNZHhFeHRlbnNpb24gPyBcIi5tZHhcIiA6IFwiLm1kXCI7XHJcblx0XHRjb25zdCBmaWxlUGF0aCA9IHRhcmdldEZvbGRlciA/IGAke3RhcmdldEZvbGRlcn0vJHtmaWxlbmFtZX0ke2V4dGVuc2lvbn1gIDogYCR7ZmlsZW5hbWV9JHtleHRlbnNpb259YDtcclxuXHJcblx0XHQvLyBUcmFjayB0aGF0IHRoaXMgZmlsZSB3aWxsIGJlIGNyZWF0ZWQgYnkgdGhlIHBsdWdpbiBCRUZPUkUgY3JlYXRpbmcgaXRcclxuXHRcdC8vIFRoaXMgcHJldmVudHMgdGhlIGNyZWF0ZSBldmVudCBmcm9tIHRyaWdnZXJpbmcgYW5vdGhlciBtb2RhbFxyXG5cdFx0aWYgKHRoaXMucGx1Z2luKSB7XHJcblx0XHRcdHRoaXMucGx1Z2luLnBsdWdpbkNyZWF0ZWRGaWxlcy5zZXQoZmlsZVBhdGgsIERhdGUubm93KCkpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIENyZWF0ZSB0aGUgZmlsZSB3aXRoIGluaXRpYWwgY29udGVudFxyXG5cdFx0bGV0IGluaXRpYWxDb250ZW50ID0gXCJcIjtcclxuXHRcdC8vIEFsd2F5cyBpbnNlcnQgcHJvcGVydGllcyB3aGVuIGF1dG9JbnNlcnRQcm9wZXJ0aWVzIGlzIGVuYWJsZWRcclxuXHRcdGlmICh0aGlzLnBsdWdpbi5zZXR0aW5ncy5hdXRvSW5zZXJ0UHJvcGVydGllcykge1xyXG5cdFx0XHRpbml0aWFsQ29udGVudCA9IHRoaXMuZ2VuZXJhdGVJbml0aWFsQ29udGVudCh0aXRsZSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dHJ5IHtcclxuXHRcdFx0Y29uc3QgbmV3RmlsZSA9IGF3YWl0IHRoaXMuYXBwLnZhdWx0LmNyZWF0ZShmaWxlUGF0aCwgaW5pdGlhbENvbnRlbnQpO1xyXG5cclxuXHRcdFx0Ly8gT3BlbiB0aGUgbmV3IGZpbGVcclxuXHRcdFx0Y29uc3QgbGVhZiA9IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRMZWFmKCk7XHJcblx0XHRcdGF3YWl0IGxlYWYub3BlbkZpbGUobmV3RmlsZSk7XHJcblxyXG5cdFx0XHQvLyBQb3NpdGlvbiBjdXJzb3IgYXQgdGhlIGVuZCBvZiBjb250ZW50IGFmdGVyIGVkaXRvciBpcyByZWFkeVxyXG5cdFx0XHQvLyBVc2UgbXVsdGlwbGUgYXR0ZW1wdHMgdG8gZW5zdXJlIGl0IHdvcmtzIGV2ZW4gaWYgZWRpdG9yIGlzbid0IHJlYWR5IGltbWVkaWF0ZWx5XHJcblx0XHRcdGNvbnN0IHBvc2l0aW9uQ3Vyc29yID0gKCkgPT4ge1xyXG5cdFx0XHRcdGNvbnN0IHZpZXcgPSBsZWFmLnZpZXc7XHJcblx0XHRcdFx0aWYgKHZpZXcgaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgJiYgdmlldy5lZGl0b3IpIHtcclxuXHRcdFx0XHRcdGNvbnN0IGVkaXRvciA9IHZpZXcuZWRpdG9yO1xyXG5cdFx0XHRcdFx0Y29uc3QgY29udGVudCA9IGVkaXRvci5nZXRWYWx1ZSgpO1xyXG5cdFx0XHRcdFx0aWYgKGNvbnRlbnQpIHtcclxuXHRcdFx0XHRcdFx0Y29uc3QgbGluZXMgPSBjb250ZW50LnNwbGl0KCdcXG4nKTtcclxuXHRcdFx0XHRcdFx0Y29uc3QgbGFzdExpbmUgPSBsaW5lcy5sZW5ndGggLSAxO1xyXG5cdFx0XHRcdFx0XHRjb25zdCBsYXN0TGluZUxlbmd0aCA9IGxpbmVzW2xhc3RMaW5lXT8ubGVuZ3RoIHx8IDA7XHJcblx0XHRcdFx0XHRcdGVkaXRvci5zZXRDdXJzb3IoeyBsaW5lOiBsYXN0TGluZSwgY2g6IGxhc3RMaW5lTGVuZ3RoIH0pO1xyXG5cdFx0XHRcdFx0XHQvLyBGb2N1cyB0aGUgZWRpdG9yIHRvIGVuc3VyZSBjdXJzb3IgaXMgdmlzaWJsZSBhbmQgZmlsZW5hbWUgaXNuJ3Qgc2VsZWN0ZWRcclxuXHRcdFx0XHRcdFx0ZWRpdG9yLmZvY3VzKCk7XHJcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdH07XHJcblxyXG5cdFx0XHQvLyBUcnkgaW1tZWRpYXRlbHlcclxuXHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XHJcblx0XHRcdFx0aWYgKCFwb3NpdGlvbkN1cnNvcigpKSB7XHJcblx0XHRcdFx0XHQvLyBJZiBpdCBkaWRuJ3Qgd29yaywgdHJ5IGFnYWluIGFmdGVyIGEgbG9uZ2VyIGRlbGF5XHJcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCgpID0+IHtcclxuXHRcdFx0XHRcdFx0cG9zaXRpb25DdXJzb3IoKTtcclxuXHRcdFx0XHRcdH0sIDIwMCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9LCAxMDApO1xyXG5cclxuXHRcdFx0cmV0dXJuIG5ld0ZpbGU7XHJcblx0XHR9IGNhdGNoIChlcnJvcikge1xyXG5cdFx0XHRjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcik7XHJcblx0XHRcdHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGNyZWF0ZSBmaWxlOiAke2Vycm9yTWVzc2FnZX1gKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdHByaXZhdGUgZ2VuZXJhdGVJbml0aWFsQ29udGVudCh0aXRsZTogc3RyaW5nKTogc3RyaW5nIHtcclxuXHRcdGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XHJcblx0XHRjb25zdCBkYXRlU3RyaW5nID0gd2luZG93Lm1vbWVudChub3cpLmZvcm1hdCh0aGlzLnBsdWdpbi5zZXR0aW5ncy5kYXRlRm9ybWF0KTtcclxuXHRcdGNvbnN0IHNsdWcgPSB0b0tlYmFiQ2FzZSh0aXRsZSk7XHJcblxyXG5cdFx0bGV0IHRlbXBsYXRlOiBzdHJpbmc7XHJcblx0XHRpZiAodGhpcy50eXBlID09PSBcIm5vdGVcIikge1xyXG5cdFx0XHQvLyBGb3IgZ2VuZXJpYyBub3RlcywgdXNlIGEgc2ltcGxlIHRlbXBsYXRlXHJcblx0XHRcdC8vIFByb3Blcmx5IGVzY2FwZSB0aGUgdGl0bGUgZm9yIFlBTUxcclxuXHRcdFx0Y29uc3QgZXNjYXBlZFRpdGxlID0gdGhpcy5lc2NhcGVZYW1sU3RyaW5nKHRpdGxlKTtcclxuXHRcdFx0dGVtcGxhdGUgPSBgLS0tXFxudGl0bGU6ICR7ZXNjYXBlZFRpdGxlfVxcbmRhdGU6ICR7ZGF0ZVN0cmluZ31cXG4tLS1cXG5gO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0Y29uc3QgY29udGVudFR5cGUgPSB0aGlzLmZpbGVPcHMuZ2V0Q29udGVudFR5cGUodGhpcy50eXBlKTtcclxuXHRcdFx0aWYgKCFjb250ZW50VHlwZSkge1xyXG5cdFx0XHRcdGNvbnN0IGVzY2FwZWRUaXRsZSA9IHRoaXMuZXNjYXBlWWFtbFN0cmluZyh0aXRsZSk7XHJcblx0XHRcdFx0dGVtcGxhdGUgPSBgLS0tXFxudGl0bGU6ICR7ZXNjYXBlZFRpdGxlfVxcbmRhdGU6ICR7ZGF0ZVN0cmluZ31cXG4tLS1cXG5gO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRlbXBsYXRlID0gY29udGVudFR5cGUudGVtcGxhdGU7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHR0ZW1wbGF0ZSA9IHRlbXBsYXRlLnJlcGxhY2UoL1xce1xce3RpdGxlXFx9XFx9L2csIHRpdGxlKTtcclxuXHRcdHRlbXBsYXRlID0gdGVtcGxhdGUucmVwbGFjZSgvXFx7XFx7ZGF0ZVxcfVxcfS9nLCBkYXRlU3RyaW5nKTtcclxuXHRcdHRlbXBsYXRlID0gdGVtcGxhdGUucmVwbGFjZSgvXFx7XFx7c2x1Z1xcfVxcfS9nLCBzbHVnKTtcclxuXHJcblx0XHRyZXR1cm4gdGVtcGxhdGU7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIGFzeW5jIGFkZFByb3BlcnRpZXNUb0ZpbGUoZmlsZTogVEZpbGUsIHRpdGxlOiBzdHJpbmcsIHR5cGU6IENvbnRlbnRUeXBlSWQpIHtcclxuXHRcdGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XHJcblx0XHRjb25zdCBkYXRlU3RyaW5nID0gd2luZG93Lm1vbWVudChub3cpLmZvcm1hdCh0aGlzLnBsdWdpbi5zZXR0aW5ncy5kYXRlRm9ybWF0KTtcclxuXHRcdGNvbnN0IHNsdWcgPSB0b0tlYmFiQ2FzZSh0aXRsZSk7XHJcblxyXG5cdFx0bGV0IHRlbXBsYXRlOiBzdHJpbmc7XHJcblx0XHRpZiAodHlwZSA9PT0gXCJub3RlXCIpIHtcclxuXHRcdFx0Ly8gRm9yIGdlbmVyaWMgbm90ZXMsIHVzZSBhIHNpbXBsZSB0ZW1wbGF0ZVxyXG5cdFx0XHQvLyBQcm9wZXJseSBlc2NhcGUgdGhlIHRpdGxlIGZvciBZQU1MXHJcblx0XHRcdGNvbnN0IGVzY2FwZWRUaXRsZSA9IHRoaXMuZXNjYXBlWWFtbFN0cmluZyh0aXRsZSk7XHJcblx0XHRcdHRlbXBsYXRlID0gYC0tLVxcbnRpdGxlOiAke2VzY2FwZWRUaXRsZX1cXG5kYXRlOiAke2RhdGVTdHJpbmd9XFxuLS0tXFxuYDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGNvbnN0IGNvbnRlbnRUeXBlID0gdGhpcy5maWxlT3BzLmdldENvbnRlbnRUeXBlKHR5cGUpO1xyXG5cdFx0XHRpZiAoIWNvbnRlbnRUeXBlKSB7XHJcblx0XHRcdFx0Y29uc3QgZXNjYXBlZFRpdGxlID0gdGhpcy5lc2NhcGVZYW1sU3RyaW5nKHRpdGxlKTtcclxuXHRcdFx0XHR0ZW1wbGF0ZSA9IGAtLS1cXG50aXRsZTogJHtlc2NhcGVkVGl0bGV9XFxuZGF0ZTogJHtkYXRlU3RyaW5nfVxcbi0tLVxcbmA7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0dGVtcGxhdGUgPSBjb250ZW50VHlwZS50ZW1wbGF0ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHRlbXBsYXRlID0gdGVtcGxhdGUucmVwbGFjZSgvXFx7XFx7dGl0bGVcXH1cXH0vZywgdGl0bGUpO1xyXG5cdFx0dGVtcGxhdGUgPSB0ZW1wbGF0ZS5yZXBsYWNlKC9cXHtcXHtkYXRlXFx9XFx9L2csIGRhdGVTdHJpbmcpO1xyXG5cdFx0dGVtcGxhdGUgPSB0ZW1wbGF0ZS5yZXBsYWNlKC9cXHtcXHtzbHVnXFx9XFx9L2csIHNsdWcpO1xyXG5cclxuXHRcdC8vIEVuc3VyZSBubyBleHRyYSBuZXdsaW5lcyBvciAtLS0gYXJlIGFkZGVkIGJleW9uZCB0aGUgdGVtcGxhdGVcclxuXHRcdGF3YWl0IHRoaXMuYXBwLnZhdWx0Lm1vZGlmeShmaWxlLCB0ZW1wbGF0ZSk7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIHBvc2l0aW9uQ3Vyc29yQXRFbmQoZmlsZTogVEZpbGUpIHtcclxuXHRcdGNvbnN0IHBvc2l0aW9uQ3Vyc29yID0gKCkgPT4ge1xyXG5cdFx0XHRjb25zdCB2aWV3ID0gdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUoTWFya2Rvd25WaWV3KTtcclxuXHRcdFx0aWYgKHZpZXcgJiYgdmlldy5maWxlID09PSBmaWxlICYmIHZpZXcuZWRpdG9yKSB7XHJcblx0XHRcdFx0Y29uc3QgZWRpdG9yID0gdmlldy5lZGl0b3I7XHJcblx0XHRcdFx0Y29uc3QgY29udGVudCA9IGVkaXRvci5nZXRWYWx1ZSgpO1xyXG5cdFx0XHRcdGlmIChjb250ZW50KSB7XHJcblx0XHRcdFx0XHRjb25zdCBsaW5lcyA9IGNvbnRlbnQuc3BsaXQoJ1xcbicpO1xyXG5cdFx0XHRcdFx0Y29uc3QgbGFzdExpbmUgPSBsaW5lcy5sZW5ndGggLSAxO1xyXG5cdFx0XHRcdFx0Y29uc3QgbGFzdExpbmVMZW5ndGggPSBsaW5lc1tsYXN0TGluZV0/Lmxlbmd0aCB8fCAwO1xyXG5cdFx0XHRcdFx0ZWRpdG9yLnNldEN1cnNvcih7IGxpbmU6IGxhc3RMaW5lLCBjaDogbGFzdExpbmVMZW5ndGggfSk7XHJcblx0XHRcdFx0XHQvLyBGb2N1cyB0aGUgZWRpdG9yIHRvIGVuc3VyZSBjdXJzb3IgaXMgdmlzaWJsZVxyXG5cdFx0XHRcdFx0ZWRpdG9yLmZvY3VzKCk7XHJcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fTtcclxuXHJcblx0XHRzZXRUaW1lb3V0KCgpID0+IHtcclxuXHRcdFx0aWYgKCFwb3NpdGlvbkN1cnNvcigpKSB7XHJcblx0XHRcdFx0Ly8gSWYgaXQgZGlkbid0IHdvcmssIHRyeSBhZ2FpbiBhZnRlciBhIGxvbmdlciBkZWxheVxyXG5cdFx0XHRcdHNldFRpbWVvdXQoKCkgPT4ge1xyXG5cdFx0XHRcdFx0cG9zaXRpb25DdXJzb3IoKTtcclxuXHRcdFx0XHR9LCAyMDApO1xyXG5cdFx0XHR9XHJcblx0XHR9LCAxMDApO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSBlc2NhcGVZYW1sU3RyaW5nKHN0cjogc3RyaW5nKTogc3RyaW5nIHtcclxuXHRcdC8vIFByb3Blcmx5IGVzY2FwZSBZQU1MIHN0cmluZyB2YWx1ZXNcclxuXHRcdC8vIFlBTUwgc3RyaW5ncyB3aXRoIHF1b3RlcyBuZWVkIHRvIGJlIHdyYXBwZWQgaW4gc2luZ2xlIHF1b3RlcyBvciBlc2NhcGVkIHByb3Blcmx5XHJcblx0XHRpZiAoc3RyLmluY2x1ZGVzKCdcIicpIHx8IHN0ci5pbmNsdWRlcyhcIidcIikgfHwgc3RyLmluY2x1ZGVzKCdcXG4nKSB8fCBzdHIuaW5jbHVkZXMoJ1xcXFwnKSkge1xyXG5cdFx0XHQvLyBGb3Igc3RyaW5ncyB3aXRoIHF1b3RlcywgbmV3bGluZXMsIG9yIGJhY2tzbGFzaGVzLCB1c2Ugc2luZ2xlIHF1b3RlcyBhbmQgZXNjYXBlIHNpbmdsZSBxdW90ZXNcclxuXHRcdFx0cmV0dXJuIGAnJHtzdHIucmVwbGFjZSgvJy9nLCBcIicnXCIpfSdgO1xyXG5cdFx0fSBlbHNlIGlmIChzdHIuaW5jbHVkZXMoXCIgXCIpIHx8IHN0ci5pbmNsdWRlcyhcIjpcIikgfHwgc3RyLmluY2x1ZGVzKFwiI1wiKSB8fCBzdHIuaW5jbHVkZXMoXCJAXCIpKSB7XHJcblx0XHRcdC8vIEZvciBzdHJpbmdzIHdpdGggc3BhY2VzIG9yIHNwZWNpYWwgWUFNTCBjaGFyYWN0ZXJzLCB3cmFwIGluIGRvdWJsZSBxdW90ZXMgYW5kIGVzY2FwZSBkb3VibGUgcXVvdGVzXHJcblx0XHRcdHJldHVybiBgXCIke3N0ci5yZXBsYWNlKC9cIi9nLCAnXFxcXFwiJyl9XCJgO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0Ly8gRm9yIHNpbXBsZSBzdHJpbmdzLCBubyBxdW90ZXMgbmVlZGVkXHJcblx0XHRcdHJldHVybiBzdHI7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRvbkNsb3NlKCkge1xyXG5cdFx0Y29uc3QgeyBjb250ZW50RWwgfSA9IHRoaXM7XHJcblx0XHRjb250ZW50RWwuZW1wdHkoKTtcclxuXHR9XHJcbn1cclxuIiwgImltcG9ydCB7IEFwcCwgUGx1Z2luU2V0dGluZ1RhYiwgU2V0dGluZywgUGxhdGZvcm0sIHNldEljb24sIFNldHRpbmdHcm91cCB9IGZyb20gXCJvYnNpZGlhblwiO1xuaW1wb3J0IHsgUGx1Z2luIH0gZnJvbSBcIm9ic2lkaWFuXCI7XG5pbXBvcnQgeyBDb250ZW50VHlwZSwgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSwgQXN0cm9Db21wb3NlclNldHRpbmdzIH0gZnJvbSBcIi4uL3R5cGVzXCI7XG5pbXBvcnQgeyBDb21tYW5kUGlja2VyTW9kYWwgfSBmcm9tIFwiLi9jb21wb25lbnRzL0NvbW1hbmRQaWNrZXJNb2RhbFwiO1xuaW1wb3J0IHsgSWNvblBpY2tlck1vZGFsIH0gZnJvbSBcIi4vY29tcG9uZW50cy9JY29uUGlja2VyTW9kYWxcIjtcbmltcG9ydCB7IENvbmZpcm1Nb2RhbCB9IGZyb20gXCIuL2NvbXBvbmVudHMvQ29uZmlybU1vZGFsXCI7XG5cbmltcG9ydCB7IHJlZ2lzdGVyQ29udGVudFR5cGVDb21tYW5kcyB9IGZyb20gXCIuLi9jb21tYW5kc1wiO1xuXG5leHBvcnQgY2xhc3MgQXN0cm9Db21wb3NlclNldHRpbmdUYWIgZXh0ZW5kcyBQbHVnaW5TZXR0aW5nVGFiIHtcblx0cGx1Z2luOiBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlO1xuXHRwdWJsaWMgaWNvbiA9ICdsdWNpZGUtcGVuY2lsLWxpbmUnO1xuXHRhdXRvUmVuYW1lQ29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXHRwb3N0c0ZvbGRlckNvbnRhaW5lcjogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcblx0b25seUF1dG9tYXRlQ29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXHRjcmVhdGlvbk1vZGVDb250YWluZXI6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG5cdGluZGV4RmlsZUNvbnRhaW5lcjogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcblx0ZXhjbHVkZWREaXJzQ29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXHR1bmRlcnNjb3JlUHJlZml4Q29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXHRhdXRvSW5zZXJ0Q29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXHRwYWdlc0ZpZWxkc0NvbnRhaW5lcjogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcblx0cGFnZXNJbmRleEZpbGVDb250YWluZXI6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG5cdHBhZ2VzT25seUF1dG9tYXRlQ29udGFpbmVyOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXHR0ZXJtaW5hbENvbW1hbmRDb250YWluZXI6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG5cdGNvbmZpZ0NvbW1hbmRDb250YWluZXI6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG5cdGN1c3RvbUNvbnRlbnRUeXBlc0NvbnRhaW5lcjogSFRNTEVsZW1lbnQgfCBudWxsID0gbnVsbDtcblx0dGVybWluYWxSaWJib25Ub2dnbGU6IFNldHRpbmcgfCBudWxsID0gbnVsbDtcblx0Y29uZmlnUmliYm9uVG9nZ2xlOiBTZXR0aW5nIHwgbnVsbCA9IG51bGw7XG5cdHByaXZhdGUgdGVybWluYWxSaWJib25Ub2dnbGVDb21wb25lbnQ6IHsgc2V0RGlzYWJsZWQ6IChkaXNhYmxlZDogYm9vbGVhbikgPT4gdm9pZCB9IHwgbnVsbCA9IG51bGw7XG5cdHByaXZhdGUgY29uZmlnUmliYm9uVG9nZ2xlQ29tcG9uZW50OiB7IHNldERpc2FibGVkOiAoZGlzYWJsZWQ6IGJvb2xlYW4pID0+IHZvaWQgfSB8IG51bGwgPSBudWxsO1xuXG5cdGNvbnN0cnVjdG9yKGFwcDogQXBwLCBwbHVnaW46IFBsdWdpbikge1xuXHRcdHN1cGVyKGFwcCwgcGx1Z2luKTtcblx0XHR0aGlzLnBsdWdpbiA9IHBsdWdpbiBhcyB1bmtub3duIGFzIEFzdHJvQ29tcG9zZXJQbHVnaW5JbnRlcmZhY2U7XG5cdH1cblxuXHQvKipcblx0ICogUmVmcmVzaCBqdXN0IHRoZSBjb250ZW50IHR5cGVzIHNlY3Rpb25cblx0ICogTW9yZSBlZmZpY2llbnQgdGhhbiByZWZyZXNoaW5nIHRoZSBlbnRpcmUgc2V0dGluZ3MgdGFiXG5cdCAqL1xuXHRwdWJsaWMgcmVmcmVzaENvbnRlbnRUeXBlcygpOiB2b2lkIHtcblx0XHRpZiAodGhpcy5jdXN0b21Db250ZW50VHlwZXNDb250YWluZXIpIHtcblx0XHRcdHRoaXMucmVuZGVyQ3VzdG9tQ29udGVudFR5cGVzKCk7XG5cdFx0fVxuXHR9XG5cblx0ZGlzcGxheSgpOiB2b2lkIHtcblx0XHRjb25zdCB7IGNvbnRhaW5lckVsIH0gPSB0aGlzO1xuXHRcdGNvbnRhaW5lckVsLmVtcHR5KCk7XG5cblx0XHQvLyBVc2UgY3VycmVudCBwbHVnaW4gc2V0dGluZ3MgKGFscmVhZHkgbG9hZGVkIGFuZCB1cC10by1kYXRlKVxuXHRcdC8vIEFsd2F5cyByZWFkIGZyZXNoIHNldHRpbmdzIHRvIGVuc3VyZSB3ZSBzaG93IG1pZ3JhdGVkIGNvbnRlbnQgdHlwZXMgaW1tZWRpYXRlbHlcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xuXG5cdFx0Ly8gUmVuZGVyIHRoZSBzZXR0aW5ncyB0YWIgd2l0aCBjdXJyZW50IHNldHRpbmdzXG5cdFx0Ly8gVGhpcyB3aWxsIHNob3cgYWxsIGNvbnRlbnQgdHlwZXMgaW5jbHVkaW5nIG5ld2x5IG1pZ3JhdGVkIG9uZXNcblx0XHR0aGlzLnJlbmRlclNldHRpbmdzVGFiKGNvbnRhaW5lckVsLCBzZXR0aW5ncyk7XG5cdH1cblxuXHRwcml2YXRlIHJlbmRlclNldHRpbmdzVGFiKGNvbnRhaW5lckVsOiBIVE1MRWxlbWVudCwgc2V0dGluZ3M6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyk6IHZvaWQge1xuXG5cdFx0Ly8gR2xvYmFsIHNldHRpbmdzIChmaXJzdCBncm91cCAtIG5vIGhlYWRpbmcpXG5cdFx0Y29uc3QgZ2VuZXJhbEdyb3VwID0gbmV3IFNldHRpbmdHcm91cChjb250YWluZXJFbCk7XG5cdFx0Z2VuZXJhbEdyb3VwLmFkZFNldHRpbmcoc2V0dGluZyA9PiB7XG5cdFx0XHRzZXR0aW5nXG5cdFx0XHRcdC5zZXROYW1lKFwiRGF0ZSBmb3JtYXRcIilcblx0XHRcdFx0Ly8gRGF0ZSBmb3JtYXQgY29kZXMgKE1NTU0sIHl5eXksIGV0Yy4pIGFyZSB0ZWNobmljYWwgbm90YXRpb24sIG5vdCBVSSB0ZXh0XG5cdFx0XHRcdC5zZXREZXNjKFwiRm9ybWF0IGZvciB0aGUgZGF0ZSBpbiBwcm9wZXJ0aWVzICh5eXl5LW1tLWRkLCBNTU1NIEQsIHl5eXksIHl5eXktbW0tZGQgSEg6bW0pXCIpXG5cdFx0XHRcdC5hZGRUZXh0KHRleHQgPT5cblx0XHRcdFx0XHR0ZXh0XG5cdFx0XHRcdFx0XHQvLyBcIllZWVktTU0tRERcIiBpcyBhIGRhdGUgZm9ybWF0IHBsYWNlaG9sZGVyLCBub3QgVUkgdGV4dFxuXHRcdFx0XHRcdFx0LnNldFBsYWNlaG9sZGVyKFwiWVlZWS1NTS1ERFwiKVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLmRhdGVGb3JtYXQpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0c2V0dGluZ3MuZGF0ZUZvcm1hdCA9IHZhbHVlIHx8IFwiWVlZWS1NTS1ERFwiO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cdFx0fSk7XG5cblx0XHRnZW5lcmFsR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdHNldHRpbmdcblx0XHRcdFx0LnNldE5hbWUoXCJFbmFibGUgY29weSBoZWFkaW5nIGxpbmtzXCIpXG5cdFx0XHRcdC5zZXREZXNjKFwiQWRkIHJpZ2h0LWNsaWNrIGNvbnRleHQgbWVudSBvcHRpb24gdG8gY29weSBoZWFkaW5nIGxpbmtzIGluIHZhcmlvdXMgZm9ybWF0cy5cIilcblx0XHRcdFx0LmFkZFRvZ2dsZSh0b2dnbGUgPT5cblx0XHRcdFx0XHR0b2dnbGVcblx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5lbmFibGVDb3B5SGVhZGluZ0xpbmspXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBib29sZWFuKSA9PiB7XG5cdFx0XHRcdFx0XHRcdHNldHRpbmdzLmVuYWJsZUNvcHlIZWFkaW5nTGluayA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0dGhpcy51cGRhdGVDb3B5SGVhZGluZ0ZpZWxkcygpO1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblx0XHR9KTtcblxuXHRcdGdlbmVyYWxHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0c2V0dGluZ1xuXHRcdFx0XHQuc2V0TmFtZShcIkRlZmF1bHQgaGVhZGluZyBsaW5rIGZvcm1hdFwiKVxuXHRcdFx0XHQvLyBcIkFzdHJvXCIgaXMgYSBwcm9wZXIgbm91biAoZnJhbWV3b3JrIG5hbWUpIGFuZCBzaG91bGQgYmUgY2FwaXRhbGl6ZWRcblx0XHRcdFx0LnNldERlc2MoXCJDaG9vc2UgdGhlIGRlZmF1bHQgZm9ybWF0IGZvciBjb3BpZWQgaGVhZGluZyBsaW5rcy4gT2JzaWRpYW4gZm9ybWF0IHJlc3BlY3RzIHlvdXIgT2JzaWRpYW4gc2V0dGluZ3MgZm9yIHdpa2lsaW5rIHZzIG1hcmtkb3duIHByZWZlcmVuY2UuIEFzdHJvIGxpbmsgdXNlcyB5b3VyIGxpbmsgYmFzZSBwYXRoIGZyb20gYWJvdmUgYW5kIGNvbnZlcnRzIHRoZSBoZWFkaW5nIGludG8ga2ViYWItY2FzZSBmb3JtYXQgYXMgYW4gYW5jaG9yIGxpbmtcIilcblx0XHRcdFx0LmFkZERyb3Bkb3duKGRyb3Bkb3duID0+XG5cdFx0XHRcdFx0ZHJvcGRvd25cblx0XHRcdFx0XHRcdC5hZGRPcHRpb24oXCJvYnNpZGlhblwiLCBcIk9ic2lkaWFuIGxpbmtcIilcblx0XHRcdFx0XHRcdC5hZGRPcHRpb24oXCJhc3Ryb1wiLCBcIkFzdHJvIGxpbmtcIilcblx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5jb3B5SGVhZGluZ0xpbmtGb3JtYXQpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0c2V0dGluZ3MuY29weUhlYWRpbmdMaW5rRm9ybWF0ID0gdmFsdWUgYXMgXCJvYnNpZGlhblwiIHwgXCJhc3Ryb1wiO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cdFx0XHQvLyBBZGQgY29uZGl0aW9uYWwgdmlzaWJpbGl0eSBjbGFzc2VzIC0ga2VlcCBzZXR0aW5nIGluIGdyb3VwXG5cdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItdmlzaWJsZVwiLCBzZXR0aW5ncy5lbmFibGVDb3B5SGVhZGluZ0xpbmspO1xuXHRcdFx0c2V0dGluZy5zZXR0aW5nRWwuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLWhpZGRlblwiLCAhc2V0dGluZ3MuZW5hYmxlQ29weUhlYWRpbmdMaW5rKTtcblx0XHR9KTtcblxuXHRcdGdlbmVyYWxHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0c2V0dGluZ1xuXHRcdFx0XHQuc2V0TmFtZShcIkFkZCB0cmFpbGluZyBzbGFzaCB0byBsaW5rc1wiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIkFkZCB0cmFpbGluZyBzbGFzaGVzIHRvIGFsbCBjb252ZXJ0ZWQgaW50ZXJuYWwgbGlua3MgKC9hYm91dC8gaW5zdGVhZCBvZiAvYWJvdXQpLlwiKVxuXHRcdFx0XHQuYWRkVG9nZ2xlKHRvZ2dsZSA9PlxuXHRcdFx0XHRcdHRvZ2dsZVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLmFkZFRyYWlsaW5nU2xhc2hUb0xpbmtzKVxuXHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5hZGRUcmFpbGluZ1NsYXNoVG9MaW5rcyA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cdFx0fSk7XG5cblx0XHRnZW5lcmFsR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdHNldHRpbmdcblx0XHRcdFx0LnNldE5hbWUoXCJQcm9jZXNzIGJhY2tncm91bmQgZmlsZSBjaGFuZ2VzXCIpXG5cdFx0XHRcdC8vIFRlY2huaWNhbCB0ZXJtcyBsaWtlIFwiT2JzaWRpYW5cIiwgXCJnaXRcIiBhcmUgcHJvcGVyIG5vdW5zIGluIHRoaXMgY29udGV4dFxuXHRcdFx0XHQuc2V0RGVzYyhcIkF1dG9tYXRpY2FsbHkgcHJvY2VzcyBuZXcgZmlsZXMgd2hlbiB0aGV5J3JlIGNoYW5nZWQgaW4gdGhlIGJhY2tncm91bmQgKGJ5IEdpdCBvciBvdGhlciBwbHVnaW5zKS4gRGlzYWJsZSB0byBwcmV2ZW50IG1vZGFsIHNwYW0gd2hlbiBmaWxlcyBhcmUgYWxyZWFkeSBwcm9jZXNzZWQgb24gb3RoZXIgZGV2aWNlcyBkdXJpbmcgYSBzeW5jLlwiKVxuXHRcdFx0XHQuYWRkVG9nZ2xlKHRvZ2dsZSA9PlxuXHRcdFx0XHRcdHRvZ2dsZVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLnByb2Nlc3NCYWNrZ3JvdW5kRmlsZUNoYW5nZXMpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBib29sZWFuKSA9PiB7XG5cdFx0XHRcdFx0XHRcdHNldHRpbmdzLnByb2Nlc3NCYWNrZ3JvdW5kRmlsZUNoYW5nZXMgPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHQpO1xuXHRcdH0pO1xuXG5cdFx0Z2VuZXJhbEdyb3VwLmFkZFNldHRpbmcoc2V0dGluZyA9PiB7XG5cdFx0XHRzZXR0aW5nXG5cdFx0XHRcdC8vIFwiTURYXCIgaXMgYSBwcm9wZXIgbm91biAoZmlsZSBmb3JtYXQpIGFuZCBzaG91bGQgYmUgY2FwaXRhbGl6ZWRcblx0XHRcdFx0LnNldE5hbWUoXCJTaG93IE1EWCBmaWxlcyBpbiBmaWxlIGV4cGxvcmVyXCIpXG5cdFx0XHRcdC5zZXREZXNjKFwiTWFrZSAubWR4IGZpbGVzIHZpc2libGUgaW4gT2JzaWRpYW4ncyBmaWxlIGV4cGxvcmVyLiBSZXF1aXJlcyByZWxvYWQgdG8gdGFrZSBlZmZlY3QuXCIpXG5cdFx0XHRcdC5hZGRUb2dnbGUodG9nZ2xlID0+XG5cdFx0XHRcdFx0dG9nZ2xlXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoc2V0dGluZ3Muc2hvd01keEZpbGVzSW5FeHBsb3Jlcilcblx0XHRcdFx0XHRcdC5vbkNoYW5nZShhc3luYyAodmFsdWU6IGJvb2xlYW4pID0+IHtcblx0XHRcdFx0XHRcdFx0c2V0dGluZ3Muc2hvd01keEZpbGVzSW5FeHBsb3JlciA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cdFx0fSk7XG5cblx0XHQvLyBQcm9wZXJ0eSBhdXRvbWF0aW9uXG5cdFx0Y29uc3QgYXV0b21hdGlvbkdyb3VwID0gbmV3IFNldHRpbmdHcm91cChjb250YWluZXJFbCkuc2V0SGVhZGluZyhcIlByb3BlcnR5IGF1dG9tYXRpb25cIik7XG5cblx0XHQvLyBBdXRvLWluc2VydCBwcm9wZXJ0aWVzIChtb3ZlZCBmcm9tIGdlbmVyYWxHcm91cClcblx0XHRhdXRvbWF0aW9uR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdHNldHRpbmdcblx0XHRcdFx0LnNldE5hbWUoXCJBdXRvLWluc2VydCBwcm9wZXJ0aWVzXCIpXG5cdFx0XHRcdC5zZXREZXNjKFwiQXV0b21hdGljYWxseSBpbnNlcnQgdGhlIHByb3BlcnRpZXMgdGVtcGxhdGUgd2hlbiBjcmVhdGluZyBuZXcgZmlsZXMuXCIpXG5cdFx0XHRcdC5hZGRUb2dnbGUodG9nZ2xlID0+XG5cdFx0XHRcdFx0dG9nZ2xlXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoc2V0dGluZ3MuYXV0b0luc2VydFByb3BlcnRpZXMpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBib29sZWFuKSA9PiB7XG5cdFx0XHRcdFx0XHRcdHNldHRpbmdzLmF1dG9JbnNlcnRQcm9wZXJ0aWVzID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblx0XHR9KTtcblxuXHRcdGF1dG9tYXRpb25Hcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0c2V0dGluZ1xuXHRcdFx0XHQuc2V0TmFtZShcIlJlbmFtZSBmaWxlIG9uIHRpdGxlIHByb3BlcnR5IGNsaWNrXCIpXG5cdFx0XHRcdC5zZXREZXNjKFwiV2hlbiBlbmFibGVkLCBjbGlja2luZyBpbnRvIHRoZSB0aXRsZSBwcm9wZXJ0eSB3aWxsIHRyaWdnZXIgdGhlIHJlbmFtZSBmaWxlIGNvbW1hbmQsIGtlZXBpbmcgdGhlIGZpbGUgc2x1ZyBpbiBzeW5jLlwiKVxuXHRcdFx0XHQuYWRkVG9nZ2xlKHRvZ2dsZSA9PlxuXHRcdFx0XHRcdHRvZ2dsZVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLnJlbmFtZU9uVGl0bGVDbGljaylcblx0XHRcdFx0XHRcdC5vbkNoYW5nZShhc3luYyAodmFsdWU6IGJvb2xlYW4pID0+IHtcblx0XHRcdFx0XHRcdFx0c2V0dGluZ3MucmVuYW1lT25UaXRsZUNsaWNrID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblx0XHR9KTtcblxuXHRcdGF1dG9tYXRpb25Hcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0c2V0dGluZ1xuXHRcdFx0XHQuc2V0TmFtZShcIlVwZGF0ZSBkYXRlIG9uIHB1Ymxpc2hcIilcblx0XHRcdFx0LnNldERlc2MoXCJVcGRhdGUgJ2RhdGUnIHByb3BlcnR5IHdoZW4gc3dpdGNoaW5nIGZyb20gZHJhZnQgdG8gcHVibGlzaGVkIHN0YXR1cy5cIilcblx0XHRcdFx0LmFkZFRvZ2dsZSh0b2dnbGUgPT5cblx0XHRcdFx0XHR0b2dnbGVcblx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5zeW5jRHJhZnREYXRlKVxuXHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5zeW5jRHJhZnREYXRlID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBzY3JvbGxUb3AgPSB0aGlzLmNvbnRhaW5lckVsLnNjcm9sbFRvcDtcblx0XHRcdFx0XHRcdFx0dGhpcy5kaXNwbGF5KCk7XG5cdFx0XHRcdFx0XHRcdHRoaXMuY29udGFpbmVyRWwuc2Nyb2xsVG9wID0gc2Nyb2xsVG9wO1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblx0XHR9KTtcblxuXHRcdGlmIChzZXR0aW5ncy5zeW5jRHJhZnREYXRlKSB7XG5cdFx0XHRhdXRvbWF0aW9uR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdFx0c2V0dGluZ1xuXHRcdFx0XHRcdC5zZXROYW1lKFwiRHJhZnQgZGV0ZWN0aW9uIG1vZGVcIilcblx0XHRcdFx0XHQuc2V0RGVzYyhcIkhvdyBkcmFmdCBzdGF0dXMgaXMgZGV0ZXJtaW5lZC4gUHJvcGVydHktYmFzZWQgdXNlcyBhIGJvb2xlYW4gcHJvcGVydHkgKGRyYWZ0OiB0cnVlKS4gVW5kZXJzY29yZSBwcmVmaXggdXNlcyB0aGUgZmlsZSBuYW1lIChfbXktcG9zdC5tZCA9IGRyYWZ0KS5cIilcblx0XHRcdFx0XHQuYWRkRHJvcGRvd24oZHJvcGRvd24gPT5cblx0XHRcdFx0XHRcdGRyb3Bkb3duXG5cdFx0XHRcdFx0XHRcdC5hZGRPcHRpb24oXCJwcm9wZXJ0eVwiLCBcIlByb3BlcnR5LWJhc2VkXCIpXG5cdFx0XHRcdFx0XHRcdC5hZGRPcHRpb24oXCJ1bmRlcnNjb3JlLXByZWZpeFwiLCBcIlVuZGVyc2NvcmUgcHJlZml4XCIpXG5cdFx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5kcmFmdERldGVjdGlvbk1vZGUgfHwgXCJwcm9wZXJ0eVwiKVxuXHRcdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgdmFsdWUgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmRyYWZ0RGV0ZWN0aW9uTW9kZSA9IHZhbHVlIGFzICdwcm9wZXJ0eScgfCAndW5kZXJzY29yZS1wcmVmaXgnO1xuXHRcdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMucGx1Z2luLmZyb250bWF0dGVyU2VydmljZT8uaW5pdGlhbGl6ZURyYWZ0U3RhdHVzTWFwKCk7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3Qgc2Nyb2xsVG9wID0gdGhpcy5jb250YWluZXJFbC5zY3JvbGxUb3A7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5kaXNwbGF5KCk7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5jb250YWluZXJFbC5zY3JvbGxUb3AgPSBzY3JvbGxUb3A7XG5cdFx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0KTtcblx0XHRcdH0pO1xuXG5cdFx0XHRpZiAoc2V0dGluZ3MuZHJhZnREZXRlY3Rpb25Nb2RlICE9PSAndW5kZXJzY29yZS1wcmVmaXgnKSB7XG5cdFx0XHRcdGF1dG9tYXRpb25Hcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRcdHNldHRpbmdcblx0XHRcdFx0XHRcdC5zZXROYW1lKFwiRHJhZnQgcHJvcGVydHkgbmFtZVwiKVxuXHRcdFx0XHRcdFx0LnNldERlc2MoXCJUaGUgcHJvcGVydHkgZmllbGQgdG8gdXNlIGZvciBkcmFmdCBzdGF0dXMuXCIpXG5cdFx0XHRcdFx0XHQuYWRkVGV4dCh0ZXh0ID0+XG5cdFx0XHRcdFx0XHRcdHRleHRcblx0XHRcdFx0XHRcdFx0XHQuc2V0UGxhY2Vob2xkZXIoXCJkcmFmdFwiKVxuXHRcdFx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5kcmFmdFByb3BlcnR5IHx8IFwiXCIpXG5cdFx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogc3RyaW5nKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5kcmFmdFByb3BlcnR5ID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0XHRcdHRoaXMucGx1Z2luLmZyb250bWF0dGVyU2VydmljZT8uaW5pdGlhbGl6ZURyYWZ0U3RhdHVzTWFwKCk7XG5cdFx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdH0pO1xuXG5cdFx0XHRcdGF1dG9tYXRpb25Hcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRcdHNldHRpbmdcblx0XHRcdFx0XHRcdC5zZXROYW1lKFwiRHJhZnQgbG9naWNcIilcblx0XHRcdFx0XHRcdC5zZXREZXNjKFwiV2hldGhlciB0aGUgcHJvcGVydHkgdmFsdWUgJ3RydWUnIG1lYW5zIGl0IGlzIGEgZHJhZnQgb3IgcHVibGlzaGVkLlwiKVxuXHRcdFx0XHRcdFx0LmFkZERyb3Bkb3duKGRyb3Bkb3duID0+XG5cdFx0XHRcdFx0XHRcdGRyb3Bkb3duXG5cdFx0XHRcdFx0XHRcdFx0LmFkZE9wdGlvbihcInRydWUtaXMtZHJhZnRcIiwgXCJUcnVlID0gRHJhZnRcIilcblx0XHRcdFx0XHRcdFx0XHQuYWRkT3B0aW9uKFwiZmFsc2UtaXMtZHJhZnRcIiwgXCJUcnVlID0gUHVibGlzaGVkXCIpXG5cdFx0XHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLmRyYWZ0TG9naWMgfHwgXCJ0cnVlLWlzLWRyYWZ0XCIpXG5cdFx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jIHZhbHVlID0+IHtcblx0XHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmRyYWZ0TG9naWMgPSB2YWx1ZSBhcyAndHJ1ZS1pcy1kcmFmdCcgfCAnZmFsc2UtaXMtZHJhZnQnO1xuXHRcdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdFx0XHR0aGlzLnBsdWdpbi5mcm9udG1hdHRlclNlcnZpY2U/LmluaXRpYWxpemVEcmFmdFN0YXR1c01hcCgpO1xuXHRcdFx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblxuXHRcdFx0YXV0b21hdGlvbkdyb3VwLmFkZFNldHRpbmcoc2V0dGluZyA9PiB7XG5cdFx0XHRcdHNldHRpbmdcblx0XHRcdFx0XHQuc2V0TmFtZShcIlB1Ymxpc2hlZCBkYXRlIHByb3BlcnR5IG5hbWVcIilcblx0XHRcdFx0XHQuc2V0RGVzYyhcIlRoZSBwcm9wZXJ0eSBmaWVsZCB0byB1cGRhdGUgd2hlbiBwdWJsaXNoZWQgKCdkYXRlJyBvciAncHViRGF0ZScpLlwiKVxuXHRcdFx0XHRcdC5hZGRUZXh0KHRleHQgPT5cblx0XHRcdFx0XHRcdHRleHRcblx0XHRcdFx0XHRcdFx0LnNldFBsYWNlaG9sZGVyKFwiZGF0ZVwiKVxuXHRcdFx0XHRcdFx0XHQuc2V0VmFsdWUoc2V0dGluZ3MucHVibGlzaERhdGVGaWVsZCB8fCBcIlwiKVxuXHRcdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5wdWJsaXNoRGF0ZUZpZWxkID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0KTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdC8vIENvbnRlbnQgdHlwZXNcblx0XHRjb25zdCBjb250ZW50VHlwZXNHcm91cCA9IG5ldyBTZXR0aW5nR3JvdXAoY29udGFpbmVyRWwpLnNldEhlYWRpbmcoXCJDb250ZW50IHR5cGVzXCIpO1xuXG5cdFx0Ly8gQWRkIGNvbnRhaW5lciBhcyBhIHNldHRpbmcgLSBoaWRlIHRoZSBzZXR0aW5nJ3MgZGVmYXVsdCBVSSwgYWRkIG91ciBjb250YWluZXIgaW5zaWRlXG5cdFx0Y29udGVudFR5cGVzR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdC8vIEhpZGUgdGhlIHNldHRpbmcncyBkZWZhdWx0IFVJIGVsZW1lbnRzIHVzaW5nIENTUyBjbGFzc2VzXG5cdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5hZGRDbGFzcyhcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctaGlkZGVuLWVsZW1lbnRzXCIpO1xuXHRcdFx0c2V0dGluZy5zZXR0aW5nRWwuYWRkQ2xhc3MoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci1mdWxsLXdpZHRoXCIpO1xuXHRcdFx0Ly8gQWRkIG91ciBjb250YWluZXIgaW5zaWRlIHRoZSBzZXR0aW5nIGVsZW1lbnQgLSBlbnN1cmUgaXQncyB2aXNpYmxlXG5cdFx0XHR0aGlzLmN1c3RvbUNvbnRlbnRUeXBlc0NvbnRhaW5lciA9IHNldHRpbmcuc2V0dGluZ0VsLmNyZWF0ZURpdih7XG5cdFx0XHRcdGNsczogXCJjdXN0b20tY29udGVudC10eXBlcy1jb250YWluZXIgYXN0cm8tY29tcG9zZXItY3VzdG9tLXR5cGVzLWNvbnRhaW5lci12aXNpYmxlXCJcblx0XHRcdH0pO1xuXHRcdH0pO1xuXHRcdC8vIFJlbmRlciBjb250ZW50IHR5cGVzIGFmdGVyIGNvbnRhaW5lciBpcyBjcmVhdGVkXG5cdFx0aWYgKHRoaXMuY3VzdG9tQ29udGVudFR5cGVzQ29udGFpbmVyKSB7XG5cdFx0XHR0aGlzLnJlbmRlckN1c3RvbUNvbnRlbnRUeXBlcygpO1xuXHRcdH1cblxuXHRcdC8vIERldmVsb3BlciBjb21tYW5kcyAoZGVza3RvcCBvbmx5IC0gbm90IGF2YWlsYWJsZSBvbiBtb2JpbGUpXG5cdFx0aWYgKCFQbGF0Zm9ybS5pc01vYmlsZSkge1xuXHRcdFx0Y29uc3QgZGV2ZWxvcGVyR3JvdXAgPSBuZXcgU2V0dGluZ0dyb3VwKGNvbnRhaW5lckVsKS5zZXRIZWFkaW5nKFwiRGV2ZWxvcGVyIGNvbW1hbmRzXCIpO1xuXG5cdFx0XHQvLyBUZXJtaW5hbCBjb21tYW5kIHNldHRpbmdzXG5cdFx0XHRkZXZlbG9wZXJHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJFbmFibGUgb3BlbiB0ZXJtaW5hbCBjb21tYW5kXCIpXG5cdFx0XHRcdFx0LnNldERlc2MoXCJFbmFibGUgY29tbWFuZCB0byBvcGVuIHRlcm1pbmFsIGluIHByb2plY3Qgcm9vdCBkaXJlY3RvcnkuXCIpXG5cdFx0XHRcdFx0LmFkZFRvZ2dsZSh0b2dnbGUgPT5cblx0XHRcdFx0XHRcdHRvZ2dsZVxuXHRcdFx0XHRcdFx0XHQuc2V0VmFsdWUoc2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZClcblx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQgPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLnVwZGF0ZVRlcm1pbmFsQ29tbWFuZEZpZWxkcygpO1xuXHRcdFx0XHRcdFx0XHRcdC8vIHJlZ2lzdGVyUmliYm9uSWNvbnMgY2hlY2tzIGJvdGggY29tbWFuZCBhbmQgaWNvbiBzZXR0aW5nc1xuXHRcdFx0XHRcdFx0XHRcdC8vIElmIGNvbW1hbmQgaXMgZW5hYmxlZCBBTkQgaWNvbiBpcyBlbmFibGVkLCBpdCB3aWxsIHNob3c7IG90aGVyd2lzZSBpdCB3aWxsIGhpZGVcblx0XHRcdFx0XHRcdFx0XHRpZiAodGhpcy5wbHVnaW4ucmVnaXN0ZXJSaWJib25JY29ucykge1xuXHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5wbHVnaW4ucmVnaXN0ZXJSaWJib25JY29ucygpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHQpO1xuXHRcdFx0fSk7XG5cblx0XHRcdC8vIENyZWF0ZSBjb250YWluZXIgZm9yIHRlcm1pbmFsIGNvbW1hbmQgZmllbGRzIC0ga2VlcCBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSB3aXRoIHVwZGF0ZSBtZXRob2RzXG5cdFx0XHR0aGlzLnRlcm1pbmFsQ29tbWFuZENvbnRhaW5lciA9IGNvbnRhaW5lckVsLmNyZWF0ZURpdih7IGNsczogXCJ0ZXJtaW5hbC1jb21tYW5kLWZpZWxkc1wiIH0pO1xuXHRcdFx0dGhpcy50ZXJtaW5hbENvbW1hbmRDb250YWluZXIuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLXZpc2libGVcIiwgc2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZCk7XG5cdFx0XHR0aGlzLnRlcm1pbmFsQ29tbWFuZENvbnRhaW5lci5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFzZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kKTtcblxuXHRcdFx0ZGV2ZWxvcGVyR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdFx0Y29uc3QgZGVzY0ZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xuXHRcdFx0XHQvLyBUZXh0IGlzIGFscmVhZHkgaW4gc2VudGVuY2UgY2FzZTsgXCJPYnNpZGlhblwiIGlzIGEgcHJvcGVyIG5vdW5cblx0XHRcdFx0ZGVzY0ZyYWdtZW50LmNyZWF0ZUVsKFwiZGl2XCIsIHsgdGV4dDogXCJQYXRoIHJlbGF0aXZlIHRvIHRoZSBPYnNpZGlhbiB2YXVsdCByb290IGZvbGRlci4gVXNlIC4uLy4uIGZvciB0d28gbGV2ZWxzIHVwLiBMZWF2ZSBibGFuayB0byB1c2UgdGhlIHZhdWx0IGZvbGRlclwiIH0pO1xuXHRcdFx0XHRkZXNjRnJhZ21lbnQuY3JlYXRlRWwoXCJkaXZcIiwgeyB0ZXh0OiBcIlRoaXMgaXMgd2hlcmUgdGhlIHRlcm1pbmFsIHdpbGwgb3Blbi4gQWJzb2x1dGUgcGF0aHMgd29yayBhbHNvLlwiIH0pO1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJQcm9qZWN0IHJvb3QgZGlyZWN0b3J5IHBhdGhcIilcblx0XHRcdFx0XHQuc2V0RGVzYyhkZXNjRnJhZ21lbnQpXG5cdFx0XHRcdFx0LmFkZFRleHQodGV4dCA9PlxuXHRcdFx0XHRcdFx0dGV4dFxuXHRcdFx0XHRcdFx0XHQuc2V0UGxhY2Vob2xkZXIoXCIuLi8uLlwiKVxuXHRcdFx0XHRcdFx0XHQuc2V0VmFsdWUoc2V0dGluZ3MudGVybWluYWxQcm9qZWN0Um9vdFBhdGgpXG5cdFx0XHRcdFx0XHRcdC5vbkNoYW5nZShhc3luYyAodmFsdWU6IHN0cmluZykgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLnRlcm1pbmFsUHJvamVjdFJvb3RQYXRoID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0Ly8gQWRkIGNsYXNzIGZvciBjb25kaXRpb25hbCB2aXNpYmlsaXR5IC0ga2VlcCBzZXR0aW5nIGluIGdyb3VwXG5cdFx0XHRcdHNldHRpbmcuc2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIHNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQpO1xuXHRcdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFzZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kKTtcblx0XHRcdH0pO1xuXG5cdFx0XHRkZXZlbG9wZXJHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRjb25zdCBkZXNjRnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG5cdFx0XHRcdC8vIFRleHQgaXMgYWxyZWFkeSBpbiBzZW50ZW5jZSBjYXNlOyBwcm9wZXIgbm91bnMgb3IgcHJvZHVjdCBuYW1lcyBsaWtlIFwibWFjT1NcIiwgXCJXaW5kb3dzXCIsIFwiTGludXhcIlxuXHRcdFx0XHRkZXNjRnJhZ21lbnQuY3JlYXRlRWwoXCJkaXZcIiwgeyB0ZXh0OiBcIkxlYXZlIGJsYW5rIHRvIHVzZSBwbGF0Zm9ybSBkZWZhdWx0cy4gT24gbWFjT1MsIHRoZSBkZWZhdWx0IGlzIFRlcm1pbmFsLiBPbiBXaW5kb3dzLCBpdCdzIFdpbmRvd3MgVGVybWluYWwgKFdpbiAxMSkgb3IgY21kLmV4ZSAoV2luIDEwKS4gT24gTGludXgsIGl0J3MgZ25vbWUtdGVybWluYWwsIGtvbnNvbGUsIG9yIHh0ZXJtXCIgfSk7XG5cdFx0XHRcdC8vIFRleHQgaXMgYWxyZWFkeSBpbiBzZW50ZW5jZSBjYXNlOyBwcm9wZXIgbm91bnMgbGlrZSBcIlRlcm1pbmFsXCIsIFwiaVRlcm1cIiwgXCJQb3dlclNoZWxsXCJcblx0XHRcdFx0ZGVzY0ZyYWdtZW50LmNyZWF0ZUVsKFwiZGl2XCIsIHsgdGV4dDogXCJFeGFtcGxlcyBpbmNsdWRlIFRlcm1pbmFsLCBpVGVybSwgUG93ZXJTaGVsbCwgYW5kIEFsYWNyaXR0eVwiIH0pO1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJUZXJtaW5hbCBhcHBsaWNhdGlvbiBuYW1lXCIpXG5cdFx0XHRcdFx0LnNldERlc2MoZGVzY0ZyYWdtZW50KVxuXHRcdFx0XHRcdC5hZGRUZXh0KHRleHQgPT5cblx0XHRcdFx0XHRcdHRleHRcblx0XHRcdFx0XHRcdFx0LnNldFBsYWNlaG9sZGVyKFwiVGVybWluYWxcIilcblx0XHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLnRlcm1pbmFsQXBwbGljYXRpb25OYW1lKVxuXHRcdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0XHRzZXR0aW5ncy50ZXJtaW5hbEFwcGxpY2F0aW9uTmFtZSA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdC8vIEFkZCBjbGFzcyBmb3IgY29uZGl0aW9uYWwgdmlzaWJpbGl0eSAtIGtlZXAgc2V0dGluZyBpbiBncm91cFxuXHRcdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItdmlzaWJsZVwiLCBzZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kKTtcblx0XHRcdFx0c2V0dGluZy5zZXR0aW5nRWwuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLWhpZGRlblwiLCAhc2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZCk7XG5cdFx0XHR9KTtcblxuXHRcdFx0ZGV2ZWxvcGVyR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdFx0c2V0dGluZ1xuXHRcdFx0XHRcdC5zZXROYW1lKFwiRW5hYmxlIGRlYnVnIGxvZ2dpbmdcIilcblx0XHRcdFx0XHQuc2V0RGVzYyhcIkxvZyB0ZXJtaW5hbCBsYXVuY2ggY29tbWFuZHMgYW5kIHBsYXRmb3JtIGRlY2lzaW9ucyB0byB0aGUgZGV2ZWxvcGVyIGNvbnNvbGUgZm9yIHRyb3VibGVzaG9vdGluZy5cIilcblx0XHRcdFx0XHQuYWRkVG9nZ2xlKHRvZ2dsZSA9PlxuXHRcdFx0XHRcdFx0dG9nZ2xlXG5cdFx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5lbmFibGVUZXJtaW5hbERlYnVnTG9nZ2luZylcblx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmVuYWJsZVRlcm1pbmFsRGVidWdMb2dnaW5nID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0Ly8gQWRkIGNsYXNzIGZvciBjb25kaXRpb25hbCB2aXNpYmlsaXR5IC0ga2VlcCBzZXR0aW5nIGluIGdyb3VwXG5cdFx0XHRcdHNldHRpbmcuc2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIHNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQpO1xuXHRcdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFzZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kKTtcblx0XHRcdH0pO1xuXG5cdFx0XHRkZXZlbG9wZXJHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJTaG93IG9wZW4gdGVybWluYWwgcmliYm9uIGljb25cIilcblx0XHRcdFx0XHQuc2V0RGVzYyhcIkFkZCBhIHJpYmJvbiBpY29uIHRvIGxhdW5jaCB0aGUgdGVybWluYWwgY29tbWFuZC5cIilcblx0XHRcdFx0XHQuYWRkVG9nZ2xlKHRvZ2dsZSA9PiB7XG5cdFx0XHRcdFx0XHR0aGlzLnRlcm1pbmFsUmliYm9uVG9nZ2xlQ29tcG9uZW50ID0gdG9nZ2xlO1xuXHRcdFx0XHRcdFx0dG9nZ2xlXG5cdFx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5lbmFibGVUZXJtaW5hbFJpYmJvbkljb24pXG5cdFx0XHRcdFx0XHRcdC5zZXREaXNhYmxlZCghc2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZClcblx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdC8vIFVwZGF0ZSBzZXR0aW5ncyBkaXJlY3RseSBvbiBwbHVnaW4gaW5zdGFuY2Vcblx0XHRcdFx0XHRcdFx0XHR0aGlzLnBsdWdpbi5zZXR0aW5ncy5lbmFibGVUZXJtaW5hbFJpYmJvbkljb24gPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5lbmFibGVUZXJtaW5hbFJpYmJvbkljb24gPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0XHQvLyBTbWFsbCBkZWxheSB0byBlbnN1cmUgc2V0dGluZ3MgYXJlIHNhdmVkLCB0aGVuIHJlLXJlZ2lzdGVyXG5cdFx0XHRcdFx0XHRcdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAodGhpcy5wbHVnaW4ucmVnaXN0ZXJSaWJib25JY29ucykge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0aGlzLnBsdWdpbi5yZWdpc3RlclJpYmJvbkljb25zKCk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fSwgNTApO1xuXHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0Ly8gQWRkIGNsYXNzIGZvciBjb25kaXRpb25hbCB2aXNpYmlsaXR5IC0ga2VlcCBzZXR0aW5nIGluIGdyb3VwXG5cdFx0XHRcdHNldHRpbmcuc2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIHNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQpO1xuXHRcdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFzZXR0aW5ncy5lbmFibGVPcGVuVGVybWluYWxDb21tYW5kKTtcblx0XHRcdFx0Ly8gU3RvcmUgcmVmZXJlbmNlIGZvciB1cGRhdGluZyBkaXNhYmxlZCBzdGF0ZVxuXHRcdFx0XHR0aGlzLnRlcm1pbmFsUmliYm9uVG9nZ2xlID0gc2V0dGluZztcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBDb25maWcgZmlsZSBjb21tYW5kIHNldHRpbmdzXG5cdFx0XHRkZXZlbG9wZXJHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJFbmFibGUgZWRpdCBjb25maWcgZmlsZSBjb21tYW5kXCIpXG5cdFx0XHRcdFx0LnNldERlc2MoXCJFbmFibGUgY29tbWFuZCB0byBvcGVuIGFzdHJvIGNvbmZpZyBmaWxlIGluIGRlZmF1bHQgZWRpdG9yLlwiKVxuXHRcdFx0XHRcdC5hZGRUb2dnbGUodG9nZ2xlID0+XG5cdFx0XHRcdFx0XHR0b2dnbGVcblx0XHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLmVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZClcblx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZCA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMudXBkYXRlQ29uZmlnQ29tbWFuZEZpZWxkcygpO1xuXHRcdFx0XHRcdFx0XHRcdC8vIHJlZ2lzdGVyUmliYm9uSWNvbnMgY2hlY2tzIGJvdGggY29tbWFuZCBhbmQgaWNvbiBzZXR0aW5nc1xuXHRcdFx0XHRcdFx0XHRcdC8vIElmIGNvbW1hbmQgaXMgZW5hYmxlZCBBTkQgaWNvbiBpcyBlbmFibGVkLCBpdCB3aWxsIHNob3c7IG90aGVyd2lzZSBpdCB3aWxsIGhpZGVcblx0XHRcdFx0XHRcdFx0XHRpZiAodGhpcy5wbHVnaW4ucmVnaXN0ZXJSaWJib25JY29ucykge1xuXHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5wbHVnaW4ucmVnaXN0ZXJSaWJib25JY29ucygpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHQpO1xuXHRcdFx0fSk7XG5cblx0XHRcdC8vIENyZWF0ZSBjb250YWluZXIgZm9yIGNvbmZpZyBjb21tYW5kIGZpZWxkcyAtIGtlZXAgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHkgd2l0aCB1cGRhdGUgbWV0aG9kc1xuXHRcdFx0dGhpcy5jb25maWdDb21tYW5kQ29udGFpbmVyID0gY29udGFpbmVyRWwuY3JlYXRlRGl2KHsgY2xzOiBcImNvbmZpZy1jb21tYW5kLWZpZWxkc1wiIH0pO1xuXHRcdFx0dGhpcy5jb25maWdDb21tYW5kQ29udGFpbmVyLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIHNldHRpbmdzLmVuYWJsZU9wZW5Db25maWdGaWxlQ29tbWFuZCk7XG5cdFx0XHR0aGlzLmNvbmZpZ0NvbW1hbmRDb250YWluZXIuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLWhpZGRlblwiLCAhc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kKTtcblxuXHRcdFx0ZGV2ZWxvcGVyR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdFx0Y29uc3QgZGVzY0ZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xuXHRcdFx0XHRkZXNjRnJhZ21lbnQuY3JlYXRlRWwoXCJkaXZcIiwgeyB0ZXh0OiBcIlBhdGggdG8gdGhlIGNvbmZpZyBmaWxlIHJlbGF0aXZlIHRvIHRoZSB2YXVsdCByb290LiBVc2UgLi4vY29uZmlnLnRzIG9yIC4uLy4uL2FzdHJvLmNvbmZpZy5tanMuXCIgfSk7XG5cdFx0XHRcdGRlc2NGcmFnbWVudC5jcmVhdGVFbChcImRpdlwiLCB7IHRleHQ6IFwiQWJzb2x1dGUgcGF0aHMgd29yayBhbHNvLlwiIH0pO1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJDb25maWcgZmlsZSBwYXRoXCIpXG5cdFx0XHRcdFx0LnNldERlc2MoZGVzY0ZyYWdtZW50KVxuXHRcdFx0XHRcdC5hZGRUZXh0KHRleHQgPT5cblx0XHRcdFx0XHRcdHRleHRcblx0XHRcdFx0XHRcdFx0LnNldFBsYWNlaG9sZGVyKFwiLi4vY29uZmlnLnRzXCIpXG5cdFx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5jb25maWdGaWxlUGF0aClcblx0XHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogc3RyaW5nKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0c2V0dGluZ3MuY29uZmlnRmlsZVBhdGggPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHQvLyBBZGQgY2xhc3MgZm9yIGNvbmRpdGlvbmFsIHZpc2liaWxpdHkgLSBrZWVwIHNldHRpbmcgaW4gZ3JvdXBcblx0XHRcdFx0c2V0dGluZy5zZXR0aW5nRWwuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLXZpc2libGVcIiwgc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kKTtcblx0XHRcdFx0c2V0dGluZy5zZXR0aW5nRWwuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLWhpZGRlblwiLCAhc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kKTtcblx0XHRcdH0pO1xuXG5cdFx0XHRkZXZlbG9wZXJHcm91cC5hZGRTZXR0aW5nKHNldHRpbmcgPT4ge1xuXHRcdFx0XHRzZXR0aW5nXG5cdFx0XHRcdFx0LnNldE5hbWUoXCJTaG93IG9wZW4gY29uZmlnIHJpYmJvbiBpY29uXCIpXG5cdFx0XHRcdFx0LnNldERlc2MoXCJBZGQgYSByaWJib24gaWNvbiB0byBsYXVuY2ggdGhlIGNvbmZpZyBmaWxlIGNvbW1hbmQuXCIpXG5cdFx0XHRcdFx0LmFkZFRvZ2dsZSh0b2dnbGUgPT4ge1xuXHRcdFx0XHRcdFx0dGhpcy5jb25maWdSaWJib25Ub2dnbGVDb21wb25lbnQgPSB0b2dnbGU7XG5cdFx0XHRcdFx0XHR0b2dnbGVcblx0XHRcdFx0XHRcdFx0LnNldFZhbHVlKHNldHRpbmdzLmVuYWJsZUNvbmZpZ1JpYmJvbkljb24pXG5cdFx0XHRcdFx0XHRcdC5zZXREaXNhYmxlZCghc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kKVxuXHRcdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBib29sZWFuKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gVXBkYXRlIHNldHRpbmdzIGRpcmVjdGx5IG9uIHBsdWdpbiBpbnN0YW5jZVxuXHRcdFx0XHRcdFx0XHRcdHRoaXMucGx1Z2luLnNldHRpbmdzLmVuYWJsZUNvbmZpZ1JpYmJvbkljb24gPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5lbmFibGVDb25maWdSaWJib25JY29uID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gU21hbGwgZGVsYXkgdG8gZW5zdXJlIHNldHRpbmdzIGFyZSBzYXZlZCwgdGhlbiByZS1yZWdpc3RlclxuXHRcdFx0XHRcdFx0XHRcdHNldFRpbWVvdXQoKCkgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKHRoaXMucGx1Z2luLnJlZ2lzdGVyUmliYm9uSWNvbnMpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5wbHVnaW4ucmVnaXN0ZXJSaWJib25JY29ucygpO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH0sIDUwKTtcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdC8vIEFkZCBjbGFzcyBmb3IgY29uZGl0aW9uYWwgdmlzaWJpbGl0eSAtIGtlZXAgc2V0dGluZyBpbiBncm91cFxuXHRcdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItdmlzaWJsZVwiLCBzZXR0aW5ncy5lbmFibGVPcGVuQ29uZmlnRmlsZUNvbW1hbmQpO1xuXHRcdFx0XHRzZXR0aW5nLnNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFzZXR0aW5ncy5lbmFibGVPcGVuQ29uZmlnRmlsZUNvbW1hbmQpO1xuXHRcdFx0XHQvLyBTdG9yZSByZWZlcmVuY2UgZm9yIHVwZGF0aW5nIGRpc2FibGVkIHN0YXRlXG5cdFx0XHRcdHRoaXMuY29uZmlnUmliYm9uVG9nZ2xlID0gc2V0dGluZztcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBIZWxwIGJ1dHRvbiByZXBsYWNlbWVudCB0b2dnbGUgKHBhcnQgb2YgZGV2ZWxvcGVyIGNvbW1hbmRzIGdyb3VwKVxuXHRcdFx0ZGV2ZWxvcGVyR3JvdXAuYWRkU2V0dGluZyhzZXR0aW5nID0+IHtcblx0XHRcdFx0c2V0dGluZ1xuXHRcdFx0XHRcdC5zZXROYW1lKCdTd2FwIG91dCBoZWxwIGJ1dHRvbiBmb3IgY3VzdG9tIGFjdGlvbicpXG5cdFx0XHRcdFx0LnNldERlc2MoJ1JlcGxhY2UgdGhlIGhlbHAgYnV0dG9uIGluIHRoZSB2YXVsdCBwcm9maWxlIGFyZWEgd2l0aCBhIGN1c3RvbSBhY3Rpb24uJylcblx0XHRcdFx0XHQuYWRkVG9nZ2xlKHRvZ2dsZSA9PiB0b2dnbGVcblx0XHRcdFx0XHRcdC5zZXRWYWx1ZShzZXR0aW5ncy5oZWxwQnV0dG9uUmVwbGFjZW1lbnQ/LmVuYWJsZWQgPz8gZmFsc2UpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgdmFsdWUgPT4ge1xuXHRcdFx0XHRcdFx0XHRpZiAoIXNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudCkge1xuXHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudCA9IHtcblx0XHRcdFx0XHRcdFx0XHRcdGVuYWJsZWQ6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHRcdFx0Y29tbWFuZElkOiAnZWRpdC1hc3Ryby1jb25maWcnLFxuXHRcdFx0XHRcdFx0XHRcdFx0aWNvbklkOiAncm9ja2V0Jyxcblx0XHRcdFx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudC5lbmFibGVkID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0XHQvLyBUcmlnZ2VyIGhlbHAgYnV0dG9uIHJlcGxhY2VtZW50IHVwZGF0ZSAoaXQgd2lsbCByZWxvYWQgc2V0dGluZ3MpXG5cdFx0XHRcdFx0XHRcdGlmICh0aGlzLnBsdWdpbi51cGRhdGVIZWxwQnV0dG9uKSB7XG5cdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4udXBkYXRlSGVscEJ1dHRvbigpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdC8vIFJlLXJlbmRlciB0byBzaG93L2hpZGUgb3B0aW9uc1xuXHRcdFx0XHRcdFx0XHR0aGlzLmRpc3BsYXkoKTtcblx0XHRcdFx0XHRcdH0pKTtcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBTaG93IGNvbW1hbmQgYW5kIGljb24gcGlja2VycyBvbmx5IGlmIGVuYWJsZWQgKHBhcnQgb2YgZGV2ZWxvcGVyIGNvbW1hbmRzIGdyb3VwKVxuXHRcdFx0aWYgKHNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudD8uZW5hYmxlZCkge1xuXHRcdFx0XHQvLyBDb21tYW5kIHBpY2tlclxuXHRcdFx0XHRjb25zdCBjb21tYW5kTmFtZSA9IHRoaXMuZ2V0Q29tbWFuZE5hbWUoc2V0dGluZ3MuaGVscEJ1dHRvblJlcGxhY2VtZW50LmNvbW1hbmRJZCk7XG5cdFx0XHRcdGRldmVsb3Blckdyb3VwLmFkZFNldHRpbmcoc2V0dGluZyA9PiB7XG5cdFx0XHRcdFx0c2V0dGluZ1xuXHRcdFx0XHRcdFx0LnNldE5hbWUoJ0NvbW1hbmQnKVxuXHRcdFx0XHRcdFx0LnNldERlc2MoJ1NlbGVjdCB0aGUgY29tbWFuZCB0byBleGVjdXRlIHdoZW4gdGhlIGJ1dHRvbiBpcyBjbGlja2VkLicpXG5cdFx0XHRcdFx0XHQuYWRkQnV0dG9uKGJ1dHRvbiA9PiBidXR0b25cblx0XHRcdFx0XHRcdFx0LnNldEJ1dHRvblRleHQoY29tbWFuZE5hbWUgfHwgJ1NlbGVjdCBjb21tYW5kJylcblx0XHRcdFx0XHRcdFx0Lm9uQ2xpY2soKCkgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IG1vZGFsID0gbmV3IENvbW1hbmRQaWNrZXJNb2RhbCh0aGlzLmFwcCwgKGNvbW1hbmRJZCkgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdFx0dm9pZCAoYXN5bmMgKCkgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZiAoIXNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHNldHRpbmdzLmhlbHBCdXR0b25SZXBsYWNlbWVudCA9IHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGVuYWJsZWQ6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb21tYW5kSWQ6ICdlZGl0LWFzdHJvLWNvbmZpZycsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRpY29uSWQ6ICdyb2NrZXQnLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0c2V0dGluZ3MuaGVscEJ1dHRvblJlcGxhY2VtZW50LmNvbW1hbmRJZCA9IGNvbW1hbmRJZDtcblx0XHRcdFx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFRyaWdnZXIgaGVscCBidXR0b24gcmVwbGFjZW1lbnQgdXBkYXRlIGltbWVkaWF0ZWx5IChpdCB3aWxsIHJlbG9hZCBzZXR0aW5ncylcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKHRoaXMucGx1Z2luLnVwZGF0ZUhlbHBCdXR0b24pIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi51cGRhdGVIZWxwQnV0dG9uKCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gUmUtcmVuZGVyIHRvIHNob3cgdXBkYXRlZCBjb21tYW5kIG5hbWVcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5kaXNwbGF5KCk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9KSgpO1xuXHRcdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0XHRcdG1vZGFsLm9wZW4oKTtcblx0XHRcdFx0XHRcdFx0fSkpO1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0XHQvLyBJY29uIHBpY2tlclxuXHRcdFx0XHRjb25zdCBpY29uTmFtZSA9IHRoaXMuZ2V0SWNvbk5hbWUoc2V0dGluZ3MuaGVscEJ1dHRvblJlcGxhY2VtZW50Lmljb25JZCk7XG5cdFx0XHRcdGRldmVsb3Blckdyb3VwLmFkZFNldHRpbmcoc2V0dGluZyA9PiB7XG5cdFx0XHRcdFx0c2V0dGluZ1xuXHRcdFx0XHRcdFx0LnNldE5hbWUoJ0ljb24nKVxuXHRcdFx0XHRcdFx0LnNldERlc2MoJ1NlbGVjdCB0aGUgaWNvbiB0byBkaXNwbGF5IG9uIHRoZSBidXR0b24uJylcblx0XHRcdFx0XHRcdC5hZGRCdXR0b24oYnV0dG9uID0+IGJ1dHRvblxuXHRcdFx0XHRcdFx0XHQuc2V0QnV0dG9uVGV4dChpY29uTmFtZSB8fCAnU2VsZWN0IGljb24uLi4nKVxuXHRcdFx0XHRcdFx0XHQub25DbGljaygoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgbW9kYWwgPSBuZXcgSWNvblBpY2tlck1vZGFsKHRoaXMuYXBwLCAoaWNvbklkKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0XHR2b2lkIChhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmICghc2V0dGluZ3MuaGVscEJ1dHRvblJlcGxhY2VtZW50KSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0c2V0dGluZ3MuaGVscEJ1dHRvblJlcGxhY2VtZW50ID0ge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGNvbW1hbmRJZDogJ2VkaXQtYXN0cm8tY29uZmlnJyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGljb25JZDogJ3JvY2tldCcsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRzZXR0aW5ncy5oZWxwQnV0dG9uUmVwbGFjZW1lbnQuaWNvbklkID0gaWNvbklkO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gVHJpZ2dlciBoZWxwIGJ1dHRvbiByZXBsYWNlbWVudCB1cGRhdGUgaW1tZWRpYXRlbHkgKGl0IHdpbGwgcmVsb2FkIHNldHRpbmdzKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZiAodGhpcy5wbHVnaW4udXBkYXRlSGVscEJ1dHRvbikge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnVwZGF0ZUhlbHBCdXR0b24oKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBSZS1yZW5kZXIgdG8gc2hvdyB1cGRhdGVkIGljb24gbmFtZVxuXHRcdFx0XHRcdFx0XHRcdFx0XHR0aGlzLmRpc3BsYXkoKTtcblx0XHRcdFx0XHRcdFx0XHRcdH0pKCk7XG5cdFx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdFx0bW9kYWwub3BlbigpO1xuXHRcdFx0XHRcdFx0XHR9KSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMudXBkYXRlQ29weUhlYWRpbmdGaWVsZHMoKTtcblx0XHQvLyBPbmx5IHVwZGF0ZSB0ZXJtaW5hbC9jb25maWcgZmllbGRzIGlmIG5vdCBvbiBtb2JpbGVcblx0XHRpZiAoIVBsYXRmb3JtLmlzTW9iaWxlKSB7XG5cdFx0XHR0aGlzLnVwZGF0ZVRlcm1pbmFsQ29tbWFuZEZpZWxkcygpO1xuXHRcdFx0dGhpcy51cGRhdGVDb25maWdDb21tYW5kRmllbGRzKCk7XG5cdFx0fVxuXHR9XG5cblxuXHR1cGRhdGVDb3B5SGVhZGluZ0ZpZWxkcygpIHtcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xuXHRcdGNvbnN0IGlzVmlzaWJsZSA9IHNldHRpbmdzLmVuYWJsZUNvcHlIZWFkaW5nTGluaztcblxuXHRcdC8vIFVwZGF0ZSB0aGUgXCJEZWZhdWx0IGhlYWRpbmcgbGluayBmb3JtYXRcIiBzZXR0aW5nIGVsZW1lbnQgdmlzaWJpbGl0eVxuXHRcdGNvbnN0IGNvbnRhaW5lckVsID0gdGhpcy5jb250YWluZXJFbDtcblx0XHRjb25zdCBhbGxTZXR0aW5ncyA9IGNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5zZXR0aW5nLWl0ZW0nKTtcblx0XHRhbGxTZXR0aW5ncy5mb3JFYWNoKChzZXR0aW5nRWwpID0+IHtcblx0XHRcdGNvbnN0IG5hbWVFbCA9IHNldHRpbmdFbC5xdWVyeVNlbGVjdG9yKCcuc2V0dGluZy1pdGVtLW5hbWUnKTtcblx0XHRcdGlmIChuYW1lRWwgJiYgbmFtZUVsLnRleHRDb250ZW50Py50cmltKCkgPT09IFwiRGVmYXVsdCBoZWFkaW5nIGxpbmsgZm9ybWF0XCIpIHtcblx0XHRcdFx0c2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIGlzVmlzaWJsZSk7XG5cdFx0XHRcdHNldHRpbmdFbC5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFpc1Zpc2libGUpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHR9XG5cblx0dXBkYXRlVGVybWluYWxDb21tYW5kRmllbGRzKCkge1xuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XG5cdFx0Y29uc3QgaXNWaXNpYmxlID0gc2V0dGluZ3MuZW5hYmxlT3BlblRlcm1pbmFsQ29tbWFuZDtcblxuXHRcdC8vIFVwZGF0ZSBjb250YWluZXIgZm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHlcblx0XHRpZiAodGhpcy50ZXJtaW5hbENvbW1hbmRDb250YWluZXIpIHtcblx0XHRcdHRoaXMudGVybWluYWxDb21tYW5kQ29udGFpbmVyLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIGlzVmlzaWJsZSk7XG5cdFx0XHR0aGlzLnRlcm1pbmFsQ29tbWFuZENvbnRhaW5lci5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFpc1Zpc2libGUpO1xuXHRcdH1cblxuXHRcdC8vIFVwZGF0ZSBpbmRpdmlkdWFsIHNldHRpbmcgZWxlbWVudHMgdGhhdCBhcmUgaW4gdGhlIGdyb3VwXG5cdFx0Ly8gRmluZCBzZXR0aW5ncyBieSB0aGVpciBuYW1lIHRleHQgY29udGVudFxuXHRcdGNvbnN0IGNvbnRhaW5lckVsID0gdGhpcy5jb250YWluZXJFbDtcblx0XHRjb25zdCBhbGxTZXR0aW5ncyA9IGNvbnRhaW5lckVsLnF1ZXJ5U2VsZWN0b3JBbGwoJy5zZXR0aW5nLWl0ZW0nKTtcblx0XHRhbGxTZXR0aW5ncy5mb3JFYWNoKChzZXR0aW5nRWwpID0+IHtcblx0XHRcdGNvbnN0IG5hbWVFbCA9IHNldHRpbmdFbC5xdWVyeVNlbGVjdG9yKCcuc2V0dGluZy1pdGVtLW5hbWUnKTtcblx0XHRcdGlmIChuYW1lRWwpIHtcblx0XHRcdFx0Y29uc3QgbmFtZSA9IG5hbWVFbC50ZXh0Q29udGVudD8udHJpbSgpO1xuXHRcdFx0XHRpZiAobmFtZSA9PT0gXCJQcm9qZWN0IHJvb3QgZGlyZWN0b3J5IHBhdGhcIiB8fCBuYW1lID09PSBcIlNob3cgb3BlbiB0ZXJtaW5hbCByaWJib24gaWNvblwiKSB7XG5cdFx0XHRcdFx0c2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIGlzVmlzaWJsZSk7XG5cdFx0XHRcdFx0c2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci1oaWRkZW5cIiwgIWlzVmlzaWJsZSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIFVwZGF0ZSByaWJib24gdG9nZ2xlIGRpc2FibGVkIHN0YXRlIHVzaW5nIHRoZSB0b2dnbGUgY29tcG9uZW50XG5cdFx0aWYgKHRoaXMudGVybWluYWxSaWJib25Ub2dnbGVDb21wb25lbnQpIHtcblx0XHRcdHRoaXMudGVybWluYWxSaWJib25Ub2dnbGVDb21wb25lbnQuc2V0RGlzYWJsZWQoIXRoaXMucGx1Z2luLnNldHRpbmdzLmVuYWJsZU9wZW5UZXJtaW5hbENvbW1hbmQpO1xuXHRcdH1cblx0fVxuXG5cdHVwZGF0ZUNvbmZpZ0NvbW1hbmRGaWVsZHMoKSB7XG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncztcblx0XHRjb25zdCBpc1Zpc2libGUgPSBzZXR0aW5ncy5lbmFibGVPcGVuQ29uZmlnRmlsZUNvbW1hbmQ7XG5cblx0XHQvLyBVcGRhdGUgY29udGFpbmVyIGZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5XG5cdFx0aWYgKHRoaXMuY29uZmlnQ29tbWFuZENvbnRhaW5lcikge1xuXHRcdFx0dGhpcy5jb25maWdDb21tYW5kQ29udGFpbmVyLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIGlzVmlzaWJsZSk7XG5cdFx0XHR0aGlzLmNvbmZpZ0NvbW1hbmRDb250YWluZXIuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLWhpZGRlblwiLCAhaXNWaXNpYmxlKTtcblx0XHR9XG5cblx0XHQvLyBVcGRhdGUgaW5kaXZpZHVhbCBzZXR0aW5nIGVsZW1lbnRzIHRoYXQgYXJlIGluIHRoZSBncm91cFxuXHRcdC8vIEZpbmQgc2V0dGluZ3MgYnkgdGhlaXIgbmFtZSB0ZXh0IGNvbnRlbnRcblx0XHRjb25zdCBjb250YWluZXJFbCA9IHRoaXMuY29udGFpbmVyRWw7XG5cdFx0Y29uc3QgYWxsU2V0dGluZ3MgPSBjb250YWluZXJFbC5xdWVyeVNlbGVjdG9yQWxsKCcuc2V0dGluZy1pdGVtJyk7XG5cdFx0YWxsU2V0dGluZ3MuZm9yRWFjaCgoc2V0dGluZ0VsKSA9PiB7XG5cdFx0XHRjb25zdCBuYW1lRWwgPSBzZXR0aW5nRWwucXVlcnlTZWxlY3RvcignLnNldHRpbmctaXRlbS1uYW1lJyk7XG5cdFx0XHRpZiAobmFtZUVsKSB7XG5cdFx0XHRcdGNvbnN0IG5hbWUgPSBuYW1lRWwudGV4dENvbnRlbnQ/LnRyaW0oKTtcblx0XHRcdFx0aWYgKG5hbWUgPT09IFwiQ29uZmlnIGZpbGUgcGF0aFwiIHx8IG5hbWUgPT09IFwiU2hvdyBvcGVuIGNvbmZpZyByaWJib24gaWNvblwiKSB7XG5cdFx0XHRcdFx0c2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIGlzVmlzaWJsZSk7XG5cdFx0XHRcdFx0c2V0dGluZ0VsLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci1oaWRkZW5cIiwgIWlzVmlzaWJsZSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9KTtcblxuXHRcdC8vIFVwZGF0ZSByaWJib24gdG9nZ2xlIGRpc2FibGVkIHN0YXRlIHVzaW5nIHRoZSB0b2dnbGUgY29tcG9uZW50XG5cdFx0aWYgKHRoaXMuY29uZmlnUmliYm9uVG9nZ2xlQ29tcG9uZW50KSB7XG5cdFx0XHR0aGlzLmNvbmZpZ1JpYmJvblRvZ2dsZUNvbXBvbmVudC5zZXREaXNhYmxlZCghdGhpcy5wbHVnaW4uc2V0dGluZ3MuZW5hYmxlT3BlbkNvbmZpZ0ZpbGVDb21tYW5kKTtcblx0XHR9XG5cdH1cblxuXHRjaGVja0ZvckZvbGRlckNvbmZsaWN0cygpIHtcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xuXHRcdGNvbnN0IGJsYW5rRm9sZGVyczogc3RyaW5nW10gPSBbXTtcblx0XHRjb25zdCBmb2xkZXJDb25mbGljdHM6IHsgW2ZvbGRlcjogc3RyaW5nXTogc3RyaW5nW10gfSA9IHt9O1xuXG5cdFx0Ly8gQ2hlY2sgY29udGVudCB0eXBlc1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRmb3IgKGNvbnN0IGNvbnRlbnRUeXBlIG9mIGNvbnRlbnRUeXBlcykge1xuXHRcdFx0aWYgKGNvbnRlbnRUeXBlLmVuYWJsZWQpIHtcblx0XHRcdFx0aWYgKCFjb250ZW50VHlwZS5mb2xkZXIgfHwgY29udGVudFR5cGUuZm9sZGVyLnRyaW0oKSA9PT0gXCJcIikge1xuXHRcdFx0XHRcdGJsYW5rRm9sZGVycy5wdXNoKGNvbnRlbnRUeXBlLm5hbWUgfHwgXCJDb250ZW50XCIpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmICghZm9sZGVyQ29uZmxpY3RzW2NvbnRlbnRUeXBlLmZvbGRlcl0pIHtcblx0XHRcdFx0XHRcdGZvbGRlckNvbmZsaWN0c1tjb250ZW50VHlwZS5mb2xkZXJdID0gW107XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGZvbGRlckNvbmZsaWN0c1tjb250ZW50VHlwZS5mb2xkZXJdLnB1c2goY29udGVudFR5cGUubmFtZSB8fCBcIkNvbnRlbnRcIik7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDaGVjayBmb3IgY29uZmxpY3RzXG5cdFx0Ly8gV2FybmluZyBib3ggcmVtb3ZlZCAtIGNvbmZsaWN0cyBhcmUgc3RpbGwgZGV0ZWN0ZWQgYXQgcnVudGltZVxuXHR9XG5cblx0cHJpdmF0ZSBhZGRDdXN0b21Db250ZW50VHlwZSgpIHtcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBuZXdUeXBlOiBDb250ZW50VHlwZSA9IHtcblx0XHRcdGlkOiBgY29udGVudC0ke0RhdGUubm93KCl9YCxcblx0XHRcdG5hbWU6IGBDb250ZW50ICR7Y29udGVudFR5cGVzLmxlbmd0aCArIDF9YCxcblx0XHRcdGZvbGRlcjogXCJcIixcblx0XHRcdGxpbmtCYXNlUGF0aDogXCJcIixcblx0XHRcdHRlbXBsYXRlOiAnLS0tXFxudGl0bGU6IFwie3t0aXRsZX19XCJcXG5kYXRlOiB7e2RhdGV9fVxcbi0tLVxcbicsXG5cdFx0XHRlbmFibGVkOiB0cnVlLFxuXHRcdFx0Y3JlYXRpb25Nb2RlOiBcImZpbGVcIixcblx0XHRcdGluZGV4RmlsZU5hbWU6IFwiXCIsXG5cdFx0XHRpZ25vcmVTdWJmb2xkZXJzOiBmYWxzZSxcblx0XHRcdGVuYWJsZVVuZGVyc2NvcmVQcmVmaXg6IGZhbHNlLFxuXHRcdFx0dXNlTWR4RXh0ZW5zaW9uOiBmYWxzZSxcblx0XHRcdG1vZGlmaWVkRGF0ZUZpZWxkOiBcIlwiLFxuXHRcdH07XG5cdFx0Y29udGVudFR5cGVzLnB1c2gobmV3VHlwZSk7XG5cdFx0c2V0dGluZ3MuY29udGVudFR5cGVzID0gY29udGVudFR5cGVzO1xuXHRcdHZvaWQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0dGhpcy5yZW5kZXJDdXN0b21Db250ZW50VHlwZXMoKTtcblx0XHR0aGlzLnBsdWdpbi5yZWdpc3RlckNyZWF0ZUV2ZW50KCk7XG5cdFx0Ly8gUmUtcmVnaXN0ZXIgY29udGVudCB0eXBlIGNvbW1hbmRzIHRvIGluY2x1ZGUgdGhlIG5ldyB0eXBlXG5cdFx0cmVnaXN0ZXJDb250ZW50VHlwZUNvbW1hbmRzKHRoaXMucGx1Z2luIGFzIHVua25vd24gYXMgUGx1Z2luLCBzZXR0aW5ncyk7XG5cdH1cblxuXHRwcml2YXRlIHJlbmRlckN1c3RvbUNvbnRlbnRUeXBlcygpIHtcblx0XHRpZiAoIXRoaXMuY3VzdG9tQ29udGVudFR5cGVzQ29udGFpbmVyKSByZXR1cm47XG5cblx0XHR0aGlzLmN1c3RvbUNvbnRlbnRUeXBlc0NvbnRhaW5lci5lbXB0eSgpO1xuXG5cdFx0Ly8gQWx3YXlzIHJlYWQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gdG8gZW5zdXJlIHdlIGhhdmUgbGF0ZXN0IGRhdGFcblx0XHQvLyBUaGlzIGlzIGNyaXRpY2FsIGFmdGVyIG1pZ3JhdGlvblxuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XG5cdFx0Y29uc3QgY29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdGNvbnRlbnRUeXBlcy5mb3JFYWNoKChjdXN0b21UeXBlOiBDb250ZW50VHlwZSwgaW5kZXg6IG51bWJlcikgPT4ge1xuXHRcdFx0aWYgKCF0aGlzLmN1c3RvbUNvbnRlbnRUeXBlc0NvbnRhaW5lcikgcmV0dXJuO1xuXHRcdFx0Y29uc3QgdHlwZUNvbnRhaW5lciA9IHRoaXMuY3VzdG9tQ29udGVudFR5cGVzQ29udGFpbmVyLmNyZWF0ZURpdih7XG5cdFx0XHRcdGNsczogXCJjdXN0b20tY29udGVudC10eXBlLWl0ZW1cIixcblx0XHRcdFx0YXR0cjogeyBcImRhdGEtdHlwZS1pZFwiOiBjdXN0b21UeXBlLmlkIH1cblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBIZWFkZXIgd2l0aCBjb250cm9sc1xuXHRcdFx0Y29uc3QgaGVhZGVyID0gdHlwZUNvbnRhaW5lci5jcmVhdGVEaXYoeyBjbHM6IFwiY3VzdG9tLWNvbnRlbnQtdHlwZS1oZWFkZXJcIiB9KTtcblx0XHRcdGhlYWRlci5jbGFzc0xpc3QuYWRkKFwiYXN0cm8tY29tcG9zZXItY3VzdG9tLXR5cGUtaGVhZGVyXCIpO1xuXG5cdFx0XHQvLyBMZWZ0IHNpZGUgLSBjb2xsYXBzZS9leHBhbmQgYnV0dG9uXG5cdFx0XHRjb25zdCBjb2xsYXBzZUJ1dHRvbiA9IGhlYWRlci5jcmVhdGVFbChcImJ1dHRvblwiLCB7XG5cdFx0XHRcdGNsczogXCJhc3Ryby1jb21wb3Nlci1jb2xsYXBzZS1idXR0b25cIixcblx0XHRcdFx0YXR0cjogeyBcImFyaWEtbGFiZWxcIjogXCJDb2xsYXBzZS9leHBhbmRcIiB9XG5cdFx0XHR9KTtcblx0XHRcdGNvbnN0IGlzQ29sbGFwc2VkID0gY3VzdG9tVHlwZS5jb2xsYXBzZWQgPz8gZmFsc2U7XG5cdFx0XHQvLyBBbHdheXMgdXNlIGNoZXZyb24tZG93biwgcm90YXRlIGl0IHdoZW4gY29sbGFwc2VkIHRvIHBvaW50IHJpZ2h0XG5cdFx0XHRzZXRJY29uKGNvbGxhcHNlQnV0dG9uLCBcImNoZXZyb24tZG93blwiKTtcblx0XHRcdGlmIChpc0NvbGxhcHNlZCkge1xuXHRcdFx0XHRjb2xsYXBzZUJ1dHRvbi5jbGFzc0xpc3QuYWRkKFwiaXMtY29sbGFwc2VkXCIpO1xuXHRcdFx0fVxuXHRcdFx0Y29sbGFwc2VCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcblx0XHRcdFx0dm9pZCB0aGlzLnRvZ2dsZUNvbnRlbnRUeXBlQ29sbGFwc2UoY3VzdG9tVHlwZS5pZCk7XG5cdFx0XHRcdC8vIFVwZGF0ZSBjbGFzcyBhZnRlciB0b2dnbGUgKGljb24gc3RheXMgdGhlIHNhbWUsIGp1c3Qgcm90YXRlcylcblx0XHRcdFx0Y29uc3QgdXBkYXRlZFR5cGUgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncy5jb250ZW50VHlwZXMuZmluZCgoY3Q6IENvbnRlbnRUeXBlKSA9PiBjdC5pZCA9PT0gY3VzdG9tVHlwZS5pZCk7XG5cdFx0XHRcdGlmICh1cGRhdGVkVHlwZSkge1xuXHRcdFx0XHRcdGlmICh1cGRhdGVkVHlwZS5jb2xsYXBzZWQpIHtcblx0XHRcdFx0XHRcdGNvbGxhcHNlQnV0dG9uLmNsYXNzTGlzdC5hZGQoXCJpcy1jb2xsYXBzZWRcIik7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdGNvbGxhcHNlQnV0dG9uLmNsYXNzTGlzdC5yZW1vdmUoXCJpcy1jb2xsYXBzZWRcIik7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdFx0Ly8gTWlkZGxlIGxlZnQgLSBjb250ZW50IHR5cGUgbmFtZVxuXHRcdFx0Y29uc3QgaGVhZGVyTmFtZSA9IGhlYWRlci5jcmVhdGVEaXYoeyBjbHM6IFwiYXN0cm8tY29tcG9zZXItaGVhZGVyLW5hbWVcIiB9KTtcblx0XHRcdGhlYWRlck5hbWUuY3JlYXRlRWwoXCJkaXZcIiwgeyB0ZXh0OiBjdXN0b21UeXBlLm5hbWUgfHwgYENvbnRlbnQgJHtpbmRleCArIDF9YCwgY2xzOiBcInNldHRpbmctaXRlbS1uYW1lXCIgfSk7XG5cblx0XHRcdC8vIE1pZGRsZSByaWdodCAtIHVwL2Rvd24gYnV0dG9ucyAoc2lkZS1ieS1zaWRlKVxuXHRcdFx0Y29uc3QgcmVvcmRlckNvbnRhaW5lciA9IGhlYWRlci5jcmVhdGVEaXYoeyBjbHM6IFwiYXN0cm8tY29tcG9zZXItcmVvcmRlci1idXR0b25zXCIgfSk7XG5cdFx0XHRjb25zdCB1cEJ1dHRvbiA9IHJlb3JkZXJDb250YWluZXIuY3JlYXRlRWwoXCJidXR0b25cIiwge1xuXHRcdFx0XHRjbHM6IFwiYXN0cm8tY29tcG9zZXItcmVvcmRlci1idXR0b25cIixcblx0XHRcdFx0YXR0cjogeyBcImFyaWEtbGFiZWxcIjogXCJNb3ZlIHVwXCIgfVxuXHRcdFx0fSk7XG5cdFx0XHRzZXRJY29uKHVwQnV0dG9uLCBcImNoZXZyb24tdXBcIik7XG5cdFx0XHR1cEJ1dHRvbi5kaXNhYmxlZCA9IGluZGV4ID09PSAwO1xuXHRcdFx0dXBCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcblx0XHRcdFx0dm9pZCB0aGlzLm1vdmVDb250ZW50VHlwZVVwKGN1c3RvbVR5cGUuaWQpO1xuXHRcdFx0fSk7XG5cblx0XHRcdGNvbnN0IGRvd25CdXR0b24gPSByZW9yZGVyQ29udGFpbmVyLmNyZWF0ZUVsKFwiYnV0dG9uXCIsIHtcblx0XHRcdFx0Y2xzOiBcImFzdHJvLWNvbXBvc2VyLXJlb3JkZXItYnV0dG9uXCIsXG5cdFx0XHRcdGF0dHI6IHsgXCJhcmlhLWxhYmVsXCI6IFwiTW92ZSBkb3duXCIgfVxuXHRcdFx0fSk7XG5cdFx0XHRzZXRJY29uKGRvd25CdXR0b24sIFwiY2hldnJvbi1kb3duXCIpO1xuXHRcdFx0ZG93bkJ1dHRvbi5kaXNhYmxlZCA9IGluZGV4ID09PSBjb250ZW50VHlwZXMubGVuZ3RoIC0gMTtcblx0XHRcdGRvd25CdXR0b24uYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcblx0XHRcdFx0dm9pZCB0aGlzLm1vdmVDb250ZW50VHlwZURvd24oY3VzdG9tVHlwZS5pZCk7XG5cdFx0XHR9KTtcblxuXHRcdFx0Ly8gUmlnaHQgc2lkZSAtIHRvZ2dsZVxuXHRcdFx0Y29uc3QgdG9nZ2xlQ29udGFpbmVyID0gaGVhZGVyLmNyZWF0ZURpdih7IGNsczogXCJjaGVja2JveC1jb250YWluZXJcIiB9KTtcblx0XHRcdGlmIChjdXN0b21UeXBlLmVuYWJsZWQpIHtcblx0XHRcdFx0dG9nZ2xlQ29udGFpbmVyLmNsYXNzTGlzdC5hZGQoXCJpcy1lbmFibGVkXCIpO1xuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCB0b2dnbGUgPSB0b2dnbGVDb250YWluZXIuY3JlYXRlRWwoXCJpbnB1dFwiLCB7IHR5cGU6IFwiY2hlY2tib3hcIiwgY2xzOiBcImNoZWNrYm94LWlucHV0XCIgfSk7XG5cdFx0XHR0b2dnbGUuY2hlY2tlZCA9IGN1c3RvbVR5cGUuZW5hYmxlZDtcblxuXHRcdFx0Ly8gQWRkIGNsaWNrIGV2ZW50IHRvIHRoZSBjb250YWluZXIgYXMgd2VsbFxuXHRcdFx0dG9nZ2xlQ29udGFpbmVyLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCAoZSkgPT4ge1xuXHRcdFx0XHR2b2lkIChhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdGNvbnN0IG5ld1ZhbHVlID0gIWN1c3RvbVR5cGUuZW5hYmxlZDtcblx0XHRcdFx0XHRjdXN0b21UeXBlLmVuYWJsZWQgPSBuZXdWYWx1ZTtcblx0XHRcdFx0XHR0b2dnbGUuY2hlY2tlZCA9IG5ld1ZhbHVlO1xuXG5cdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0dGhpcy5wbHVnaW4ucmVnaXN0ZXJDcmVhdGVFdmVudCgpO1xuXG5cdFx0XHRcdFx0Ly8gVXBkYXRlIHRoZSBjb250YWluZXIgY2xhc3MgZm9yIHZpc3VhbCBmZWVkYmFja1xuXHRcdFx0XHRcdGlmIChuZXdWYWx1ZSkge1xuXHRcdFx0XHRcdFx0dG9nZ2xlQ29udGFpbmVyLmNsYXNzTGlzdC5hZGQoXCJpcy1lbmFibGVkXCIpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0b2dnbGVDb250YWluZXIuY2xhc3NMaXN0LnJlbW92ZShcImlzLWVuYWJsZWRcIik7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gVXBkYXRlIHZpc2liaWxpdHlcblx0XHRcdFx0XHR0aGlzLnVwZGF0ZUN1c3RvbUNvbnRlbnRUeXBlVmlzaWJpbGl0eShjdXN0b21UeXBlLmlkLCBuZXdWYWx1ZSk7XG5cblx0XHRcdFx0XHQvLyBSZS1yZWdpc3RlciBjb250ZW50IHR5cGUgY29tbWFuZHMgdG8gcmVmbGVjdCBlbmFibGVkL2Rpc2FibGVkIHN0YXRlXG5cdFx0XHRcdFx0cmVnaXN0ZXJDb250ZW50VHlwZUNvbW1hbmRzKHRoaXMucGx1Z2luIGFzIHVua25vd24gYXMgUGx1Z2luLCB0aGlzLnBsdWdpbi5zZXR0aW5ncyk7XG5cblx0XHRcdFx0XHQvLyBDb25mbGljdCBjaGVja2luZyByZW1vdmVkIGZyb20gc2V0dGluZ3MgVUlcblx0XHRcdFx0fSkoKTtcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBBbHNvIGFkZCBjaGFuZ2UgZXZlbnQgYXMgYmFja3VwXG5cdFx0XHR0b2dnbGUuYWRkRXZlbnRMaXN0ZW5lcihcImNoYW5nZVwiLCAoZSkgPT4ge1xuXHRcdFx0XHR2b2lkIChhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSAoZS50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkuY2hlY2tlZDtcblx0XHRcdFx0XHRjdXN0b21UeXBlLmVuYWJsZWQgPSB2YWx1ZTtcblx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHR0aGlzLnBsdWdpbi5yZWdpc3RlckNyZWF0ZUV2ZW50KCk7XG5cblx0XHRcdFx0XHQvLyBVcGRhdGUgdGhlIGNvbnRhaW5lciBjbGFzcyBmb3IgdmlzdWFsIGZlZWRiYWNrXG5cdFx0XHRcdFx0aWYgKHZhbHVlKSB7XG5cdFx0XHRcdFx0XHR0b2dnbGVDb250YWluZXIuY2xhc3NMaXN0LmFkZChcImlzLWVuYWJsZWRcIik7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRvZ2dsZUNvbnRhaW5lci5jbGFzc0xpc3QucmVtb3ZlKFwiaXMtZW5hYmxlZFwiKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBVcGRhdGUgdmlzaWJpbGl0eVxuXHRcdFx0XHRcdHRoaXMudXBkYXRlQ3VzdG9tQ29udGVudFR5cGVWaXNpYmlsaXR5KGN1c3RvbVR5cGUuaWQsIHZhbHVlKTtcblxuXHRcdFx0XHRcdC8vIFJlLXJlZ2lzdGVyIGNvbnRlbnQgdHlwZSBjb21tYW5kcyB0byByZWZsZWN0IGVuYWJsZWQvZGlzYWJsZWQgc3RhdGVcblx0XHRcdFx0XHRyZWdpc3RlckNvbnRlbnRUeXBlQ29tbWFuZHModGhpcy5wbHVnaW4gYXMgdW5rbm93biBhcyBQbHVnaW4sIHRoaXMucGx1Z2luLnNldHRpbmdzKTtcblx0XHRcdFx0fSkoKTtcblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBTZXR0aW5ncyBjb250YWluZXIgdGhhdCBjYW4gYmUgY29sbGFwc2VkXG5cdFx0XHRjb25zdCBzZXR0aW5nc0NvbnRhaW5lciA9IHR5cGVDb250YWluZXIuY3JlYXRlRGl2KHtcblx0XHRcdFx0Y2xzOiBcImN1c3RvbS1jb250ZW50LXR5cGUtc2V0dGluZ3NcIixcblx0XHRcdFx0YXR0cjogeyBcImRhdGEtdHlwZS1pZFwiOiBjdXN0b21UeXBlLmlkIH1cblx0XHRcdH0pO1xuXG5cdFx0XHQvLyBTZXQgaW5pdGlhbCB2aXNpYmlsaXR5IHN0YXRlIGJhc2VkIG9uIGVuYWJsZWQgYW5kIGNvbGxhcHNlZCBzdGF0ZVxuXHRcdFx0Y29uc3QgaW5pdGlhbGx5Q29sbGFwc2VkID0gY3VzdG9tVHlwZS5jb2xsYXBzZWQgPz8gZmFsc2U7XG5cdFx0XHRjb25zdCBpbml0aWFsbHlWaXNpYmxlID0gY3VzdG9tVHlwZS5lbmFibGVkICYmICFpbml0aWFsbHlDb2xsYXBzZWQ7XG5cdFx0XHRpZiAoaW5pdGlhbGx5VmlzaWJsZSkge1xuXHRcdFx0XHRzZXR0aW5nc0NvbnRhaW5lci5jbGFzc0xpc3QuYWRkKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItdmlzaWJsZVwiKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHNldHRpbmdzQ29udGFpbmVyLmNsYXNzTGlzdC5hZGQoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci1oaWRkZW5cIik7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvbnRlbnQgdHlwZSBuYW1lXG5cdFx0XHRjb25zdCBuYW1lQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRuZXcgU2V0dGluZyhuYW1lQ29udGFpbmVyKVxuXHRcdFx0XHQuc2V0TmFtZShcIkNvbnRlbnQgdHlwZSBuYW1lXCIpXG5cdFx0XHRcdC5zZXREZXNjKFwiRGlzcGxheSBuYW1lIGZvciB0aGlzIGNvbnRlbnQgdHlwZSAoJ3Byb2plY3RzJywgJ25vdGVzJywgJ3R1dG9yaWFscycpXCIpXG5cdFx0XHRcdC5hZGRUZXh0KHRleHQgPT4ge1xuXHRcdFx0XHRcdHRleHRcblx0XHRcdFx0XHRcdC5zZXRQbGFjZWhvbGRlcihcIkVudGVyIGNvbnRlbnQgdHlwZSBuYW1lXCIpXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoY3VzdG9tVHlwZS5uYW1lKVxuXHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogc3RyaW5nKSA9PiB7XG5cdFx0XHRcdFx0XHRcdGN1c3RvbVR5cGUubmFtZSA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdFx0Ly8gUmUtcmVnaXN0ZXIgY29udGVudCB0eXBlIGNvbW1hbmRzIHRvIHVwZGF0ZSBjb21tYW5kIG5hbWVcblx0XHRcdFx0XHRcdFx0cmVnaXN0ZXJDb250ZW50VHlwZUNvbW1hbmRzKHRoaXMucGx1Z2luIGFzIHVua25vd24gYXMgUGx1Z2luLCB0aGlzLnBsdWdpbi5zZXR0aW5ncyk7XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fSk7XG5cblx0XHRcdC8vIEZvbGRlciBsb2NhdGlvblxuXHRcdFx0Y29uc3QgZm9sZGVyQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRjb25zdCBmb2xkZXJTZXR0aW5nID0gbmV3IFNldHRpbmcoZm9sZGVyQ29udGFpbmVyKVxuXHRcdFx0XHQuc2V0TmFtZShcIkZvbGRlciBsb2NhdGlvblwiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIkZvbGRlciBwYXRoIHdoZXJlIHRoaXMgY29udGVudCB0eXBlIHdpbGwgYmUgY3JlYXRlZC4gTGVhdmUgYmxhbmsgdG8gdXNlIHRoZSB2YXVsdCBmb2xkZXIuIFN1cHBvcnRzIHdpbGRjYXJkcyBsaWtlIGRpcmVjdG9yeS8qIG9yIGRpcmVjdG9yeS8qLyogdG8gbWF0Y2ggc3BlY2lmaWMgZm9sZGVyIGRlcHRocy5cIilcblx0XHRcdFx0LmFkZFRleHQodGV4dCA9PiB7XG5cdFx0XHRcdFx0dGV4dFxuXHRcdFx0XHRcdFx0LnNldFBsYWNlaG9sZGVyKFwiRW50ZXIgZm9sZGVyIHBhdGggKCdkb2NzJywgJ2RvY3MvKicsICdkb2NzLyovKicpIG9yIGxlYXZlIGJsYW5rIGZvciB2YXVsdCByb290XCIpXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoY3VzdG9tVHlwZS5mb2xkZXIpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0Y3VzdG9tVHlwZS5mb2xkZXIgPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHRcdHRoaXMucGx1Z2luLnJlZ2lzdGVyQ3JlYXRlRXZlbnQoKTtcblx0XHRcdFx0XHRcdFx0dGhpcy51cGRhdGVDdXN0b21Db250ZW50VHlwZUlnbm9yZVN1YmZvbGRlcnNGaWVsZChjdXN0b21UeXBlLmlkKTtcblx0XHRcdFx0XHRcdFx0Ly8gVXBkYXRlIGNvbmZsaWN0IHdhcm5pbmdzIGZvciBhbGwgY29udGVudCB0eXBlcyAoZm9sZGVyIGNoYW5nZSBtYXkgYWZmZWN0IG90aGVycylcblx0XHRcdFx0XHRcdFx0Y29uc3QgYWxsQ29udGVudFR5cGVzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdFx0XHRcdFx0XHRmb3IgKGNvbnN0IGN0IG9mIGFsbENvbnRlbnRUeXBlcykge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMudXBkYXRlRm9sZGVyQ29uZmxpY3RXYXJuaW5nKGN0LmlkLCBudWxsKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pO1xuXG5cdFx0XHQvLyBBZGQgY29uZmxpY3Qgd2FybmluZyBlbGVtZW50XG5cdFx0XHRmb2xkZXJDb250YWluZXIuY3JlYXRlRGl2KHsgY2xzOiBcImFzdHJvLWNvbXBvc2VyLWNvbmZsaWN0LXdhcm5pbmcgaGlkZGVuXCIsIGF0dHI6IHsgXCJkYXRhLXR5cGUtaWRcIjogY3VzdG9tVHlwZS5pZCB9IH0pO1xuXHRcdFx0dGhpcy51cGRhdGVGb2xkZXJDb25mbGljdFdhcm5pbmcoY3VzdG9tVHlwZS5pZCwgZm9sZGVyU2V0dGluZyk7XG5cblx0XHRcdC8vIElnbm9yZSBzdWJmb2xkZXJzIChvbmx5IHNob3cgd2hlbiBmb2xkZXIgaXMgc2V0KVxuXHRcdFx0Y29uc3QgaWdub3JlU3ViZm9sZGVyc0NvbnRhaW5lciA9IHNldHRpbmdzQ29udGFpbmVyLmNyZWF0ZURpdih7IGNsczogXCJjdXN0b20taWdub3JlLXN1YmZvbGRlcnMtZmllbGRcIiB9KTtcblx0XHRcdGlnbm9yZVN1YmZvbGRlcnNDb250YWluZXIuc2V0QXR0cmlidXRlKFwiZGF0YS10eXBlLWlkXCIsIGN1c3RvbVR5cGUuaWQpO1xuXHRcdFx0aWdub3JlU3ViZm9sZGVyc0NvbnRhaW5lci5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItdmlzaWJsZVwiLCAhIWN1c3RvbVR5cGUuZm9sZGVyKTtcblx0XHRcdGlnbm9yZVN1YmZvbGRlcnNDb250YWluZXIuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLWhpZGRlblwiLCAhY3VzdG9tVHlwZS5mb2xkZXIpO1xuXHRcdFx0bmV3IFNldHRpbmcoaWdub3JlU3ViZm9sZGVyc0NvbnRhaW5lcilcblx0XHRcdFx0LnNldE5hbWUoXCJJZ25vcmUgc3ViZm9sZGVyc1wiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIldoZW4gZW5hYmxlZCwgYXV0b21hdGlvbiB3aWxsIG9ubHkgdHJpZ2dlciBmb3IgbmV3IC5tZCBmaWxlcyB3aXRoaW4gdGhpcyBjb250ZW50IHR5cGUncyBmb2xkZXIgYW5kIG9uZSBsZXZlbCBkb3duIChmb3IgZm9sZGVyLWJhc2VkIGNvbnRlbnQpLiBGaWxlcyBpbiBkZWVwZXIgc3ViZm9sZGVycyB3aWxsIGJlIGlnbm9yZWQuXCIpXG5cdFx0XHRcdC5hZGRUb2dnbGUodG9nZ2xlID0+XG5cdFx0XHRcdFx0dG9nZ2xlXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoY3VzdG9tVHlwZS5pZ25vcmVTdWJmb2xkZXJzIHx8IGZhbHNlKVxuXHRcdFx0XHRcdFx0Lm9uQ2hhbmdlKGFzeW5jICh2YWx1ZTogYm9vbGVhbikgPT4ge1xuXHRcdFx0XHRcdFx0XHRjdXN0b21UeXBlLmlnbm9yZVN1YmZvbGRlcnMgPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHQpO1xuXG5cdFx0XHQvLyBVbmRlcnNjb3JlIHByZWZpeFxuXHRcdFx0Y29uc3QgdW5kZXJzY29yZVByZWZpeENvbnRhaW5lciA9IHNldHRpbmdzQ29udGFpbmVyLmNyZWF0ZURpdigpO1xuXHRcdFx0bmV3IFNldHRpbmcodW5kZXJzY29yZVByZWZpeENvbnRhaW5lcilcblx0XHRcdFx0LnNldE5hbWUoXCJVc2UgdW5kZXJzY29yZSBwcmVmaXggZm9yIGRyYWZ0c1wiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIkFkZCBhbiB1bmRlcnNjb3JlIHByZWZpeCAoX2NvbnRlbnQtdGl0bGUpIHRvIG5ldyBub3RlcyBieSBkZWZhdWx0IHdoZW4gZW5hYmxlZC4gVGhpcyBoaWRlcyB0aGVtIGZyb20gYXN0cm8sIHdoaWNoIGNhbiBiZSBoZWxwZnVsIGZvciBkcmFmdHNcIilcblx0XHRcdFx0LmFkZFRvZ2dsZSh0b2dnbGUgPT5cblx0XHRcdFx0XHR0b2dnbGVcblx0XHRcdFx0XHRcdC5zZXRWYWx1ZShjdXN0b21UeXBlLmVuYWJsZVVuZGVyc2NvcmVQcmVmaXggfHwgZmFsc2UpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBib29sZWFuKSA9PiB7XG5cdFx0XHRcdFx0XHRcdGN1c3RvbVR5cGUuZW5hYmxlVW5kZXJzY29yZVByZWZpeCA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdCk7XG5cblx0XHRcdC8vIExpbmsgYmFzZSBwYXRoXG5cdFx0XHRjb25zdCBsaW5rQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRuZXcgU2V0dGluZyhsaW5rQ29udGFpbmVyKVxuXHRcdFx0XHQuc2V0TmFtZShcIkxpbmsgYmFzZSBwYXRoXCIpXG5cdFx0XHRcdC5zZXREZXNjKFwiQmFzZSBwYXRoIGZvciBjb252ZXJ0ZWQgbGlua3MgKCcvcHJvamVjdHMvJywgJy9ub3Rlcy90dXRvcmlhbHMvJywgbGVhdmUgYmxhbmsgZm9yIHJvb3QgLykuXCIpXG5cdFx0XHRcdC5hZGRUZXh0KHRleHQgPT4ge1xuXHRcdFx0XHRcdHRleHRcblx0XHRcdFx0XHRcdC5zZXRQbGFjZWhvbGRlcihcIkVudGVyIGxpbmsgYmFzZSBwYXRoXCIpXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoY3VzdG9tVHlwZS5saW5rQmFzZVBhdGggfHwgXCJcIilcblx0XHRcdFx0XHRcdC5vbkNoYW5nZShhc3luYyAodmFsdWU6IHN0cmluZykgPT4ge1xuXHRcdFx0XHRcdFx0XHRjdXN0b21UeXBlLmxpbmtCYXNlUGF0aCA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0Ly8gQ3JlYXRpb24gbW9kZVxuXHRcdFx0Y29uc3QgY3JlYXRpb25Nb2RlQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRuZXcgU2V0dGluZyhjcmVhdGlvbk1vZGVDb250YWluZXIpXG5cdFx0XHRcdC5zZXROYW1lKFwiQ3JlYXRpb24gbW9kZVwiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIkhvdyB0byBjcmVhdGUgbmV3IGVudHJpZXM6IGZpbGUtYmFzZWQgb3IgZm9sZGVyLWJhc2VkIHdpdGggYW4gaW5kZXggZmlsZS5cIilcblx0XHRcdFx0LmFkZERyb3Bkb3duKGRyb3Bkb3duID0+XG5cdFx0XHRcdFx0ZHJvcGRvd25cblx0XHRcdFx0XHRcdC5hZGRPcHRpb24oXCJmaWxlXCIsIFwiRmlsZS1iYXNlZCAoY29udGVudC10aXRsZS5tZClcIilcblx0XHRcdFx0XHRcdC5hZGRPcHRpb24oXCJmb2xkZXJcIiwgXCJGb2xkZXItYmFzZWQgKGNvbnRlbnQtdGl0bGUvaW5kZXgubWQpXCIpXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoY3VzdG9tVHlwZS5jcmVhdGlvbk1vZGUpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0Y3VzdG9tVHlwZS5jcmVhdGlvbk1vZGUgPSB2YWx1ZSBhcyBcImZpbGVcIiB8IFwiZm9sZGVyXCI7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0XHR0aGlzLnVwZGF0ZUN1c3RvbUNvbnRlbnRUeXBlSW5kZXhGaWxlRmllbGQoY3VzdG9tVHlwZS5pZCk7XG5cdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHQpO1xuXG5cdFx0XHQvLyBJbmRleCBmaWxlIG5hbWUgKG9ubHkgc2hvdyBmb3IgZm9sZGVyLWJhc2VkKVxuXHRcdFx0Y29uc3QgaW5kZXhGaWxlQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KHsgY2xzOiBcImN1c3RvbS1pbmRleC1maWxlLWZpZWxkXCIgfSk7XG5cdFx0XHRpbmRleEZpbGVDb250YWluZXIuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLXZpc2libGVcIiwgY3VzdG9tVHlwZS5jcmVhdGlvbk1vZGUgPT09IFwiZm9sZGVyXCIpO1xuXHRcdFx0aW5kZXhGaWxlQ29udGFpbmVyLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci1oaWRkZW5cIiwgY3VzdG9tVHlwZS5jcmVhdGlvbk1vZGUgIT09IFwiZm9sZGVyXCIpO1xuXHRcdFx0bmV3IFNldHRpbmcoaW5kZXhGaWxlQ29udGFpbmVyKVxuXHRcdFx0XHQuc2V0TmFtZShcIkluZGV4IGZpbGUgbmFtZVwiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIk5hbWUgZm9yIGluZGV4IGZpbGVzIGluIGZvbGRlci1iYXNlZCBjb250ZW50ICh3aXRob3V0IC5tZCBleHRlbnNpb24pLiBEZWZhdWx0cyB0byAnaW5kZXgnIGlmIGxlZnQgYmxhbmsuXCIpXG5cdFx0XHRcdC5hZGRUZXh0KHRleHQgPT5cblx0XHRcdFx0XHR0ZXh0XG5cdFx0XHRcdFx0XHQuc2V0UGxhY2Vob2xkZXIoXCJpbmRleFwiKVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKGN1c3RvbVR5cGUuaW5kZXhGaWxlTmFtZSlcblx0XHRcdFx0XHRcdC5vbkNoYW5nZShhc3luYyAodmFsdWU6IHN0cmluZykgPT4ge1xuXHRcdFx0XHRcdFx0XHRjdXN0b21UeXBlLmluZGV4RmlsZU5hbWUgPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0XHRcdFx0XHR9KVxuXHRcdFx0XHQpO1xuXG5cdFx0XHQvLyBVc2UgTURYIGV4dGVuc2lvblxuXHRcdFx0Y29uc3QgdXNlTWR4Q29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRuZXcgU2V0dGluZyh1c2VNZHhDb250YWluZXIpXG5cdFx0XHRcdC8vIFwiTURYXCIgaXMgYSBwcm9wZXIgbm91biAoZmlsZSBmb3JtYXQpIGFuZCBzaG91bGQgYmUgY2FwaXRhbGl6ZWRcblx0XHRcdFx0LnNldE5hbWUoXCJVc2UgTURYIGluc3RlYWQgb2YgTURcIilcblx0XHRcdFx0LnNldERlc2MoXCJDcmVhdGUgZmlsZXMgd2l0aCAubWR4IGV4dGVuc2lvbiBpbnN0ZWFkIG9mIC5tZCBleHRlbnNpb24uXCIpXG5cdFx0XHRcdC5hZGRUb2dnbGUodG9nZ2xlID0+XG5cdFx0XHRcdFx0dG9nZ2xlXG5cdFx0XHRcdFx0XHQuc2V0VmFsdWUoY3VzdG9tVHlwZS51c2VNZHhFeHRlbnNpb24gfHwgZmFsc2UpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBib29sZWFuKSA9PiB7XG5cdFx0XHRcdFx0XHRcdGN1c3RvbVR5cGUudXNlTWR4RXh0ZW5zaW9uID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblxuXHRcdFx0Ly8gTW9kaWZpZWQgZGF0ZSBwcm9wZXJ0eVxuXHRcdFx0Y29uc3QgbW9kaWZpZWREYXRlQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRuZXcgU2V0dGluZyhtb2RpZmllZERhdGVDb250YWluZXIpXG5cdFx0XHRcdC5zZXROYW1lKFwiTW9kaWZpZWQgZGF0ZSBwcm9wZXJ0eVwiKVxuXHRcdFx0XHQuc2V0RGVzYyhcIlRoZSBwcm9wZXJ0eSBmaWVsZCB0byB1cGRhdGUgd2l0aCB0aGUgbW9kaWZpZWQgZGF0ZSBmb3IgdGhpcyBjb250ZW50IHR5cGUuIExlYXZlIGJsYW5rIHRvIGRpc2FibGUuXCIpXG5cdFx0XHRcdC5hZGRUZXh0KHRleHQgPT5cblx0XHRcdFx0XHR0ZXh0XG5cdFx0XHRcdFx0XHQuc2V0UGxhY2Vob2xkZXIoXCJtb2RpZmllZFwiKVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKGN1c3RvbVR5cGUubW9kaWZpZWREYXRlRmllbGQgfHwgXCJcIilcblx0XHRcdFx0XHRcdC5vbkNoYW5nZShhc3luYyAodmFsdWU6IHN0cmluZykgPT4ge1xuXHRcdFx0XHRcdFx0XHRjdXN0b21UeXBlLm1vZGlmaWVkRGF0ZUZpZWxkID0gdmFsdWU7XG5cdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdFx0XHRcdFx0fSlcblx0XHRcdFx0KTtcblxuXHRcdFx0Ly8gVGVtcGxhdGVcblx0XHRcdGNvbnN0IHRlbXBsYXRlQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRuZXcgU2V0dGluZyh0ZW1wbGF0ZUNvbnRhaW5lcilcblx0XHRcdFx0LnNldE5hbWUoXCJQcm9wZXJ0aWVzIHRlbXBsYXRlXCIpXG5cdFx0XHRcdC5hZGRUZXh0QXJlYSh0ZXh0ID0+IHtcblx0XHRcdFx0XHR0ZXh0XG5cdFx0XHRcdFx0XHQuc2V0UGxhY2Vob2xkZXIoJy0tLVxcbnRpdGxlOiBcInt7dGl0bGV9fVwiXFxuZGF0ZToge3tkYXRlfX1cXG4tLS1cXG4nKVxuXHRcdFx0XHRcdFx0LnNldFZhbHVlKGN1c3RvbVR5cGUudGVtcGxhdGUpXG5cdFx0XHRcdFx0XHQub25DaGFuZ2UoYXN5bmMgKHZhbHVlOiBzdHJpbmcpID0+IHtcblx0XHRcdFx0XHRcdFx0Y3VzdG9tVHlwZS50ZW1wbGF0ZSA9IHZhbHVlO1xuXHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdHRleHQuaW5wdXRFbC5jbGFzc0xpc3QuYWRkKFwiYXN0cm8tY29tcG9zZXItdGVtcGxhdGUtdGV4dGFyZWFcIik7XG5cdFx0XHRcdFx0cmV0dXJuIHRleHQ7XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC50aGVuKChzZXR0aW5nKSA9PiB7XG5cdFx0XHRcdFx0c2V0dGluZy5kZXNjRWwuZW1wdHkoKTtcblx0XHRcdFx0XHRjb25zdCBkZXNjRGl2ID0gc2V0dGluZy5kZXNjRWwuY3JlYXRlRWwoXCJkaXZcIik7XG5cdFx0XHRcdFx0ZGVzY0Rpdi5jcmVhdGVFbChcImRpdlwiLCB7IHRleHQ6IFwiVGVtcGxhdGUgZm9yIG5ldyBmaWxlcyBvZiB0aGlzIGNvbnRlbnQgdHlwZS5cIiB9KTtcblx0XHRcdFx0XHRkZXNjRGl2LmNyZWF0ZUVsKFwiZGl2XCIsIHsgdGV4dDogXCJWYXJpYWJsZXMgaW5jbHVkZSB7e3RpdGxlfX0sIHt7ZGF0ZX19LCBhbmQge3tzbHVnfX0uXCIgfSk7XG5cdFx0XHRcdFx0ZGVzY0Rpdi5jcmVhdGVFbChcImRpdlwiLCB7IHRleHQ6IFwiRG8gbm90IHdyYXAge3tkYXRlfX0gaW4gcXVvdGVzIGFzIGl0IHJlcHJlc2VudHMgYSBkYXRldGltZSB2YWx1ZSwgbm90IGEgc3RyaW5nLlwiIH0pO1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0Ly8gUmVtb3ZlIGJ1dHRvbiBhdCB0aGUgYm90dG9tIChubyBkaXZpZGVyKVxuXHRcdFx0Y29uc3QgcmVtb3ZlQ29udGFpbmVyID0gc2V0dGluZ3NDb250YWluZXIuY3JlYXRlRGl2KCk7XG5cdFx0XHRjb25zdCByZW1vdmVTZXR0aW5nID0gbmV3IFNldHRpbmcocmVtb3ZlQ29udGFpbmVyKVxuXHRcdFx0XHQuc2V0TmFtZShcIlwiKVxuXHRcdFx0XHQuYWRkQnV0dG9uKGJ1dHRvbiA9PiB7XG5cdFx0XHRcdFx0YnV0dG9uXG5cdFx0XHRcdFx0XHQuc2V0QnV0dG9uVGV4dChcIlJlbW92ZVwiKVxuXHRcdFx0XHRcdFx0LnNldFdhcm5pbmcoKVxuXHRcdFx0XHRcdFx0Lm9uQ2xpY2soYXN5bmMgKCkgPT4ge1xuXHRcdFx0XHRcdFx0XHRjb25zdCBjb250ZW50VHlwZSA9IHRoaXMucGx1Z2luLnNldHRpbmdzLmNvbnRlbnRUeXBlcy5maW5kKGN0ID0+IGN0LmlkID09PSBjdXN0b21UeXBlLmlkKTtcblx0XHRcdFx0XHRcdFx0Y29uc3QgdHlwZU5hbWUgPSBjb250ZW50VHlwZT8ubmFtZSB8fCBcImNvbnRlbnQgdHlwZVwiO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBtb2RhbCA9IG5ldyBDb25maXJtTW9kYWwoXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5hcHAsXG5cdFx0XHRcdFx0XHRcdFx0YEFyZSB5b3Ugc3VyZSB5b3Ugd2FudCB0byByZW1vdmUgXCIke3R5cGVOYW1lfVwiPyBUaGlzIGFjdGlvbiBjYW5ub3QgYmUgdW5kb25lLmAsXG5cdFx0XHRcdFx0XHRcdFx0XCJSZW1vdmVcIixcblx0XHRcdFx0XHRcdFx0XHRcIkNhbmNlbFwiXG5cdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IGNvbmZpcm1lZCA9IGF3YWl0IG1vZGFsLndhaXRGb3JSZXN1bHQoKTtcblx0XHRcdFx0XHRcdFx0aWYgKGNvbmZpcm1lZCkge1xuXHRcdFx0XHRcdFx0XHRcdGF3YWl0IHRoaXMucmVtb3ZlQ3VzdG9tQ29udGVudFR5cGUoY3VzdG9tVHlwZS5pZCk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9KTtcblxuXHRcdFx0Ly8gSGlkZSB0aGUgZGl2aWRlciBsaW5lIGZvciB0aGUgcmVtb3ZlIGJ1dHRvblxuXHRcdFx0cmVtb3ZlU2V0dGluZy5zZXR0aW5nRWwuY2xhc3NMaXN0LmFkZChcImFzdHJvLWNvbXBvc2VyLXJlbW92ZS1zZXR0aW5nXCIpO1xuXG5cdFx0XHQvLyBTZXQgaW5pdGlhbCB2aXNpYmlsaXR5IChjaGVja3MgYm90aCBlbmFibGVkIGFuZCBjb2xsYXBzZWQgc3RhdGUpXG5cdFx0XHR0aGlzLnVwZGF0ZUN1c3RvbUNvbnRlbnRUeXBlVmlzaWJpbGl0eShjdXN0b21UeXBlLmlkLCBjdXN0b21UeXBlLmVuYWJsZWQpO1xuXHRcdH0pO1xuXG5cdFx0Ly8gVXBkYXRlIGNvbmZsaWN0IHdhcm5pbmdzIGZvciBhbGwgdHlwZXMgYWZ0ZXIgcmVuZGVyaW5nIChmb2xkZXIgY2hhbmdlcyBtYXkgYWZmZWN0IG90aGVycylcblx0XHRjb250ZW50VHlwZXMuZm9yRWFjaCgoY3VzdG9tVHlwZTogQ29udGVudFR5cGUpID0+IHtcblx0XHRcdHRoaXMudXBkYXRlRm9sZGVyQ29uZmxpY3RXYXJuaW5nKGN1c3RvbVR5cGUuaWQsIG51bGwpO1xuXHRcdH0pO1xuXG5cdFx0Ly8gQWRkIGZsb2F0aW5nIGJ1dHRvbiBmb3IgY3JlYXRpbmcgbmV3IGN1c3RvbSBjb250ZW50IHR5cGVzIChubyBzZXR0aW5ncyBiYWNrZ3JvdW5kKVxuXHRcdGNvbnN0IGFkZEJ1dHRvbkNvbnRhaW5lciA9IHRoaXMuY3VzdG9tQ29udGVudFR5cGVzQ29udGFpbmVyLmNyZWF0ZURpdih7IGNsczogXCJhc3Ryby1jb21wb3Nlci1hZGQtYnV0dG9uLWNvbnRhaW5lclwiIH0pO1xuXHRcdGNvbnN0IGFkZEJ1dHRvbiA9IGFkZEJ1dHRvbkNvbnRhaW5lci5jcmVhdGVFbChcImJ1dHRvblwiLCB7XG5cdFx0XHRjbHM6IFwibW9kLWN0YVwiLFxuXHRcdFx0dGV4dDogXCJBZGQgY29udGVudCB0eXBlXCJcblx0XHR9KTtcblx0XHRhZGRCdXR0b24uYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsICgpID0+IHtcblx0XHRcdHRoaXMuYWRkQ3VzdG9tQ29udGVudFR5cGUoKTtcblx0XHR9KTtcblx0fVxuXG5cdHByaXZhdGUgdXBkYXRlQ3VzdG9tQ29udGVudFR5cGVWaXNpYmlsaXR5KHR5cGVJZDogc3RyaW5nLCBlbmFibGVkOiBib29sZWFuKSB7XG5cdFx0Y29uc3Qgc2V0dGluZ3NDb250YWluZXIgPSB0aGlzLmN1c3RvbUNvbnRlbnRUeXBlc0NvbnRhaW5lcj8ucXVlcnlTZWxlY3RvcihgW2RhdGEtdHlwZS1pZD1cIiR7dHlwZUlkfVwiXS5jdXN0b20tY29udGVudC10eXBlLXNldHRpbmdzYCkgYXMgSFRNTEVsZW1lbnQ7XG5cdFx0aWYgKHNldHRpbmdzQ29udGFpbmVyKSB7XG5cdFx0XHRjb25zdCBjb250ZW50VHlwZXMgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncy5jb250ZW50VHlwZXMgfHwgW107XG5cdFx0XHRjb25zdCBjb250ZW50VHlwZSA9IGNvbnRlbnRUeXBlcy5maW5kKChjdDogQ29udGVudFR5cGUpID0+IGN0LmlkID09PSB0eXBlSWQpO1xuXHRcdFx0Y29uc3QgaXNDb2xsYXBzZWQgPSBjb250ZW50VHlwZT8uY29sbGFwc2VkID8/IGZhbHNlO1xuXHRcdFx0Y29uc3Qgc2hvdWxkQmVWaXNpYmxlID0gZW5hYmxlZCAmJiAhaXNDb2xsYXBzZWQ7XG5cblx0XHRcdHNldHRpbmdzQ29udGFpbmVyLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIHNob3VsZEJlVmlzaWJsZSk7XG5cdFx0XHRzZXR0aW5nc0NvbnRhaW5lci5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFzaG91bGRCZVZpc2libGUpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgdXBkYXRlQ3VzdG9tQ29udGVudFR5cGVJbmRleEZpbGVGaWVsZCh0eXBlSWQ6IHN0cmluZykge1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHRoaXMucGx1Z2luLnNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBjdXN0b21UeXBlID0gY29udGVudFR5cGVzLmZpbmQodHlwZSA9PiB0eXBlLmlkID09PSB0eXBlSWQpO1xuXHRcdGlmICghY3VzdG9tVHlwZSkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgaW5kZXhGaWxlQ29udGFpbmVyID0gdGhpcy5jdXN0b21Db250ZW50VHlwZXNDb250YWluZXI/LnF1ZXJ5U2VsZWN0b3IoYFtkYXRhLXR5cGUtaWQ9XCIke3R5cGVJZH1cIl0gLmN1c3RvbS1pbmRleC1maWxlLWZpZWxkYCkgYXMgSFRNTEVsZW1lbnQ7XG5cdFx0aWYgKGluZGV4RmlsZUNvbnRhaW5lcikge1xuXHRcdFx0aW5kZXhGaWxlQ29udGFpbmVyLmNsYXNzTGlzdC50b2dnbGUoXCJhc3Ryby1jb21wb3Nlci1zZXR0aW5nLWNvbnRhaW5lci12aXNpYmxlXCIsIGN1c3RvbVR5cGUuY3JlYXRpb25Nb2RlID09PSBcImZvbGRlclwiKTtcblx0XHRcdGluZGV4RmlsZUNvbnRhaW5lci5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsIGN1c3RvbVR5cGUuY3JlYXRpb25Nb2RlICE9PSBcImZvbGRlclwiKTtcblx0XHR9XG5cdH1cblxuXHRwcml2YXRlIHVwZGF0ZUN1c3RvbUNvbnRlbnRUeXBlSWdub3JlU3ViZm9sZGVyc0ZpZWxkKHR5cGVJZDogc3RyaW5nKSB7XG5cdFx0Y29uc3QgY29udGVudFR5cGVzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdGNvbnN0IGN1c3RvbVR5cGUgPSBjb250ZW50VHlwZXMuZmluZCh0eXBlID0+IHR5cGUuaWQgPT09IHR5cGVJZCk7XG5cdFx0aWYgKCFjdXN0b21UeXBlKSByZXR1cm47XG5cblx0XHRjb25zdCBpZ25vcmVTdWJmb2xkZXJzQ29udGFpbmVyID0gdGhpcy5jdXN0b21Db250ZW50VHlwZXNDb250YWluZXI/LnF1ZXJ5U2VsZWN0b3IoYFtkYXRhLXR5cGUtaWQ9XCIke3R5cGVJZH1cIl0uY3VzdG9tLWlnbm9yZS1zdWJmb2xkZXJzLWZpZWxkYCkgYXMgSFRNTEVsZW1lbnQ7XG5cdFx0aWYgKGlnbm9yZVN1YmZvbGRlcnNDb250YWluZXIpIHtcblx0XHRcdGlnbm9yZVN1YmZvbGRlcnNDb250YWluZXIuY2xhc3NMaXN0LnRvZ2dsZShcImFzdHJvLWNvbXBvc2VyLXNldHRpbmctY29udGFpbmVyLXZpc2libGVcIiwgISFjdXN0b21UeXBlLmZvbGRlciAmJiBjdXN0b21UeXBlLmZvbGRlci50cmltKCkgIT09IFwiXCIpO1xuXHRcdFx0aWdub3JlU3ViZm9sZGVyc0NvbnRhaW5lci5jbGFzc0xpc3QudG9nZ2xlKFwiYXN0cm8tY29tcG9zZXItc2V0dGluZy1jb250YWluZXItaGlkZGVuXCIsICFjdXN0b21UeXBlLmZvbGRlciB8fCBjdXN0b21UeXBlLmZvbGRlci50cmltKCkgPT09IFwiXCIpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgdXBkYXRlRm9sZGVyQ29uZmxpY3RXYXJuaW5nKHR5cGVJZDogc3RyaW5nLCBzZXR0aW5nOiBTZXR0aW5nIHwgbnVsbCkge1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHRoaXMucGx1Z2luLnNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBjdXJyZW50VHlwZSA9IGNvbnRlbnRUeXBlcy5maW5kKHR5cGUgPT4gdHlwZS5pZCA9PT0gdHlwZUlkKTtcblx0XHRpZiAoIWN1cnJlbnRUeXBlKSByZXR1cm47XG5cblx0XHRjb25zdCBjb25mbGljdFdhcm5pbmdFbCA9IHRoaXMuY3VzdG9tQ29udGVudFR5cGVzQ29udGFpbmVyPy5xdWVyeVNlbGVjdG9yKGBbZGF0YS10eXBlLWlkPVwiJHt0eXBlSWR9XCJdLmFzdHJvLWNvbXBvc2VyLWNvbmZsaWN0LXdhcm5pbmdgKSBhcyBIVE1MRWxlbWVudDtcblx0XHRpZiAoIWNvbmZsaWN0V2FybmluZ0VsKSByZXR1cm47XG5cblx0XHQvLyBGaW5kIGNvbmZsaWN0cyAtIG90aGVyIGNvbnRlbnQgdHlwZXMgd2l0aCB0aGUgc2FtZSBmb2xkZXIgcGF0dGVyblxuXHRcdGNvbnN0IGN1cnJlbnRGb2xkZXIgPSAoY3VycmVudFR5cGUuZm9sZGVyIHx8IFwiXCIpLnRyaW0oKTtcblx0XHRjb25zdCBjb25mbGljdGluZ1R5cGVzOiBzdHJpbmdbXSA9IFtdO1xuXG5cdFx0Zm9yIChjb25zdCBvdGhlclR5cGUgb2YgY29udGVudFR5cGVzKSB7XG5cdFx0XHRpZiAob3RoZXJUeXBlLmlkID09PSB0eXBlSWQgfHwgIW90aGVyVHlwZS5lbmFibGVkKSBjb250aW51ZTtcblxuXHRcdFx0Y29uc3Qgb3RoZXJGb2xkZXIgPSAob3RoZXJUeXBlLmZvbGRlciB8fCBcIlwiKS50cmltKCk7XG5cblx0XHRcdC8vIENoZWNrIGlmIGZvbGRlcnMgY29uZmxpY3Rcblx0XHRcdC8vIEJvdGggYmxhbmsgPSBjb25mbGljdCAoYm90aCBtYXRjaCB2YXVsdCByb290KVxuXHRcdFx0aWYgKGN1cnJlbnRGb2xkZXIgPT09IFwiXCIgJiYgb3RoZXJGb2xkZXIgPT09IFwiXCIpIHtcblx0XHRcdFx0Y29uZmxpY3RpbmdUeXBlcy5wdXNoKG90aGVyVHlwZS5uYW1lIHx8IFwiVW5uYW1lZFwiKTtcblx0XHRcdH1cblx0XHRcdC8vIFNhbWUgZm9sZGVyID0gY29uZmxpY3Rcblx0XHRcdGVsc2UgaWYgKGN1cnJlbnRGb2xkZXIgPT09IG90aGVyRm9sZGVyICYmIGN1cnJlbnRGb2xkZXIgIT09IFwiXCIpIHtcblx0XHRcdFx0Y29uZmxpY3RpbmdUeXBlcy5wdXNoKG90aGVyVHlwZS5uYW1lIHx8IFwiVW5uYW1lZFwiKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoY29uZmxpY3RpbmdUeXBlcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRjb25mbGljdFdhcm5pbmdFbC5yZW1vdmVDbGFzcyhcImhpZGRlblwiKTtcblx0XHRcdGNvbmZsaWN0V2FybmluZ0VsLnRleHRDb250ZW50ID0gYENvbmZsaWN0OiAke2NvbmZsaWN0aW5nVHlwZXMuam9pbihcIiwgXCIpfSBhbHNvIHVzZSR7Y29uZmxpY3RpbmdUeXBlcy5sZW5ndGggPT09IDEgPyBcInNcIiA6IFwiXCJ9IHRoaXMgZm9sZGVyLiBNb3JlIHNwZWNpZmljIHBhdHRlcm5zIHdpbGwgdGFrZSBwcmlvcml0eS5gO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjb25mbGljdFdhcm5pbmdFbC5hZGRDbGFzcyhcImhpZGRlblwiKTtcblx0XHR9XG5cdH1cblxuXG5cdHByaXZhdGUgYXN5bmMgbW92ZUNvbnRlbnRUeXBlVXAodHlwZUlkOiBzdHJpbmcpIHtcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBjdXJyZW50SW5kZXggPSBjb250ZW50VHlwZXMuZmluZEluZGV4KChjdDogQ29udGVudFR5cGUpID0+IGN0LmlkID09PSB0eXBlSWQpO1xuXG5cdFx0aWYgKGN1cnJlbnRJbmRleCA8PSAwKSByZXR1cm47IC8vIEFscmVhZHkgYXQgdGhlIHRvcFxuXG5cdFx0Ly8gU3dhcCB3aXRoIHByZXZpb3VzIGl0ZW1cblx0XHRbY29udGVudFR5cGVzW2N1cnJlbnRJbmRleF0sIGNvbnRlbnRUeXBlc1tjdXJyZW50SW5kZXggLSAxXV0gPSBbY29udGVudFR5cGVzW2N1cnJlbnRJbmRleCAtIDFdLCBjb250ZW50VHlwZXNbY3VycmVudEluZGV4XV07XG5cdFx0c2V0dGluZ3MuY29udGVudFR5cGVzID0gY29udGVudFR5cGVzO1xuXHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdHRoaXMucmVuZGVyQ3VzdG9tQ29udGVudFR5cGVzKCk7XG5cdH1cblxuXHRwcml2YXRlIGFzeW5jIG1vdmVDb250ZW50VHlwZURvd24odHlwZUlkOiBzdHJpbmcpIHtcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBjdXJyZW50SW5kZXggPSBjb250ZW50VHlwZXMuZmluZEluZGV4KChjdDogQ29udGVudFR5cGUpID0+IGN0LmlkID09PSB0eXBlSWQpO1xuXG5cdFx0aWYgKGN1cnJlbnRJbmRleCA8IDAgfHwgY3VycmVudEluZGV4ID49IGNvbnRlbnRUeXBlcy5sZW5ndGggLSAxKSByZXR1cm47IC8vIEFscmVhZHkgYXQgdGhlIGJvdHRvbVxuXG5cdFx0Ly8gU3dhcCB3aXRoIG5leHQgaXRlbVxuXHRcdFtjb250ZW50VHlwZXNbY3VycmVudEluZGV4XSwgY29udGVudFR5cGVzW2N1cnJlbnRJbmRleCArIDFdXSA9IFtjb250ZW50VHlwZXNbY3VycmVudEluZGV4ICsgMV0sIGNvbnRlbnRUeXBlc1tjdXJyZW50SW5kZXhdXTtcblx0XHRzZXR0aW5ncy5jb250ZW50VHlwZXMgPSBjb250ZW50VHlwZXM7XG5cdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0dGhpcy5yZW5kZXJDdXN0b21Db250ZW50VHlwZXMoKTtcblx0fVxuXG5cdHByaXZhdGUgYXN5bmMgdG9nZ2xlQ29udGVudFR5cGVDb2xsYXBzZSh0eXBlSWQ6IHN0cmluZykge1xuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XG5cdFx0Y29uc3QgY29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlID0gY29udGVudFR5cGVzLmZpbmQoKGN0OiBDb250ZW50VHlwZSkgPT4gY3QuaWQgPT09IHR5cGVJZCk7XG5cblx0XHRpZiAoIWNvbnRlbnRUeXBlKSByZXR1cm47XG5cblx0XHRjb250ZW50VHlwZS5jb2xsYXBzZWQgPSAhY29udGVudFR5cGUuY29sbGFwc2VkO1xuXHRcdGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuXHRcdHRoaXMudXBkYXRlQ3VzdG9tQ29udGVudFR5cGVWaXNpYmlsaXR5KHR5cGVJZCwgY29udGVudFR5cGUuZW5hYmxlZCk7XG5cdH1cblxuXHRwcml2YXRlIGFzeW5jIHJlbW92ZUN1c3RvbUNvbnRlbnRUeXBlKHR5cGVJZDogc3RyaW5nKSB7XG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncztcblx0XHRjb25zdCBjb250ZW50VHlwZXMgPSBzZXR0aW5ncy5jb250ZW50VHlwZXMgfHwgW107XG5cdFx0c2V0dGluZ3MuY29udGVudFR5cGVzID0gY29udGVudFR5cGVzLmZpbHRlcigoY3Q6IENvbnRlbnRUeXBlKSA9PiBjdC5pZCAhPT0gdHlwZUlkKTtcblx0XHQvLyBDUklUSUNBTDogQXdhaXQgdGhlIHNhdmUgdG8gZW5zdXJlIGRlbGV0aW9uIGlzIHBlcnNpc3RlZCBiZWZvcmUgYW55IHJlbG9hZHMgaGFwcGVuXG5cdFx0YXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG5cdFx0dGhpcy5yZW5kZXJDdXN0b21Db250ZW50VHlwZXMoKTtcblx0XHR0aGlzLnBsdWdpbi5yZWdpc3RlckNyZWF0ZUV2ZW50KCk7XG5cdFx0Ly8gUmUtcmVnaXN0ZXIgY29udGVudCB0eXBlIGNvbW1hbmRzIHRvIHJlbW92ZSB0aGUgZGVsZXRlZCB0eXBlXG5cdFx0cmVnaXN0ZXJDb250ZW50VHlwZUNvbW1hbmRzKHRoaXMucGx1Z2luIGFzIHVua25vd24gYXMgUGx1Z2luLCBzZXR0aW5ncyk7XG5cdH1cblxuXHRwcml2YXRlIGdldENvbW1hbmROYW1lKGNvbW1hbmRJZDogc3RyaW5nKTogc3RyaW5nIHtcblx0XHRpZiAoIWNvbW1hbmRJZCkgcmV0dXJuICcnO1xuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCBjb21tYW5kUmVnaXN0cnkgPSAodGhpcy5hcHAgYXMgdW5rbm93biBhcyB7IGNvbW1hbmRzPzogeyBsaXN0Q29tbWFuZHM/OiAoKSA9PiBBcnJheTx7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZyB9PjsgY29tbWFuZHM/OiBSZWNvcmQ8c3RyaW5nLCB7IGlkOiBzdHJpbmc7IG5hbWU6IHN0cmluZyB9PiB9IH0pLmNvbW1hbmRzO1xuXG5cdFx0XHQvLyBNZXRob2QgMTogVHJ5IGxpc3RDb21tYW5kcygpXG5cdFx0XHRpZiAoY29tbWFuZFJlZ2lzdHJ5ICYmIHR5cGVvZiBjb21tYW5kUmVnaXN0cnkubGlzdENvbW1hbmRzID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0Y29uc3QgYWxsQ29tbWFuZHMgPSBjb21tYW5kUmVnaXN0cnkubGlzdENvbW1hbmRzKCk7XG5cdFx0XHRcdFx0Y29uc3QgY29tbWFuZCA9IGFsbENvbW1hbmRzLmZpbmQoKGNtZDogeyBpZDogc3RyaW5nOyBuYW1lPzogc3RyaW5nIH0pID0+IGNtZC5pZCA9PT0gY29tbWFuZElkKTtcblx0XHRcdFx0XHRpZiAoY29tbWFuZD8ubmFtZSkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGNvbW1hbmQubmFtZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdFx0XHRjb25zb2xlLndhcm4oJ1tBc3RybyBDb21wb3Nlcl0gRXJyb3IgZ2V0dGluZyBjb21tYW5kIG5hbWUgdmlhIGxpc3RDb21tYW5kcygpOicsIGUpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIE1ldGhvZCAyOiBUcnkgYWNjZXNzaW5nIHRoZSBpbnRlcm5hbCBjb21tYW5kcyByZWdpc3RyeSBkaXJlY3RseVxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0Y29uc3QgcmVnaXN0cnkgPSBjb21tYW5kUmVnaXN0cnk/LmNvbW1hbmRzO1xuXHRcdFx0XHRpZiAocmVnaXN0cnkgJiYgdHlwZW9mIHJlZ2lzdHJ5ID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRcdGNvbnN0IGNvbW1hbmQgPSAocmVnaXN0cnkgYXMgUmVjb3JkPHN0cmluZywgeyBuYW1lPzogc3RyaW5nIH0+KVtjb21tYW5kSWRdO1xuXHRcdFx0XHRcdGlmIChjb21tYW5kPy5uYW1lKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gY29tbWFuZC5uYW1lO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSBjYXRjaCAoZSkge1xuXHRcdFx0XHRjb25zb2xlLndhcm4oJ1tBc3RybyBDb21wb3Nlcl0gRXJyb3IgZ2V0dGluZyBjb21tYW5kIG5hbWUgdmlhIHJlZ2lzdHJ5OicsIGUpO1xuXHRcdFx0fVxuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdGNvbnNvbGUud2FybignW0FzdHJvIENvbXBvc2VyXSBFcnJvciBnZXR0aW5nIGNvbW1hbmQgbmFtZTonLCBlKTtcblx0XHR9XG5cdFx0Ly8gUmV0dXJuIGVtcHR5IHN0cmluZyBpZiBjb21tYW5kIG5vdCBmb3VuZCwgc28gaXQgc2hvd3MgXCJTZWxlY3QgY29tbWFuZC4uLlwiIHBsYWNlaG9sZGVyXG5cdFx0cmV0dXJuICcnO1xuXHR9XG5cblx0cHJpdmF0ZSBnZXRJY29uTmFtZShpY29uSWQ6IHN0cmluZyk6IHN0cmluZyB7XG5cdFx0aWYgKCFpY29uSWQpIHJldHVybiAnJztcblx0XHQvLyBDb252ZXJ0IGljb24gSUQgdG8gYSByZWFkYWJsZSBuYW1lLCByZW1vdmluZyBsdWNpZGUtIHByZWZpeCBpZiBwcmVzZW50XG5cdFx0cmV0dXJuIGljb25JZFxuXHRcdFx0LnJlcGxhY2UoL15sdWNpZGUtLywgJycpIC8vIFJlbW92ZSBsdWNpZGUtIHByZWZpeFxuXHRcdFx0LnNwbGl0KCctJylcblx0XHRcdC5tYXAod29yZCA9PiB3b3JkLmNoYXJBdCgwKS50b1VwcGVyQ2FzZSgpICsgd29yZC5zbGljZSgxKSlcblx0XHRcdC5qb2luKCcgJyk7XG5cdH1cbn1cbiIsICIvKipcclxuICogQ29tbWFuZCBQaWNrZXIgTW9kYWxcclxuICogU2VhcmNoYWJsZSBtb2RhbCBmb3Igc2VsZWN0aW5nIGFuIE9ic2lkaWFuIGNvbW1hbmRcclxuICovXHJcblxyXG5pbXBvcnQgeyBBcHAsIEZ1enp5U3VnZ2VzdE1vZGFsIH0gZnJvbSAnb2JzaWRpYW4nO1xyXG5cclxuaW50ZXJmYWNlIENvbW1hbmRPcHRpb24ge1xyXG5cdGlkOiBzdHJpbmc7XHJcblx0bmFtZTogc3RyaW5nO1xyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgQ29tbWFuZFBpY2tlck1vZGFsIGV4dGVuZHMgRnV6enlTdWdnZXN0TW9kYWw8Q29tbWFuZE9wdGlvbj4ge1xyXG5cdHByaXZhdGUgb25TZWxlY3Q6IChjb21tYW5kSWQ6IHN0cmluZykgPT4gdm9pZDtcclxuXHJcblx0Y29uc3RydWN0b3IoYXBwOiBBcHAsIG9uU2VsZWN0OiAoY29tbWFuZElkOiBzdHJpbmcpID0+IHZvaWQpIHtcclxuXHRcdHN1cGVyKGFwcCk7XHJcblx0XHR0aGlzLm9uU2VsZWN0ID0gb25TZWxlY3Q7XHJcblx0fVxyXG5cclxuXHRnZXRJdGVtcygpOiBDb21tYW5kT3B0aW9uW10ge1xyXG5cdFx0Ly8gR2V0IGFsbCBhdmFpbGFibGUgY29tbWFuZHNcclxuXHRcdC8vIFRyeSBtdWx0aXBsZSBtZXRob2RzIHRvIGVuc3VyZSB3ZSBnZXQgQUxMIGNvbW1hbmRzLCBub3QganVzdCBjb250ZXh0LWZpbHRlcmVkIG9uZXNcclxuXHRcdGNvbnN0IGNvbW1hbmRSZWdpc3RyeSA9ICh0aGlzLmFwcCBhcyB7IGNvbW1hbmRzPzogeyBsaXN0Q29tbWFuZHM/OiAoKSA9PiBDb21tYW5kT3B0aW9uW107IGNvbW1hbmRzPzogUmVjb3JkPHN0cmluZywgQ29tbWFuZE9wdGlvbj47IGNvbW1hbmRSZWdpc3RyeT86IFJlY29yZDxzdHJpbmcsIENvbW1hbmRPcHRpb24+IH0gfSkuY29tbWFuZHM7XHJcblx0XHRcclxuXHRcdC8vIFVzZSBhIFNldCB0byBkZWR1cGxpY2F0ZSBieSBjb21tYW5kIElEXHJcblx0XHRjb25zdCBjb21tYW5kTWFwID0gbmV3IE1hcDxzdHJpbmcsIENvbW1hbmRPcHRpb24+KCk7XHJcblx0XHRcclxuXHRcdC8vIE1ldGhvZCAxOiBUcnkgbGlzdENvbW1hbmRzKCkgLSBidXQgdGhpcyBtaWdodCBiZSBjb250ZXh0LWZpbHRlcmVkXHJcblx0XHRpZiAoY29tbWFuZFJlZ2lzdHJ5ICYmIHR5cGVvZiBjb21tYW5kUmVnaXN0cnkubGlzdENvbW1hbmRzID09PSAnZnVuY3Rpb24nKSB7XHJcblx0XHRcdHRyeSB7XHJcblx0XHRcdFx0Y29uc3QgY29tbWFuZHMgPSBjb21tYW5kUmVnaXN0cnkubGlzdENvbW1hbmRzKCk7XHJcblx0XHRcdFx0Zm9yIChjb25zdCBjb21tYW5kIG9mIGNvbW1hbmRzKSB7XHJcblx0XHRcdFx0XHRpZiAoY29tbWFuZCAmJiBjb21tYW5kLmlkICYmIGNvbW1hbmQubmFtZSAmJiAhY29tbWFuZE1hcC5oYXMoY29tbWFuZC5pZCkpIHtcclxuXHRcdFx0XHRcdFx0Y29tbWFuZE1hcC5zZXQoY29tbWFuZC5pZCwge1xyXG5cdFx0XHRcdFx0XHRcdGlkOiBjb21tYW5kLmlkLFxyXG5cdFx0XHRcdFx0XHRcdG5hbWU6IGNvbW1hbmQubmFtZVxyXG5cdFx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0gY2F0Y2ggKGUpIHtcclxuXHRcdFx0XHRjb25zb2xlLndhcm4oJ1tBc3RybyBDb21wb3Nlcl0gRXJyb3IgZ2V0dGluZyBjb21tYW5kcyB2aWEgbGlzdENvbW1hbmRzKCk6JywgZSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0Ly8gTWV0aG9kIDI6IFRyeSBhY2Nlc3NpbmcgdGhlIGludGVybmFsIGNvbW1hbmRzIHJlZ2lzdHJ5IGRpcmVjdGx5XHJcblx0XHQvLyBUaGlzIHNob3VsZCBnaXZlIHVzIEFMTCBjb21tYW5kcyByZWdhcmRsZXNzIG9mIGNvbnRleHRcclxuXHRcdHRyeSB7XHJcblx0XHRcdGNvbnN0IHJlZ2lzdHJ5ID0gY29tbWFuZFJlZ2lzdHJ5Py5jb21tYW5kcztcclxuXHRcdFx0aWYgKHJlZ2lzdHJ5ICYmIHR5cGVvZiByZWdpc3RyeSA9PT0gJ29iamVjdCcpIHtcclxuXHRcdFx0XHRjb25zdCBhbGxDb21tYW5kcyA9IE9iamVjdC52YWx1ZXMocmVnaXN0cnkpO1xyXG5cdFx0XHRcdGZvciAoY29uc3QgY29tbWFuZCBvZiBhbGxDb21tYW5kcykge1xyXG5cdFx0XHRcdFx0aWYgKGNvbW1hbmQgJiYgY29tbWFuZC5pZCAmJiBjb21tYW5kLm5hbWUgJiYgIWNvbW1hbmRNYXAuaGFzKGNvbW1hbmQuaWQpKSB7XHJcblx0XHRcdFx0XHRcdGNvbW1hbmRNYXAuc2V0KGNvbW1hbmQuaWQsIHtcclxuXHRcdFx0XHRcdFx0XHRpZDogY29tbWFuZC5pZCxcclxuXHRcdFx0XHRcdFx0XHRuYW1lOiBjb21tYW5kLm5hbWVcclxuXHRcdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9IGNhdGNoIChlKSB7XHJcblx0XHRcdGNvbnNvbGUud2FybignW0FzdHJvIENvbXBvc2VyXSBFcnJvciBnZXR0aW5nIGNvbW1hbmRzIHZpYSByZWdpc3RyeTonLCBlKTtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0Ly8gTWV0aG9kIDM6IFRyeSBhY2Nlc3NpbmcgdmlhIGludGVybmFsIHN0cnVjdHVyZSAoZmFsbGJhY2spXHJcblx0XHR0cnkge1xyXG5cdFx0XHRjb25zdCBpbnRlcm5hbFJlZ2lzdHJ5ID0gY29tbWFuZFJlZ2lzdHJ5Py5jb21tYW5kUmVnaXN0cnk7XHJcblx0XHRcdGlmIChpbnRlcm5hbFJlZ2lzdHJ5ICYmIHR5cGVvZiBpbnRlcm5hbFJlZ2lzdHJ5ID09PSAnb2JqZWN0Jykge1xyXG5cdFx0XHRcdGNvbnN0IGFsbENvbW1hbmRzID0gT2JqZWN0LnZhbHVlcyhpbnRlcm5hbFJlZ2lzdHJ5KTtcclxuXHRcdFx0XHRmb3IgKGNvbnN0IGNvbW1hbmQgb2YgYWxsQ29tbWFuZHMpIHtcclxuXHRcdFx0XHRcdGlmIChjb21tYW5kICYmIGNvbW1hbmQuaWQgJiYgY29tbWFuZC5uYW1lICYmICFjb21tYW5kTWFwLmhhcyhjb21tYW5kLmlkKSkge1xyXG5cdFx0XHRcdFx0XHRjb21tYW5kTWFwLnNldChjb21tYW5kLmlkLCB7XHJcblx0XHRcdFx0XHRcdFx0aWQ6IGNvbW1hbmQuaWQsXHJcblx0XHRcdFx0XHRcdFx0bmFtZTogY29tbWFuZC5uYW1lXHJcblx0XHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fSBjYXRjaCAoZSkge1xyXG5cdFx0XHRjb25zb2xlLndhcm4oJ1tBc3RybyBDb21wb3Nlcl0gRXJyb3IgZ2V0dGluZyBjb21tYW5kcyB2aWEgaW50ZXJuYWwgcmVnaXN0cnk6JywgZSk7XHJcblx0XHR9XHJcblx0XHRcclxuXHRcdGNvbnN0IGNvbW1hbmRPcHRpb25zID0gQXJyYXkuZnJvbShjb21tYW5kTWFwLnZhbHVlcygpKTtcclxuXHRcdFxyXG5cdFx0Ly8gU29ydCBhbHBoYWJldGljYWxseSBieSBuYW1lXHJcblx0XHRjb21tYW5kT3B0aW9ucy5zb3J0KChhLCBiKSA9PiBhLm5hbWUubG9jYWxlQ29tcGFyZShiLm5hbWUpKTtcclxuXHRcdFxyXG5cdFx0cmV0dXJuIGNvbW1hbmRPcHRpb25zO1xyXG5cdH1cclxuXHJcblx0Z2V0SXRlbVRleHQoaXRlbTogQ29tbWFuZE9wdGlvbik6IHN0cmluZyB7XHJcblx0XHRyZXR1cm4gaXRlbS5uYW1lO1xyXG5cdH1cclxuXHJcblx0b25DaG9vc2VJdGVtKGl0ZW06IENvbW1hbmRPcHRpb24sIGV2dDogTW91c2VFdmVudCB8IEtleWJvYXJkRXZlbnQpOiB2b2lkIHtcclxuXHRcdHRoaXMub25TZWxlY3QoaXRlbS5pZCk7XHJcblx0fVxyXG5cclxuXHQvLyBPdmVycmlkZSB0byBzaG93IGNvbW1hbmQgbmFtZSBvbmx5XHJcblx0cmVuZGVyU3VnZ2VzdGlvbihtYXRjaDogeyBpdGVtOiBDb21tYW5kT3B0aW9uIH0sIGVsOiBIVE1MRWxlbWVudCk6IHZvaWQge1xyXG5cdFx0Y29uc3QgaXRlbSA9IG1hdGNoLml0ZW07XHJcblx0XHRlbC5jcmVhdGVEaXYoeyBjbHM6ICdzdWdnZXN0aW9uLXRpdGxlJywgdGV4dDogaXRlbS5uYW1lIH0pO1xyXG5cdH1cclxufVxyXG5cclxuIiwgIi8qKlxyXG4gKiBJY29uIFBpY2tlciBNb2RhbFxyXG4gKiBTZWFyY2hhYmxlIG1vZGFsIGZvciBzZWxlY3RpbmcgYSBMdWNpZGUgaWNvblxyXG4gKi9cclxuXHJcbmltcG9ydCB7IEFwcCwgRnV6enlTdWdnZXN0TW9kYWwsIHNldEljb24sIGdldEljb25JZHMsIHJlcXVpcmVBcGlWZXJzaW9uIH0gZnJvbSAnb2JzaWRpYW4nO1xyXG5cclxuaW50ZXJmYWNlIEljb25PcHRpb24ge1xyXG5cdGlkOiBzdHJpbmc7XHJcblx0bmFtZTogc3RyaW5nO1xyXG59XHJcblxyXG4vLyBHZXQgaWNvbiBsaXN0IGZyb20gT2JzaWRpYW4gQVBJIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIHVzZSBmYWxsYmFjayBsaXN0XHJcbmNvbnN0IGdldEljb25MaXN0ID0gKCk6IHN0cmluZ1tdID0+IHtcclxuXHRpZiAocmVxdWlyZUFwaVZlcnNpb24gJiYgcmVxdWlyZUFwaVZlcnNpb24oJzEuNy4zJykgJiYgZ2V0SWNvbklkcykge1xyXG5cdFx0dHJ5IHtcclxuXHRcdFx0cmV0dXJuIGdldEljb25JZHMoKTtcclxuXHRcdH0gY2F0Y2ggKGUpIHtcclxuXHRcdFx0Y29uc29sZS53YXJuKCdbQXN0cm8gQ29tcG9zZXJdIEVycm9yIGdldHRpbmcgaWNvbiBJRHMgZnJvbSBPYnNpZGlhbjonLCBlKTtcclxuXHRcdH1cclxuXHR9XHJcblx0Ly8gRmFsbGJhY2sgdG8gYSBiYXNpYyBsaXN0IGlmIEFQSSBpcyBub3QgYXZhaWxhYmxlXHJcblx0cmV0dXJuIFtcclxuXHRcdCdzZXR0aW5ncy0yJywgJ3NldHRpbmdzJywgJ2hlbHAtY2lyY2xlJywgJ2luZm8nLCAnc3RhcicsICdoZWFydCcsICdib29rbWFyaycsXHJcblx0XHQnaG9tZScsICdzZWFyY2gnLCAnYmVsbCcsICdtYWlsJywgJ3VzZXInLCAndXNlcnMnLCAnZm9sZGVyJywgJ2ZpbGUnLCAnZmlsZS10ZXh0JyxcclxuXHRcdCdpbWFnZScsICd2aWRlbycsICdtdXNpYycsICdjYWxlbmRhcicsICdjbG9jaycsICdlZGl0JywgJ3BlbmNpbCcsICd0cmFzaCcsXHJcblx0XHQnY29weScsICdjdXQnLCAncGFzdGUnLCAnZG93bmxvYWQnLCAndXBsb2FkJywgJ3NhdmUnLCAnc2hhcmUnLCAnbGluaycsXHJcblx0XHQnZXh0ZXJuYWwtbGluaycsICdsb2NrJywgJ3VubG9jaycsICdleWUnLCAnZXllLW9mZicsICdrZXknLCAnc2hpZWxkJyxcclxuXHRcdCdjaGVjaycsICd4JywgJ3BsdXMnLCAnbWludXMnLCAnYXJyb3ctbGVmdCcsICdhcnJvdy1yaWdodCcsICdhcnJvdy11cCcsXHJcblx0XHQnYXJyb3ctZG93bicsICdjaGV2cm9uLWxlZnQnLCAnY2hldnJvbi1yaWdodCcsICdjaGV2cm9uLXVwJywgJ2NoZXZyb24tZG93bicsXHJcblx0XHQnbWVudScsICdtb3JlLWhvcml6b250YWwnLCAnbW9yZS12ZXJ0aWNhbCcsICdncmlkJywgJ2xpc3QnLCAnbGF5b3V0JyxcclxuXHRcdCdjb2x1bW5zJywgJ3Jvd3MnLCAnbWF4aW1pemUnLCAnbWluaW1pemUnLCAnem9vbS1pbicsICd6b29tLW91dCcsXHJcblx0XHQncmVmcmVzaC1jdycsICdwbGF5JywgJ3BhdXNlJywgJ3N0b3AnLCAnc3VuJywgJ21vb24nLCAnY2xvdWQnLCAnemFwJyxcclxuXHRcdCd3YW5kLTInLCAnd2FuZCcsICd3YW5kLXNwYXJrbGVzJywgJ3BhbGV0dGUnLCAnYnJ1c2gnLCAnc2xpZGVycycsXHJcblx0XHQncG93ZXInLCAnd2lmaScsICdibHVldG9vdGgnLCAnbW9uaXRvcicsICdsYXB0b3AnLCAnc21hcnRwaG9uZScsXHJcblx0XHQnY2FtZXJhJywgJ21pYycsICdoZWFkcGhvbmVzJywgJ2NvZGUnLCAndGVybWluYWwnLCAndGVybWluYWwtc3F1YXJlJyxcclxuXHRcdCdnaXRodWInLCAnZ2l0bGFiJywgJ2dpdC1icmFuY2gnLCAnZ2l0LWNvbW1pdCcsICdkYXRhYmFzZScsICdzZXJ2ZXInLFxyXG5cdFx0J2Nsb3VkLWRvd25sb2FkJywgJ2Nsb3VkLXVwbG9hZCcsICd0YWcnLCAndGFncycsICdmbGFnJywgJ3BpbicsXHJcblx0XHQnbWFwLXBpbicsICdjb21wYXNzJywgJ2dsb2JlJywgJ3JvY2tldCcsICdjYXInLCAnYmlrZScsICdyb2JvdCcsXHJcblx0XHQnYXBwbGUnLCAnd2luZG93cycsICdsaW51eCcsICdjaHJvbWUnLCAnZmlyZWZveCcsICdzYWZhcmknLFxyXG5cdFx0J2NyZWRpdC1jYXJkJywgJ3dhbGxldCcsICdjb2lucycsICdib29rJywgJ2Jvb2stb3BlbicsICdhd2FyZCcsXHJcblx0XHQndHJvcGh5JywgJ2JhZGdlJywgJ3dyZW5jaCcsICd0b29sJywgJ3BhY2thZ2UnLCAnYm94JywgJ2FyY2hpdmUnLFxyXG5cdFx0J3NlbmQnLCAncmVwbHknLCAnZm9yd2FyZCcsICdtYWlsLW9wZW4nLCAndGFnLXBsdXMnLCAndGFnLW1pbnVzJyxcclxuXHRcdCdmbGFnLW9mZicsICdwaW4tb2ZmJywgJ21hcC1waW4tb2ZmJywgJ25hdmlnYXRpb24nLCAnbWFwJywgJ2VhcnRoJyxcclxuXHRcdCdwbGFuZScsICdzaGlwJywgJ2FuY2hvcicsICdoZWxpY29wdGVyJywgJ2Ryb25lJywgJ2FuZHJvaWQnLFxyXG5cdFx0J2tleWhvbGUnLCAna2V5cycsICdmaW5nZXJwcmludCcsICdzY2FuJywgJ3FyLWNvZGUnLCAnYmFyY29kZScsXHJcblx0XHQncmVjZWlwdCcsICdwaWdneS1iYW5rJywgJ2Jhbmtub3RlJ1xyXG5cdF07XHJcbn07XHJcblxyXG4vLyBDb252ZXJ0IGljb24gSURzIHRvIEljb25PcHRpb24gZm9ybWF0XHJcbmNvbnN0IExVQ0lERV9JQ09OUzogSWNvbk9wdGlvbltdID0gZ2V0SWNvbkxpc3QoKS5tYXAoaWQgPT4gKHtcclxuXHRpZDogaWQsXHJcblx0bmFtZTogaWRcclxuXHRcdC5yZXBsYWNlKC9ebHVjaWRlLS8sICcnKSAvLyBSZW1vdmUgbHVjaWRlLSBwcmVmaXggZm9yIGRpc3BsYXlcclxuXHRcdC5yZXBsYWNlKC8tL2csICcgJylcclxuXHRcdC5yZXBsYWNlKC8oXlxcd3sxfSl8KFxccytcXHd7MX0pL2csIChsZXR0ZXIpID0+IGxldHRlci50b1VwcGVyQ2FzZSgpKVxyXG59KSkuc29ydCgoYSwgYikgPT4gYS5uYW1lLmxvY2FsZUNvbXBhcmUoYi5uYW1lKSk7XHJcblxyXG5leHBvcnQgY2xhc3MgSWNvblBpY2tlck1vZGFsIGV4dGVuZHMgRnV6enlTdWdnZXN0TW9kYWw8SWNvbk9wdGlvbj4ge1xyXG5cdHByaXZhdGUgb25TZWxlY3Q6IChpY29uSWQ6IHN0cmluZykgPT4gdm9pZDtcclxuXHJcblx0Y29uc3RydWN0b3IoYXBwOiBBcHAsIG9uU2VsZWN0OiAoaWNvbklkOiBzdHJpbmcpID0+IHZvaWQpIHtcclxuXHRcdHN1cGVyKGFwcCk7XHJcblx0XHR0aGlzLm9uU2VsZWN0ID0gb25TZWxlY3Q7XHJcblx0fVxyXG5cclxuXHRnZXRJdGVtcygpOiBJY29uT3B0aW9uW10ge1xyXG5cdFx0cmV0dXJuIExVQ0lERV9JQ09OUztcclxuXHR9XHJcblxyXG5cdGdldEl0ZW1UZXh0KGl0ZW06IEljb25PcHRpb24pOiBzdHJpbmcge1xyXG5cdFx0cmV0dXJuIGl0ZW0ubmFtZTtcclxuXHR9XHJcblxyXG5cdG9uQ2hvb3NlSXRlbShpdGVtOiBJY29uT3B0aW9uLCBldnQ6IE1vdXNlRXZlbnQgfCBLZXlib2FyZEV2ZW50KTogdm9pZCB7XHJcblx0XHQvLyBTdGFuZGFyZGl6ZSBpY29uIElEIGJ5IHJlbW92aW5nIGx1Y2lkZS0gcHJlZml4XHJcblx0XHRjb25zdCBub3JtYWxpemVkSWQgPSBpdGVtLmlkLnJlcGxhY2UoL15sdWNpZGUtLywgJycpO1xyXG5cdFx0dGhpcy5vblNlbGVjdChub3JtYWxpemVkSWQpO1xyXG5cdH1cclxuXHJcblx0Ly8gT3ZlcnJpZGUgdG8gc2hvdyBpY29uIHByZXZpZXdcclxuXHRyZW5kZXJTdWdnZXN0aW9uKG1hdGNoOiB7IGl0ZW06IEljb25PcHRpb24gfSwgZWw6IEhUTUxFbGVtZW50KTogdm9pZCB7XHJcblx0XHRjb25zdCBpdGVtID0gbWF0Y2guaXRlbTtcclxuXHRcdGVsLmFkZENsYXNzKCdtb2QtY29tcGxleCcpO1xyXG5cdFx0Y29uc3QgY29udGVudCA9IGVsLmNyZWF0ZURpdih7IGNsczogJ3N1Z2dlc3Rpb24tY29udGVudCcgfSk7XHJcblx0XHRjb250ZW50LmNyZWF0ZURpdih7IGNsczogJ3N1Z2dlc3Rpb24tdGl0bGUnLCB0ZXh0OiBpdGVtLm5hbWUgfSk7XHJcblxyXG5cdFx0Ly8gQ3JlYXRlIGljb24gcHJldmlldyB1c2luZyBPYnNpZGlhbidzIHNldEljb25cclxuXHRcdGNvbnN0IGF1eCA9IGVsLmNyZWF0ZURpdih7IGNsczogJ3N1Z2dlc3Rpb24tYXV4JyB9KTtcclxuXHRcdHNldEljb24oYXV4LmNyZWF0ZVNwYW4oeyBjbHM6ICdzdWdnZXN0aW9uLWZsYWlyJyB9KSwgaXRlbS5pZCk7XHJcblx0fVxyXG59XHJcblxyXG4iLCAiaW1wb3J0IHsgQXBwLCBNb2RhbCB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIENvbmZpcm1Nb2RhbCBleHRlbmRzIE1vZGFsIHtcclxuXHRyZXN1bHQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuXHRyZXNvbHZlUHJvbWlzZTogKChyZXN1bHQ6IGJvb2xlYW4pID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XHJcblxyXG5cdGNvbnN0cnVjdG9yKGFwcDogQXBwLCBwcml2YXRlIG1lc3NhZ2U6IHN0cmluZywgcHJpdmF0ZSBjb25maXJtVGV4dDogc3RyaW5nID0gXCJDb25maXJtXCIsIHByaXZhdGUgY2FuY2VsVGV4dDogc3RyaW5nID0gXCJDYW5jZWxcIikge1xyXG5cdFx0c3VwZXIoYXBwKTtcclxuXHR9XHJcblxyXG5cdG9uT3BlbigpIHtcclxuXHRcdGNvbnN0IHsgY29udGVudEVsIH0gPSB0aGlzO1xyXG5cdFx0Y29udGVudEVsLmVtcHR5KCk7XHJcblx0XHRjb250ZW50RWwuYWRkQ2xhc3MoXCJhc3Ryby1jb21wb3Nlci1jb25maXJtLW1vZGFsXCIpO1xyXG5cclxuXHRcdGNvbnRlbnRFbC5jcmVhdGVFbChcInBcIiwgeyB0ZXh0OiB0aGlzLm1lc3NhZ2UgfSk7XHJcblxyXG5cdFx0Y29uc3QgYnV0dG9uQ29udGFpbmVyID0gY29udGVudEVsLmNyZWF0ZURpdih7IGNsczogXCJtb2RhbC1idXR0b24tY29udGFpbmVyXCIgfSk7XHJcblxyXG5cdFx0Y29uc3QgY2FuY2VsQnV0dG9uID0gYnV0dG9uQ29udGFpbmVyLmNyZWF0ZUVsKFwiYnV0dG9uXCIsIHtcclxuXHRcdFx0dGV4dDogdGhpcy5jYW5jZWxUZXh0LFxyXG5cdFx0fSk7XHJcblx0XHRjYW5jZWxCdXR0b24ub25jbGljayA9ICgpID0+IHtcclxuXHRcdFx0dGhpcy5yZXN1bHQgPSBmYWxzZTtcclxuXHRcdFx0dGhpcy5jbG9zZSgpO1xyXG5cdFx0fTtcclxuXHJcblx0XHRjb25zdCBjb25maXJtQnV0dG9uID0gYnV0dG9uQ29udGFpbmVyLmNyZWF0ZUVsKFwiYnV0dG9uXCIsIHtcclxuXHRcdFx0dGV4dDogdGhpcy5jb25maXJtVGV4dCxcclxuXHRcdFx0Y2xzOiBcIm1vZC1jdGEgbW9kLXdhcm5pbmdcIixcclxuXHRcdH0pO1xyXG5cdFx0Y29uZmlybUJ1dHRvbi5vbmNsaWNrID0gKCkgPT4ge1xyXG5cdFx0XHR0aGlzLnJlc3VsdCA9IHRydWU7XHJcblx0XHRcdHRoaXMuY2xvc2UoKTtcclxuXHRcdH07XHJcblx0fVxyXG5cclxuXHRvbkNsb3NlKCkge1xyXG5cdFx0Y29uc3QgeyBjb250ZW50RWwgfSA9IHRoaXM7XHJcblx0XHRjb250ZW50RWwuZW1wdHkoKTtcclxuXHRcdGlmICh0aGlzLnJlc29sdmVQcm9taXNlKSB7XHJcblx0XHRcdHRoaXMucmVzb2x2ZVByb21pc2UodGhpcy5yZXN1bHQpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0YXN5bmMgd2FpdEZvclJlc3VsdCgpOiBQcm9taXNlPGJvb2xlYW4+IHtcclxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xyXG5cdFx0XHR0aGlzLnJlc29sdmVQcm9taXNlID0gcmVzb2x2ZTtcclxuXHRcdFx0dGhpcy5vcGVuKCk7XHJcblx0XHR9KTtcclxuXHR9XHJcbn1cclxuXHJcbiIsICJpbXBvcnQgeyBURmlsZSwgSGVhZGluZ0NhY2hlLCBBcHAgfSBmcm9tIFwib2JzaWRpYW5cIjtcbmltcG9ydCB7IEFzdHJvQ29tcG9zZXJTZXR0aW5ncywgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgbWF0Y2hlc0ZvbGRlclBhdHRlcm4sIHNvcnRCeVBhdHRlcm5TcGVjaWZpY2l0eSB9IGZyb20gXCIuL3BhdGgtbWF0Y2hpbmdcIjtcbmltcG9ydCB7IHRvS2ViYWJDYXNlIH0gZnJvbSBcIi4vc3RyaW5nLXV0aWxzXCI7XG5cbmV4cG9ydCBjbGFzcyBIZWFkaW5nTGlua0dlbmVyYXRvciB7XG5cdGNvbnN0cnVjdG9yKHByaXZhdGUgc2V0dGluZ3M6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncywgcHJpdmF0ZSBwbHVnaW4/OiBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlKSB7IH1cblxuXHQvLyBHZXQgZnJlc2ggc2V0dGluZ3MgZnJvbSBwbHVnaW4gaWYgYXZhaWxhYmxlLCBvdGhlcndpc2UgdXNlIHN0b3JlZCBzZXR0aW5nc1xuXHRwcml2YXRlIGdldFNldHRpbmdzKCk6IEFzdHJvQ29tcG9zZXJTZXR0aW5ncyB7XG5cdFx0Ly8gQWx3YXlzIHByZWZlciBwbHVnaW4gc2V0dGluZ3MgKHRoZXkncmUga2VwdCB1cCB0byBkYXRlKVxuXHRcdGlmICh0aGlzLnBsdWdpbj8uc2V0dGluZ3MpIHtcblx0XHRcdHJldHVybiB0aGlzLnBsdWdpbi5zZXR0aW5ncztcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuc2V0dGluZ3M7XG5cdH1cblxuXHQvKipcblx0ICogQ29udmVydHMgdGV4dCB0byBrZWJhYi1jYXNlIHNsdWcgZm9yIFVSTHNcblx0ICovXG5cdC8vIExvY2FsIHRvS2ViYWJDYXNlIHJlbW92ZWQsIHVzaW5nIGltcG9ydGVkIG9uZSBpbnN0ZWFkXG5cblx0LyoqXG5cdCAqIEdldHMgdGhlIEFzdHJvLWNvbXBhdGlibGUgVVJMIGZyb20gYW4gaW50ZXJuYWwgbGluayAoY29waWVkIGZyb20gTGlua0NvbnZlcnRlcilcblx0ICovXG5cdHByaXZhdGUgZ2V0QXN0cm9VcmxGcm9tSW50ZXJuYWxMaW5rKGxpbms6IHN0cmluZyk6IHN0cmluZyB7XG5cdFx0Y29uc3QgaGFzaEluZGV4ID0gbGluay5pbmRleE9mKCcjJyk7XG5cdFx0bGV0IHBhdGggPSBoYXNoSW5kZXggPj0gMCA/IGxpbmsuc2xpY2UoMCwgaGFzaEluZGV4KSA6IGxpbms7XG5cdFx0Y29uc3QgYW5jaG9yID0gaGFzaEluZGV4ID49IDAgPyBsaW5rLnNsaWNlKGhhc2hJbmRleCkgOiAnJztcblxuXHRcdHBhdGggPSBwYXRoLnJlcGxhY2UoL1xcLm1kJC8sIFwiXCIpO1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIGNvbnRlbnQgdHlwZSBhbmQgYXBwcm9wcmlhdGUgYmFzZSBwYXRoXG5cdFx0bGV0IGJhc2VQYXRoID0gXCJcIjtcblx0XHRsZXQgY29udGVudEZvbGRlciA9IFwiXCI7XG5cdFx0bGV0IGNyZWF0aW9uTW9kZTogXCJmaWxlXCIgfCBcImZvbGRlclwiID0gXCJmaWxlXCI7XG5cdFx0bGV0IGluZGV4RmlsZU5hbWUgPSBcIlwiO1xuXG5cdFx0Ly8gQ2hlY2sgYWxsIGNvbnRlbnQgdHlwZXMsIHNvcnRlZCBieSBwYXR0ZXJuIHNwZWNpZmljaXR5IChtb3JlIHNwZWNpZmljIGZpcnN0KVxuXHRcdGNvbnN0IHNldHRpbmdzID0gdGhpcy5nZXRTZXR0aW5ncygpO1xuXHRcdGNvbnN0IGNvbnRlbnRUeXBlcyA9IHNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcblx0XHRjb25zdCBzb3J0ZWRUeXBlcyA9IHNvcnRCeVBhdHRlcm5TcGVjaWZpY2l0eShjb250ZW50VHlwZXMpO1xuXG5cdFx0Zm9yIChjb25zdCBjb250ZW50VHlwZSBvZiBzb3J0ZWRUeXBlcykge1xuXHRcdFx0aWYgKCFjb250ZW50VHlwZS5lbmFibGVkKSBjb250aW51ZTtcblxuXHRcdFx0bGV0IG1hdGNoZXMgPSBmYWxzZTtcblxuXHRcdFx0Ly8gSGFuZGxlIGJsYW5rIGZvbGRlciAocm9vdCkgLSBtYXRjaGVzIGZpbGVzIGluIHZhdWx0IHJvb3Qgb25seVxuXHRcdFx0aWYgKCFjb250ZW50VHlwZS5mb2xkZXIgfHwgY29udGVudFR5cGUuZm9sZGVyLnRyaW0oKSA9PT0gXCJcIikge1xuXHRcdFx0XHRpZiAoIXBhdGguaW5jbHVkZXMoXCIvXCIpIHx8IHBhdGguc3BsaXQoXCIvXCIpLmxlbmd0aCA9PT0gMSkge1xuXHRcdFx0XHRcdG1hdGNoZXMgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2UgaWYgKG1hdGNoZXNGb2xkZXJQYXR0ZXJuKHBhdGgsIGNvbnRlbnRUeXBlLmZvbGRlcikpIHtcblx0XHRcdFx0bWF0Y2hlcyA9IHRydWU7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChtYXRjaGVzKSB7XG5cdFx0XHRcdGNvbnRlbnRGb2xkZXIgPSBjb250ZW50VHlwZS5mb2xkZXIgfHwgXCJcIjtcblx0XHRcdFx0YmFzZVBhdGggPSBjb250ZW50VHlwZS5saW5rQmFzZVBhdGggfHwgXCJcIjtcblx0XHRcdFx0Y3JlYXRpb25Nb2RlID0gY29udGVudFR5cGUuY3JlYXRpb25Nb2RlO1xuXHRcdFx0XHRpbmRleEZpbGVOYW1lID0gY29udGVudFR5cGUuaW5kZXhGaWxlTmFtZSB8fCBcIlwiO1xuXHRcdFx0XHRicmVhazsgLy8gTW9zdCBzcGVjaWZpYyBwYXR0ZXJuIHdpbnNcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBTdHJpcCBjb250ZW50IGZvbGRlciBpZiBwcmVzZW50XG5cdFx0aWYgKGNvbnRlbnRGb2xkZXIpIHtcblx0XHRcdHBhdGggPSBwYXRoLnNsaWNlKGNvbnRlbnRGb2xkZXIubGVuZ3RoICsgMSk7XG5cdFx0fVxuXG5cdFx0bGV0IGFkZFRyYWlsaW5nU2xhc2ggPSBmYWxzZTtcblxuXHRcdC8vIFNtYXJ0IGRldGVjdGlvbjogaWYgdGhlIGZpbGVuYW1lIG1hdGNoZXMgdGhlIGluZGV4IGZpbGUgbmFtZSAocmVnYXJkbGVzcyBvZiBjcmVhdGlvbiBtb2RlKSxcblx0XHQvLyB0cmVhdCBpdCBhcyBmb2xkZXItYmFzZWQgbG9naWNcblx0XHQvLyBOb3RlOiBXZSBvbmx5IHNldCBhZGRUcmFpbGluZ1NsYXNoIGhlcmU7IHRoZSBmaW5hbCBjaGVjayB3aWxsIHByZXZlbnQgaXQgaWYgdGhlcmUncyBhbiBhbmNob3Jcblx0XHRpZiAoaW5kZXhGaWxlTmFtZSAmJiBpbmRleEZpbGVOYW1lLnRyaW0oKSAhPT0gXCJcIikge1xuXHRcdFx0Y29uc3QgcGFydHMgPSBwYXRoLnNwbGl0KCcvJyk7XG5cdFx0XHRpZiAocGFydHNbcGFydHMubGVuZ3RoIC0gMV0gPT09IGluZGV4RmlsZU5hbWUpIHtcblx0XHRcdFx0cGFydHMucG9wKCk7XG5cdFx0XHRcdHBhdGggPSBwYXJ0cy5qb2luKCcvJyk7XG5cdFx0XHRcdGFkZFRyYWlsaW5nU2xhc2ggPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSBpZiAoY3JlYXRpb25Nb2RlID09PSBcImZvbGRlclwiKSB7XG5cdFx0XHQvLyBGYWxsYmFjayB0byBvcmlnaW5hbCBsb2dpYyBpZiBubyBpbmRleCBmaWxlIG5hbWUgaXMgc3BlY2lmaWVkXG5cdFx0XHQvLyBEZWZhdWx0IHRvIFwiaW5kZXhcIiB3aGVuIGluZGV4RmlsZU5hbWUgaXMgYmxhbmtcblx0XHRcdGNvbnN0IGRlZmF1bHRJbmRleE5hbWUgPSBcImluZGV4XCI7XG5cdFx0XHRjb25zdCBwYXJ0cyA9IHBhdGguc3BsaXQoJy8nKTtcblx0XHRcdGlmIChwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXSA9PT0gZGVmYXVsdEluZGV4TmFtZSkge1xuXHRcdFx0XHRwYXJ0cy5wb3AoKTtcblx0XHRcdFx0cGF0aCA9IHBhcnRzLmpvaW4oJy8nKTtcblx0XHRcdFx0YWRkVHJhaWxpbmdTbGFzaCA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Y29uc3Qgc2x1Z1BhcnRzID0gcGF0aC5zcGxpdCgnLycpLm1hcChwYXJ0ID0+IHRvS2ViYWJDYXNlKHBhcnQpKTtcblx0XHRjb25zdCBzbHVnID0gc2x1Z1BhcnRzLmpvaW4oJy8nKTtcblxuXHRcdC8vIEZvcm1hdCBiYXNlIHBhdGhcblx0XHRpZiAoYmFzZVBhdGgpIHtcblx0XHRcdGlmICghYmFzZVBhdGguc3RhcnRzV2l0aChcIi9cIikpIGJhc2VQYXRoID0gXCIvXCIgKyBiYXNlUGF0aDtcblx0XHRcdGlmICghYmFzZVBhdGguZW5kc1dpdGgoXCIvXCIpKSBiYXNlUGF0aCArPSBcIi9cIjtcblx0XHR9XG5cblx0XHQvLyBEZXRlcm1pbmUgaWYgd2Ugc2hvdWxkIGFkZCB0cmFpbGluZyBzbGFzaFxuXHRcdC8vIENSSVRJQ0FMOiBOZXZlciBhZGQgdHJhaWxpbmcgc2xhc2ggYmVmb3JlIGFuIGFuY2hvciAoZS5nLiwgL2Fib3V0I2hlYWRpbmcgbm90IC9hYm91dC8jaGVhZGluZylcblx0XHQvLyBUaGlzIGlzIGVzcGVjaWFsbHkgaW1wb3J0YW50IGZvciBhbmNob3IgbGlua3MgZnJvbSBjb3B5IGhlYWRpbmcgVVJMIGZ1bmN0aW9uYWxpdHlcblx0XHQvLyBBbmNob3IgbGlua3Mgc2hvdWxkIE5FVkVSIGhhdmUgdHJhaWxpbmcgc2xhc2hlcywgcmVnYXJkbGVzcyBvZiBzZXR0aW5nc1xuXHRcdGNvbnN0IHNob3VsZEFkZFRyYWlsaW5nU2xhc2ggPSAoc2V0dGluZ3MuYWRkVHJhaWxpbmdTbGFzaFRvTGlua3MgfHwgYWRkVHJhaWxpbmdTbGFzaCkgJiYgIWFuY2hvcjtcblxuXHRcdHJldHVybiBgJHtiYXNlUGF0aH0ke3NsdWd9JHtzaG91bGRBZGRUcmFpbGluZ1NsYXNoID8gJy8nIDogJyd9JHthbmNob3J9YDtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZW5lcmF0ZXMgYSBzdGFuZGFyZCBPYnNpZGlhbiBsaW5rIHRvIGEgaGVhZGluZywgcmVzcGVjdGluZyB1c2VyJ3MgbGluayBmb3JtYXQgcHJlZmVyZW5jZVxuXHQgKi9cblx0Z2VuZXJhdGVPYnNpZGlhbkxpbmsoYXBwOiBBcHAsIGZpbGU6IFRGaWxlLCBoZWFkaW5nOiBIZWFkaW5nQ2FjaGUpOiBzdHJpbmcge1xuXHRcdGNvbnN0IGhlYWRpbmdUZXh0ID0gaGVhZGluZy5oZWFkaW5nO1xuXG5cdFx0Ly8gQ2hlY2sgaWYgdXNlciBwcmVmZXJzIHdpa2lsaW5rcyBieSB0ZXN0aW5nIE9ic2lkaWFuJ3MgZGVmYXVsdCBiZWhhdmlvclxuXHRcdGNvbnN0IHRlc3RMaW5rID0gYXBwLmZpbGVNYW5hZ2VyLmdlbmVyYXRlTWFya2Rvd25MaW5rKGZpbGUsICcnLCAnJyk7XG5cdFx0aWYgKHRlc3RMaW5rLnN0YXJ0c1dpdGgoJ1tbJykpIHtcblx0XHRcdC8vIFVzZXIgcHJlZmVycyB3aWtpbGlua3MgLSB1c2UganVzdCB0aGUgZmlsZW5hbWUgKGJhc2VuYW1lKSB3aXRob3V0IHBhdGhcblx0XHRcdGNvbnN0IGZpbGVOYW1lID0gZmlsZS5iYXNlbmFtZTtcblx0XHRcdHJldHVybiBgW1ske2ZpbGVOYW1lfSMke2hlYWRpbmdUZXh0fXwke2hlYWRpbmdUZXh0fV1dYDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gVXNlciBwcmVmZXJzIG1hcmtkb3duIGxpbmtzIC0gdXNlIE9ic2lkaWFuJ3MgbWV0aG9kIHdpdGggaGVhZGluZyB0ZXh0IGFzLWlzIChVUkwtZW5jb2RlZClcblx0XHRcdC8vIEdldCB0aGUgYmFzZSBsaW5rIGZyb20gT2JzaWRpYW4gKHJlc3BlY3RzIHVzZXIncyBwYXRoIHNldHRpbmdzKVxuXHRcdFx0Y29uc3QgYmFzZUxpbmsgPSBhcHAuZmlsZU1hbmFnZXIuZ2VuZXJhdGVNYXJrZG93bkxpbmsoZmlsZSwgJycsICcnKTtcblx0XHRcdC8vIEV4dHJhY3QgdGhlIHBhdGggcGFydCBhbmQgYWRkIG91ciBhbmNob3Igd2l0aCBwcm9wZXIgZGlzcGxheSB0ZXh0XG5cdFx0XHRpZiAoYmFzZUxpbmsuc3RhcnRzV2l0aCgnW1snKSkge1xuXHRcdFx0XHQvLyBUaGlzIHNob3VsZG4ndCBoYXBwZW4gc2luY2Ugd2UncmUgaW4gdGhlIG1hcmtkb3duIGJyYW5jaCwgYnV0IGp1c3QgaW4gY2FzZVxuXHRcdFx0XHRjb25zdCBmaWxlTmFtZSA9IGZpbGUuYmFzZW5hbWU7XG5cdFx0XHRcdHJldHVybiBgW1ske2ZpbGVOYW1lfSMke2hlYWRpbmdUZXh0fXwke2hlYWRpbmdUZXh0fV1dYDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIEV4dHJhY3QgdGhlIHBhdGggZnJvbSB0aGUgZ2VuZXJhdGVkIGxpbmsgYW5kIHJlY29uc3RydWN0IHdpdGggcHJvcGVyIGRpc3BsYXkgdGV4dFxuXHRcdFx0XHRjb25zdCBtYXRjaCA9IGJhc2VMaW5rLm1hdGNoKC9cXFsoW15cXF1dKylcXF1cXCgoW14pXSspXFwpLyk7XG5cdFx0XHRcdGlmIChtYXRjaCkge1xuXHRcdFx0XHRcdGNvbnN0IFssICwgcGF0aF0gPSBtYXRjaDtcblx0XHRcdFx0XHQvLyBGb3IgT2JzaWRpYW4sIHVzZSB0aGUgaGVhZGluZyB0ZXh0IGFzLWlzIChVUkwtZW5jb2RlZCksIG5vdCBrZWJhYi1jYXNlXG5cdFx0XHRcdFx0cmV0dXJuIGBbJHtoZWFkaW5nVGV4dH1dKCR7cGF0aH0jJHtlbmNvZGVVUklDb21wb25lbnQoaGVhZGluZ1RleHQpfSlgO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdC8vIEZhbGxiYWNrIHRvIG1hbnVhbCBjb25zdHJ1Y3Rpb25cblx0XHRcdFx0XHRjb25zdCBlbmNvZGVkRmlsZW5hbWUgPSBlbmNvZGVVUklDb21wb25lbnQoZmlsZS5uYW1lKTtcblx0XHRcdFx0XHQvLyBGb3IgT2JzaWRpYW4sIHVzZSB0aGUgaGVhZGluZyB0ZXh0IGFzLWlzIChVUkwtZW5jb2RlZClcblx0XHRcdFx0XHRyZXR1cm4gYFske2hlYWRpbmdUZXh0fV0oJHtlbmNvZGVkRmlsZW5hbWV9IyR7ZW5jb2RlVVJJQ29tcG9uZW50KGhlYWRpbmdUZXh0KX0pYDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBHZW5lcmF0ZXMgYSBzdGFuZGFyZCBPYnNpZGlhbiB3aWtpbGluayB0byBhIGhlYWRpbmdcblx0ICovXG5cdGdlbmVyYXRlT2JzaWRpYW5XaWtpbGluayhmaWxlOiBURmlsZSwgaGVhZGluZzogSGVhZGluZ0NhY2hlKTogc3RyaW5nIHtcblx0XHRjb25zdCBoZWFkaW5nVGV4dCA9IGhlYWRpbmcuaGVhZGluZztcblx0XHQvLyBVc2UganVzdCB0aGUgZmlsZW5hbWUgKGJhc2VuYW1lKSwgbm90IHRoZSBmdWxsIHBhdGhcblx0XHRjb25zdCBmaWxlTmFtZSA9IGZpbGUuYmFzZW5hbWU7XG5cdFx0cmV0dXJuIGBbWyR7ZmlsZU5hbWV9IyR7aGVhZGluZ1RleHR9fCR7aGVhZGluZ1RleHR9XV1gO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdlbmVyYXRlcyBhbiBBc3Ryby1jb21wYXRpYmxlIG1hcmtkb3duIGxpbmsgdG8gYSBoZWFkaW5nXG5cdCAqL1xuXHRnZW5lcmF0ZUFzdHJvTGluayhmaWxlOiBURmlsZSwgaGVhZGluZzogSGVhZGluZ0NhY2hlKTogc3RyaW5nIHtcblx0XHRjb25zdCBoZWFkaW5nVGV4dCA9IGhlYWRpbmcuaGVhZGluZztcblx0XHRjb25zdCBhbmNob3IgPSB0b0tlYmFiQ2FzZShoZWFkaW5nVGV4dCk7XG5cdFx0Ly8gVXNlIHRoZSBzYW1lIGxvZ2ljIGFzIHRoZSBleGlzdGluZyBsaW5rIGNvbnZlcnRlclxuXHRcdGNvbnN0IGludGVybmFsTGluayA9IGAke2ZpbGUucGF0aH0jJHthbmNob3J9YDtcblx0XHRjb25zdCBhc3Ryb1VybCA9IHRoaXMuZ2V0QXN0cm9VcmxGcm9tSW50ZXJuYWxMaW5rKGludGVybmFsTGluayk7XG5cdFx0cmV0dXJuIGBbJHtoZWFkaW5nVGV4dH1dKCR7YXN0cm9Vcmx9KWA7XG5cdH1cblxuXHQvKipcblx0ICogR2VuZXJhdGVzIGFuIEFzdHJvLWNvbXBhdGlibGUgd2lraWxpbmsgdG8gYSBoZWFkaW5nXG5cdCAqL1xuXHRnZW5lcmF0ZUFzdHJvV2lraWxpbmsoZmlsZTogVEZpbGUsIGhlYWRpbmc6IEhlYWRpbmdDYWNoZSk6IHN0cmluZyB7XG5cdFx0Y29uc3QgaGVhZGluZ1RleHQgPSBoZWFkaW5nLmhlYWRpbmc7XG5cdFx0Y29uc3QgYW5jaG9yID0gdG9LZWJhYkNhc2UoaGVhZGluZ1RleHQpO1xuXHRcdC8vIFVzZSB0aGUgc2FtZSBsb2dpYyBhcyB0aGUgZXhpc3RpbmcgbGluayBjb252ZXJ0ZXJcblx0XHRjb25zdCBpbnRlcm5hbExpbmsgPSBgJHtmaWxlLnBhdGh9IyR7YW5jaG9yfWA7XG5cdFx0Y29uc3QgYXN0cm9VcmwgPSB0aGlzLmdldEFzdHJvVXJsRnJvbUludGVybmFsTGluayhpbnRlcm5hbExpbmspO1xuXHRcdC8vIENyZWF0ZSBhIHdpa2lsaW5rIHdpdGggdGhlIEFzdHJvIFVSTCBhcyB0aGUgdGFyZ2V0XG5cdFx0cmV0dXJuIGBbWyR7aGVhZGluZ1RleHR9fCR7YXN0cm9Vcmx9XV1gO1xuXHR9XG5cblx0LyoqXG5cdCAqIEV4dHJhY3RzIHRoZSBVUkwgZnJvbSBhIG1hcmtkb3duIGxpbmsgb3Igd2lraWxpbmtcblx0ICovXG5cdGV4dHJhY3RVcmwobGluazogc3RyaW5nKTogc3RyaW5nIHtcblx0XHQvLyBIYW5kbGUgbWFya2Rvd24gbGlua3M6IFt0ZXh0XSh1cmwpXG5cdFx0Y29uc3QgbWFya2Rvd25NYXRjaCA9IGxpbmsubWF0Y2goL1xcWyhbXlxcXV0rKVxcXVxcKChbXildKylcXCkvKTtcblx0XHRpZiAobWFya2Rvd25NYXRjaCkge1xuXHRcdFx0cmV0dXJuIG1hcmtkb3duTWF0Y2hbMl07XG5cdFx0fVxuXG5cdFx0Ly8gSGFuZGxlIHdpa2lsaW5rczogW1twYXRoI2hlYWRpbmd8dGV4dF1dIG9yIFtbcGF0aCNoZWFkaW5nXV1cblx0XHRjb25zdCB3aWtpbGlua01hdGNoID0gbGluay5tYXRjaCgvXFxbXFxbKFteXFxdXSspXFxdXFxdLyk7XG5cdFx0aWYgKHdpa2lsaW5rTWF0Y2gpIHtcblx0XHRcdGNvbnN0IGNvbnRlbnQgPSB3aWtpbGlua01hdGNoWzFdO1xuXHRcdFx0Ly8gRXh0cmFjdCB0aGUgcGF0aCBwYXJ0IChiZWZvcmUgfCBpZiBwcmVzZW50KVxuXHRcdFx0Y29uc3QgcGF0aFBhcnQgPSBjb250ZW50LnNwbGl0KCd8JylbMF07XG5cdFx0XHRyZXR1cm4gcGF0aFBhcnQ7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgaXQgZG9lc24ndCBtYXRjaCBlaXRoZXIgZm9ybWF0LCByZXR1cm4gYXMtaXMgKG1pZ2h0IGFscmVhZHkgYmUgYSBVUkwpXG5cdFx0cmV0dXJuIGxpbms7XG5cdH1cblxuXHQvKipcblx0ICogR2VuZXJhdGVzIHRoZSBhcHByb3ByaWF0ZSBsaW5rIGZvcm1hdCBiYXNlZCBvbiBzZXR0aW5nc1xuXHQgKi9cblx0Z2VuZXJhdGVMaW5rKGFwcDogQXBwLCBmaWxlOiBURmlsZSwgaGVhZGluZzogSGVhZGluZ0NhY2hlKTogc3RyaW5nIHtcblx0XHRjb25zdCBzZXR0aW5ncyA9IHRoaXMuZ2V0U2V0dGluZ3MoKTtcblx0XHRpZiAoc2V0dGluZ3MuY29weUhlYWRpbmdMaW5rRm9ybWF0ID09PSBcImFzdHJvXCIpIHtcblx0XHRcdC8vIEFzdHJvIGZvcm1hdCBhbHdheXMgdXNlcyBtYXJrZG93biBsaW5rcyAod2lraWxpbmtzIHdpdGggQXN0cm8gVVJMcyBkb24ndCBtYWtlIHNlbnNlKVxuXHRcdFx0cmV0dXJuIHRoaXMuZ2VuZXJhdGVBc3Ryb0xpbmsoZmlsZSwgaGVhZGluZyk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIFVzZSBPYnNpZGlhbidzIGJ1aWx0LWluIG1ldGhvZCB3aGljaCByZXNwZWN0cyB1c2VyIHNldHRpbmdzXG5cdFx0XHRyZXR1cm4gdGhpcy5nZW5lcmF0ZU9ic2lkaWFuTGluayhhcHAsIGZpbGUsIGhlYWRpbmcpO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBGaW5kcyB0aGUgaGVhZGluZyBhdCBhIHNwZWNpZmljIGxpbmUgaW4gYSBmaWxlXG5cdCAqL1xuXHRmaW5kSGVhZGluZ0F0TGluZShhcHA6IEFwcCwgZmlsZTogVEZpbGUsIGxpbmU6IG51bWJlcik6IEhlYWRpbmdDYWNoZSB8IG51bGwge1xuXHRcdGNvbnN0IGNhY2hlID0gYXBwLm1ldGFkYXRhQ2FjaGUuZ2V0RmlsZUNhY2hlKGZpbGUpO1xuXHRcdGlmICghY2FjaGUgfHwgIWNhY2hlLmhlYWRpbmdzKSB7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cblx0XHQvLyBGaW5kIHRoZSBoZWFkaW5nIHRoYXQgY29udGFpbnMgdGhpcyBsaW5lXG5cdFx0Zm9yIChsZXQgaSA9IGNhY2hlLmhlYWRpbmdzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG5cdFx0XHRjb25zdCBoZWFkaW5nID0gY2FjaGUuaGVhZGluZ3NbaV07XG5cdFx0XHRpZiAoaGVhZGluZy5wb3NpdGlvbi5zdGFydC5saW5lIDw9IGxpbmUpIHtcblx0XHRcdFx0cmV0dXJuIGhlYWRpbmc7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cbn1cbiIsICJpbXBvcnQgeyBBcHAsIE5vdGljZSB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgeyBDb250ZW50VHlwZSwgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSB9IGZyb20gXCIuLi90eXBlc1wiO1xyXG5pbXBvcnQgeyBNaWdyYXRpb25Nb2RhbCwgTWlncmF0aW9uQ29uZmxpY3RSZXN1bHQgfSBmcm9tIFwiLi4vdWkvY29tcG9uZW50cy9NaWdyYXRpb25Nb2RhbFwiO1xyXG5pbXBvcnQgeyBBc3Ryb0NvbXBvc2VyU2V0dGluZ1RhYiB9IGZyb20gXCIuLi91aS9zZXR0aW5ncy10YWJcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBNaWdyYXRpb25TZXJ2aWNlIHtcclxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgYXBwOiBBcHAsIHByaXZhdGUgcGx1Z2luOiBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlKSB7IH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIE1pZ3JhdGUgb2xkIHBvc3RzL3BhZ2VzIHNldHRpbmdzIHRvIHVuaWZpZWQgY29udGVudCB0eXBlc1xyXG4gICAgICovXHJcbiAgICBwdWJsaWMgYXN5bmMgbWlncmF0ZVNldHRpbmdzSWZOZWVkZWQoKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICAgICAgY29uc3Qgc2V0dGluZ3MgPSB0aGlzLnBsdWdpbi5zZXR0aW5ncztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgbWlncmF0aW9uIGlzIGFscmVhZHkgY29tcGxldGVkXHJcbiAgICAgICAgaWYgKHNldHRpbmdzLm1pZ3JhdGlvbkNvbXBsZXRlZCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgb2xkIHNldHRpbmdzIHRvIG1pZ3JhdGVcclxuICAgICAgICBjb25zdCBoYXNQb3N0c1NldHRpbmdzID0gc2V0dGluZ3MuYXV0b21hdGVQb3N0Q3JlYXRpb24gIT09IHVuZGVmaW5lZCAmJiBzZXR0aW5ncy5hdXRvbWF0ZVBvc3RDcmVhdGlvbjtcclxuICAgICAgICBjb25zdCBoYXNQYWdlc1NldHRpbmdzID0gc2V0dGluZ3MuZW5hYmxlUGFnZXMgIT09IHVuZGVmaW5lZCAmJiBzZXR0aW5ncy5lbmFibGVQYWdlcztcclxuXHJcbiAgICAgICAgaWYgKCFoYXNQb3N0c1NldHRpbmdzICYmICFoYXNQYWdlc1NldHRpbmdzKSB7XHJcbiAgICAgICAgICAgIC8vIE5vIG9sZCBzZXR0aW5ncyB0byBtaWdyYXRlLCBtYXJrIGFzIGNvbXBsZXRlZFxyXG4gICAgICAgICAgICBzZXR0aW5ncy5taWdyYXRpb25Db21wbGV0ZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgZm9yIG5hbWluZyBjb25mbGljdHNcclxuICAgICAgICBjb25zdCBsZWdhY3lDb250ZW50VHlwZXMgPSAoc2V0dGluZ3MgYXMgdW5rbm93biBhcyB7IGN1c3RvbUNvbnRlbnRUeXBlcz86IENvbnRlbnRUeXBlW10gfSkuY3VzdG9tQ29udGVudFR5cGVzO1xyXG4gICAgICAgIGNvbnN0IGV4aXN0aW5nQ29udGVudFR5cGVzID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IGxlZ2FjeUNvbnRlbnRUeXBlcyB8fCBbXTtcclxuICAgICAgICBjb25zdCBjb25mbGljdHM6IHN0cmluZ1tdID0gW107XHJcbiAgICAgICAgaWYgKGV4aXN0aW5nQ29udGVudFR5cGVzLnNvbWUoKGN0OiBDb250ZW50VHlwZSkgPT4gY3QubmFtZSA9PT0gXCJQb3N0c1wiKSkge1xyXG4gICAgICAgICAgICBjb25mbGljdHMucHVzaChcIlBvc3RzXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZXhpc3RpbmdDb250ZW50VHlwZXMuc29tZSgoY3Q6IENvbnRlbnRUeXBlKSA9PiBjdC5uYW1lID09PSBcIlBhZ2VzXCIpKSB7XHJcbiAgICAgICAgICAgIGNvbmZsaWN0cy5wdXNoKFwiUGFnZXNcIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsZXQgc2hvdWxkTWlncmF0ZSA9IHRydWU7XHJcblxyXG4gICAgICAgIC8vIElmIGNvbmZsaWN0cyBleGlzdCwgcHJvbXB0IHVzZXJcclxuICAgICAgICBpZiAoY29uZmxpY3RzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcclxuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgIHZvaWQgKGFzeW5jICgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG1vZGFsID0gbmV3IE1pZ3JhdGlvbk1vZGFsKHRoaXMuYXBwLCBjb25mbGljdHMpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgdGltZW91dFByb21pc2UgPSBuZXcgUHJvbWlzZTxNaWdyYXRpb25Db25mbGljdFJlc3VsdD4oKHRpbWVvdXRSZXNvbHZlKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbWVvdXRSZXNvbHZlKHsgYWN0aW9uOiBcInNraXBcIiB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LCAzMDAwMCk7IC8vIDMwIHNlY29uZCB0aW1lb3V0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBQcm9taXNlLnJhY2UoW1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGFsLndhaXRGb3JSZXN1bHQoKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lb3V0UHJvbWlzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdC5hY3Rpb24gPT09IFwic2tpcFwiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvdWxkTWlncmF0ZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBOb3RpY2UoXCJNaWdyYXRpb24gc2tpcHBlZC4gT2xkIHBvc3RzL3BhZ2VzIHNldHRpbmdzIHdpbGwgYmUgaWdub3JlZC5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJNaWdyYXRpb24gbW9kYWwgZXJyb3I6XCIsIGVycm9yKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3VsZE1pZ3JhdGUgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldyBOb3RpY2UoXCJNaWdyYXRpb24gc2tpcHBlZCBkdWUgdG8gZXJyb3IuIFlvdSBjYW4gbWlncmF0ZSBtYW51YWxseSBpbiBzZXR0aW5ncy5cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pKCk7XHJcbiAgICAgICAgICAgICAgICB9LCA1MDApOyAvLyBTbWFsbCBkZWxheSB0byBlbnN1cmUgVUkgaXMgcmVhZHlcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXNob3VsZE1pZ3JhdGUpIHtcclxuICAgICAgICAgICAgc2V0dGluZ3MubWlncmF0aW9uQ29tcGxldGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFBlcmZvcm0gbWlncmF0aW9uXHJcbiAgICAgICAgY29uc3QgbWlncmF0ZWRUeXBlczogQ29udGVudFR5cGVbXSA9IFtdO1xyXG5cclxuICAgICAgICAvLyBNaWdyYXRlIFBvc3RzXHJcbiAgICAgICAgaWYgKGhhc1Bvc3RzU2V0dGluZ3MgJiYgIWNvbmZsaWN0cy5pbmNsdWRlcyhcIlBvc3RzXCIpKSB7XHJcbiAgICAgICAgICAgIGNvbnN0IHBvc3RzVHlwZTogQ29udGVudFR5cGUgPSB7XHJcbiAgICAgICAgICAgICAgICBpZDogYHBvc3RzLSR7RGF0ZS5ub3coKX1gLFxyXG4gICAgICAgICAgICAgICAgbmFtZTogXCJQb3N0c1wiLFxyXG4gICAgICAgICAgICAgICAgZm9sZGVyOiBzZXR0aW5ncy5wb3N0c0ZvbGRlciB8fCBcIlwiLFxyXG4gICAgICAgICAgICAgICAgbGlua0Jhc2VQYXRoOiBzZXR0aW5ncy5wb3N0c0xpbmtCYXNlUGF0aCB8fCBcIlwiLFxyXG4gICAgICAgICAgICAgICAgdGVtcGxhdGU6IHNldHRpbmdzLmRlZmF1bHRUZW1wbGF0ZSB8fCAnLS0tXFxudGl0bGU6IFwie3t0aXRsZX19XCJcXG5kYXRlOiB7e2RhdGV9fVxcbnRhZ3M6IFtdXFxuLS0tXFxuJyxcclxuICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBjcmVhdGlvbk1vZGU6IHNldHRpbmdzLmNyZWF0aW9uTW9kZSB8fCBcImZpbGVcIixcclxuICAgICAgICAgICAgICAgIGluZGV4RmlsZU5hbWU6IHNldHRpbmdzLmluZGV4RmlsZU5hbWUgfHwgXCJcIixcclxuICAgICAgICAgICAgICAgIGlnbm9yZVN1YmZvbGRlcnM6IHNldHRpbmdzLm9ubHlBdXRvbWF0ZUluUG9zdHNGb2xkZXIgfHwgZmFsc2UsXHJcbiAgICAgICAgICAgICAgICBlbmFibGVVbmRlcnNjb3JlUHJlZml4OiBzZXR0aW5ncy5lbmFibGVVbmRlcnNjb3JlUHJlZml4IHx8IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgdXNlTWR4RXh0ZW5zaW9uOiBmYWxzZSxcclxuICAgICAgICAgICAgICAgIG1vZGlmaWVkRGF0ZUZpZWxkOiBcIlwiLFxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICBtaWdyYXRlZFR5cGVzLnB1c2gocG9zdHNUeXBlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIE1pZ3JhdGUgUGFnZXNcclxuICAgICAgICBpZiAoaGFzUGFnZXNTZXR0aW5ncyAmJiAhY29uZmxpY3RzLmluY2x1ZGVzKFwiUGFnZXNcIikpIHtcclxuICAgICAgICAgICAgY29uc3QgcGFnZXNUeXBlOiBDb250ZW50VHlwZSA9IHtcclxuICAgICAgICAgICAgICAgIGlkOiBgcGFnZXMtJHtEYXRlLm5vdygpfWAsXHJcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlBhZ2VzXCIsXHJcbiAgICAgICAgICAgICAgICBmb2xkZXI6IHNldHRpbmdzLnBhZ2VzRm9sZGVyIHx8IFwiXCIsXHJcbiAgICAgICAgICAgICAgICBsaW5rQmFzZVBhdGg6IHNldHRpbmdzLnBhZ2VzTGlua0Jhc2VQYXRoIHx8IFwiXCIsXHJcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZTogc2V0dGluZ3MucGFnZVRlbXBsYXRlIHx8ICctLS1cXG50aXRsZTogXCJ7e3RpdGxlfX1cIlxcbmRlc2NyaXB0aW9uOiBcIlwiXFxuLS0tXFxuJyxcclxuICAgICAgICAgICAgICAgIGVuYWJsZWQ6IHRydWUsXHJcbiAgICAgICAgICAgICAgICBjcmVhdGlvbk1vZGU6IHNldHRpbmdzLnBhZ2VzQ3JlYXRpb25Nb2RlIHx8IFwiZmlsZVwiLFxyXG4gICAgICAgICAgICAgICAgaW5kZXhGaWxlTmFtZTogc2V0dGluZ3MucGFnZXNJbmRleEZpbGVOYW1lIHx8IFwiXCIsXHJcbiAgICAgICAgICAgICAgICBpZ25vcmVTdWJmb2xkZXJzOiBzZXR0aW5ncy5vbmx5QXV0b21hdGVJblBhZ2VzRm9sZGVyIHx8IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgZW5hYmxlVW5kZXJzY29yZVByZWZpeDogZmFsc2UsXHJcbiAgICAgICAgICAgICAgICB1c2VNZHhFeHRlbnNpb246IGZhbHNlLFxyXG4gICAgICAgICAgICAgICAgbW9kaWZpZWREYXRlRmllbGQ6IFwiXCIsXHJcbiAgICAgICAgICAgIH07XHJcbiAgICAgICAgICAgIG1pZ3JhdGVkVHlwZXMucHVzaChwYWdlc1R5cGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uc3QgZXhpc3RpbmdGcm9tTmV3ID0gc2V0dGluZ3MuY29udGVudFR5cGVzIHx8IFtdO1xyXG4gICAgICAgIGNvbnN0IGV4aXN0aW5nRnJvbUxlZ2FjeSA9IGxlZ2FjeUNvbnRlbnRUeXBlcyB8fCBbXTtcclxuXHJcbiAgICAgICAgbGV0IGV4aXN0aW5nVHlwZXM6IENvbnRlbnRUeXBlW10gPSBleGlzdGluZ0Zyb21OZXcubGVuZ3RoID4gMCA/IGV4aXN0aW5nRnJvbU5ldyA6IGV4aXN0aW5nRnJvbUxlZ2FjeTtcclxuICAgICAgICBsZXQgZmluYWxUeXBlczogQ29udGVudFR5cGVbXSA9IFsuLi5leGlzdGluZ1R5cGVzXTtcclxuXHJcbiAgICAgICAgaWYgKG1pZ3JhdGVkVHlwZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICBjb25zdCBleGlzdGluZ05hbWVzID0gbmV3IFNldChleGlzdGluZ1R5cGVzLm1hcChjdCA9PiBjdC5uYW1lKSk7XHJcbiAgICAgICAgICAgIGNvbnN0IG5ld01pZ3JhdGVkVHlwZXMgPSBtaWdyYXRlZFR5cGVzLmZpbHRlcihtdCA9PiAhZXhpc3RpbmdOYW1lcy5oYXMobXQubmFtZSkpO1xyXG5cclxuICAgICAgICAgICAgaWYgKG5ld01pZ3JhdGVkVHlwZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgZmluYWxUeXBlcyA9IFsuLi5leGlzdGluZ1R5cGVzLCAuLi5uZXdNaWdyYXRlZFR5cGVzXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgc2V0dGluZ3MuY29udGVudFR5cGVzID0gZmluYWxUeXBlcztcclxuXHJcbiAgICAgICAgLy8gQ2xlYW4gdXAgbGVnYWN5IGZpZWxkc1xyXG4gICAgICAgIGNvbnN0IGxlZ2FjeUZpZWxkcyA9IFtcclxuICAgICAgICAgICAgJ2N1c3RvbUNvbnRlbnRUeXBlcycsICdlbmFibGVVbmRlcnNjb3JlUHJlZml4JywgJ3Bvc3RzRm9sZGVyJywgJ3Bvc3RzTGlua0Jhc2VQYXRoJyxcclxuICAgICAgICAgICAgJ2F1dG9tYXRlUG9zdENyZWF0aW9uJywgJ2NyZWF0aW9uTW9kZScsICdpbmRleEZpbGVOYW1lJywgJ2V4Y2x1ZGVkRGlyZWN0b3JpZXMnLFxyXG4gICAgICAgICAgICAnb25seUF1dG9tYXRlSW5Qb3N0c0ZvbGRlcicsICdlbmFibGVQYWdlcycsICdwYWdlc0ZvbGRlcicsICdwYWdlc0xpbmtCYXNlUGF0aCcsXHJcbiAgICAgICAgICAgICdwYWdlc0NyZWF0aW9uTW9kZScsICdwYWdlc0luZGV4RmlsZU5hbWUnLCAncGFnZVRlbXBsYXRlJywgJ29ubHlBdXRvbWF0ZUluUGFnZXNGb2xkZXInXHJcbiAgICAgICAgXTtcclxuXHJcbiAgICAgICAgY29uc3Qgc2V0dGluZ3NSZWNvcmQgPSBzZXR0aW5ncyBhcyB1bmtub3duIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xyXG4gICAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgbGVnYWN5RmllbGRzKSB7XHJcbiAgICAgICAgICAgIGRlbGV0ZSBzZXR0aW5nc1JlY29yZFtmaWVsZF07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBzZXR0aW5ncy5taWdyYXRpb25Db21wbGV0ZWQgPSB0cnVlO1xyXG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xyXG4gICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLmxvYWRTZXR0aW5ncygpO1xyXG5cclxuICAgICAgICBpZiAobWlncmF0ZWRUeXBlcy5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICAgIG5ldyBOb3RpY2UoYE1pZ3JhdGlvbiBjb21wbGV0ZWQ6ICR7bWlncmF0ZWRUeXBlcy5sZW5ndGh9IGNvbnRlbnQgdHlwZShzKSBtaWdyYXRlZC5gKTtcclxuXHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucGx1Z2luLnNldHRpbmdzVGFiIGluc3RhbmNlb2YgQXN0cm9Db21wb3NlclNldHRpbmdUYWIpIHtcclxuICAgICAgICAgICAgICAgICAgICBjb25zdCBzZXR0aW5nc1RhYiA9IHRoaXMucGx1Z2luLnNldHRpbmdzVGFiO1xyXG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChzZXR0aW5nc1RhYi5jdXN0b21Db250ZW50VHlwZXNDb250YWluZXIgfHwgc2V0dGluZ3NUYWIuY29udGFpbmVyRWwpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNldHRpbmdzVGFiLmRpc3BsYXkoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiQ291bGQgbm90IHJlZnJlc2ggc2V0dGluZ3MgdGFiIGFmdGVyIG1pZ3JhdGlvbjpcIiwgZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9LCAzMDApO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufVxyXG4iLCAiaW1wb3J0IHsgQXBwLCBNb2RhbCB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5cclxuZXhwb3J0IGludGVyZmFjZSBNaWdyYXRpb25Db25mbGljdFJlc3VsdCB7XHJcblx0YWN0aW9uOiBcInNraXBcIiB8IFwibWlncmF0ZVwiO1xyXG59XHJcblxyXG5leHBvcnQgY2xhc3MgTWlncmF0aW9uTW9kYWwgZXh0ZW5kcyBNb2RhbCB7XHJcblx0cmVzdWx0OiBNaWdyYXRpb25Db25mbGljdFJlc3VsdCB8IG51bGwgPSBudWxsO1xyXG5cdHJlc29sdmVQcm9taXNlOiAoKHJlc3VsdDogTWlncmF0aW9uQ29uZmxpY3RSZXN1bHQpID0+IHZvaWQpIHwgbnVsbCA9IG51bGw7XHJcblxyXG5cdGNvbnN0cnVjdG9yKGFwcDogQXBwLCBjb25mbGljdHM6IHN0cmluZ1tdKSB7XHJcblx0XHRzdXBlcihhcHApO1xyXG5cdH1cclxuXHJcblx0b25PcGVuKCkge1xyXG5cdFx0Y29uc3QgeyBjb250ZW50RWwgfSA9IHRoaXM7XHJcblx0XHRjb250ZW50RWwuZW1wdHkoKTtcclxuXHRcdGNvbnRlbnRFbC5hZGRDbGFzcyhcImFzdHJvLWNvbXBvc2VyLW1pZ3JhdGlvbi1tb2RhbFwiKTtcclxuXHJcblx0XHRjb250ZW50RWwuY3JlYXRlRWwoXCJoMlwiLCB7IHRleHQ6IFwiTWlncmF0aW9uIGNvbmZsaWN0IGRldGVjdGVkXCIgfSk7XHJcblxyXG5cdFx0Y29udGVudEVsLmNyZWF0ZUVsKFwicFwiLCB7XHJcblx0XHRcdHRleHQ6IFwiWW91IGhhdmUgZXhpc3RpbmcgY29udGVudCB0eXBlcyB3aXRoIG5hbWVzIHRoYXQgY29uZmxpY3Qgd2l0aCBwb3N0cyBvciBwYWdlcy4gSG93IHdvdWxkIHlvdSBsaWtlIHRvIHByb2NlZWQ/XCIsXHJcblx0XHR9KTtcclxuXHJcblx0XHRjb25zdCBjb25mbGljdExpc3QgPSBjb250ZW50RWwuY3JlYXRlRWwoXCJ1bFwiKTtcclxuXHRcdGNvbmZsaWN0TGlzdC5jcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJTa2lwIG1pZ3JhdGlvbjoga2VlcCB5b3VyIGV4aXN0aW5nIHBvc3RzL3BhZ2VzIHNldHRpbmdzICh0aGV5IHdpbGwgYmUgaWdub3JlZClcIiB9KTtcclxuXHRcdGNvbmZsaWN0TGlzdC5jcmVhdGVFbChcImxpXCIsIHsgdGV4dDogXCJNaWdyYXRlIHdpdGggcmVuYW1lZCB0eXBlczogY3JlYXRlICdwb3N0cyAobWlncmF0ZWQpJyBhbmQgJ3BhZ2VzIChtaWdyYXRlZCknIGNvbnRlbnQgdHlwZXNcIiB9KTtcclxuXHJcblx0XHRjb25zdCBidXR0b25Db250YWluZXIgPSBjb250ZW50RWwuY3JlYXRlRGl2KHsgY2xzOiBcIm1vZGFsLWJ1dHRvbi1jb250YWluZXJcIiB9KTtcclxuXHJcblx0XHRjb25zdCBza2lwQnV0dG9uID0gYnV0dG9uQ29udGFpbmVyLmNyZWF0ZUVsKFwiYnV0dG9uXCIsIHtcclxuXHRcdFx0dGV4dDogXCJTa2lwIG1pZ3JhdGlvblwiLFxyXG5cdFx0XHRjbHM6IFwibW9kLWN0YVwiLFxyXG5cdFx0fSk7XHJcblx0XHRza2lwQnV0dG9uLm9uY2xpY2sgPSAoKSA9PiB7XHJcblx0XHRcdHRoaXMucmVzdWx0ID0geyBhY3Rpb246IFwic2tpcFwiIH07XHJcblx0XHRcdHRoaXMuY2xvc2UoKTtcclxuXHRcdH07XHJcblxyXG5cdFx0Y29uc3QgbWlncmF0ZUJ1dHRvbiA9IGJ1dHRvbkNvbnRhaW5lci5jcmVhdGVFbChcImJ1dHRvblwiLCB7XHJcblx0XHRcdHRleHQ6IFwiTWlncmF0ZSB3aXRoIHJlbmFtZWQgdHlwZXNcIixcclxuXHRcdFx0Y2xzOiBcIm1vZC1jdGFcIixcclxuXHRcdH0pO1xyXG5cdFx0bWlncmF0ZUJ1dHRvbi5vbmNsaWNrID0gKCkgPT4ge1xyXG5cdFx0XHR0aGlzLnJlc3VsdCA9IHsgYWN0aW9uOiBcIm1pZ3JhdGVcIiB9O1xyXG5cdFx0XHR0aGlzLmNsb3NlKCk7XHJcblx0XHR9O1xyXG5cdH1cclxuXHJcblx0b25DbG9zZSgpIHtcclxuXHRcdGNvbnN0IHsgY29udGVudEVsIH0gPSB0aGlzO1xyXG5cdFx0Y29udGVudEVsLmVtcHR5KCk7XHJcblx0XHRpZiAodGhpcy5yZXNvbHZlUHJvbWlzZSAmJiB0aGlzLnJlc3VsdCkge1xyXG5cdFx0XHR0aGlzLnJlc29sdmVQcm9taXNlKHRoaXMucmVzdWx0KTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdGFzeW5jIHdhaXRGb3JSZXN1bHQoKTogUHJvbWlzZTxNaWdyYXRpb25Db25mbGljdFJlc3VsdD4ge1xyXG5cdFx0cmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiB7XHJcblx0XHRcdHRoaXMucmVzb2x2ZVByb21pc2UgPSByZXNvbHZlO1xyXG5cdFx0XHR0aGlzLm9wZW4oKTtcclxuXHRcdH0pO1xyXG5cdH1cclxufVxyXG5cclxuIiwgImltcG9ydCB7IEFwcCwgVEZpbGUsIE5vdGljZSB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgeyBDb250ZW50VHlwZSwgQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZSB9IGZyb20gXCIuLi90eXBlc1wiO1xyXG5pbXBvcnQgeyBDT05TVEFOVFMgfSBmcm9tIFwiLi4vc2V0dGluZ3NcIjtcclxuaW1wb3J0IHsgbWF0Y2hlc0ZvbGRlclBhdHRlcm4sIHNvcnRCeVBhdHRlcm5TcGVjaWZpY2l0eSB9IGZyb20gXCIuLi91dGlscy9wYXRoLW1hdGNoaW5nXCI7XHJcbmltcG9ydCB7IFRpdGxlTW9kYWwgfSBmcm9tIFwiLi4vdWkvdGl0bGUtbW9kYWxcIjtcclxuXHJcbmV4cG9ydCBjbGFzcyBDcmVhdGVFdmVudFNlcnZpY2Uge1xyXG4gICAgcHJpdmF0ZSBsYXN0UHJvY2Vzc2VkRmlsZXM6IE1hcDxzdHJpbmcsIG51bWJlcj4gPSBuZXcgTWFwKCk7XHJcblxyXG4gICAgY29uc3RydWN0b3IoXHJcbiAgICAgICAgcHJpdmF0ZSBhcHA6IEFwcCxcclxuICAgICAgICBwcml2YXRlIHBsdWdpbjogQXN0cm9Db21wb3NlclBsdWdpbkludGVyZmFjZVxyXG4gICAgKSB7IH1cclxuXHJcbiAgICBwdWJsaWMgaGFuZGxlQ3JlYXRlKGZpbGU6IFRGaWxlKTogdm9pZCB7XHJcbiAgICAgICAgdm9pZCAoYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xyXG5cclxuICAgICAgICAgICAgaWYgKCEoZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSB8fCAoZmlsZS5leHRlbnNpb24gIT09IFwibWRcIiAmJiBmaWxlLmV4dGVuc2lvbiAhPT0gXCJtZHhcIikpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgY29uc3QgZmlsZVBhdGggPSBmaWxlLnBhdGg7XHJcblxyXG4gICAgICAgICAgICAvLyBTa2lwIGlmIHRoaXMgZmlsZSB3YXMgY3JlYXRlZCBieSB0aGUgcGx1Z2luIGl0c2VsZiAoVFRMIGNoZWNrKVxyXG4gICAgICAgICAgICBjb25zdCBjcmVhdGVkVGltZSA9IHRoaXMucGx1Z2luLnBsdWdpbkNyZWF0ZWRGaWxlcy5nZXQoZmlsZVBhdGgpO1xyXG4gICAgICAgICAgICBpZiAoY3JlYXRlZFRpbWUgJiYgbm93IC0gY3JlYXRlZFRpbWUgPCA1ICogNjAgKiAxMDAwKSB7IC8vIDUgbWludXRlcyBUVExcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gUGVyLWZpbGUgZGVib3VuY2UgY2hlY2tcclxuICAgICAgICAgICAgY29uc3QgbGFzdFByb2Nlc3NlZCA9IHRoaXMubGFzdFByb2Nlc3NlZEZpbGVzLmdldChmaWxlUGF0aCkgfHwgMDtcclxuICAgICAgICAgICAgaWYgKGxhc3RQcm9jZXNzZWQgPiAwICYmIG5vdyAtIGxhc3RQcm9jZXNzZWQgPCBDT05TVEFOVFMuREVCT1VOQ0VfTVMpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2xlYW4gdXAgb2xkIGVudHJpZXMgaW4gbG9jYWwgZGVib3VuY2UgbWFwXHJcbiAgICAgICAgICAgIGlmIChsYXN0UHJvY2Vzc2VkID4gMCAmJiBub3cgLSBsYXN0UHJvY2Vzc2VkID4gMjAwMCkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5sYXN0UHJvY2Vzc2VkRmlsZXMuZGVsZXRlKGZpbGVQYXRoKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gUGVyaW9kaWMgY2xlYW51cCBvZiBkZWJvdW5jZSBtYXBcclxuICAgICAgICAgICAgY29uc3QgcGVyaW9kaWNDdXRvZmYgPSBub3cgLSBDT05TVEFOVFMuREVCT1VOQ0VfTVMgKiAyO1xyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtwYXRoLCB0aW1lXSBvZiB0aGlzLmxhc3RQcm9jZXNzZWRGaWxlcy5lbnRyaWVzKCkpIHtcclxuICAgICAgICAgICAgICAgIGlmICh0aW1lIDwgcGVyaW9kaWNDdXRvZmYpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxhc3RQcm9jZXNzZWRGaWxlcy5kZWxldGUocGF0aCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnRUeXBlcyA9IHRoaXMucGx1Z2luLnNldHRpbmdzLmNvbnRlbnRUeXBlcyB8fCBbXTtcclxuICAgICAgICAgICAgY29uc3QgaGFzRW5hYmxlZENvbnRlbnRUeXBlcyA9IGNvbnRlbnRUeXBlcy5zb21lKGN0ID0+IGN0LmVuYWJsZWQpO1xyXG5cclxuICAgICAgICAgICAgaWYgKCFoYXNFbmFibGVkQ29udGVudFR5cGVzKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGNvbnN0IHNvcnRlZENvbnRlbnRUeXBlcyA9IHNvcnRCeVBhdHRlcm5TcGVjaWZpY2l0eShjb250ZW50VHlwZXMpO1xyXG4gICAgICAgICAgICBsZXQgbWF0Y2hlZENvbnRlbnRUeXBlSWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xyXG4gICAgICAgICAgICBjb25zdCBtYXRjaGluZ1R5cGVzOiBDb250ZW50VHlwZVtdID0gW107XHJcblxyXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGNvbnRlbnRUeXBlIG9mIHNvcnRlZENvbnRlbnRUeXBlcykge1xyXG4gICAgICAgICAgICAgICAgaWYgKCFjb250ZW50VHlwZS5lbmFibGVkKSBjb250aW51ZTtcclxuXHJcbiAgICAgICAgICAgICAgICBsZXQgbWF0Y2hlcyA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmICghY29udGVudFR5cGUuZm9sZGVyIHx8IGNvbnRlbnRUeXBlLmZvbGRlci50cmltKCkgPT09IFwiXCIpIHtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIWZpbGVQYXRoLmluY2x1ZGVzKFwiL1wiKSB8fCBmaWxlUGF0aC5zcGxpdChcIi9cIikubGVuZ3RoID09PSAxKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoZXMgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobWF0Y2hlc0ZvbGRlclBhdHRlcm4oZmlsZVBhdGgsIGNvbnRlbnRUeXBlLmZvbGRlcikpIHtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoY29udGVudFR5cGUuaWdub3JlU3ViZm9sZGVycykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwYXRoU2VnbWVudHMgPSBmaWxlUGF0aC5zcGxpdChcIi9cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhdGhEZXB0aCA9IHBhdGhTZWdtZW50cy5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhdHRlcm5TZWdtZW50cyA9IGNvbnRlbnRUeXBlLmZvbGRlci5zcGxpdChcIi9cIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGV4cGVjdGVkRGVwdGggPSBwYXR0ZXJuU2VnbWVudHMubGVuZ3RoO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbnRlbnRUeXBlLmNyZWF0aW9uTW9kZSA9PT0gXCJmb2xkZXJcIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZm9sZGVyRGVwdGggPSBwYXRoRGVwdGggLSAxO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGZvbGRlckRlcHRoID09PSBleHBlY3RlZERlcHRoIHx8IGZvbGRlckRlcHRoID09PSBleHBlY3RlZERlcHRoICsgMSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoZXMgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhdGhEZXB0aCA9PT0gZXhwZWN0ZWREZXB0aCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoZXMgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWF0Y2hlcyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIGlmIChtYXRjaGVzKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbWF0Y2hpbmdUeXBlcy5wdXNoKGNvbnRlbnRUeXBlKTtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIW1hdGNoZWRDb250ZW50VHlwZUlkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoZWRDb250ZW50VHlwZUlkID0gY29udGVudFR5cGUuaWQ7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBpZiAobWF0Y2hpbmdUeXBlcy5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCB0eXBlTmFtZXMgPSBtYXRjaGluZ1R5cGVzLm1hcChjdCA9PiBjdC5uYW1lIHx8IFwiVW5uYW1lZFwiKS5qb2luKFwiLCBcIik7XHJcbiAgICAgICAgICAgICAgICBuZXcgTm90aWNlKGBNdWx0aXBsZSBjb250ZW50IHR5cGVzICgke3R5cGVOYW1lc30pIG1hdGNoIHRoaXMgZmlsZS4gVXNpbmcgbW9zdCBzcGVjaWZpYzogJHttYXRjaGluZ1R5cGVzWzBdLm5hbWUgfHwgXCJVbm5hbWVkXCJ9YCk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGlmICghbWF0Y2hlZENvbnRlbnRUeXBlSWQpIHtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgY29uc3Qgc3RhdCA9IGF3YWl0IHRoaXMuYXBwLnZhdWx0LmFkYXB0ZXIuc3RhdChmaWxlLnBhdGgpO1xyXG4gICAgICAgICAgICBjb25zdCBpc05ld05vdGUgPSBzdGF0Py5tdGltZSAmJiAobm93IC0gc3RhdC5tdGltZSA8IENPTlNUQU5UUy5TVEFUX01USU1FX1RIUkVTSE9MRCk7XHJcblxyXG4gICAgICAgICAgICBpZiAoIWlzTmV3Tm90ZSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvLyBDSEVDSyBCQUNLR1JPVU5EIFBST0NFU1NJTkcgT05MWSBGT1IgTk9OLUNSRUFUSU9OIEVWRU5UU1xyXG4gICAgICAgICAgICAvLyBBY3R1YWxseSwgaGFuZGxlQ3JlYXRlIGlzIE9OTFkgZm9yIGNyZWF0aW9uLiBcclxuICAgICAgICAgICAgLy8gVGhlIGNoZWNrIHdhcyBwcmV2ZW50aW5nIHRoZSBtb2RhbCBmcm9tIG9wZW5pbmcgaWYgdGhlIGFjdGl2ZSBmaWxlIHdhcyBub3QgeWV0IHNldCB0byB0aGUgbmV3IGZpbGUuXHJcbiAgICAgICAgICAgIGNvbnN0IGFjdGl2ZUZpbGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xyXG4gICAgICAgICAgICBjb25zdCBpc0FjdGl2ZUZpbGUgPSBhY3RpdmVGaWxlICYmIGFjdGl2ZUZpbGUucGF0aCA9PT0gZmlsZS5wYXRoO1xyXG4gICAgICAgICAgICBpZiAoIXRoaXMucGx1Z2luLnNldHRpbmdzLnByb2Nlc3NCYWNrZ3JvdW5kRmlsZUNoYW5nZXMgJiYgIWlzQWN0aXZlRmlsZSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgNTApKTtcclxuXHJcbiAgICAgICAgICAgIGxldCBjb250ZW50OiBzdHJpbmc7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcclxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciByZWFkaW5nIGZpbGUgZm9yIGNyZWF0ZSBkZXRlY3Rpb246XCIsIGVycm9yKTtcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgaWYgKGNvbnRlbnQudHJpbSgpLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgICAgIGlmIChjb250ZW50LnN0YXJ0c1dpdGgoJy0tLScpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnJvbnRtYXR0ZXJFbmQgPSBjb250ZW50LmluZGV4T2YoJ1xcbi0tLScsIDMpO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmIChmcm9udG1hdHRlckVuZCAhPT0gLTEpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgZnJvbnRtYXR0ZXJUZXh0ID0gY29udGVudC5zbGljZSg0LCBmcm9udG1hdHRlckVuZCkudHJpbSgpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBsaW5lcyA9IGZyb250bWF0dGVyVGV4dC5zcGxpdCgnXFxuJykuZmlsdGVyKGxpbmUgPT4gbGluZS50cmltKCkubGVuZ3RoID4gMCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXRoaXMucGx1Z2luLnNldHRpbmdzLnByb2Nlc3NCYWNrZ3JvdW5kRmlsZUNoYW5nZXMgJiYgbGluZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobGluZXMubGVuZ3RoID4gMSB8fCAobGluZXMubGVuZ3RoID09PSAxICYmICFsaW5lc1swXS5zdGFydHNXaXRoKCd0aXRsZTonKSkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRlbnRXaXRob3V0RnJvbnRtYXR0ZXIgPSBjb250ZW50LnN0YXJ0c1dpdGgoJy0tLScpXHJcbiAgICAgICAgICAgICAgICAgICAgPyBjb250ZW50LnNsaWNlKGNvbnRlbnQuaW5kZXhPZignXFxuLS0tJywgMykgKyA0KS50cmltKClcclxuICAgICAgICAgICAgICAgICAgICA6IGNvbnRlbnQudHJpbSgpO1xyXG4gICAgICAgICAgICAgICAgaWYgKGNvbnRlbnRXaXRob3V0RnJvbnRtYXR0ZXIubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgdGhpcy5sYXN0UHJvY2Vzc2VkRmlsZXMuc2V0KGZpbGUucGF0aCwgbm93KTtcclxuXHJcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5sYXN0UHJvY2Vzc2VkRmlsZXMuZGVsZXRlKGZpbGUucGF0aCk7XHJcbiAgICAgICAgICAgIH0sIENPTlNUQU5UUy5ERUJPVU5DRV9NUyArIDEwMCk7XHJcblxyXG4gICAgICAgICAgICBuZXcgVGl0bGVNb2RhbCh0aGlzLmFwcCwgZmlsZSwgdGhpcy5wbHVnaW4sIG1hdGNoZWRDb250ZW50VHlwZUlkLCBmYWxzZSwgdHJ1ZSkub3BlbigpO1xyXG4gICAgICAgIH0pKCk7XHJcbiAgICB9XHJcbn1cclxuIiwgImltcG9ydCB7IEFwcCwgVEZpbGUsIG1vbWVudCwgVEFic3RyYWN0RmlsZSB9IGZyb20gXCJvYnNpZGlhblwiO1xyXG5pbXBvcnQgeyBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlLCBDb250ZW50VHlwZSB9IGZyb20gXCIuLi90eXBlc1wiO1xyXG5cclxuZXhwb3J0IGNsYXNzIEZyb250bWF0dGVyU2VydmljZSB7XHJcbiAgICBwcml2YXRlIGxhc3RQcm9jZXNzZWRGaWxlOiBzdHJpbmcgPSBcIlwiO1xyXG4gICAgcHJpdmF0ZSBsYXN0UHJvY2Vzc2VkVGltZTogbnVtYmVyID0gMDtcclxuICAgIHByaXZhdGUgZGVib3VuY2VUaW1lb3V0OiBudW1iZXIgfCBudWxsID0gbnVsbDtcclxuICAgIHByaXZhdGUgZHJhZnRTdGF0dXNNYXA6IE1hcDxzdHJpbmcsIGJvb2xlYW4+ID0gbmV3IE1hcCgpO1xyXG4gICAgcHJpdmF0ZSBjb250ZW50SGFzaENhY2hlOiBNYXA8c3RyaW5nLCBzdHJpbmc+ID0gbmV3IE1hcCgpO1xyXG5cclxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgYXBwOiBBcHAsIHByaXZhdGUgcGx1Z2luOiBBc3Ryb0NvbXBvc2VyUGx1Z2luSW50ZXJmYWNlKSB7XHJcbiAgICAgICAgdGhpcy5yZWdpc3RlckV2ZW50cygpO1xyXG5cclxuICAgICAgICAvLyBBbHNvIHJlLWluaXRpYWxpemUgd2hlbiBsYXlvdXQgaXMgcmVhZHkganVzdCBpbiBjYXNlXHJcbiAgICAgICAgdGhpcy5hcHAud29ya3NwYWNlLm9uTGF5b3V0UmVhZHkoKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLmluaXRpYWxpemVEcmFmdFN0YXR1c01hcCgpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBkZXN0cm95KCkge1xyXG4gICAgICAgIC8vIE5vLW9wLCBrZXB0IGZvciBpbnRlcmZhY2UgY29tcGF0aWJpbGl0eVxyXG4gICAgfVxyXG5cclxuICAgIHB1YmxpYyBpbml0aWFsaXplRHJhZnRTdGF0dXNNYXAoKSB7XHJcbiAgICAgICAgdGhpcy5kcmFmdFN0YXR1c01hcC5jbGVhcigpO1xyXG4gICAgICAgIGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XHJcbiAgICAgICAgY29uc3QgaXNVbmRlcnNjb3JlTW9kZSA9IHNldHRpbmdzLmRyYWZ0RGV0ZWN0aW9uTW9kZSA9PT0gJ3VuZGVyc2NvcmUtcHJlZml4JztcclxuICAgICAgICBjb25zdCBkcmFmdFByb3AgPSBzZXR0aW5ncy5kcmFmdFByb3BlcnR5IHx8IFwiZHJhZnRcIjtcclxuICAgICAgICAvLyBJbmNsdWRlIGJvdGggLm1kIGFuZCAubWR4IGZpbGVzXHJcbiAgICAgICAgY29uc3QgZmlsZXMgPSB0aGlzLmFwcC52YXVsdC5nZXRGaWxlcygpLmZpbHRlcihmID0+IGYgaW5zdGFuY2VvZiBURmlsZSAmJiAoZi5leHRlbnNpb24gPT09ICdtZCcgfHwgZi5leHRlbnNpb24gPT09ICdtZHgnKSkgYXMgVEZpbGVbXTtcclxuXHJcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XHJcbiAgICAgICAgICAgIGlmIChpc1VuZGVyc2NvcmVNb2RlKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmRyYWZ0U3RhdHVzTWFwLnNldChmaWxlLnBhdGgsIGZpbGUubmFtZS5zdGFydHNXaXRoKCdfJykpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgY2FjaGUgPSB0aGlzLmFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZShmaWxlKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHJhd1ZhbHVlID0gY2FjaGU/LmZyb250bWF0dGVyPy5bZHJhZnRQcm9wXTtcclxuICAgICAgICAgICAgICAgIHRoaXMuZHJhZnRTdGF0dXNNYXAuc2V0KGZpbGUucGF0aCwgdGhpcy5jYWxjdWxhdGVJc0RyYWZ0KHJhd1ZhbHVlLCBzZXR0aW5ncykpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgY2FsY3VsYXRlSXNEcmFmdChyYXdWYWx1ZTogYW55LCBzZXR0aW5nczogYW55KTogYm9vbGVhbiB7XHJcbiAgICAgICAgLy8gSWYgdW5kZWZpbmVkL251bGwsIGFzc3VtZSBpdCdzIE5PVCBhIGRyYWZ0IHVubGVzcyBsb2dpYyBzYXlzIG90aGVyd2lzZVxyXG4gICAgICAgIGlmIChyYXdWYWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHJhd1ZhbHVlID09PSBudWxsKSByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgICAgIC8vIENvbnZlcnQgdG8gc3RyaW5nIGZvciBlYXNpZXIgbWF0Y2hpbmcgaWYgaXQncyBub3QgYSBib29sZWFuXHJcbiAgICAgICAgY29uc3QgdmFsID0gU3RyaW5nKHJhd1ZhbHVlKS50b0xvd2VyQ2FzZSgpO1xyXG5cclxuICAgICAgICBpZiAoc2V0dGluZ3MuZHJhZnRMb2dpYyA9PT0gJ2ZhbHNlLWlzLWRyYWZ0Jykge1xyXG4gICAgICAgICAgICAvLyBcIkZhbHNlID0gUHVibGlzaGVkXCIsIHNvIGl0J3MgYSBkcmFmdCBpZiBpdCBpcyBmYWxzZSwgXCJmYWxzZVwiLCBcIjBcIiwgZXRjLlxyXG4gICAgICAgICAgICByZXR1cm4gdmFsID09PSAnZmFsc2UnIHx8IHZhbCA9PT0gJzAnIHx8IHJhd1ZhbHVlID09PSBmYWxzZTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAvLyBcIlRydWUgPSBEcmFmdFwiLCBzbyBpdCdzIGEgZHJhZnQgaWYgaXQgaXMgdHJ1ZSwgXCJ0cnVlXCIsIFwiMVwiLCBldGMuXHJcbiAgICAgICAgICAgIHJldHVybiB2YWwgPT09ICd0cnVlJyB8fCB2YWwgPT09ICcxJyB8fCByYXdWYWx1ZSA9PT0gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSByZWdpc3RlckV2ZW50cygpIHtcclxuICAgICAgICAvLyBXYXRjaCBmb3IgbWV0YWRhdGEgY2hhbmdlcyAocHJvcGVydHktYmFzZWQgZHJhZnQgc3luYylcclxuICAgICAgICB0aGlzLnBsdWdpbi5yZWdpc3RlckV2ZW50KFxyXG4gICAgICAgICAgICB0aGlzLmFwcC5tZXRhZGF0YUNhY2hlLm9uKFwiY2hhbmdlZFwiLCAoZmlsZSkgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMub25NZXRhZGF0YUNoYW5nZShmaWxlKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSlcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBXYXRjaCBmb3IgcmVuYW1lcyAodW5kZXJzY29yZS1wcmVmaXggZHJhZnQgc3luYylcclxuICAgICAgICB0aGlzLnBsdWdpbi5yZWdpc3RlckV2ZW50KFxyXG4gICAgICAgICAgICB0aGlzLmFwcC52YXVsdC5vbihcInJlbmFtZVwiLCAoZmlsZSwgb2xkUGF0aCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgaWYgKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMub25SZW5hbWUoZmlsZSwgb2xkUGF0aCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gV2F0Y2ggZm9yIGZpbGUgb3BlbiB0byBsYXppbHkgcG9wdWxhdGUgaGFzaCBjYWNoZSBmb3IgdGhlIGFjdGl2ZSBmaWxlXHJcbiAgICAgICAgdGhpcy5wbHVnaW4ucmVnaXN0ZXJFdmVudChcclxuICAgICAgICAgICAgdGhpcy5hcHAud29ya3NwYWNlLm9uKFwiZmlsZS1vcGVuXCIsIChmaWxlKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAoZmlsZSBpbnN0YW5jZW9mIFRGaWxlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgdm9pZCAoYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IHRoaXMuYXBwLnZhdWx0LnJlYWQoZmlsZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbnRlbnRIYXNoQ2FjaGUuc2V0KGZpbGUucGF0aCwgdGhpcy5nZXRDb250ZW50SGFzaChjb250ZW50KSk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBsYXppbHkgaW5pdGlhbGl6ZSBjb250ZW50IGhhc2ggZm9yICR7ZmlsZS5wYXRofTpgLCBlKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0pKCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIG9uUmVuYW1lKGZpbGU6IFRGaWxlLCBvbGRQYXRoOiBzdHJpbmcpIHtcclxuICAgICAgICBjb25zdCBzZXR0aW5ncyA9IHRoaXMucGx1Z2luLnNldHRpbmdzO1xyXG4gICAgICAgIGlmICghc2V0dGluZ3Muc3luY0RyYWZ0RGF0ZSkgcmV0dXJuO1xyXG5cclxuICAgICAgICBjb25zdCBvbGROYW1lID0gb2xkUGF0aC5zcGxpdChcIi9cIikucG9wKCkgfHwgXCJcIjtcclxuICAgICAgICBjb25zdCBuZXdOYW1lID0gZmlsZS5uYW1lO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpZiBpdCB3YXMgYW4gdW5kZXJzY29yZSBkcmFmdCBhbmQgaXMgbm93IG5vdFxyXG4gICAgICAgIGlmIChvbGROYW1lLnN0YXJ0c1dpdGgoXCJfXCIpICYmICFuZXdOYW1lLnN0YXJ0c1dpdGgoXCJfXCIpKSB7XHJcbiAgICAgICAgICAgIC8vIENoZWNrIGdsb2JhbCBzZXR0aW5nIG9yIHBlci1jb250ZW50LXR5cGUgc2V0dGluZ1xyXG4gICAgICAgICAgICBpZiAoc2V0dGluZ3MuZHJhZnREZXRlY3Rpb25Nb2RlID09PSAndW5kZXJzY29yZS1wcmVmaXgnKSB7XHJcbiAgICAgICAgICAgICAgICB2b2lkIHRoaXMudXBkYXRlRGF0ZShmaWxlKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gdGhpcy5wbHVnaW4uZmlsZU9wcz8uZ2V0Q29udGVudFR5cGVCeVBhdGgoZmlsZS5wYXRoKTtcclxuICAgICAgICAgICAgICAgIGlmIChjb250ZW50VHlwZT8uZW5hYmxlVW5kZXJzY29yZVByZWZpeCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZvaWQgdGhpcy51cGRhdGVEYXRlKGZpbGUpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgb25NZXRhZGF0YUNoYW5nZShmaWxlOiBURmlsZSkge1xyXG4gICAgICAgIGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XHJcblxyXG4gICAgICAgIC8vIEluIHVuZGVyc2NvcmUtcHJlZml4IG1vZGUsIGRyYWZ0IHRyYW5zaXRpb25zIGFyZSBoYW5kbGVkIGJ5IG9uUmVuYW1lLCBub3QgbWV0YWRhdGEgY2hhbmdlcy5cclxuICAgICAgICAvLyBTa2lwIHByb3BlcnR5LWJhc2VkIGRyYWZ0IGRldGVjdGlvbiBlbnRpcmVseSB0byBhdm9pZCBwaGFudG9tIHRyYW5zaXRpb25zLlxyXG4gICAgICAgIGlmIChzZXR0aW5ncy5kcmFmdERldGVjdGlvbk1vZGUgPT09ICd1bmRlcnNjb3JlLXByZWZpeCcpIHtcclxuICAgICAgICAgICAgLy8gU3RpbGwgaGFuZGxlIG1vZGlmaWVkIGRhdGUgc3luYyBpZiBhcHBsaWNhYmxlXHJcbiAgICAgICAgICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gdGhpcy5wbHVnaW4uZmlsZU9wcz8uZ2V0Q29udGVudFR5cGVCeVBhdGgoZmlsZS5wYXRoKTtcclxuICAgICAgICAgICAgY29uc3QgaGFzTW9kaWZpZWRGaWVsZCA9ICEhY29udGVudFR5cGU/Lm1vZGlmaWVkRGF0ZUZpZWxkO1xyXG4gICAgICAgICAgICBpZiAoIWhhc01vZGlmaWVkRmllbGQpIHJldHVybjtcclxuXHJcbiAgICAgICAgICAgIGNvbnN0IGFjdGl2ZUZpbGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xyXG4gICAgICAgICAgICBjb25zdCBpc0FjdGl2ZUZpbGUgPSBhY3RpdmVGaWxlICYmIGFjdGl2ZUZpbGUucGF0aCA9PT0gZmlsZS5wYXRoO1xyXG4gICAgICAgICAgICBpZiAoIXNldHRpbmdzLnByb2Nlc3NCYWNrZ3JvdW5kRmlsZUNoYW5nZXMgJiYgIWlzQWN0aXZlRmlsZSkgcmV0dXJuO1xyXG5cclxuICAgICAgICAgICAgdm9pZCB0aGlzLnByb2Nlc3NGaWxlKGZpbGUsIGZhbHNlLCBjb250ZW50VHlwZSk7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIENoZWNrIGJhY2tncm91bmQgcHJvY2Vzc2luZ1xyXG4gICAgICAgIGNvbnN0IGFjdGl2ZUZpbGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xyXG4gICAgICAgIGNvbnN0IGlzQWN0aXZlRmlsZSA9IGFjdGl2ZUZpbGUgJiYgYWN0aXZlRmlsZS5wYXRoID09PSBmaWxlLnBhdGg7XHJcbiAgICAgICAgaWYgKCFzZXR0aW5ncy5wcm9jZXNzQmFja2dyb3VuZEZpbGVDaGFuZ2VzICYmICFpc0FjdGl2ZUZpbGUpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gTmVlZCB0byBjaGVjayBjb250ZW50IHR5cGUgdG8gc2VlIGlmIG1vZGlmaWVkIGRhdGUgaXMgZW5hYmxlZCBmb3IgVEhJUyB0eXBlXHJcbiAgICAgICAgY29uc3QgY29udGVudFR5cGUgPSB0aGlzLnBsdWdpbi5maWxlT3BzPy5nZXRDb250ZW50VHlwZUJ5UGF0aChmaWxlLnBhdGgpO1xyXG4gICAgICAgIGNvbnN0IGhhc01vZGlmaWVkRmllbGQgPSAhIWNvbnRlbnRUeXBlPy5tb2RpZmllZERhdGVGaWVsZDtcclxuXHJcbiAgICAgICAgaWYgKCFzZXR0aW5ncy5zeW5jRHJhZnREYXRlICYmICFoYXNNb2RpZmllZEZpZWxkKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFRyYWNrIGRyYWZ0IHN0YXR1cyBjaGFuZ2VzIChwcm9wZXJ0eS1iYXNlZCBvbmx5KVxyXG4gICAgICAgIGNvbnN0IGNhY2hlID0gdGhpcy5hcHAubWV0YWRhdGFDYWNoZS5nZXRGaWxlQ2FjaGUoZmlsZSk7XHJcbiAgICAgICAgY29uc3QgZHJhZnRQcm9wID0gc2V0dGluZ3MuZHJhZnRQcm9wZXJ0eSB8fCBcImRyYWZ0XCI7XHJcbiAgICAgICAgY29uc3QgcmF3VmFsdWUgPSBjYWNoZT8uZnJvbnRtYXR0ZXI/LltkcmFmdFByb3BdO1xyXG5cclxuICAgICAgICAvLyBMb2dpYzogdHJ1ZS1pcy1kcmFmdCB2cyBmYWxzZS1pcy1kcmFmdFxyXG4gICAgICAgIGNvbnN0IGlzQ3VycmVudGx5RHJhZnQgPSB0aGlzLmNhbGN1bGF0ZUlzRHJhZnQocmF3VmFsdWUsIHNldHRpbmdzKTtcclxuXHJcbiAgICAgICAgLy8gSWYgaXQncyB0aGUgZmlyc3QgdGltZSB3ZSBzZWUgdGhpcyBmaWxlLCBqdXN0IHJlY29yZCBpdCBhbmQgc2tpcFxyXG4gICAgICAgIGlmICghdGhpcy5kcmFmdFN0YXR1c01hcC5oYXMoZmlsZS5wYXRoKSkge1xyXG4gICAgICAgICAgICB0aGlzLmRyYWZ0U3RhdHVzTWFwLnNldChmaWxlLnBhdGgsIGlzQ3VycmVudGx5RHJhZnQpO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25zdCBwcmV2aW91c0RyYWZ0U3RhdHVzID0gdGhpcy5kcmFmdFN0YXR1c01hcC5nZXQoZmlsZS5wYXRoKTtcclxuXHJcbiAgICAgICAgbGV0IGRyYWZ0U3RhdHVzQ2hhbmdlZFRvUHVibGlzaGVkID0gZmFsc2U7XHJcbiAgICAgICAgLy8gVHJhbnNpdGlvbiBmcm9tIGRyYWZ0IHRvIG5vbi1kcmFmdFxyXG4gICAgICAgIGlmIChwcmV2aW91c0RyYWZ0U3RhdHVzID09PSB0cnVlICYmIGlzQ3VycmVudGx5RHJhZnQgPT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgIGRyYWZ0U3RhdHVzQ2hhbmdlZFRvUHVibGlzaGVkID0gdHJ1ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFVwZGF0ZSB0aGUgbWFwIGZvciBuZXh0IHRpbWVcclxuICAgICAgICB0aGlzLmRyYWZ0U3RhdHVzTWFwLnNldChmaWxlLnBhdGgsIGlzQ3VycmVudGx5RHJhZnQpO1xyXG5cclxuICAgICAgICAvLyBJZiBubyBwdWJsaWNhdGlvbiBjaGFuZ2UgYW5kIG5vIG1vZGlmaWVkIGZpZWxkIHRvIHVwZGF0ZSwgc2tpcCBwcm9jZXNzaW5nXHJcbiAgICAgICAgaWYgKCFkcmFmdFN0YXR1c0NoYW5nZWRUb1B1Ymxpc2hlZCAmJiAhaGFzTW9kaWZpZWRGaWVsZCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBQcmV2ZW50IGluZmluaXRlIGxvb3BzIGFuZCByZWR1bmRhbnQgcHJvY2Vzc2luZ1xyXG4gICAgICAgIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XHJcbiAgICAgICAgaWYgKHRoaXMubGFzdFByb2Nlc3NlZEZpbGUgPT09IGZpbGUucGF0aCAmJiBub3cgLSB0aGlzLmxhc3RQcm9jZXNzZWRUaW1lIDwgMjAwMCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBVc2UgYSBkZWJvdW5jZSB0byB3YWl0IGZvciB3cml0aW5nIHRvIGZpbmlzaFxyXG4gICAgICAgIGlmICh0aGlzLmRlYm91bmNlVGltZW91dCkge1xyXG4gICAgICAgICAgICB3aW5kb3cuY2xlYXJUaW1lb3V0KHRoaXMuZGVib3VuY2VUaW1lb3V0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMuZGVib3VuY2VUaW1lb3V0ID0gd2luZG93LnNldFRpbWVvdXQoYXN5bmMgKCkgPT4ge1xyXG4gICAgICAgICAgICAvLyBDaGVjayBpZiBjb250ZW50IChleGNsdWRpbmcgZnJvbnRtYXR0ZXIpIGhhcyBhY3R1YWxseSBjaGFuZ2VkXHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRIYXNoID0gdGhpcy5nZXRDb250ZW50SGFzaChjb250ZW50KTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzSGFzaCA9IHRoaXMuY29udGVudEhhc2hDYWNoZS5nZXQoZmlsZS5wYXRoKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBVcGRhdGUgY2FjaGUgaW1tZWRpYXRlbHkgdG8gcHJldmVudCByZS1wcm9jZXNzaW5nIGV2ZW4gaWYgd2Ugc2tpcFxyXG4gICAgICAgICAgICAgICAgdGhpcy5jb250ZW50SGFzaENhY2hlLnNldChmaWxlLnBhdGgsIGN1cnJlbnRIYXNoKTtcclxuXHJcbiAgICAgICAgICAgICAgICBpZiAocHJldmlvdXNIYXNoID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBGaXJzdCB0aW1lIHdlJ3JlIHNlZWluZyB0aGUgY29udGVudCBvZiBhbiBleGlzdGluZyBmaWxlIChsYXp5IGluaXQgdmlhIGV2ZW50KVxyXG4gICAgICAgICAgICAgICAgICAgIC8vIElmIHdlIG1pc3NlZCB0aGUgZmlsZS1vcGVuIChlLmcuIGl0IHdhcyBhbHJlYWR5IG9wZW4gb24gc3RhcnQpLCBcclxuICAgICAgICAgICAgICAgICAgICAvLyB3ZSdsbCB0cmVhdCB0aGlzIGZpcnN0IGNoYW5nZSBhcyB0aGUgYmFzZWxpbmUgdW5sZXNzIGl0J3MgYSBwdWJsaWNhdGlvbiBjaGFuZ2UuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFkcmFmdFN0YXR1c0NoYW5nZWRUb1B1Ymxpc2hlZCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwcmV2aW91c0hhc2ggPT09IGN1cnJlbnRIYXNoKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gT25seSBzdWItcHVibGljYXRpb24gY2hhbmdlcyAobGlrZSBtZXRhZGF0YSkgaGFwcGVuZWQsIHNraXAgbW9kaWZpZWQgZGF0ZSB1cGRhdGVcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIWRyYWZ0U3RhdHVzQ2hhbmdlZFRvUHVibGlzaGVkKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAvLyBJZiBoYXNoZXMgZGlmZmVyLCBvciBpdCdzIGEgcHVibGljYXRpb24gY2hhbmdlLCB3ZSBwcm9jZWVkIHRvIHByb2Nlc3NGaWxlXHJcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYEZhaWxlZCB0byBjaGVjayBjb250ZW50IGhhc2ggZm9yICR7ZmlsZS5wYXRofTpgLCBlKTtcclxuICAgICAgICAgICAgICAgIC8vIEZhbGxiYWNrIHRvIHByb2Nlc3NpbmcgaWYgcmVhZCBmYWlscywgb3IgcmV0dXJuPyBcclxuICAgICAgICAgICAgICAgIC8vIEJldHRlciB0byByZXR1cm4gdG8gYmUgc2FmZSBhZ2FpbnN0IGFjY2lkZW50YWwgdXBkYXRlc1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICB2b2lkIHRoaXMucHJvY2Vzc0ZpbGUoZmlsZSwgZHJhZnRTdGF0dXNDaGFuZ2VkVG9QdWJsaXNoZWQsIGNvbnRlbnRUeXBlKTtcclxuICAgICAgICB9LCA1MDApO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgZ2V0Q29udGVudEhhc2goY29udGVudDogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgICAgICAvLyAxLiBTdHJpcCBmcm9udG1hdHRlclxyXG4gICAgICAgIGxldCBib2R5ID0gY29udGVudDtcclxuICAgICAgICBpZiAoY29udGVudC5zdGFydHNXaXRoKCctLS0nKSkge1xyXG4gICAgICAgICAgICBjb25zdCBlbmQgPSBjb250ZW50LmluZGV4T2YoJ1xcbi0tLScsIDMpO1xyXG4gICAgICAgICAgICBpZiAoZW5kICE9PSAtMSkge1xyXG4gICAgICAgICAgICAgICAgYm9keSA9IGNvbnRlbnQuc2xpY2UoZW5kICsgNCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIDIuIE5vcm1hbGl6ZSB3aGl0ZXNwYWNlOiBjb2xsYXBzZSBhbGwgd2hpdGVzcGFjZSBpbnRvIHNpbmdsZSBzcGFjZXMgYW5kIHRyaW1cclxuICAgICAgICBjb25zdCBub3JtYWxpemVkID0gYm9keS5yZXBsYWNlKC9cXHMrL2csICcgJykudHJpbSgpO1xyXG5cclxuICAgICAgICAvLyAzLiBTaW1wbGUgaGFzaGluZyAoY29uY2F0ZW5hdGluZyBsZW5ndGggYW5kIGZpcnN0L2xhc3QgYml0cyBpcyB1c3VhbGx5IGVub3VnaCBmb3IgbG9jYWwgY2hhbmdlIGRldGVjdGlvbiwgXHJcbiAgICAgICAgLy8gYnV0IGxldCdzIGRvIGEgc2xpZ2h0bHkgYmV0dGVyIG9uZSBpZiB3ZSB3YW50IHRvIGJlIHJvYnVzdCwgb3IganVzdCB1c2UgdGhlIG5vcm1hbGl6ZWQgc3RyaW5nIGlmIG1lbW9yeSBhbGxvd3MpXHJcbiAgICAgICAgLy8gR2l2ZW4gT2JzaWRpYW4gdmF1bHRzIGNhbiBiZSBsYXJnZSwgYSBzbWFsbCBoYXNoIGlzIHNhZmVyLlxyXG4gICAgICAgIHJldHVybiB0aGlzLnNpbXBsZUhhc2gobm9ybWFsaXplZCk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBzaW1wbGVIYXNoKHN0cjogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgICAgICBsZXQgaGFzaCA9IDA7XHJcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgICAgY29uc3QgY2hhciA9IHN0ci5jaGFyQ29kZUF0KGkpO1xyXG4gICAgICAgICAgICBoYXNoID0gKChoYXNoIDw8IDUpIC0gaGFzaCkgKyBjaGFyO1xyXG4gICAgICAgICAgICBoYXNoIHw9IDA7IC8vIENvbnZlcnQgdG8gMzJiaXQgaW50ZWdlclxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gaGFzaC50b1N0cmluZygpICsgXCJfXCIgKyBzdHIubGVuZ3RoO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgYXN5bmMgdXBkYXRlRGF0ZShmaWxlOiBURmlsZSkge1xyXG4gICAgICAgIGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XHJcbiAgICAgICAgY29uc3QgZGF0ZUZpZWxkID0gc2V0dGluZ3MucHVibGlzaERhdGVGaWVsZCB8fCBcImRhdGVcIjtcclxuXHJcbiAgICAgICAgYXdhaXQgdGhpcy5hcHAuZmlsZU1hbmFnZXIucHJvY2Vzc0Zyb250TWF0dGVyKGZpbGUsIChmcm9udG1hdHRlcikgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCB0b2RheSA9IG1vbWVudCgpLmZvcm1hdChzZXR0aW5ncy5kYXRlRm9ybWF0KTtcclxuICAgICAgICAgICAgaWYgKGZyb250bWF0dGVyW2RhdGVGaWVsZF0gIT09IHRvZGF5KSB7XHJcbiAgICAgICAgICAgICAgICBmcm9udG1hdHRlcltkYXRlRmllbGRdID0gdG9kYXk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmxhc3RQcm9jZXNzZWRGaWxlID0gZmlsZS5wYXRoO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5sYXN0UHJvY2Vzc2VkVGltZSA9IERhdGUubm93KCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGFzeW5jIHByb2Nlc3NGaWxlKGZpbGU6IFRGaWxlLCBkcmFmdFN0YXR1c0NoYW5nZWRUb1B1Ymxpc2hlZDogYm9vbGVhbiwgY29udGVudFR5cGU6IENvbnRlbnRUeXBlIHwgbnVsbCB8IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGNvbnN0IHNldHRpbmdzID0gdGhpcy5wbHVnaW4uc2V0dGluZ3M7XHJcbiAgICAgICAgY29uc3QgcHVibGlzaERhdGVGaWVsZCA9IHNldHRpbmdzLnB1Ymxpc2hEYXRlRmllbGQgfHwgXCJkYXRlXCI7XHJcblxyXG4gICAgICAgIGF3YWl0IHRoaXMuYXBwLmZpbGVNYW5hZ2VyLnByb2Nlc3NGcm9udE1hdHRlcihmaWxlLCAoZnJvbnRtYXR0ZXIpID0+IHtcclxuICAgICAgICAgICAgbGV0IGNoYW5nZWQgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgICAgIC8vIEhhbmRsZSBEcmFmdCBTeW5jICh0cmlnZ2VyZWQgb25seSBvbiB0aGUgc3BlY2lmaWMgdHJhbnNpdGlvbilcclxuICAgICAgICAgICAgaWYgKHNldHRpbmdzLnN5bmNEcmFmdERhdGUgJiYgZHJhZnRTdGF0dXNDaGFuZ2VkVG9QdWJsaXNoZWQpIHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IHRvZGF5ID0gbW9tZW50KCkuZm9ybWF0KHNldHRpbmdzLmRhdGVGb3JtYXQpO1xyXG4gICAgICAgICAgICAgICAgaWYgKGZyb250bWF0dGVyW3B1Ymxpc2hEYXRlRmllbGRdICE9PSB0b2RheSkge1xyXG4gICAgICAgICAgICAgICAgICAgIGZyb250bWF0dGVyW3B1Ymxpc2hEYXRlRmllbGRdID0gdG9kYXk7XHJcbiAgICAgICAgICAgICAgICAgICAgY2hhbmdlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIEhhbmRsZSBNb2RpZmllZCBEYXRlIFN5bmNcclxuICAgICAgICAgICAgY29uc3QgbW9kaWZpZWRGaWVsZCA9IGNvbnRlbnRUeXBlPy5tb2RpZmllZERhdGVGaWVsZDtcclxuICAgICAgICAgICAgaWYgKG1vZGlmaWVkRmllbGQgJiYgZnJvbnRtYXR0ZXJbbW9kaWZpZWRGaWVsZF0gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICAgICAgY29uc3Qgbm93ID0gbW9tZW50KCkuZm9ybWF0KHNldHRpbmdzLmRhdGVGb3JtYXQpO1xyXG4gICAgICAgICAgICAgICAgaWYgKGZyb250bWF0dGVyW21vZGlmaWVkRmllbGRdICE9PSBub3cpIHtcclxuICAgICAgICAgICAgICAgICAgICBmcm9udG1hdHRlclttb2RpZmllZEZpZWxkXSA9IG5vdztcclxuICAgICAgICAgICAgICAgICAgICBjaGFuZ2VkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgaWYgKGNoYW5nZWQpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMubGFzdFByb2Nlc3NlZEZpbGUgPSBmaWxlLnBhdGg7XHJcbiAgICAgICAgICAgICAgICB0aGlzLmxhc3RQcm9jZXNzZWRUaW1lID0gRGF0ZS5ub3coKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG59XHJcbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsSUFBQUEsb0JBT087OztBQ3dGQSxJQUFNLG1CQUFtQixDQUFDLFFBQVEsV0FBVyxZQUFZO0FBRXpELElBQU0sWUFBWTtBQUFBLEVBQ3hCLGFBQWE7QUFBQSxFQUNiLHNCQUFzQjtB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QXlCLENBQUMsS0FBSyxTQUFTLDRCQUE0QixDQUFDLEtBQUssU0FBUztBQUN6RixVQUFNLHVCQUF1QixDQUFDLEtBQUssU0FBUywwQkFBMEIsQ0FBQyxLQUFLLFNBQVM7QUFFckYsVUFBTSxZQUFZLFlBQVksaUJBQWlCLFlBQVk7QUFDM0QsZUFBVyxRQUFRLE1BQU0sS0FBSyxTQUFTLEdBQUc7QUFDekMsWUFBTSxNQUFNLEtBQUssY0FBYyxLQUFLO0FBQ3BDLFVBQUksS0FBSztBQUNSLFlBQUksV0FBVyxJQUFJLGFBQWEsYUFBYSxLQUFLLElBQUksYUFBYSxjQUFjLEtBQ2hGLElBQUksYUFBYSxXQUFXLE1BQzNCLElBQUksVUFBVSxTQUFTLHdCQUF3QixJQUFJLG9CQUFvQixVQUN2RSxJQUFJLFVBQVUsU0FBUyxlQUFlLElBQUksV0FBVyxVQUNyRCxJQUFJLFVBQVUsU0FBUyxlQUFlLElBQUksV0FBVztBQUV2RCxZQUFJLFNBQVUsWUFBVyxTQUFTLFFBQVEsWUFBWSxFQUFFO0FBRXhELFlBQUksMEJBQTBCLGFBQWEsbUJBQW1CO0FBQzdELGVBQUksVUFBSyxnQkFBTCxtQkFBa0IsY0FBYyxTQUFTLFlBQWEsTUFBSyxPQUFPO0FBQUEsUUFDdkU7QUFDQSxZQUFJLHlCQUF5QixhQUFhLFlBQVksYUFBYSxXQUFXO0FBQzdFLGVBQUksVUFBSyxnQkFBTCxtQkFBa0IsY0FBYyxTQUFTLFVBQVcsTUFBSyxPQUFPO0FBQUEsUUFDckU7QUFBQSxNQUNEO0FBQUEsSUFDRDtBQUFBLEVBQ0Q7QUFDRDsiLAogICJuYW1lcyI6IFsiaW1wb3J0X29ic2lkaWFuIiwgImltcG9ydF9vYnNpZGlhbiIsICJuZXdGaWxlIiwgImltcG9ydF9vYnNpZGlhbiIsICJpbXBvcnRfb2JzaWRpYW4iLCAiaW1wb3J0X29ic2lkaWFuIiwgImNvbnRlbnRUeXBlIiwgIl9hIiwgImhhc01hdGNoaW5nQ29udGVudFR5cGUiLCAic2V0dGluZ3MiLCAicGx1Z2luSW50ZXJmYWNlIiwgImZpbGUiLCAidHlwZSIsICJpbXBvcnRfb2JzaWRpYW4iLCAiaW1wb3J0X29ic2lkaWFuIiwgImltcG9ydF9vYnNpZGlhbiIsICJpbXBvcnRfb2JzaWRpYW4iLCAiX2EiLCAidG9nZ2xlIiwgImltcG9ydF9vYnNpZGlhbiIsICJpbXBvcnRfb2JzaWRpYW4iLCAiaW1wb3J0X29ic2lkaWFuIiwgImltcG9ydF9vYnNpZGlhbiIsICJjb250ZW50VHlwZSIsICJoYXNNb2RpZmllZEZpZWxkIiwgImFjdGl2ZUZpbGUiLCAiaXNBY3RpdmVGaWxlIiwgIl9hIiwgIl9iIl0KfQo= diff --git a/src/content/.obsidian/plugins/astro-composer/manifest.json b/src/content/.obsidian/plugins/astro-composer/manifest.json new file mode 100644 index 0000000..a9fa122 --- /dev/null +++ b/src/content/.obsidian/plugins/astro-composer/manifest.json @@ -0,0 +1 @@ +{"id":"astro-composer","name":"Astro Composer","version":"0.11.9","minAppVersion":"1.11.0","description":"Turn your notes into posts and pages for your Astro blog with automated content management features.","author":"David V. Kimball","authorUrl":"https://davidvkimball.com","fundingUrl":"https://patreon.com/davidvkimball","isDesktopOnly":false} \ No newline at end of file diff --git a/src/content/.obsidian/plugins/astro-composer/styles.css b/src/content/.obsidian/plugins/astro-composer/styles.css new file mode 100644 index 0000000..b54e3e5 --- /dev/null +++ b/src/content/.obsidian/plugins/astro-composer/styles.css @@ -0,0 +1,372 @@ +.astro-composer-title-input { + width: 100%; + margin-bottom: 16px; + padding: 8px; +} + +.astro-composer-button-container { + display: flex; + gap: 8px; + justify-content: flex-end; + margin-top: 16px; +} + +/* Ensure all buttons in the button container use default cursor */ +.astro-composer-button-container button { + cursor: default !important; +} + +.astro-composer-button-container button:hover { + cursor: default !important; +} + +.astro-composer-cancel-button, +.astro-composer-create-button { + padding: 6px 12px; + border-radius: 4px; + cursor: default !important; +} + +.astro-composer-cancel-button:hover, +.astro-composer-create-button:hover { + cursor: default !important; +} + +.astro-composer-create-button.mod-cta { + background-color: var(--interactive-accent); + color: var(--text-on-accent); + cursor: default !important; +} + +.astro-composer-create-button.mod-cta:hover { + background-color: var(--interactive-accent-hover); + cursor: default !important; +} + +.astro-composer-template-textarea { + height: 300px; /* Adjusted for 5-10 lines of properties */ + width: 100%; + padding: 8px; + resize: vertical; /* Allow vertical resizing */ + margin-bottom: 16px; +} + +.astro-composer-modal { + padding: 20px; + max-width: 500px; + margin: 0 auto; +} + +.astro-composer-modal h2 { + margin-top: 0; +} + +/* Custom Content Types Styling */ +.custom-content-types-container { + margin-top: 0; +} + +.custom-content-type-item { + border: 1px solid var(--background-modifier-border); + border-radius: 6px; + padding: 16px; + margin-bottom: 16px; + background-color: var(--background-secondary); +} + +.custom-content-type-header { + display: flex; + justify-content: space-between; + align-items: center; +} + +.custom-content-type-header .setting-item { + margin-bottom: 0; +} + +.custom-content-type-header .setting-item-name { + font-weight: 600; + color: var(--text-normal); +} + +.custom-content-type-item .setting-item { + margin-bottom: 12px; +} + +.custom-content-type-item .setting-item:last-child { + margin-bottom: 0; +} + +/* Add spacing between settings in custom content types since we removed dividers */ +.custom-content-type-settings > div { + margin-bottom: 16px; +} + +.custom-content-type-settings > div:last-child { + margin-bottom: 0; +} + +.custom-content-type-settings { + transition: all 0.2s ease-in-out; + padding-top: 12px; +} + +.custom-content-type-settings[style*="none"] { + opacity: 0; + transform: translateY(-10px); +} + +/* Mobile-specific improvements for Astro Composer modal */ +@media (max-width: 768px) { + /* Force mobile positioning for all modals containing our content */ + .modal:has(.astro-composer-title-input) { + position: fixed !important; + top: 10% !important; + left: 50% !important; + transform: translateX(-50%) !important; + max-height: 50vh !important; + overflow-y: auto !important; + width: 90vw !important; + max-width: 500px !important; + } + + /* Only target our specific modal content, not all modals */ + .modal .astro-composer-title-input { + font-size: 16px; /* Prevents zoom on iOS */ + padding: 12px; + border: 1px solid var(--background-modifier-border); + border-radius: 4px; + } + + /* Ensure our modal content is properly sized on mobile */ + .modal .astro-composer-button-container { + flex-direction: column; + gap: 12px; + } + + .modal .astro-composer-cancel-button, + .modal .astro-composer-create-button { + width: 100%; + padding: 12px; + font-size: 16px; + cursor: default !important; + } + + .modal .astro-composer-cancel-button:hover, + .modal .astro-composer-create-button:hover { + cursor: default !important; + } +} + +/* Fallback for browsers that don't support :has() */ +.astro-composer-mobile-modal { + position: fixed !important; + top: 10% !important; + left: 50% !important; + transform: translateX(-50%) !important; + max-height: 50vh !important; + overflow-y: auto !important; + width: 90vw !important; + max-width: 500px !important; +} + +/* Settings UI utility classes */ +.astro-composer-setting-container-visible { + display: block; +} + +.astro-composer-setting-container-hidden { + display: none; +} + +.astro-composer-custom-type-header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; +} + +.astro-composer-header-name { + flex: 1; + min-width: 0; +} + +/* Collapse button */ +.astro-composer-collapse-button { + background: transparent !important; + border: none !important; + padding: 4px; + margin-right: 4px; + cursor: default; + color: var(--text-muted); + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + transition: background-color 0.2s ease, color 0.2s ease; + box-shadow: none !important; +} + +.astro-composer-collapse-button:hover { + background-color: var(--background-modifier-hover); + color: var(--text-normal); +} + +.astro-composer-collapse-button:active { + background-color: var(--background-modifier-active); +} + +.astro-composer-collapse-button svg { + transition: transform 0.2s ease; +} + +.astro-composer-collapse-button.is-collapsed svg { + transform: rotate(-90deg); +} + +/* Reorder buttons container */ +.astro-composer-reorder-buttons { + display: flex; + flex-direction: row; + gap: 4px; + margin-right: 8px; + align-items: center; +} + +/* Reorder buttons - minimal icon-only style */ +.astro-composer-reorder-button { + background: transparent !important; + border: none !important; + padding: 4px; + cursor: default; + color: var(--text-muted); + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + transition: background-color 0.2s ease, color 0.2s ease; + line-height: 1; + opacity: 0.6; + box-shadow: none !important; +} + +.astro-composer-reorder-button:hover:not(:disabled) { + background-color: var(--background-modifier-hover); + color: var(--text-normal); + opacity: 1; +} + +.astro-composer-reorder-button:active:not(:disabled) { + background-color: var(--background-modifier-active); +} + +.astro-composer-reorder-button:disabled { + opacity: 0.2; + cursor: default; +} + +.astro-composer-reorder-button svg { + width: 16px; + height: 16px; +} + +.astro-composer-remove-setting { + border-top: none; +} + +.astro-composer-add-button { + border-top: none; +} + +/* Floating button container - no settings background, right-aligned */ +.astro-composer-add-button-container { + display: flex; + justify-content: flex-end; + margin-top: 16px; + margin-bottom: 0; + padding: 0; + background: transparent; + border: none; +} + +.astro-composer-add-button-container button { + margin: 0; +} + +/* Settings tab - hidden setting elements */ +/* Only hide the setting item info elements, not nested ones inside content types */ +.astro-composer-setting-hidden-elements > .setting-item-info > .setting-item-name, +.astro-composer-setting-hidden-elements > .setting-item-info > .setting-item-description, +.astro-composer-setting-hidden-elements > .setting-item-control { + display: none; +} + +.astro-composer-setting-hidden-elements { + border-top: none; + padding-top: 0; + padding-bottom: 0; +} + +.astro-composer-setting-container-full-width { + display: block; + width: 100%; +} + +.astro-composer-custom-types-container-visible { + display: block !important; + width: 100% !important; + visibility: visible !important; +} + +/* Ensure custom content types container is always visible even when parent has hidden elements */ +.astro-composer-setting-hidden-elements .custom-content-types-container { + display: block !important; + visibility: visible !important; +} + +/* Ensure content type items inside the container are visible */ +.custom-content-types-container .custom-content-type-item { + display: block !important; + visibility: visible !important; +} + +/* Conflict warning styles */ +.astro-composer-conflict-warning { + color: var(--text-warning); + font-size: 0.9em; + margin-top: 0.5em; +} + +.astro-composer-conflict-warning.hidden { + display: none; +} + +/* Help button replacement */ +/* No special display needed - inherits from parent flex container */ + +/* Ribbon context menu hiding - these will be applied via classes */ +.astro-composer-hide-terminal-icon .menu-item:has(svg[data-lucide="terminal-square"]), +.astro-composer-hide-terminal-icon .menu-item:has(.lucide-terminal-square), +.astro-composer-hide-terminal-icon .menu-item .menu-item-icon:has(svg[data-lucide="terminal-square"]), +.astro-composer-hide-terminal-icon .menu-item .menu-item-icon:has(.lucide-terminal-square) { + display: none !important; +} + +.astro-composer-hide-config-icon .menu-item:has(svg[data-lucide="wrench"]), +.astro-composer-hide-config-icon .menu-item:has(svg[data-lucide="rocket"]), +.astro-composer-hide-config-icon .menu-item:has(.lucide-wrench), +.astro-composer-hide-config-icon .menu-item:has(.lucide-rocket), +.astro-composer-hide-config-icon .menu-item .menu-item-icon:has(svg[data-lucide="wrench"]), +.astro-composer-hide-config-icon .menu-item .menu-item-icon:has(svg[data-lucide="rocket"]), +.astro-composer-hide-config-icon .menu-item .menu-item-icon:has(.lucide-wrench), +.astro-composer-hide-config-icon .menu-item .menu-item-icon:has(.lucide-rocket) { + display: none !important; +} + +/* Help button hiding */ +.astro-composer-hide-help-button .workspace-drawer-vault-actions .clickable-icon:has(svg.help) { + display: none !important; +} + + +/* Scoped to only this plugin's settings container to avoid affecting other plugins */ diff --git a/src/content/.obsidian/plugins/astro-modular-settings/data.json b/src/content/.obsidian/plugins/astro-modular-settings/data.json new file mode 100644 index 0000000..ca14a13 --- /dev/null +++ b/src/content/.obsidian/plugins/astro-modular-settings/data.json @@ -0,0 +1,253 @@ +{ + "runWizardOnStartup": true, + "currentTemplate": "standard", + "currentTheme": "oxygen", + "customThemeFile": "custom", + "contentOrganization": "file-based", + "themeColors": { + "mode": "simple", + "simpleColors": { + "accent": "#5865f2", + "background": "#1e1e1e" + } + }, + "siteInfo": { + "site": "https://astro-modular.netlify.app", + "title": "Astro Modular", + "description": "A flexible blog theme designed for Obsidian users.", + "author": "David V. Kimball", + "language": "en", + "faviconThemeAdaptive": true, + "defaultOgImageAlt": "Astro Modular logo." + }, + "layout": { + "contentWidth": "45rem" + }, + "tableOfContents": { + "enabled": true, + "depth": 4 + }, + "footer": { + "enabled": true, + "content": "© 2025 {author}. Built with the Astro Modular theme.", + "showSocialIconsInFooter": true + }, + "seo": { + "defaultOgImageAlt": "Astro Modular logo." + }, + "navigation": { + "showNavigation": true, + "style": "traditional", + "showMobileMenu": true, + "pages": [ + { + "title": "Posts", + "url": "/posts/" + }, + { + "title": "Projects", + "url": "/projects/" + }, + { + "title": "Docs", + "url": "/docs/" + }, + { + "title": "About", + "url": "/about/", + "children": [ + { + "title": "Privacy Policy", + "url": "/privacy-policy/" + } + ] + }, + { + "title": "GitHub", + "url": "https://github.com/davidvkimball/astro-modular" + } + ], + "social": [ + { + "title": "X", + "url": "https://x.com/davidvkimball", + "icon": "x-twitter" + }, + { + "title": "GitHub", + "url": "https://github.com/davidvkimball", + "icon": "github" + } + ] + }, + "commandPalette": { + "enabled": true, + "shortcut": "ctrl+K", + "placeholder": "Search posts", + "search": { + "posts": true, + "pages": false, + "projects": false, + "docs": false + }, + "sections": { + "quickActions": true, + "pages": true, + "social": true + }, + "quickActions": { + "enabled": true, + "toggleMode": true, + "graphView": true, + "changeTheme": true + } + }, + "homeOptions": { + "featuredPost": { + "enabled": true, + "type": "latest", + "slug": "getting-started" + }, + "recentPosts": { + "enabled": true, + "count": 7 + }, + "projects": { + "enabled": true, + "count": 2 + }, + "docs": { + "enabled": true, + "count": 3 + }, + "blurb": { + "placement": "below" + } + }, + "postOptions": { + "postsPerPage": 6, + "readingTime": true, + "wordCount": true, + "tags": true, + "linkedMentions": { + "enabled": true, + "linkedMentionsCompact": false + }, + "graphView": { + "enabled": true, + "showInSidebar": true, + "maxNodes": 100, + "showOrphanedPosts": true + }, + "postNavigation": true, + "showPostCardCoverImages": "featured-and-posts", + "postCardAspectRatio": "og", + "customPostCardAspectRatio": "2.5/1", + "comments": { + "enabled": false, + "provider": "giscus", + "rawScript": "", + "repo": "", + "repoId": "", + "category": "", + "categoryId": "", + "mapping": "", + "strict": "", + "reactions": "", + "metadata": "", + "inputPosition": "", + "theme": "", + "lang": "", + "loading": "" + } + }, + "features": { + "commandPalette": true, + "readingTime": true, + "linkedMentions": true, + "linkedMentionsCompact": false, + "graphView": true, + "postNavigation": true, + "hideScrollBar": false, + "scrollToTop": true, + "showSocialIconsInFooter": true, + "profilePicture": false, + "comments": false, + "featureButton": "mode", + "showPostCardCoverImages": "featured-and-posts", + "postCardAspectRatio": "og", + "customPostCardAspectRatio": "2.5/1", + "quickActions": { + "enabled": true, + "toggleMode": true, + "graphView": true, + "changeTheme": true + } + }, + "typography": { + "headingFont": "Inter", + "proseFont": "Inter", + "monoFont": "JetBrains Mono", + "fontSource": "local", + "fontDisplay": "swap", + "customFonts": { + "heading": "", + "prose": "", + "mono": "", + "urls": "" + } + }, + "optionalFeatures": { + "profilePicture": { + "enabled": false, + "image": "/profile.jpg", + "alt": "Profile picture", + "size": "md", + "url": "", + "placement": "footer", + "style": "circle" + }, + "comments": { + "enabled": false, + "provider": "giscus", + "rawScript": "", + "repo": "", + "repoId": "", + "category": "", + "categoryId": "", + "mapping": "", + "strict": "", + "reactions": "", + "metadata": "", + "inputPosition": "", + "theme": "", + "lang": "", + "loading": "" + } + }, + "deployment": { + "platform": "netlify" + }, + "pluginConfig": { + "obsidianSettings": { + "attachmentLocation": "subfolder", + "subfolderName": "attachments" + }, + "astroComposerSettings": { + "creationMode": "file", + "indexFileName": "index" + }, + "imageInserterSettings": { + "valueFormat": "[[attachments/{image-url}]]", + "insertFormat": "[[attachments/{image-url}]]" + } + }, + "optionalContentTypes": { + "projects": true, + "docs": true + }, + "availableThemes": "default", + "customThemes": "", + "customThemeGenerationEnabled": false, + "removeRibbonIcon": false +} \ No newline at end of file diff --git a/src/content/.obsidian/plugins/astro-modular-settings/main.js b/src/content/.obsidian/plugins/astro-modular-settings/main.js new file mode 100644 index 0000000..315900c --- /dev/null +++ b/src/content/.obsidian/plugins/astro-modular-settings/main.js @@ -0,0 +1,10634 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ + +"use strict"; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __export = (target, all) => { + for (var name4 in all) + __defProp(target, name4, { get: all[name4], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// src/types.ts +var FONT_OPTIONS, DEFAULT_SETTINGS, THEME_OPTIONS, TEMPLATE_OPTIONS; +var init_types = __esm({ + "src/types.ts"() { + "use strict"; + FONT_OPTIONS = [ + "Inter", + "Roboto", + "Open Sans", + "Lato", + "Poppins", + "Source Sans Pro", + "Nunito", + "Montserrat", + "Playfair Display", + "Merriweather", + "Lora", + "Crimson Text", + "PT Serif", + "Libre Baskerville", + "Fira Code", + "JetBrains Mono", + "Source Code Pro", + "IBM Plex Mono", + "Cascadia Code" + ]; + DEFAULT_SETTINGS = { + runWizardOnStartup: true, + currentTemplate: "standard", + currentTheme: "oxygen", + customThemeFile: "custom", + contentOrganization: "file-based", + themeColors: { + mode: "simple", + extractedColors: void 0, + simpleColors: { + accent: "#5865f2", + background: "#1e1e1e" + }, + lastExtracted: void 0 + }, + siteInfo: { + site: "https://astro-modular.netlify.app", + title: "Astro Modular", + homepageTitle: "", + description: "A flexible blog theme designed for Obsidian users.", + author: "David V. Kimball", + language: "en", + faviconThemeAdaptive: true, + defaultOgImageAlt: "Astro Modular logo." + }, + layout: { + contentWidth: "45rem" + }, + tableOfContents: { + enabled: true, + depth: 4 + }, + footer: { + enabled: true, + content: '\xA9 2025 {author}. Built with the Astro Modular theme.', + showSocialIconsInFooter: true + }, + seo: { + defaultOgImageAlt: "Astro Modular logo." + }, + navigation: { + showNavigation: true, + style: "traditional", + showMobileMenu: true, + pages: [ + { title: "Posts", url: "/posts" }, + { title: "Projects", url: "/projects" }, + { title: "Docs", url: "/docs" }, + { title: "About", url: "/about" }, + { title: "GitHub", url: "https://github.com/davidvkimball/astro-modular" } + ], + social: [ + { title: "X", url: "https://x.com/davidvkimball", icon: "x-twitter" }, + { title: "GitHub", url: "https://github.com/davidvkimball", icon: "github" } + ] + }, + commandPalette: { + enabled: true, + shortcut: "ctrl+K", + placeholder: "Search posts", + search: { + posts: true, + pages: false, + projects: false, + docs: false + }, + sections: { + quickActions: true, + pages: true, + social: true + }, + quickActions: { + enabled: true, + toggleMode: true, + graphView: true, + changeTheme: true + } + }, + homeOptions: { + featuredPost: { + enabled: true, + type: "latest", + slug: "getting-started" + }, + recentPosts: { + enabled: true, + count: 7 + }, + projects: { + enabled: true, + count: 2 + }, + docs: { + enabled: true, + count: 3 + }, + blurb: { + placement: "below" + } + }, + postOptions: { + postsPerPage: 6, + readingTime: true, + wordCount: true, + tags: true, + linkedMentions: { + enabled: true, + linkedMentionsCompact: false + }, + graphView: { + enabled: true, + showInSidebar: true, + maxNodes: 100, + showOrphanedPosts: true + }, + postNavigation: true, + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + comments: { + enabled: false, + provider: "giscus", + rawScript: "", + repo: "davidvkimball/astro-modular", + repoId: "R_kgDOPllfKw", + category: "General", + categoryId: "DIC_kwDOPllfK84CvUpx", + mapping: "pathname", + strict: "0", + reactions: "1", + metadata: "0", + inputPosition: "bottom", + theme: "preferred_color_scheme", + lang: "en", + loading: "lazy" + } + }, + features: { + commandPalette: true, + readingTime: true, + linkedMentions: true, + linkedMentionsCompact: false, + comments: false, + graphView: true, + postNavigation: true, + hideScrollBar: false, + scrollToTop: true, + featureButton: "mode", + showSocialIconsInFooter: true, + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + profilePicture: false, + quickActions: { + enabled: true, + toggleMode: true, + graphView: true, + changeTheme: true + } + }, + typography: { + headingFont: "Inter", + proseFont: "Inter", + monoFont: "JetBrains Mono", + fontSource: "local", + fontDisplay: "swap", + customFonts: { + heading: "", + prose: "", + mono: "", + urls: "" + } + }, + optionalFeatures: { + profilePicture: { + enabled: false, + image: "/profile.jpg", + alt: "Profile picture", + size: "md", + url: "", + placement: "footer", + style: "circle" + }, + comments: { + enabled: false, + provider: "giscus", + rawScript: "", + repo: "davidvkimball/astro-modular", + repoId: "R_kgDOPllfKw", + category: "General", + categoryId: "DIC_kwDOPllfK84CvUpx", + mapping: "pathname", + strict: "0", + reactions: "1", + metadata: "0", + inputPosition: "bottom", + theme: "preferred_color_scheme", + lang: "en", + loading: "lazy" + } + }, + deployment: { + platform: "netlify" + }, + pluginConfig: { + obsidianSettings: { + attachmentLocation: "subfolder", + subfolderName: "attachments" + }, + astroComposerSettings: { + creationMode: "file", + indexFileName: "index" + }, + imageManagerSettings: { + customPropertyLinkFormat: "[[attachments/{image-url}]]" + } + }, + optionalContentTypes: { + projects: true, + // Will be overridden based on template + docs: true + // Will be overridden based on template + }, + availableThemes: "default", + customThemes: "", + customThemeGenerationEnabled: false, + removeRibbonIcon: false + }; + THEME_OPTIONS = [ + { + id: "oxygen", + name: "Oxygen", + description: "Modern, clean design", + previewColors: ["#075985", "#38bdf8"], + backgroundColorLight: "#f8fafc", + backgroundColorDark: "#020617" + }, + { + id: "minimal", + name: "Minimal", + description: "Understated with high contrast", + previewColors: ["#2d383c", "#87bfcf"], + backgroundColorLight: "#fafafa", + backgroundColorDark: "#1a1a1a" + }, + { + id: "atom", + name: "Atom", + description: "Dark theme with vibrant accents", + previewColors: ["#075985", "#578af2"], + backgroundColorLight: "#f8fafc", + backgroundColorDark: "#181a1f" + }, + { + id: "ayu", + name: "Ayu", + description: "Clean theme with warm colors", + previewColors: ["#99521a", "#ff9933"], + backgroundColorLight: "#f8f8f0", + backgroundColorDark: "#0f1419" + }, + { + id: "catppuccin", + name: "Catppuccin", + description: "Pastel color palette", + previewColors: ["#95624f", "#df7763"], + backgroundColorLight: "#fef7ed", + backgroundColorDark: "#181825" + }, + { + id: "charcoal", + name: "Charcoal", + description: "Dark, professional look", + previewColors: ["#202020", "#c0c0c0"], + backgroundColorLight: "#f8f8f8", + backgroundColorDark: "#000000" + }, + { + id: "dracula", + name: "Dracula", + description: "Dark theme with purple accents", + previewColors: ["#7c3aed", "#a78bfa"], + backgroundColorLight: "#f8f8f2", + backgroundColorDark: "#191a21" + }, + { + id: "everforest", + name: "Everforest", + description: "Soft, warm colors", + previewColors: ["#5a7a5a", "#83c092"], + backgroundColorLight: "#f7f6f3", + backgroundColorDark: "#2d353b" + }, + { + id: "flexoki", + name: "Flexoki", + description: "Based on Material Design 3", + previewColors: ["#16504a", "#4dbdb5"], + backgroundColorLight: "#fefefe", + backgroundColorDark: "#100f0f" + }, + { + id: "gruvbox", + name: "Gruvbox", + description: "Retro groove color scheme", + previewColors: ["#7a5412", "#f78b33"], + backgroundColorLight: "#fbf1c7", + backgroundColorDark: "#1d2021" + }, + { + id: "macos", + name: "macOS", + description: "Native macOS appearance", + previewColors: ["#002e66", "#339fff"], + backgroundColorLight: "#f5f5f7", + backgroundColorDark: "#141414" + }, + { + id: "nord", + name: "Nord", + description: "Arctic-inspired color palette", + previewColors: ["#2e4c63", "#5e94b8"], + backgroundColorLight: "#f8fafc", + backgroundColorDark: "#2e3440" + }, + { + id: "obsidian", + name: "Obsidian", + description: "Matches Obsidian's default theme", + previewColors: ["#522994", "#9c75ff"], + backgroundColorLight: "#f8f8f8", + backgroundColorDark: "#0a0a0a" + }, + { + id: "rose-pine", + name: "Ros\xE9 Pine", + description: "All natural pine, faux fir, and winter", + previewColors: ["#ab2142", "#ef97a9"], + backgroundColorLight: "#faf4ed", + backgroundColorDark: "#191724" + }, + { + id: "sky", + name: "Sky", + description: "Light, airy design", + previewColors: ["#136194", "#46aad0"], + backgroundColorLight: "#f0f9ff", + backgroundColorDark: "#232729" + }, + { + id: "solarized", + name: "Solarized", + description: "Precision colors for machines and people", + previewColors: ["#0e3754", "#339fff"], + backgroundColorLight: "#fdf6e3", + backgroundColorDark: "#002b36" + }, + { + id: "things", + name: "Things", + description: "Clean, minimal design", + previewColors: ["#1e3a8a", "#4d95f7"], + backgroundColorLight: "#f8fafc", + backgroundColorDark: "#17191c" + }, + { + id: "custom", + name: "Custom", + description: "Use a custom theme file", + previewColors: ["#666666", "#999999"], + backgroundColorLight: "#ffffff", + backgroundColorDark: "#000000" + } + ]; + TEMPLATE_OPTIONS = [ + { + id: "standard", + name: "Standard", + description: "Full-featured blog with all default options enabled", + features: ["Command palette", "Table of contents", "Reading time", "Linked mentions", "Footer", "Social icons", "Scroll to top", "Dark mode toggle"], + recommended: true + }, + { + id: "compact", + name: "Compact", + description: "Balanced setup for smaller sites with optimized layout", + features: ["Command palette", "Table of contents", "Reading time", "Compact linked mentions", "Custom aspect ratio"], + recommended: false + }, + { + id: "minimal", + name: "Minimal", + description: "Clean, simple blog with minimal features and content", + features: ["Command palette", "Search posts/pages", "Minimal navigation"], + recommended: false + } + ]; + } +}); + +// src/ui/wizard/WizardState.ts +var WizardStateManager; +var init_WizardState = __esm({ + "src/ui/wizard/WizardState.ts"() { + "use strict"; + WizardStateManager = class { + constructor(plugin) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n; + this.plugin = plugin; + const settings = plugin.settings; + this.state = { + currentStep: 1, + totalSteps: 10, + selectedTemplate: settings.currentTemplate, + selectedTheme: settings.currentTheme, + selectedContentOrg: settings.contentOrganization, + selectedSiteInfo: settings.siteInfo, + selectedNavigation: settings.navigation, + selectedFeatures: (() => { + var _a2, _b2; + const templateFeatures = { + "standard": { + commandPalette: true, + readingTime: true, + linkedMentions: true, + linkedMentionsCompact: false, + graphView: true, + postNavigation: true, + hideScrollBar: false, + scrollToTop: true, + showSocialIconsInFooter: true, + profilePicture: false, + comments: false, + featureButton: "mode", + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + quickActions: { + enabled: true, + toggleMode: true, + graphView: true, + changeTheme: true + } + }, + "compact": { + commandPalette: true, + readingTime: true, + linkedMentions: true, + linkedMentionsCompact: true, + graphView: false, + postNavigation: true, + hideScrollBar: false, + scrollToTop: true, + showSocialIconsInFooter: false, + profilePicture: false, + comments: false, + featureButton: "none", + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + quickActions: { + enabled: true, + toggleMode: true, + graphView: true, + changeTheme: true + } + }, + "minimal": { + commandPalette: true, + readingTime: false, + linkedMentions: false, + linkedMentionsCompact: false, + graphView: false, + postNavigation: false, + hideScrollBar: true, + scrollToTop: true, + showSocialIconsInFooter: false, + profilePicture: false, + comments: false, + featureButton: "none", + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + quickActions: { + enabled: true, + toggleMode: true, + graphView: true, + changeTheme: true + } + }, + "custom": { + // For custom, use current settings + ...settings.features + } + }; + const templateFeaturesResult = templateFeatures[settings.currentTemplate] || templateFeatures["standard"]; + if ((_a2 = settings.optionalFeatures) == null ? void 0 : _a2.profilePicture) { + templateFeaturesResult.profilePicture = settings.optionalFeatures.profilePicture.enabled; + } + if ((_b2 = settings.optionalFeatures) == null ? void 0 : _b2.comments) { + templateFeaturesResult.comments = settings.optionalFeatures.comments.enabled; + } + return templateFeaturesResult; + })(), + selectedTypography: settings.typography, + selectedOptionalFeatures: { + profilePicture: { + enabled: ((_b = (_a = settings.optionalFeatures) == null ? void 0 : _a.profilePicture) == null ? void 0 : _b.enabled) || false, + image: ((_d = (_c = settings.optionalFeatures) == null ? void 0 : _c.profilePicture) == null ? void 0 : _d.image) || "/profile.jpg", + alt: ((_f = (_e = settings.optionalFeatures) == null ? void 0 : _e.profilePicture) == null ? void 0 : _f.alt) || "Profile picture", + size: ((_h = (_g = settings.optionalFeatures) == null ? void 0 : _g.profilePicture) == null ? void 0 : _h.size) || "md", + url: ((_j = (_i = settings.optionalFeatures) == null ? void 0 : _i.profilePicture) == null ? void 0 : _j.url) || "", + placement: ((_l = (_k = settings.optionalFeatures) == null ? void 0 : _k.profilePicture) == null ? void 0 : _l.placement) || "footer", + style: ((_n = (_m = settings.optionalFeatures) == null ? void 0 : _m.profilePicture) == null ? void 0 : _n.style) || "circle" + }, + comments: (() => { + var _a2, _b2, _c2; + const commentsEnabled = ((_b2 = (_a2 = settings.optionalFeatures) == null ? void 0 : _a2.comments) == null ? void 0 : _b2.enabled) || false; + const existingComments = (_c2 = settings.optionalFeatures) == null ? void 0 : _c2.comments; + if (!commentsEnabled) { + return { + enabled: false, + provider: (existingComments == null ? void 0 : existingComments.provider) || "giscus", + rawScript: (existingComments == null ? void 0 : existingComments.rawScript) || "", + repo: (existingComments == null ? void 0 : existingComments.repo) || "", + repoId: (existingComments == null ? void 0 : existingComments.repoId) || "", + category: (existingComments == null ? void 0 : existingComments.category) || "", + categoryId: (existingComments == null ? void 0 : existingComments.categoryId) || "", + mapping: (existingComments == null ? void 0 : existingComments.mapping) || "", + strict: (existingComments == null ? void 0 : existingComments.strict) || "", + reactions: (existingComments == null ? void 0 : existingComments.reactions) || "", + metadata: (existingComments == null ? void 0 : existingComments.metadata) || "", + inputPosition: (existingComments == null ? void 0 : existingComments.inputPosition) || "", + theme: (existingComments == null ? void 0 : existingComments.theme) || "", + lang: (existingComments == null ? void 0 : existingComments.lang) || "", + loading: (existingComments == null ? void 0 : existingComments.loading) || "" + }; + } + return { + enabled: true, + provider: (existingComments == null ? void 0 : existingComments.provider) || "giscus", + rawScript: (existingComments == null ? void 0 : existingComments.rawScript) || "", + repo: (existingComments == null ? void 0 : existingComments.repo) || "davidvkimball/astro-modular", + repoId: (existingComments == null ? void 0 : existingComments.repoId) || "R_kgDOPllfKw", + category: (existingComments == null ? void 0 : existingComments.category) || "General", + categoryId: (existingComments == null ? void 0 : existingComments.categoryId) || "DIC_kwDOPllfK84CvUpx", + mapping: (existingComments == null ? void 0 : existingComments.mapping) || "pathname", + strict: (existingComments == null ? void 0 : existingComments.strict) || "0", + reactions: (existingComments == null ? void 0 : existingComments.reactions) || "1", + metadata: (existingComments == null ? void 0 : existingComments.metadata) || "0", + inputPosition: (existingComments == null ? void 0 : existingComments.inputPosition) || "bottom", + theme: (existingComments == null ? void 0 : existingComments.theme) || "preferred_color_scheme", + lang: (existingComments == null ? void 0 : existingComments.lang) || "en", + loading: (existingComments == null ? void 0 : existingComments.loading) || "lazy" + }; + })() + }, + selectedOptionalContentTypes: (() => { + const isStandard = settings.currentTemplate === "standard"; + return { + projects: isStandard, + docs: isStandard + }; + })(), + selectedDeployment: settings.deployment.platform, + runWizardOnStartup: settings.runWizardOnStartup + }; + } + getState() { + return this.state; + } + updateState(updates) { + this.state = { ...this.state, ...updates }; + } + setState(updates) { + this.state = { ...this.state, ...updates }; + } + nextStep() { + if (this.state.currentStep < this.state.totalSteps) { + this.state.currentStep++; + } + } + previousStep() { + if (this.state.currentStep > 1) { + this.state.currentStep--; + } + } + canGoNext() { + return this.state.currentStep < this.state.totalSteps; + } + canGoPrevious() { + return this.state.currentStep > 1; + } + getProgress() { + return this.state.currentStep / this.state.totalSteps * 100; + } + refreshState() { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p; + const settings = this.plugin.settings; + this.state.selectedTemplate = settings.currentTemplate; + this.state.selectedTheme = settings.currentTheme; + this.state.selectedContentOrg = settings.contentOrganization; + this.state.selectedSiteInfo = settings.siteInfo; + this.state.selectedNavigation = settings.navigation; + this.state.selectedTypography = settings.typography; + this.state.selectedDeployment = settings.deployment.platform; + this.state.runWizardOnStartup = settings.runWizardOnStartup; + const templateFeatures = { + "standard": { + commandPalette: true, + readingTime: true, + linkedMentions: true, + linkedMentionsCompact: false, + graphView: true, + postNavigation: true, + hideScrollBar: false, + scrollToTop: true, + showSocialIconsInFooter: true, + profilePicture: false, + comments: false, + featureButton: "mode", + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + quickActions: { enabled: true, toggleMode: true, graphView: true, changeTheme: true } + }, + "compact": { + commandPalette: true, + readingTime: true, + linkedMentions: true, + linkedMentionsCompact: true, + graphView: false, + postNavigation: true, + hideScrollBar: false, + scrollToTop: true, + showSocialIconsInFooter: false, + profilePicture: false, + comments: false, + featureButton: "none", + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + quickActions: { enabled: true, toggleMode: true, graphView: true, changeTheme: true } + }, + "minimal": { + commandPalette: true, + readingTime: false, + linkedMentions: false, + linkedMentionsCompact: false, + graphView: false, + postNavigation: false, + hideScrollBar: true, + scrollToTop: true, + showSocialIconsInFooter: false, + profilePicture: false, + comments: false, + featureButton: "none", + showPostCardCoverImages: "featured-and-posts", + postCardAspectRatio: "og", + customPostCardAspectRatio: "2.5/1", + quickActions: { enabled: true, toggleMode: true, graphView: true, changeTheme: true } + } + }; + const templateFeaturesResult = templateFeatures[settings.currentTemplate] || templateFeatures["standard"]; + if ((_a = settings.optionalFeatures) == null ? void 0 : _a.profilePicture) { + templateFeaturesResult.profilePicture = settings.optionalFeatures.profilePicture.enabled; + } + if ((_b = settings.optionalFeatures) == null ? void 0 : _b.comments) { + templateFeaturesResult.comments = settings.optionalFeatures.comments.enabled; + } + this.state.selectedFeatures = templateFeaturesResult; + this.state.selectedOptionalFeatures = { + profilePicture: { + enabled: ((_d = (_c = settings.optionalFeatures) == null ? void 0 : _c.profilePicture) == null ? void 0 : _d.enabled) || false, + image: ((_f = (_e = settings.optionalFeatures) == null ? void 0 : _e.profilePicture) == null ? void 0 : _f.image) || "/profile.jpg", + alt: ((_h = (_g = settings.optionalFeatures) == null ? void 0 : _g.profilePicture) == null ? void 0 : _h.alt) || "Profile picture", + size: ((_j = (_i = settings.optionalFeatures) == null ? void 0 : _i.profilePicture) == null ? void 0 : _j.size) || "md", + url: ((_l = (_k = settings.optionalFeatures) == null ? void 0 : _k.profilePicture) == null ? void 0 : _l.url) || "", + placement: ((_n = (_m = settings.optionalFeatures) == null ? void 0 : _m.profilePicture) == null ? void 0 : _n.placement) || "footer", + style: ((_p = (_o = settings.optionalFeatures) == null ? void 0 : _o.profilePicture) == null ? void 0 : _p.style) || "circle" + }, + comments: (() => { + var _a2, _b2, _c2; + const commentsEnabled = ((_b2 = (_a2 = settings.optionalFeatures) == null ? void 0 : _a2.comments) == null ? void 0 : _b2.enabled) || false; + const existingComments = (_c2 = settings.optionalFeatures) == null ? void 0 : _c2.comments; + if (!commentsEnabled) { + return { + enabled: false, + provider: (existingComments == null ? void 0 : existingComments.provider) || "giscus", + rawScript: (existingComments == null ? void 0 : existingComments.rawScript) || "", + repo: (existingComments == null ? void 0 : existingComments.repo) || "", + repoId: (existingComments == null ? void 0 : existingComments.repoId) || "", + category: (existingComments == null ? void 0 : existingComments.category) || "", + categoryId: (existingComments == null ? void 0 : existingComments.categoryId) || "", + mapping: (existingComments == null ? void 0 : existingComments.mapping) || "", + strict: (existingComments == null ? void 0 : existingComments.strict) || "", + reactions: (existingComments == null ? void 0 : existingComments.reactions) || "", + metadata: (existingComments == null ? void 0 : existingComments.metadata) || "", + inputPosition: (existingComments == null ? void 0 : existingComments.inputPosition) || "", + theme: (existingComments == null ? void 0 : existingComments.theme) || "", + lang: (existingComments == null ? void 0 : existingComments.lang) || "", + loading: (existingComments == null ? void 0 : existingComments.loading) || "" + }; + } + return { + enabled: true, + provider: (existingComments == null ? void 0 : existingComments.provider) || "giscus", + rawScript: (existingComments == null ? void 0 : existingComments.rawScript) || "", + repo: (existingComments == null ? void 0 : existingComments.repo) || "davidvkimball/astro-modular", + repoId: (existingComments == null ? void 0 : existingComments.repoId) || "R_kgDOPllfKw", + category: (existingComments == null ? void 0 : existingComments.category) || "General", + categoryId: (existingComments == null ? void 0 : existingComments.categoryId) || "DIC_kwDOPllfK84CvUpx", + mapping: (existingComments == null ? void 0 : existingComments.mapping) || "pathname", + strict: (existingComments == null ? void 0 : existingComments.strict) || "0", + reactions: (existingComments == null ? void 0 : existingComments.reactions) || "1", + metadata: (existingComments == null ? void 0 : existingComments.metadata) || "0", + inputPosition: (existingComments == null ? void 0 : existingComments.inputPosition) || "bottom", + theme: (existingComments == null ? void 0 : existingComments.theme) || "preferred_color_scheme", + lang: (existingComments == null ? void 0 : existingComments.lang) || "en", + loading: (existingComments == null ? void 0 : existingComments.loading) || "lazy" + }; + })() + }; + const isStandard = settings.currentTemplate === "standard"; + this.state.selectedOptionalContentTypes = { + projects: isStandard, + docs: isStandard + }; + } + buildFinalSettings() { + var _a, _b, _c, _d, _e, _f, _g, _h; + const settings = this.plugin.settings; + const originalTemplate = settings.currentTemplate; + settings.currentTemplate = this.state.selectedTemplate; + settings.currentTheme = this.state.selectedTheme; + settings.contentOrganization = this.state.selectedContentOrg; + settings.siteInfo = this.state.selectedSiteInfo; + settings.navigation = this.state.selectedNavigation; + settings.features = this.state.selectedFeatures; + settings.typography = this.state.selectedTypography; + settings.optionalFeatures = this.state.selectedOptionalFeatures; + settings.deployment.platform = this.state.selectedDeployment; + settings.runWizardOnStartup = this.state.runWizardOnStartup; + if (this.state.selectedFeatures) { + if ((_a = settings.postOptions) == null ? void 0 : _a.graphView) { + settings.postOptions.graphView.enabled = (_b = this.state.selectedFeatures.graphView) != null ? _b : false; + } + if ((_c = settings.postOptions) == null ? void 0 : _c.linkedMentions) { + settings.postOptions.linkedMentions.enabled = (_d = this.state.selectedFeatures.linkedMentions) != null ? _d : false; + settings.postOptions.linkedMentions.linkedMentionsCompact = (_e = this.state.selectedFeatures.linkedMentionsCompact) != null ? _e : false; + } + if (((_f = settings.commandPalette) == null ? void 0 : _f.quickActions) && this.state.selectedFeatures.quickActions) { + settings.commandPalette.quickActions = { + ...settings.commandPalette.quickActions, + ...this.state.selectedFeatures.quickActions + }; + } + } + if (this.state.selectedTemplate !== originalTemplate) { + const templatePreset = this.plugin.configManager.getTemplatePreset(this.state.selectedTemplate); + if (templatePreset && templatePreset.config) { + if (templatePreset.config.tableOfContents) { + settings.tableOfContents = { ...settings.tableOfContents, ...templatePreset.config.tableOfContents }; + } + } + } + if ((_g = settings.optionalFeatures) == null ? void 0 : _g.profilePicture) { + settings.features.profilePicture = settings.optionalFeatures.profilePicture.enabled; + } + if ((_h = settings.optionalFeatures) == null ? void 0 : _h.comments) { + settings.features.comments = settings.optionalFeatures.comments.enabled; + if (!settings.postOptions) { + settings.postOptions = { postsPerPage: 6, readingTime: true, wordCount: true, tags: true, linkedMentions: { enabled: true, linkedMentionsCompact: false }, graphView: { enabled: true, showInSidebar: true, maxNodes: 100, showOrphanedPosts: true }, postNavigation: true, showPostCardCoverImages: "featured-and-posts", postCardAspectRatio: "og", customPostCardAspectRatio: "2.5/1", comments: { ...settings.optionalFeatures.comments } }; + } else if (!settings.postOptions.comments) { + settings.postOptions.comments = { ...settings.optionalFeatures.comments }; + } else { + settings.postOptions.comments.enabled = settings.optionalFeatures.comments.enabled; + Object.assign(settings.postOptions.comments, settings.optionalFeatures.comments); + } + } + settings.optionalContentTypes = this.state.selectedOptionalContentTypes; + } + }; + } +}); + +// src/ui/wizard/BaseWizardStep.ts +var BaseWizardStep; +var init_BaseWizardStep = __esm({ + "src/ui/wizard/BaseWizardStep.ts"() { + "use strict"; + BaseWizardStep = class { + constructor(app, modal, stateManager, plugin) { + this.app = app; + this.modal = modal; + this.stateManager = stateManager; + this.plugin = plugin; + } + nextStep() { + this.stateManager.nextStep(); + this.modal.close(); + } + previousStep() { + this.stateManager.previousStep(); + this.modal.close(); + } + updateState(updates) { + this.stateManager.updateState(updates); + } + getState() { + return this.stateManager.getState(); + } + }; + } +}); + +// src/ui/wizard/WelcomeStep.ts +var WelcomeStep; +var init_WelcomeStep = __esm({ + "src/ui/wizard/WelcomeStep.ts"() { + "use strict"; + init_BaseWizardStep(); + WelcomeStep = class extends BaseWizardStep { + render(container) { + var _a, _b, _c, _d, _e, _f; + const state = this.getState(); + const welcomeContent = container.createDiv("welcome-content"); + welcomeContent.createEl("h2", { text: "Welcome to Astro Modular!" }); + welcomeContent.createEl("p", { text: "This wizard will help you set up your Astro Modular theme with the perfect configuration for your needs." }); + const checkboxOption = welcomeContent.createDiv("checkbox-option"); + const checkbox = checkboxOption.createEl("input", { type: "checkbox" }); + checkbox.id = "run-wizard-startup"; + if (state.runWizardOnStartup) { + checkbox.setAttribute("checked", "checked"); + } + const label = checkboxOption.createEl("label", { text: "Run this wizard on startup" }); + label.setAttribute("for", "run-wizard-startup"); + const siteInfoForm = welcomeContent.createDiv("site-info-form"); + siteInfoForm.createEl("h3", { text: "Site information" }); + const urlGroup = siteInfoForm.createDiv("form-group"); + const urlLabel = urlGroup.createEl("label", { text: "URL" }); + urlLabel.setAttribute("for", "site-url"); + const urlInput = urlGroup.createEl("input", { type: "text" }); + urlInput.id = "site-url"; + urlInput.placeholder = "https://astro-modular.netlify.app"; + urlInput.setAttribute("value", state.selectedSiteInfo.site); + const titleGroup = siteInfoForm.createDiv("form-group"); + const titleLabel = titleGroup.createEl("label", { text: "Title" }); + titleLabel.setAttribute("for", "site-title"); + const titleInput = titleGroup.createEl("input", { type: "text" }); + titleInput.id = "site-title"; + titleInput.placeholder = "Astro Modular"; + titleInput.setAttribute("value", state.selectedSiteInfo.title); + const descGroup = siteInfoForm.createDiv("form-group"); + const descLabel = descGroup.createEl("label", { text: "Description" }); + descLabel.setAttribute("for", "site-description"); + const descInput = descGroup.createEl("input", { type: "text" }); + descInput.id = "site-description"; + descInput.placeholder = "A flexible blog theme designed for Obsidian users."; + descInput.setAttribute("value", state.selectedSiteInfo.description); + const authorGroup = siteInfoForm.createDiv("form-group"); + const authorLabel = authorGroup.createEl("label", { text: "Author name" }); + authorLabel.setAttribute("for", "site-author"); + const authorInput = authorGroup.createEl("input", { type: "text" }); + authorInput.id = "site-author"; + authorInput.placeholder = "David V. Kimball"; + authorInput.setAttribute("value", state.selectedSiteInfo.author); + const langGroup = siteInfoForm.createDiv("form-group"); + const langLabel = langGroup.createEl("label", { text: "Language" }); + langLabel.setAttribute("for", "site-language"); + const langInput = langGroup.createEl("input", { type: "text" }); + langInput.id = "site-language"; + langInput.placeholder = "en"; + langInput.setAttribute("value", state.selectedSiteInfo.language); + (_a = container.querySelector("#run-wizard-startup")) == null ? void 0 : _a.addEventListener("change", (e) => { + const target = e.target; + this.updateState({ runWizardOnStartup: target.checked }); + }); + (_b = container.querySelector("#site-url")) == null ? void 0 : _b.addEventListener("input", (e) => { + const currentState = this.getState(); + this.updateState({ + selectedSiteInfo: { + ...currentState.selectedSiteInfo, + site: e.target.value + } + }); + }); + (_c = container.querySelector("#site-title")) == null ? void 0 : _c.addEventListener("input", (e) => { + const currentState = this.getState(); + this.updateState({ + selectedSiteInfo: { + ...currentState.selectedSiteInfo, + title: e.target.value + } + }); + }); + (_d = container.querySelector("#site-description")) == null ? void 0 : _d.addEventListener("input", (e) => { + const currentState = this.getState(); + this.updateState({ + selectedSiteInfo: { + ...currentState.selectedSiteInfo, + description: e.target.value + } + }); + }); + (_e = container.querySelector("#site-author")) == null ? void 0 : _e.addEventListener("input", (e) => { + const currentState = this.getState(); + this.updateState({ + selectedSiteInfo: { + ...currentState.selectedSiteInfo, + author: e.target.value + } + }); + }); + (_f = container.querySelector("#site-language")) == null ? void 0 : _f.addEventListener("input", (e) => { + const currentState = this.getState(); + this.updateState({ + selectedSiteInfo: { + ...currentState.selectedSiteInfo, + language: e.target.value + } + }); + }); + } + }; + } +}); + +// src/ui/wizard/TemplateStep.ts +var import_obsidian, TemplateStep; +var init_TemplateStep = __esm({ + "src/ui/wizard/TemplateStep.ts"() { + "use strict"; + init_BaseWizardStep(); + init_types(); + import_obsidian = require("obsidian"); + TemplateStep = class extends BaseWizardStep { + render(container) { + const state = this.getState(); + const templateSelectionDiv = container.createDiv("template-selection"); + templateSelectionDiv.createEl("h2", { text: "Choose your preset" }); + templateSelectionDiv.createEl("p", { text: "Select a preset that best fits your content type and goals." }); + const templateOptions = templateSelectionDiv.createDiv("template-options"); + TEMPLATE_OPTIONS.forEach((template) => { + const templateOption = templateOptions.createDiv("template-option"); + if (state.selectedTemplate === template.id) { + templateOption.addClass("selected"); + } + templateOption.setAttribute("data-template", template.id); + const templateHeader = templateOption.createDiv("template-header"); + templateHeader.createEl("h3", { text: template.name }); + if (template.recommended) { + templateHeader.createEl("span", { text: "Default", cls: "recommended" }); + } + templateOption.createEl("p", { text: template.description, cls: "template-description" }); + const templateFeatures = templateOption.createDiv("template-features"); + template.features.forEach((feature) => { + templateFeatures.createEl("span", { text: feature, cls: "feature-tag" }); + }); + templateOption.addEventListener("click", () => { + const templateId = template.id; + this.updateState({ selectedTemplate: templateId }); + const isStandard = templateId === "standard"; + this.updateState({ + selectedOptionalContentTypes: { + projects: isStandard, + docs: isStandard + } + }); + this.syncFeaturesWithTemplate(templateId); + this.render(container); + }); + }); + const templateSelectionEl = container.querySelector(".template-selection"); + if (templateSelectionEl) { + const setting = new import_obsidian.Setting(templateSelectionEl).setName("Edit config.ts directly (advanced)").setDesc("Skip the wizard and edit your Astro configuration file directly.").addButton((button) => button.setButtonText("Edit config.ts").onClick(() => { + this.openConfigFile(); + })); + const settingEl = setting.settingEl; + if (settingEl) { + settingEl.setCssProps({ marginTop: "2rem" }); + } + } + } + syncFeaturesWithTemplate(template) { + const pluginInstance = this.plugin; + const templatePreset = pluginInstance.configManager.getTemplatePreset(template); + if (!templatePreset || !templatePreset.config || !templatePreset.config.features) { + console.error("Template preset not found:", template); + return; + } + this.updateState({ + selectedFeatures: templatePreset.config.features + }); + } + async updatePluginSettingsWithTemplate(template) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A; + const pluginForUpdate = this.plugin; + const settings = pluginForUpdate.settings; + const templatePreset = pluginForUpdate.configManager.getTemplatePreset(template); + if (!templatePreset || !templatePreset.config) { + console.error("Template preset not found:", template); + return; + } + const templateConfig = pluginForUpdate.configManager.getTemplateConfig(template, settings); + if (templatePreset.config.features) { + const currentComments = settings.features.comments; + const currentProfilePicture = settings.features.profilePicture; + settings.features = { ...settings.features, ...templatePreset.config.features }; + settings.features.comments = currentComments; + settings.features.profilePicture = currentProfilePicture; + if ((_a = settings.postOptions) == null ? void 0 : _a.graphView) { + settings.postOptions.graphView.enabled = (_b = templatePreset.config.features.graphView) != null ? _b : false; + settings.features.graphView = settings.postOptions.graphView.enabled; + } + if ((_c = settings.postOptions) == null ? void 0 : _c.linkedMentions) { + settings.postOptions.linkedMentions.enabled = (_d = templatePreset.config.features.linkedMentions) != null ? _d : false; + settings.postOptions.linkedMentions.linkedMentionsCompact = (_e = templatePreset.config.features.linkedMentionsCompact) != null ? _e : false; + } + if (((_f = settings.commandPalette) == null ? void 0 : _f.quickActions) && templatePreset.config.features.quickActions) { + settings.commandPalette.quickActions = { ...settings.commandPalette.quickActions, ...templatePreset.config.features.quickActions }; + } + } + if (templateConfig.commandPalette && typeof templateConfig.commandPalette === "object") { + const commandPalette = templateConfig.commandPalette; + settings.commandPalette = { + ...settings.commandPalette, + enabled: (_g = commandPalette.enabled) != null ? _g : settings.commandPalette.enabled, + placeholder: (_h = commandPalette.placeholder) != null ? _h : settings.commandPalette.placeholder, + shortcut: (_i = commandPalette.shortcut) != null ? _i : settings.commandPalette.shortcut, + search: { + ...settings.commandPalette.search, + ...commandPalette.search && typeof commandPalette.search === "object" ? commandPalette.search : {} + }, + sections: { + ...settings.commandPalette.sections, + ...commandPalette.sections && typeof commandPalette.sections === "object" ? commandPalette.sections : {} + }, + quickActions: { + ...settings.commandPalette.quickActions, + ...((_j = templatePreset.config.features) == null ? void 0 : _j.quickActions) || {} + } + }; + if (templatePreset.config.features && templatePreset.config.features.quickActions) { + settings.features.quickActions = { + ...settings.features.quickActions, + ...templatePreset.config.features.quickActions + }; + } + } + if (templateConfig.homeOptions && typeof templateConfig.homeOptions === "object") { + const homeOptions = templateConfig.homeOptions; + settings.homeOptions = { + ...settings.homeOptions, + featuredPost: { + ...settings.homeOptions.featuredPost, + ...homeOptions.featuredPost && typeof homeOptions.featuredPost === "object" ? homeOptions.featuredPost : {} + }, + recentPosts: { + ...settings.homeOptions.recentPosts, + ...homeOptions.recentPosts && typeof homeOptions.recentPosts === "object" ? homeOptions.recentPosts : {} + }, + projects: { + ...settings.homeOptions.projects, + ...homeOptions.projects && typeof homeOptions.projects === "object" ? homeOptions.projects : {} + }, + docs: { + ...settings.homeOptions.docs, + ...homeOptions.docs && typeof homeOptions.docs === "object" ? homeOptions.docs : {} + }, + blurb: { + ...settings.homeOptions.blurb, + ...homeOptions.blurb && typeof homeOptions.blurb === "object" ? homeOptions.blurb : {} + } + }; + } + if (templateConfig.postOptions && typeof templateConfig.postOptions === "object") { + const postOptions = templateConfig.postOptions; + settings.postOptions = { + ...settings.postOptions, + postsPerPage: (_k = postOptions.postsPerPage) != null ? _k : settings.postOptions.postsPerPage, + readingTime: (_l = postOptions.readingTime) != null ? _l : settings.postOptions.readingTime, + wordCount: (_m = postOptions.wordCount) != null ? _m : settings.postOptions.wordCount, + tags: (_n = postOptions.tags) != null ? _n : settings.postOptions.tags, + postNavigation: (_o = postOptions.postNavigation) != null ? _o : settings.postOptions.postNavigation, + showPostCardCoverImages: (_p = postOptions.showPostCardCoverImages) != null ? _p : settings.postOptions.showPostCardCoverImages, + postCardAspectRatio: (_q = postOptions.postCardAspectRatio) != null ? _q : settings.postOptions.postCardAspectRatio, + linkedMentions: { + ...settings.postOptions.linkedMentions, + ...postOptions.linkedMentions && typeof postOptions.linkedMentions === "object" ? postOptions.linkedMentions : {} + }, + graphView: { + ...settings.postOptions.graphView, + enabled: (_r = postOptions.graphView && typeof postOptions.graphView === "object" ? postOptions.graphView.enabled : void 0) != null ? _r : settings.postOptions.graphView.enabled, + showInSidebar: (_s = postOptions.graphView && typeof postOptions.graphView === "object" ? postOptions.graphView.showInSidebar : void 0) != null ? _s : settings.postOptions.graphView.showInSidebar, + maxNodes: (_t = postOptions.graphView && typeof postOptions.graphView === "object" ? postOptions.graphView.maxNodes : void 0) != null ? _t : settings.postOptions.graphView.maxNodes, + showOrphanedPosts: (_u = postOptions.graphView && typeof postOptions.graphView === "object" ? postOptions.graphView.showOrphanedPosts : void 0) != null ? _u : settings.postOptions.graphView.showOrphanedPosts + }, + comments: settings.postOptions.comments + // Preserve comments + }; + } + if (templateConfig.navigation && typeof templateConfig.navigation === "object") { + const navigation = templateConfig.navigation; + settings.navigation = { + ...settings.navigation, + showNavigation: (_v = navigation.showNavigation) != null ? _v : settings.navigation.showNavigation, + showMobileMenu: (_w = navigation.showMobileMenu) != null ? _w : settings.navigation.showMobileMenu, + style: (_x = navigation.style) != null ? _x : settings.navigation.style + // Preserve pages and social arrays from user settings + }; + } + if (templatePreset.config.tableOfContents) { + settings.tableOfContents = { ...settings.tableOfContents, ...templatePreset.config.tableOfContents }; + } + if (templateConfig.optionalContentTypes && typeof templateConfig.optionalContentTypes === "object") { + const optionalContentTypes = templateConfig.optionalContentTypes; + settings.optionalContentTypes = { + projects: (_y = optionalContentTypes.projects) != null ? _y : false, + docs: (_z = optionalContentTypes.docs) != null ? _z : false + }; + } + if (templateConfig.footer && typeof templateConfig.footer === "object") { + const footer = templateConfig.footer; + const showSocialIconsInFooter = (_A = footer.showSocialIconsInFooter) != null ? _A : settings.footer.showSocialIconsInFooter; + settings.footer = { + ...settings.footer, + showSocialIconsInFooter + }; + settings.features.showSocialIconsInFooter = showSocialIconsInFooter; + } + await this.plugin.saveData(settings); + const pluginInstance = this.plugin; + await pluginInstance.loadSettings(); + this.refreshSettingsTab(); + } + refreshSettingsTab() { + const plugin = this.plugin; + const settingsTab = plugin.settingsTab; + if (settingsTab && typeof settingsTab.display === "function") { + settingsTab.display(); + } + } + openConfigFile() { + try { + const fs = require("fs"); + const path = require("path"); + const electronModule = require("electron"); + const shellRaw = electronModule.shell; + const vaultAdapter = this.app.vault.adapter; + const vaultPath = vaultAdapter.basePath || vaultAdapter.path; + const vaultPathString = typeof vaultPath === "string" ? vaultPath : vaultPath ? String(vaultPath) : ""; + if (!shellRaw || typeof shellRaw !== "object" || !("openPath" in shellRaw) || typeof shellRaw.openPath !== "function") { + throw new Error("Electron shell API not available"); + } + const shell = shellRaw; + const configPath = path.join(vaultPathString, "..", "config.ts"); + if (fs.existsSync(configPath)) { + shell.openPath(configPath); + } else { + fs.writeFileSync(configPath, "// Astro Modular Configuration\n// Customize your settings here\n\nexport const siteConfig = {\n // Add your configuration here\n};\n"); + shell.openPath(configPath); + } + new import_obsidian.Notice("Opening config.ts for direct editing"); + this.modal.close(); + } catch (error) { + new import_obsidian.Notice(`Error opening config file: ${error instanceof Error ? error.message : String(error)}`); + } + } + }; + } +}); + +// src/ui/wizard/ThemeStep.ts +var ThemeStep; +var init_ThemeStep = __esm({ + "src/ui/wizard/ThemeStep.ts"() { + "use strict"; + init_BaseWizardStep(); + init_types(); + ThemeStep = class extends BaseWizardStep { + render(container) { + const state = this.getState(); + const isDarkMode = this.isObsidianDarkMode(); + const wizardThemes = THEME_OPTIONS.filter((theme) => theme.id !== "custom"); + const themeSelection = container.createDiv("theme-selection"); + themeSelection.createEl("h2", { text: "Choose your theme" }); + themeSelection.createEl("p", { text: "Select a color scheme that matches your style and content." }); + const themeOptions = themeSelection.createDiv("theme-options"); + wizardThemes.forEach((theme) => { + const themeOption = themeOptions.createDiv("theme-option"); + if (state.selectedTheme === theme.id) { + themeOption.addClass("selected"); + } + themeOption.setAttribute("data-theme", theme.id); + themeOption.setCssProps({ + background: isDarkMode ? theme.backgroundColorDark : theme.backgroundColorLight + }); + const themePreview = themeOption.createDiv("theme-preview"); + themePreview.setCssProps({ + background: `linear-gradient(135deg, ${theme.previewColors.join(", ")})` + }); + const previewContent = themePreview.createDiv("theme-preview-content"); + const previewText = previewContent.createDiv("preview-text"); + previewText.textContent = "Sample text"; + const previewAccent = previewContent.createDiv("preview-accent"); + previewAccent.textContent = "Accent"; + const themeInfo = themeOption.createDiv("theme-info"); + themeInfo.createEl("h3", { text: theme.name }); + themeOption.addEventListener("click", () => { + this.updateState({ selectedTheme: theme.id }); + this.render(container); + }); + }); + } + isObsidianDarkMode() { + const body = document.body; + const isDarkClass = body.classList.contains("theme-dark") || body.classList.contains("dark"); + const computedStyle = getComputedStyle(document.documentElement); + const colorScheme = computedStyle.getPropertyValue("color-scheme").trim(); + const isDarkProperty = colorScheme === "dark"; + const bgColor = computedStyle.getPropertyValue("--background-primary").trim(); + const isDarkBackground = Boolean(bgColor && (bgColor.includes("#") && parseInt(bgColor.slice(1, 3), 16) < 128 || bgColor.includes("rgb") && bgColor.includes("0, 0, 0") || bgColor.includes("hsl") && bgColor.includes("0, 0%, 0%"))); + return isDarkClass || isDarkProperty || isDarkBackground; + } + }; + } +}); + +// src/ui/wizard/FontStep.ts +var import_obsidian2, FontStep; +var init_FontStep = __esm({ + "src/ui/wizard/FontStep.ts"() { + "use strict"; + init_BaseWizardStep(); + init_types(); + import_obsidian2 = require("obsidian"); + FontStep = class extends BaseWizardStep { + render(container) { + const state = this.getState(); + const fontSelection = container.createDiv("font-selection"); + fontSelection.createEl("h2", { text: "Choose your fonts" }); + fontSelection.createEl("p", { text: "Select fonts for headings, body text, and code." }); + const fontOptions = fontSelection.createDiv("font-options"); + const createFontDropdown = (name4, desc, currentValue, onChange) => { + new import_obsidian2.Setting(fontOptions).setName(name4).setDesc(desc).addDropdown((dropdown) => { + FONT_OPTIONS.forEach((font) => { + dropdown.addOption(font, font); + }); + dropdown.setValue(currentValue).onChange(onChange); + }); + }; + createFontDropdown( + "Heading Font", + "Font for headings and titles", + state.selectedTypography.headingFont, + (value) => this.updateTypographySetting("headingFont", value, state) + ); + createFontDropdown( + "Body Font", + "Font for body text and paragraphs", + state.selectedTypography.proseFont, + (value) => this.updateTypographySetting("proseFont", value, state) + ); + createFontDropdown( + "Monospace Font", + "Font for code blocks and inline code", + state.selectedTypography.monoFont, + (value) => this.updateTypographySetting("monoFont", value, state) + ); + new import_obsidian2.Setting(fontOptions).setName("Font source").setDesc("Choose how fonts are loaded").addDropdown((dropdown) => { + dropdown.addOption("local", "Local (Google Fonts)"); + dropdown.addOption("cdn", "CDN (Custom)"); + dropdown.setValue(state.selectedTypography.fontSource).onChange((value) => { + this.updateTypographySetting("fontSource", value, state); + this.render(container); + }); + }); + if (state.selectedTypography.fontSource === "cdn") { + new import_obsidian2.Setting(fontOptions).setName("Custom font URLs").setDesc("Comma-separated URLs for custom fonts").addText((text) => { + var _a; + return text.setValue(((_a = state.selectedTypography.customFonts) == null ? void 0 : _a.urls) || "").setPlaceholder("https://fonts.googleapis.com/css2?family=Custom+Font:wght@400;600&display=swap").onChange((value) => this.updateCustomFontSetting("urls", value, state)); + }); + new import_obsidian2.Setting(fontOptions).setName("Custom heading font name").setDesc("Font family name for headings").addText((text) => { + var _a; + return text.setValue(((_a = state.selectedTypography.customFonts) == null ? void 0 : _a.heading) || "").setPlaceholder("Custom Heading Font").onChange((value) => this.updateCustomFontSetting("heading", value, state)); + }); + new import_obsidian2.Setting(fontOptions).setName("Custom body font name").setDesc("Font family name for body text").addText((text) => { + var _a; + return text.setValue(((_a = state.selectedTypography.customFonts) == null ? void 0 : _a.prose) || "").setPlaceholder("Custom Body Font").onChange((value) => this.updateCustomFontSetting("prose", value, state)); + }); + new import_obsidian2.Setting(fontOptions).setName("Custom monospace font name").setDesc("Font family name for code").addText((text) => { + var _a; + return text.setValue(((_a = state.selectedTypography.customFonts) == null ? void 0 : _a.mono) || "").setPlaceholder("Custom Monospace Font").onChange((value) => this.updateCustomFontSetting("mono", value, state)); + }); + } + } + updateTypographySetting(key, value, state) { + const currentState = this.getState(); + this.updateState({ + selectedTypography: { + ...currentState.selectedTypography, + [key]: value + } + }); + } + updateCustomFontSetting(key, value, state) { + const currentState = this.getState(); + this.updateState({ + selectedTypography: { + ...currentState.selectedTypography, + customFonts: { + ...currentState.selectedTypography.customFonts, + [key]: value + } + } + }); + } + }; + } +}); + +// src/ui/wizard/ContentOrgStep.ts +var ContentOrgStep; +var init_ContentOrgStep = __esm({ + "src/ui/wizard/ContentOrgStep.ts"() { + "use strict"; + init_BaseWizardStep(); + ContentOrgStep = class extends BaseWizardStep { + render(container) { + const state = this.getState(); + const contentOrgSelection = container.createDiv("content-org-selection"); + contentOrgSelection.createEl("h2", { text: "Content organization" }); + contentOrgSelection.createEl("p", { text: "Choose how you want to organize your content and assets." }); + const orgOptions = contentOrgSelection.createDiv("org-options"); + const fileBasedOption = orgOptions.createDiv("org-option"); + if (state.selectedContentOrg === "file-based") { + fileBasedOption.addClass("selected"); + } + fileBasedOption.setAttribute("data-org", "file-based"); + const fileBasedHeader = fileBasedOption.createDiv("org-header"); + fileBasedHeader.createEl("h3", { text: "File-based" }); + fileBasedHeader.createEl("span", { text: "Default", cls: "default-badge" }); + fileBasedOption.createEl("p", { text: "Single markdown files with images in attachments subfolder" }); + const fileBasedExample = fileBasedOption.createDiv("org-example"); + const fileBasedPre = fileBasedExample.createEl("pre"); + fileBasedPre.createEl("code", { text: "posts/\n\u251C\u2500\u2500 my-post.md\n\u2514\u2500\u2500 attachments/\n \u2514\u2500\u2500 image.jpg" }); + const folderBasedOption = orgOptions.createDiv("org-option"); + if (state.selectedContentOrg === "folder-based") { + folderBasedOption.addClass("selected"); + } + folderBasedOption.setAttribute("data-org", "folder-based"); + const folderBasedHeader = folderBasedOption.createDiv("org-header"); + folderBasedHeader.createEl("h3", { text: "Folder-based" }); + folderBasedOption.createEl("p", { text: "Each post gets its own folder with co-located assets" }); + const folderBasedExample = folderBasedOption.createDiv("org-example"); + const folderBasedPre = folderBasedExample.createEl("pre"); + folderBasedPre.createEl("code", { text: "posts/\n\u251C\u2500\u2500 my-post/\n\u2502 \u251C\u2500\u2500 index.md\n\u2502 \u2514\u2500\u2500 image.jpg\n\u2514\u2500\u2500 another-post/\n \u251C\u2500\u2500 index.md\n \u2514\u2500\u2500 image.jpg" }); + fileBasedOption.addEventListener("click", () => { + this.updateState({ selectedContentOrg: "file-based" }); + this.render(container); + }); + folderBasedOption.addEventListener("click", () => { + this.updateState({ selectedContentOrg: "folder-based" }); + this.render(container); + }); + } + }; + } +}); + +// src/ui/wizard/NavigationStep.ts +var import_obsidian3, NavigationStep; +var init_NavigationStep = __esm({ + "src/ui/wizard/NavigationStep.ts"() { + "use strict"; + init_BaseWizardStep(); + import_obsidian3 = require("obsidian"); + NavigationStep = class extends BaseWizardStep { + render(container) { + const state = this.getState(); + const navigationSelection = container.createDiv("navigation-selection"); + navigationSelection.createEl("h2", { text: "Navigation setup" }); + navigationSelection.createEl("p", { text: "Configure your site navigation and social links." }); + const navigationSections = navigationSelection.createDiv("navigation-sections"); + const pagesSection = navigationSections.createDiv("nav-section"); + pagesSection.createEl("h3", { text: "Navigation pages" }); + pagesSection.createEl("p", { text: "Add pages to your main navigation menu. Leave URL empty to create dropdown-only parents." }); + const pagesList = pagesSection.createDiv("nav-items"); + pagesList.id = "pages-list"; + state.selectedNavigation.pages.forEach((page, index) => { + this.renderPageItem(pagesList, page, index); + }); + const addPageBtn = pagesSection.createEl("button", { text: "+ Add page", cls: "nav-add" }); + addPageBtn.id = "add-page"; + const socialSection = navigationSections.createDiv("nav-section"); + socialSection.createEl("h3", { text: "Social links" }); + socialSection.createEl("p", { text: "Add social media links for your footer." }); + const socialList = socialSection.createDiv("nav-items"); + socialList.id = "social-list"; + state.selectedNavigation.social.forEach((social, index) => { + this.renderSocialItem(socialList, social, index); + }); + const addSocialBtn = socialSection.createEl("button", { text: "+ Add social link", cls: "nav-add" }); + addSocialBtn.id = "add-social"; + this.setupEventHandlers(container); + } + renderPageItem(container, page, index) { + const hasChildren = page.children && page.children.length > 0; + const navItem = container.createDiv("nav-item"); + navItem.setAttribute("data-index", index.toString()); + navItem.setAttribute("draggable", "true"); + const itemContent = navItem.createDiv("nav-item-content"); + const itemFields = itemContent.createDiv("nav-item-fields"); + const titleInput = itemFields.createEl("input", { + type: "text", + cls: "nav-title", + // False positive: Placeholder text for input field + // eslint-disable-next-line obsidianmd/ui/sentence-case + attr: { placeholder: "Page Title", draggable: "false" } + }); + titleInput.value = page.title || ""; + const urlInput = itemFields.createEl("input", { + type: "text", + cls: "nav-url", + attr: { placeholder: "/page-url (leave empty for dropdown-only)", draggable: "false" } + }); + urlInput.value = page.url || ""; + const itemActions = itemContent.createDiv("nav-item-actions"); + itemActions.createEl("button", { + text: "+ child", + cls: "nav-add-child", + attr: { "data-index": index.toString(), title: "Add child page" } + }); + const removeBtn = itemActions.createEl("button", { + cls: "nav-remove mod-warning", + attr: { "data-index": index.toString(), "data-icon": "trash", title: "Remove", "aria-label": "Remove" } + }); + (0, import_obsidian3.setIcon)(removeBtn, "trash"); + const childrenContainer = navItem.createDiv("nav-children-container"); + childrenContainer.setAttribute("data-parent-index", index.toString()); + if (!hasChildren) { + childrenContainer.setCssProps({ display: "none" }); + } + childrenContainer.createDiv("nav-children-label").textContent = "Child pages:"; + const childrenDiv = childrenContainer.createDiv("nav-children"); + childrenDiv.setAttribute("data-parent-index", index.toString()); + if (hasChildren && page.children) { + page.children.forEach((child, childIndex) => { + this.renderChildItem(childrenDiv, child, index, childIndex); + }); + } + } + renderChildItem(container, child, parentIndex, childIndex) { + const childItem = container.createDiv("nav-child-item"); + childItem.setAttribute("data-index", parentIndex.toString()); + childItem.setAttribute("data-child-index", childIndex.toString()); + const itemFields = childItem.createDiv("nav-item-fields"); + const titleInput = itemFields.createEl("input", { + type: "text", + cls: "nav-child-title", + // False positive: Placeholder text for input field + // eslint-disable-next-line obsidianmd/ui/sentence-case + attr: { placeholder: "Child Title", draggable: "false" } + }); + titleInput.value = child.title || ""; + const urlInput = itemFields.createEl("input", { + type: "text", + cls: "nav-child-url", + attr: { placeholder: "/child-url", draggable: "false" } + }); + urlInput.value = child.url || ""; + const removeBtn = childItem.createEl("button", { + cls: "nav-child-remove mod-warning", + attr: { + "data-index": parentIndex.toString(), + "data-child-index": childIndex.toString(), + "data-icon": "trash", + title: "Remove", + "aria-label": "Remove" + } + }); + (0, import_obsidian3.setIcon)(removeBtn, "trash"); + } + renderSocialItem(container, social, index) { + const navItem = container.createDiv("nav-item"); + navItem.setAttribute("data-index", index.toString()); + navItem.setAttribute("draggable", "true"); + const itemContent = navItem.createDiv("nav-item-content"); + const itemFields = itemContent.createDiv("nav-item-fields"); + const titleInput = itemFields.createEl("input", { + type: "text", + cls: "nav-title", + // False positive: Placeholder text for input field + // eslint-disable-next-line obsidianmd/ui/sentence-case + attr: { placeholder: "Social Title", draggable: "false" } + }); + titleInput.value = social.title || ""; + const urlInput = itemFields.createEl("input", { + type: "text", + cls: "nav-url", + attr: { placeholder: "https://example.com", draggable: "false" } + }); + urlInput.value = social.url || ""; + const removeBtn = itemContent.createEl("button", { + cls: "nav-remove mod-warning", + attr: { "data-index": index.toString(), "data-icon": "trash", title: "Remove", "aria-label": "Remove" } + }); + (0, import_obsidian3.setIcon)(removeBtn, "trash"); + const iconRow = navItem.createDiv("nav-icon-row"); + const iconInput = iconRow.createEl("input", { + type: "text", + cls: "nav-icon", + // False positive: Placeholder text for input field (kebab-case format) + // eslint-disable-next-line obsidianmd/ui/sentence-case + attr: { placeholder: "icon-name", draggable: "false" } + }); + iconInput.value = social.icon || ""; + const iconHelp = iconRow.createDiv("nav-icon-help"); + iconHelp.createEl("small", { text: "Icon names from FontAwesome Brands" }); + } + setupEventHandlers(container) { + const state = this.getState(); + const pagesList = container.querySelector("#pages-list"); + if (pagesList) { + const pagesInputHandler = (e) => { + const target = e.target; + if (target.classList.contains("nav-title")) { + const item = target.closest(".nav-item"); + const index = parseInt((item == null ? void 0 : item.getAttribute("data-index")) || "0"); + state.selectedNavigation.pages[index].title = target.value; + } else if (target.classList.contains("nav-url")) { + const item = target.closest(".nav-item"); + const index = parseInt((item == null ? void 0 : item.getAttribute("data-index")) || "0"); + if (target.value.trim() === "") { + delete state.selectedNavigation.pages[index].url; + } else { + state.selectedNavigation.pages[index].url = target.value; + } + } else if (target.classList.contains("nav-child-title")) { + const childItem = target.closest(".nav-child-item"); + const parentIndex = parseInt((childItem == null ? void 0 : childItem.getAttribute("data-index")) || "0"); + const childIndex = parseInt((childItem == null ? void 0 : childItem.getAttribute("data-child-index")) || "0"); + if (!state.selectedNavigation.pages[parentIndex].children) { + state.selectedNavigation.pages[parentIndex].children = []; + } + if (!state.selectedNavigation.pages[parentIndex].children[childIndex]) { + state.selectedNavigation.pages[parentIndex].children[childIndex] = { title: "", url: "" }; + } + state.selectedNavigation.pages[parentIndex].children[childIndex].title = target.value; + } else if (target.classList.contains("nav-child-url")) { + const childItem = target.closest(".nav-child-item"); + const parentIndex = parseInt((childItem == null ? void 0 : childItem.getAttribute("data-index")) || "0"); + const childIndex = parseInt((childItem == null ? void 0 : childItem.getAttribute("data-child-index")) || "0"); + if (!state.selectedNavigation.pages[parentIndex].children) { + state.selectedNavigation.pages[parentIndex].children = []; + } + if (!state.selectedNavigation.pages[parentIndex].children[childIndex]) { + state.selectedNavigation.pages[parentIndex].children[childIndex] = { title: "", url: "" }; + } + state.selectedNavigation.pages[parentIndex].children[childIndex].url = target.value; + } + }; + const pagesListWithHandlers = pagesList; + if (pagesListWithHandlers._inputHandler) { + pagesList.removeEventListener("input", pagesListWithHandlers._inputHandler); + } + pagesListWithHandlers._inputHandler = pagesInputHandler; + pagesList.addEventListener("input", pagesInputHandler); + } + const socialList = container.querySelector("#social-list"); + if (socialList) { + const socialInputHandler = (e) => { + const target = e.target; + if (target.classList.contains("nav-title") || target.classList.contains("nav-url") || target.classList.contains("nav-icon")) { + const item = target.closest(".nav-item"); + const index = parseInt((item == null ? void 0 : item.getAttribute("data-index")) || "0"); + const field = target.classList.contains("nav-title") ? "title" : target.classList.contains("nav-url") ? "url" : "icon"; + state.selectedNavigation.social[index][field] = target.value; + } + }; + const socialListWithHandlers = socialList; + if (socialListWithHandlers._inputHandler) { + socialList.removeEventListener("input", socialListWithHandlers._inputHandler); + } + socialListWithHandlers._inputHandler = socialInputHandler; + socialList.addEventListener("input", socialInputHandler); + } + const addPageBtn = container.querySelector("#add-page"); + if (addPageBtn) { + const addPageHandler = () => { + state.selectedNavigation.pages.push({ title: "New Page", url: "/new-page" }); + this.render(container); + }; + const addPageBtnWithHandlers = addPageBtn; + if (addPageBtnWithHandlers._clickHandler) { + addPageBtn.removeEventListener("click", addPageBtnWithHandlers._clickHandler); + } + addPageBtnWithHandlers._clickHandler = addPageHandler; + addPageBtn.addEventListener("click", addPageHandler); + } + const addSocialBtn = container.querySelector("#add-social"); + if (addSocialBtn) { + const addSocialHandler = () => { + state.selectedNavigation.social.push({ title: "New Social", url: "https://example.com", icon: "" }); + this.render(container); + }; + const addSocialBtnWithHandlers = addSocialBtn; + if (addSocialBtnWithHandlers._clickHandler) { + addSocialBtn.removeEventListener("click", addSocialBtnWithHandlers._clickHandler); + } + addSocialBtnWithHandlers._clickHandler = addSocialHandler; + addSocialBtn.addEventListener("click", addSocialHandler); + } + const removeHandler = (e) => { + const target = e.target; + if (target.classList.contains("nav-remove")) { + e.preventDefault(); + e.stopPropagation(); + const index = parseInt(target.getAttribute("data-index") || "0"); + const isPage = target.closest("#pages-list"); + if (isPage) { + state.selectedNavigation.pages.splice(index, 1); + } else { + state.selectedNavigation.social.splice(index, 1); + } + this.render(container); + } else if (target.classList.contains("nav-child-remove")) { + e.preventDefault(); + e.stopPropagation(); + const parentIndex = parseInt(target.getAttribute("data-index") || "0"); + const childIndex = parseInt(target.getAttribute("data-child-index") || "0"); + if (state.selectedNavigation.pages[parentIndex].children) { + state.selectedNavigation.pages[parentIndex].children.splice(childIndex, 1); + if (state.selectedNavigation.pages[parentIndex].children.length === 0) { + delete state.selectedNavigation.pages[parentIndex].children; + } + const navItem = target.closest(".nav-item"); + const childrenContainer = navItem == null ? void 0 : navItem.querySelector(".nav-children-container"); + if (childrenContainer && (!state.selectedNavigation.pages[parentIndex].children || state.selectedNavigation.pages[parentIndex].children.length === 0)) { + childrenContainer.setCssProps({ display: "none" }); + } + } + this.render(container); + } else if (target.classList.contains("nav-add-child")) { + e.preventDefault(); + e.stopPropagation(); + const index = parseInt(target.getAttribute("data-index") || "0"); + if (!state.selectedNavigation.pages[index].children) { + state.selectedNavigation.pages[index].children = []; + } + state.selectedNavigation.pages[index].children.push({ title: "New Child", url: "/new-child" }); + const navItem = target.closest(".nav-item"); + const childrenContainer = navItem == null ? void 0 : navItem.querySelector(".nav-children-container"); + if (childrenContainer) { + childrenContainer.setCssProps({ display: "block" }); + } + this.render(container); + } + }; + const containerWithHandlers = container; + if (containerWithHandlers._removeHandler) { + container.removeEventListener("click", containerWithHandlers._removeHandler); + } + containerWithHandlers._removeHandler = removeHandler; + container.addEventListener("click", removeHandler); + this.setupDragAndDrop(container); + } + setupDragAndDrop(container) { + const state = this.getState(); + let draggedElement = null; + const dragStartHandler = (e) => { + const target = e.target; + if (target.classList.contains("nav-item")) { + draggedElement = target; + target.setCssProps({ opacity: "0.5" }); + } + }; + const dragEndHandler = (e) => { + const target = e.target; + if (target.classList.contains("nav-item")) { + target.setCssProps({ opacity: "1" }); + draggedElement = null; + } + }; + const dragOverHandler = (e) => { + e.preventDefault(); + const target = e.target; + if (target.classList.contains("nav-item") && draggedElement && target !== draggedElement) { + const rect = target.getBoundingClientRect(); + const midpoint = rect.top + rect.height / 2; + if (e.clientY < midpoint) { + target.setCssProps({ + borderTop: "2px solid var(--interactive-accent)", + borderBottom: "none" + }); + } else { + target.setCssProps({ + borderBottom: "2px solid var(--interactive-accent)", + borderTop: "none" + }); + } + } + }; + const dragLeaveHandler = (e) => { + const target = e.target; + if (target.classList.contains("nav-item")) { + target.setCssProps({ + borderTop: "none", + borderBottom: "none" + }); + } + }; + const dropHandler = (e) => { + e.preventDefault(); + const target = e.target; + if (target.classList.contains("nav-item") && draggedElement) { + const targetIndex = parseInt(target.getAttribute("data-index") || "0"); + const draggedIndex = parseInt(draggedElement.getAttribute("data-index") || "0"); + const isPage = target.closest("#pages-list"); + const isSocial = target.closest("#social-list"); + target.setCssProps({ + borderTop: "none", + borderBottom: "none" + }); + if (targetIndex !== draggedIndex) { + if (isPage) { + const draggedItem = state.selectedNavigation.pages.splice(draggedIndex, 1)[0]; + state.selectedNavigation.pages.splice(targetIndex, 0, draggedItem); + } else if (isSocial) { + const draggedItem = state.selectedNavigation.social.splice(draggedIndex, 1)[0]; + state.selectedNavigation.social.splice(targetIndex, 0, draggedItem); + } + this.render(container); + } + } + }; + const containerWithHandlers = container; + if (containerWithHandlers._dragStartHandler) { + container.removeEventListener("dragstart", containerWithHandlers._dragStartHandler); + } + if (containerWithHandlers._dragEndHandler) { + container.removeEventListener("dragend", containerWithHandlers._dragEndHandler); + } + if (containerWithHandlers._dragOverHandler) { + container.removeEventListener("dragover", containerWithHandlers._dragOverHandler); + } + if (containerWithHandlers._dragLeaveHandler) { + container.removeEventListener("dragleave", containerWithHandlers._dragLeaveHandler); + } + if (containerWithHandlers._dropHandler) { + container.removeEventListener("drop", containerWithHandlers._dropHandler); + } + containerWithHandlers._dragStartHandler = dragStartHandler; + containerWithHandlers._dragEndHandler = dragEndHandler; + containerWithHandlers._dragOverHandler = dragOverHandler; + containerWithHandlers._dragLeaveHandler = dragLeaveHandler; + containerWithHandlers._dropHandler = dropHandler; + container.addEventListener("dragstart", dragStartHandler); + container.addEventListener("dragend", dragEndHandler); + container.addEventListener("dragover", dragOverHandler); + container.addEventListener("dragleave", dragLeaveHandler); + container.addEventListener("drop", dropHandler); + } + }; + } +}); + +// src/utils/GiscusScriptParser.ts +var GiscusScriptParser_exports = {}; +__export(GiscusScriptParser_exports, { + GiscusScriptParser: () => GiscusScriptParser +}); +var GiscusScriptParser; +var init_GiscusScriptParser = __esm({ + "src/utils/GiscusScriptParser.ts"() { + "use strict"; + GiscusScriptParser = class { + /** + * Parse a Giscus script tag and extract all data attributes + */ + static parseScript(scriptContent) { + try { + const normalizedScript = scriptContent.trim(); + if (!normalizedScript.includes("giscus.app/client.js")) { + return null; + } + const dataAttributes = {}; + const dataAttributeRegex = /data-([a-z-]+)="([^"]*)"/g; + let match; + while ((match = dataAttributeRegex.exec(normalizedScript)) !== null) { + const [, attributeName, value] = match; + dataAttributes[attributeName] = value; + } + const config4 = { + repo: dataAttributes["repo"] || "", + repoId: dataAttributes["repo-id"] || "", + category: dataAttributes["category"] || "", + categoryId: dataAttributes["category-id"] || "", + // Optional attributes - use empty string if not present (so they can be cleared) + mapping: dataAttributes["mapping"] !== void 0 ? dataAttributes["mapping"] : "", + strict: dataAttributes["strict"] !== void 0 ? dataAttributes["strict"] : "", + reactions: dataAttributes["reactions-enabled"] !== void 0 ? dataAttributes["reactions-enabled"] : "", + metadata: dataAttributes["emit-metadata"] !== void 0 ? dataAttributes["emit-metadata"] : "", + inputPosition: dataAttributes["input-position"] !== void 0 ? dataAttributes["input-position"] : "", + theme: dataAttributes["theme"] !== void 0 ? dataAttributes["theme"] : "", + lang: dataAttributes["lang"] !== void 0 ? dataAttributes["lang"] : "", + loading: dataAttributes["loading"] !== void 0 ? dataAttributes["loading"] : "" + }; + if (!config4.repo || !config4.repoId) { + return null; + } + return config4; + } catch (error) { + console.error("Error parsing Giscus script:", error); + return null; + } + } + /** + * Validate that a script looks like a valid Giscus script + */ + static validateScript(scriptContent) { + const normalizedScript = scriptContent.trim(); + if (!normalizedScript.includes("giscus.app/client.js")) { + return { valid: false, error: "Script must contain giscus.app/client.js" }; + } + if (!normalizedScript.includes("")) { + return { valid: false, error: "Script must be a valid HTML script tag" }; + } + const parsed = this.parseScript(scriptContent); + if (!parsed) { + return { valid: false, error: "Could not parse Giscus configuration from script" }; + } + if (!parsed.repo) { + return { valid: false, error: "Repository (data-repo) is required" }; + } + if (!parsed.repoId) { + return { valid: false, error: "Repository ID (data-repo-id) is required" }; + } + return { valid: true }; + } + /** + * Generate a sample Giscus script for placeholder text + */ + static getSampleScript() { + return ` + + + + + + + + + + + + + + + + + Skip to main content + + + +
+ + +
+
+ +
+
+ + +