From 1662cbdaf057d375d34cf911cb5a96a03744cd71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Sun, 22 Feb 2026 20:40:14 +0900 Subject: [PATCH 001/179] [ZEPPELIN-6358] simplify utils, promote POM usage, and consolidate base logic from #5101 ### What is this PR for? ### PR Description This PR improves the readability and maintainability of the E2E notebook tests. - Removed over-abstracted util and wrapper methods - Moved test logic from util files into the test cases - Simplified page objects to focus on direct UI interactions - Consolidated shared logic into a base page class As a result, the tests are clearer, flatter, and easier to maintain. ### What type of PR is it? Refactoring ### Todos ### What is the Jira issue? ZEPPELIN-6358 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5131 from dididy/e2e/notebook-edited. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/e2e/models/base-page.ts | 69 ++++- .../{theme.page.ts => dark-mode-page.ts} | 14 +- zeppelin-web-angular/e2e/models/home-page.ts | 144 +++------- .../e2e/models/home-page.util.ts | 233 ---------------- zeppelin-web-angular/e2e/models/login-page.ts | 20 +- .../e2e/models/notebook-repo-item.util.ts | 37 +++ .../e2e/models/notebook-repos-page.ts | 29 +- .../e2e/models/notebook-repos-page.util.ts | 137 ---------- .../e2e/models/notebook.util.ts | 24 +- .../e2e/models/published-paragraph-page.ts | 32 +-- .../models/published-paragraph-page.util.ts | 222 +--------------- .../e2e/models/workspace-page.ts | 9 - .../e2e/models/workspace-page.util.ts | 38 +-- zeppelin-web-angular/e2e/tests/app.spec.ts | 14 +- .../anonymous-login-redirect.spec.ts | 102 ++++--- .../e2e/tests/home/home-page-elements.spec.ts | 63 ++--- .../home-page-enhanced-functionality.spec.ts | 60 +++-- .../home/home-page-external-links.spec.ts | 48 ++-- .../e2e/tests/home/home-page-layout.spec.ts | 14 +- .../home/home-page-note-operations.spec.ts | 43 ++- .../home/home-page-notebook-actions.spec.ts | 67 +++-- .../published/published-paragraph.spec.ts | 251 ++++++++++++++---- .../e2e/tests/theme/dark-mode.spec.ts | 86 +++--- .../notebook-repo-item-display.spec.ts | 2 +- .../notebook-repo-item-edit.spec.ts | 15 +- ...notebook-repo-item-form-validation.spec.ts | 42 +-- .../notebook-repo-item-settings.spec.ts | 26 +- .../notebook-repo-item-workflow.spec.ts | 33 +-- .../notebook-repos-page-structure.spec.ts | 13 +- .../tests/workspace/workspace-main.spec.ts | 37 ++- zeppelin-web-angular/e2e/utils.ts | 2 +- 31 files changed, 707 insertions(+), 1219 deletions(-) rename zeppelin-web-angular/e2e/models/{theme.page.ts => dark-mode-page.ts} (81%) delete mode 100644 zeppelin-web-angular/e2e/models/home-page.util.ts create mode 100644 zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts delete mode 100644 zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts diff --git a/zeppelin-web-angular/e2e/models/base-page.ts b/zeppelin-web-angular/e2e/models/base-page.ts index c3d9004fdec..539f096cbb8 100644 --- a/zeppelin-web-angular/e2e/models/base-page.ts +++ b/zeppelin-web-angular/e2e/models/base-page.ts @@ -10,7 +10,7 @@ * limitations under the License. */ -import { Locator, Page } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; export const E2E_TEST_FOLDER = 'E2E_TEST_FOLDER'; export const BASE_URL = 'http://localhost:4200'; @@ -23,12 +23,32 @@ export class BasePage { readonly zeppelinPageHeader: Locator; readonly zeppelinHeader: Locator; + readonly modalTitle: Locator; + readonly modalBody: Locator; + readonly modalContent: Locator; + + readonly okButton: Locator; + readonly cancelButton: Locator; + readonly runButton: Locator; + + readonly welcomeTitle: Locator; + constructor(page: Page) { this.page = page; this.zeppelinNodeList = page.locator('zeppelin-node-list'); this.zeppelinWorkspace = page.locator('zeppelin-workspace'); this.zeppelinPageHeader = page.locator('zeppelin-page-header'); this.zeppelinHeader = page.locator('zeppelin-header'); + + this.modalTitle = page.locator('.ant-modal-confirm-title, .ant-modal-title'); + this.modalBody = page.locator('.ant-modal-confirm-content, .ant-modal-body'); + this.modalContent = page.locator('.ant-modal-body'); + + this.okButton = page.locator('button:has-text("OK")'); + this.cancelButton = page.locator('button:has-text("Cancel")'); + this.runButton = page.locator('button:has-text("Run")'); + + this.welcomeTitle = page.getByRole('heading', { name: 'Welcome to Zeppelin!' }); } async waitForPageLoad(): Promise { @@ -63,4 +83,51 @@ export class BasePage { async getElementText(locator: Locator): Promise { return (await locator.textContent()) || ''; } + + async waitForFormLabels(labelTexts: string[], timeout = 10000): Promise { + await this.page.waitForFunction( + texts => { + const labels = Array.from(document.querySelectorAll('nz-form-label')); + return texts.some(text => labels.some(l => l.textContent?.includes(text))); + }, + labelTexts, + { timeout } + ); + } + + async waitForElementAttribute( + selector: string, + attribute: string, + exists: boolean = true, + timeout = 10000 + ): Promise { + const locator = this.page.locator(selector); + if (exists) { + await expect(locator).toHaveAttribute(attribute, { timeout }); + } else { + await expect(locator).not.toHaveAttribute(attribute, { timeout }); + } + } + + async waitForRouterOutletChild(timeout = 10000): Promise { + await expect(this.page.locator('zeppelin-workspace router-outlet + *')).toHaveCount(1, { timeout }); + } + + async fillAndVerifyInput( + locator: Locator, + value: string, + options?: { timeout?: number; clearFirst?: boolean } + ): Promise { + const { timeout = 10000, clearFirst = true } = options || {}; + + await expect(locator).toBeVisible({ timeout }); + await expect(locator).toBeEnabled({ timeout: 5000 }); + + if (clearFirst) { + await locator.clear(); + } + + await locator.fill(value); + await expect(locator).toHaveValue(value); + } } diff --git a/zeppelin-web-angular/e2e/models/theme.page.ts b/zeppelin-web-angular/e2e/models/dark-mode-page.ts similarity index 81% rename from zeppelin-web-angular/e2e/models/theme.page.ts rename to zeppelin-web-angular/e2e/models/dark-mode-page.ts index 5285ac45902..98f77c89335 100644 --- a/zeppelin-web-angular/e2e/models/theme.page.ts +++ b/zeppelin-web-angular/e2e/models/dark-mode-page.ts @@ -11,36 +11,36 @@ */ import { expect, Locator, Page } from '@playwright/test'; +import { BasePage } from './base-page'; -export class ThemePage { - readonly page: Page; +export class DarkModePage extends BasePage { readonly themeToggleButton: Locator; readonly rootElement: Locator; constructor(page: Page) { - this.page = page; + super(page); this.themeToggleButton = page.locator('zeppelin-theme-toggle button'); this.rootElement = page.locator('html'); } async toggleTheme() { - await this.themeToggleButton.click(); + await this.themeToggleButton.click({ timeout: 15000 }); } async assertDarkTheme() { - await expect(this.rootElement).toHaveClass(/dark/); + await expect(this.rootElement).toHaveClass(/dark/, { timeout: 10000 }); await expect(this.rootElement).toHaveAttribute('data-theme', 'dark'); await expect(this.themeToggleButton).toHaveText('dark_mode'); } async assertLightTheme() { - await expect(this.rootElement).toHaveClass(/light/); + await expect(this.rootElement).toHaveClass(/light/, { timeout: 10000 }); await expect(this.rootElement).toHaveAttribute('data-theme', 'light'); await expect(this.themeToggleButton).toHaveText('light_mode'); } async assertSystemTheme() { - await expect(this.themeToggleButton).toHaveText('smart_toy'); + await expect(this.themeToggleButton).toHaveText('smart_toy', { timeout: 60000 }); } async setThemeInLocalStorage(theme: 'light' | 'dark' | 'system') { diff --git a/zeppelin-web-angular/e2e/models/home-page.ts b/zeppelin-web-angular/e2e/models/home-page.ts index 872784dfa06..52c39df8b33 100644 --- a/zeppelin-web-angular/e2e/models/home-page.ts +++ b/zeppelin-web-angular/e2e/models/home-page.ts @@ -11,18 +11,12 @@ */ import { expect, Locator, Page } from '@playwright/test'; -import { getCurrentPath, waitForUrlNotContaining } from '../utils'; import { BasePage } from './base-page'; export class HomePage extends BasePage { - readonly welcomeHeading: Locator; readonly notebookSection: Locator; readonly helpSection: Locator; readonly communitySection: Locator; - readonly createNewNoteButton: Locator; - readonly importNoteButton: Locator; - readonly searchInput: Locator; - readonly filterInput: Locator; readonly zeppelinLogo: Locator; readonly anonymousUserIndicator: Locator; readonly welcomeSection: Locator; @@ -31,11 +25,12 @@ export class HomePage extends BasePage { readonly helpCommunityColumn: Locator; readonly welcomeDescription: Locator; readonly refreshNoteButton: Locator; - readonly refreshIcon: Locator; - readonly notebookList: Locator; readonly notebookHeading: Locator; readonly helpHeading: Locator; readonly communityHeading: Locator; + readonly createNoteModal: Locator; + readonly createNoteButton: Locator; + readonly notebookNameInput: Locator; readonly externalLinks: { documentation: Locator; mailingList: Locator; @@ -52,27 +47,13 @@ export class HomePage extends BasePage { clearOutput: Locator; moveToTrash: Locator; }; - folderActions: { - createNote: Locator; - renameFolder: Locator; - moveToTrash: Locator; - }; - trashActions: { - restoreAll: Locator; - emptyAll: Locator; - }; }; constructor(page: Page) { super(page); - this.welcomeHeading = page.locator('h1', { hasText: 'Welcome to Zeppelin!' }); this.notebookSection = page.locator('text=Notebook').first(); this.helpSection = page.locator('text=Help').first(); this.communitySection = page.locator('text=Community').first(); - this.createNewNoteButton = page.locator('text=Create new Note'); - this.importNoteButton = page.locator('text=Import Note'); - this.searchInput = page.locator('textbox', { hasText: 'Search' }); - this.filterInput = page.locator('input[placeholder*="Filter"]'); this.zeppelinLogo = page.locator('text=Zeppelin').first(); this.anonymousUserIndicator = page.locator('text=anonymous'); this.welcomeSection = page.locator('.welcome'); @@ -81,11 +62,12 @@ export class HomePage extends BasePage { this.helpCommunityColumn = page.locator('[nz-col]').last(); this.welcomeDescription = page.locator('.welcome').getByText('Zeppelin is web-based notebook'); this.refreshNoteButton = page.locator('a.refresh-note'); - this.refreshIcon = page.locator('a.refresh-note i[nz-icon]'); - this.notebookList = page.locator('zeppelin-node-list'); this.notebookHeading = this.notebookColumn.locator('h3'); this.helpHeading = page.locator('h3').filter({ hasText: 'Help' }); this.communityHeading = page.locator('h3').filter({ hasText: 'Community' }); + this.createNoteModal = page.locator('div.ant-modal-content'); + this.createNoteButton = this.createNoteModal.locator('button', { hasText: 'Create' }); + this.notebookNameInput = this.createNoteModal.locator('input[name="noteName"]'); this.externalLinks = { documentation: page.locator('a[href*="zeppelin.apache.org/docs"]'), @@ -103,67 +85,30 @@ export class HomePage extends BasePage { renameNote: page.locator('.file .operation a[nztooltiptitle*="Rename note"]'), clearOutput: page.locator('.file .operation a[nztooltiptitle*="Clear output"]'), moveToTrash: page.locator('.file .operation a[nztooltiptitle*="Move note to Trash"]') - }, - folderActions: { - createNote: page.locator('.folder .operation a[nztooltiptitle*="Create new note"]'), - renameFolder: page.locator('.folder .operation a[nztooltiptitle*="Rename folder"]'), - moveToTrash: page.locator('.folder .operation a[nztooltiptitle*="Move folder to Trash"]') - }, - trashActions: { - restoreAll: page.locator('.folder .operation a[nztooltiptitle*="Restore all"]'), - emptyAll: page.locator('.folder .operation a[nztooltiptitle*="Empty all"]') } }; } - async navigateToHome(): Promise { - await this.page.goto('/', { waitUntil: 'load' }); - await this.waitForPageLoad(); - } - async navigateToLogin(): Promise { - await this.page.goto('/#/login', { waitUntil: 'load' }); - await this.waitForPageLoad(); + await this.navigateToRoute('/login'); // Wait for potential redirect to complete by checking URL change - await waitForUrlNotContaining(this.page, '#/login'); + await this.waitForUrlNotContaining('#/login'); } async isHomeContentDisplayed(): Promise { - try { - await expect(this.welcomeHeading).toBeVisible(); - return true; - } catch { - return false; - } + return this.welcomeTitle.isVisible(); } async isAnonymousUser(): Promise { - try { - await expect(this.anonymousUserIndicator).toBeVisible(); - return true; - } catch { - return false; - } + return this.anonymousUserIndicator.isVisible(); } async clickZeppelinLogo(): Promise { - await this.zeppelinLogo.click(); - } - - async getCurrentURL(): Promise { - return this.page.url(); - } - - getCurrentPath(): string { - return getCurrentPath(this.page); - } - - async getPageTitle(): Promise { - return this.page.title(); + await this.zeppelinLogo.click({ timeout: 15000 }); } async getWelcomeHeadingText(): Promise { - const text = await this.welcomeHeading.textContent(); + const text = await this.welcomeTitle.textContent(); return text || ''; } @@ -173,65 +118,48 @@ export class HomePage extends BasePage { } async clickRefreshNotes(): Promise { - await this.refreshNoteButton.click(); + await this.refreshNoteButton.click({ timeout: 15000 }); } async isNotebookListVisible(): Promise { - return this.notebookList.isVisible(); + return this.zeppelinNodeList.isVisible(); } async clickCreateNewNote(): Promise { - await this.nodeList.createNewNoteLink.click(); + await this.nodeList.createNewNoteLink.click({ timeout: 15000 }); + await this.createNoteModal.waitFor({ state: 'visible' }); } - async clickImportNote(): Promise { - await this.nodeList.importNoteLink.click(); - } + async createNote(notebookName: string): Promise { + await this.clickCreateNewNote(); - async filterNotes(searchTerm: string): Promise { - await this.nodeList.filterInput.fill(searchTerm); - } + // Wait for the modal form to be fully rendered with proper labels + await this.page.waitForSelector('nz-form-label', { timeout: 10000 }); - async isRefreshIconSpinning(): Promise { - const spinAttribute = await this.refreshIcon.getAttribute('nzSpin'); - return spinAttribute === 'true' || spinAttribute === ''; - } + await this.waitForFormLabels(['Note Name', 'Clone Note']); - async waitForRefreshToComplete(): Promise { - await this.page.waitForFunction( - () => { - const icon = document.querySelector('a.refresh-note i[nz-icon]'); - return icon && !icon.hasAttribute('nzSpin'); - }, - { timeout: 10000 } - ); + // Fill and verify the notebook name input + await this.fillAndVerifyInput(this.notebookNameInput, notebookName); + + // Click the 'Create' button in the modal + await expect(this.createNoteButton).toBeEnabled({ timeout: 5000 }); + await this.createNoteButton.click({ timeout: 15000 }); + await this.waitForPageLoad(); } - async getDocumentationLinkHref(): Promise { - return this.externalLinks.documentation.getAttribute('href'); + async clickImportNote(): Promise { + await this.nodeList.importNoteLink.click({ timeout: 15000 }); } - async areExternalLinksVisible(): Promise { - const links = [ - this.externalLinks.documentation, - this.externalLinks.mailingList, - this.externalLinks.issuesTracking, - this.externalLinks.github - ]; - - for (const link of links) { - if (!(await link.isVisible())) { - return false; - } - } - return true; + async filterNotes(searchTerm: string): Promise { + await this.nodeList.filterInput.fill(searchTerm, { timeout: 15000 }); } - async isWelcomeSectionVisible(): Promise { - return this.welcomeSection.isVisible(); + async waitForRefreshToComplete(): Promise { + await this.waitForElementAttribute('a.refresh-note i[nz-icon]', 'nzSpin', false); } - async isMoreInfoGridVisible(): Promise { - return this.moreInfoGrid.isVisible(); + async getDocumentationLinkHref(): Promise { + return this.externalLinks.documentation.getAttribute('href'); } } diff --git a/zeppelin-web-angular/e2e/models/home-page.util.ts b/zeppelin-web-angular/e2e/models/home-page.util.ts deleted file mode 100644 index 5a5a6ff2108..00000000000 --- a/zeppelin-web-angular/e2e/models/home-page.util.ts +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { expect, Page } from '@playwright/test'; -import { getBasicPageMetadata } from '../utils'; -import { HomePage } from './home-page'; - -export class HomePageUtil { - private homePage: HomePage; - private page: Page; - - constructor(page: Page) { - this.page = page; - this.homePage = new HomePage(page); - } - - async verifyAnonymousUserRedirectFromLogin(): Promise<{ - isLoginUrlMaintained: boolean; - isHomeContentDisplayed: boolean; - isAnonymousUser: boolean; - currentPath: string; - }> { - await this.homePage.navigateToLogin(); - - const currentPath = this.homePage.getCurrentPath(); - const isLoginUrlMaintained = currentPath.includes('#/login'); - const isHomeContentDisplayed = await this.homePage.isHomeContentDisplayed(); - const isAnonymousUser = await this.homePage.isAnonymousUser(); - - return { - isLoginUrlMaintained, - isHomeContentDisplayed, - isAnonymousUser, - currentPath - }; - } - - async verifyHomePageElements(): Promise { - await expect(this.homePage.welcomeHeading).toBeVisible(); - await expect(this.homePage.notebookSection).toBeVisible(); - await expect(this.homePage.helpSection).toBeVisible(); - await expect(this.homePage.communitySection).toBeVisible(); - } - - async verifyExternalLinks(): Promise { - await expect(this.homePage.externalLinks.documentation).toBeVisible(); - await expect(this.homePage.externalLinks.mailingList).toBeVisible(); - await expect(this.homePage.externalLinks.issuesTracking).toBeVisible(); - await expect(this.homePage.externalLinks.github).toBeVisible(); - } - - async testNavigationConsistency(): Promise<{ - pathBeforeClick: string; - pathAfterClick: string; - homeContentMaintained: boolean; - }> { - const pathBeforeClick = this.homePage.getCurrentPath(); - - await this.homePage.clickZeppelinLogo(); - await this.homePage.waitForPageLoad(); - - const pathAfterClick = this.homePage.getCurrentPath(); - const homeContentMaintained = await this.homePage.isHomeContentDisplayed(); - - return { - pathBeforeClick, - pathAfterClick, - homeContentMaintained - }; - } - - async getHomePageMetadata(): Promise<{ - title: string; - path: string; - isAnonymous: boolean; - }> { - const basicMetadata = await getBasicPageMetadata(this.page); - const isAnonymous = await this.homePage.isAnonymousUser(); - - return { - ...basicMetadata, - isAnonymous - }; - } - - async verifyWelcomeSection(): Promise { - await expect(this.homePage.welcomeSection).toBeVisible(); - await expect(this.homePage.welcomeHeading).toBeVisible(); - - const headingText = await this.homePage.getWelcomeHeadingText(); - expect(headingText.trim()).toBe('Welcome to Zeppelin!'); - - const welcomeText = await this.homePage.welcomeDescription.textContent(); - expect(welcomeText).toContain('web-based notebook'); - expect(welcomeText).toContain('interactive data analytics'); - } - - async verifyNotebookSection(): Promise { - await expect(this.homePage.notebookSection).toBeVisible(); - await expect(this.homePage.notebookHeading).toBeVisible(); - await expect(this.homePage.refreshNoteButton).toBeVisible(); - - // Wait for notebook list to load with timeout - await this.page.waitForSelector('zeppelin-node-list', { timeout: 10000 }); - await expect(this.homePage.notebookList).toBeVisible(); - - // Additional wait for content to load - await this.page.waitForTimeout(1000); - } - - async verifyNotebookRefreshFunctionality(): Promise { - await this.homePage.clickRefreshNotes(); - - // Wait for refresh operation to complete - await this.page.waitForTimeout(2000); - - // Ensure the notebook list is still visible after refresh - await expect(this.homePage.notebookList).toBeVisible(); - const isStillVisible = await this.homePage.isNotebookListVisible(); - expect(isStillVisible).toBe(true); - } - - async verifyHelpSection(): Promise { - await expect(this.homePage.helpSection).toBeVisible(); - await expect(this.homePage.helpHeading).toBeVisible(); - } - - async verifyCommunitySection(): Promise { - await expect(this.homePage.communitySection).toBeVisible(); - await expect(this.homePage.communityHeading).toBeVisible(); - } - - async testExternalLinkTargets(): Promise<{ - documentationHref: string | null; - mailingListHref: string | null; - issuesTrackingHref: string | null; - githubHref: string | null; - }> { - // Get the parent links that contain the text - const docLink = this.page.locator('a').filter({ hasText: 'Zeppelin documentation' }); - const mailLink = this.page.locator('a').filter({ hasText: 'Mailing list' }); - const issuesLink = this.page.locator('a').filter({ hasText: 'Issues tracking' }); - const githubLink = this.page.locator('a').filter({ hasText: 'Github' }); - - return { - documentationHref: await docLink.getAttribute('href'), - mailingListHref: await mailLink.getAttribute('href'), - issuesTrackingHref: await issuesLink.getAttribute('href'), - githubHref: await githubLink.getAttribute('href') - }; - } - - async verifyNotebookActions(): Promise { - await expect(this.homePage.nodeList.createNewNoteLink).toBeVisible(); - await expect(this.homePage.nodeList.importNoteLink).toBeVisible(); - await expect(this.homePage.nodeList.filterInput).toBeVisible(); - await expect(this.homePage.nodeList.tree).toBeVisible(); - } - - async testNotebookRefreshLoadingState(): Promise { - const refreshButton = this.page.locator('a.refresh-note'); - const refreshIcon = this.page.locator('a.refresh-note i[nz-icon]'); - - await expect(refreshButton).toBeVisible(); - await expect(refreshIcon).toBeVisible(); - - await this.homePage.clickRefreshNotes(); - - await this.page.waitForTimeout(500); - - await expect(refreshIcon).toBeVisible(); - } - - async verifyCreateNewNoteWorkflow(): Promise { - await this.homePage.clickCreateNewNote(); - - await this.page.waitForFunction( - () => { - return document.querySelector('zeppelin-note-create') !== null; - }, - { timeout: 10000 } - ); - } - - async verifyImportNoteWorkflow(): Promise { - await this.homePage.clickImportNote(); - - await this.page.waitForFunction( - () => { - return document.querySelector('zeppelin-note-import') !== null; - }, - { timeout: 10000 } - ); - } - - async testFilterFunctionality(filterTerm: string): Promise { - await this.homePage.filterNotes(filterTerm); - - await this.page.waitForTimeout(1000); - - const filteredResults = await this.page.locator('nz-tree .node').count(); - expect(filteredResults).toBeGreaterThanOrEqual(0); - } - - async verifyDocumentationVersionLink(): Promise { - const href = await this.homePage.getDocumentationLinkHref(); - expect(href).toContain('zeppelin.apache.org/docs'); - expect(href).toMatch(/\/docs\/\d+\.\d+\.\d+(-SNAPSHOT)?\//); - } - - async verifyAllExternalLinksTargetBlank(): Promise { - const links = [ - this.homePage.externalLinks.documentation, - this.homePage.externalLinks.mailingList, - this.homePage.externalLinks.issuesTracking, - this.homePage.externalLinks.github - ]; - - for (const link of links) { - const target = await link.getAttribute('target'); - expect(target).toBe('_blank'); - } - } -} diff --git a/zeppelin-web-angular/e2e/models/login-page.ts b/zeppelin-web-angular/e2e/models/login-page.ts index cf9e003d778..7e897868835 100644 --- a/zeppelin-web-angular/e2e/models/login-page.ts +++ b/zeppelin-web-angular/e2e/models/login-page.ts @@ -17,37 +17,33 @@ export class LoginPage extends BasePage { readonly userNameInput: Locator; readonly passwordInput: Locator; readonly loginButton: Locator; - readonly welcomeTitle: Locator; readonly formContainer: Locator; + readonly errorMessage: Locator; constructor(page: Page) { super(page); this.userNameInput = page.getByRole('textbox', { name: 'User Name' }); this.passwordInput = page.getByRole('textbox', { name: 'Password' }); this.loginButton = page.getByRole('button', { name: 'Login' }); - this.welcomeTitle = page.getByRole('heading', { name: 'Welcome to Zeppelin!' }); this.formContainer = page.locator('form[nz-form]'); + this.errorMessage = page.locator("text=The username and password that you entered don't match.").first(); } async navigate(): Promise { - await this.page.goto('/#/login'); - await this.waitForPageLoad(); + await this.navigateToRoute('/login'); } async login(username: string, password: string): Promise { - await this.userNameInput.fill(username); - await this.passwordInput.fill(password); - await this.loginButton.click(); + await this.userNameInput.fill(username, { timeout: 15000 }); + await this.passwordInput.fill(password, { timeout: 15000 }); + await this.loginButton.click({ timeout: 15000 }); } async waitForErrorMessage(): Promise { - await this.page.waitForSelector("text=The username and password that you entered don't match.", { timeout: 5000 }); + await this.errorMessage.waitFor({ state: 'visible', timeout: 5000 }); } async getErrorMessageText(): Promise { - return ( - (await this.page.locator("text=The username and password that you entered don't match.").first().textContent()) || - '' - ); + return this.getElementText(this.errorMessage); } } diff --git a/zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts b/zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts new file mode 100644 index 00000000000..06cdab7ed2c --- /dev/null +++ b/zeppelin-web-angular/e2e/models/notebook-repo-item.util.ts @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page } from '@playwright/test'; +import { NotebookRepoItemPage } from './notebook-repos-page'; +import { BasePage } from './base-page'; + +export class NotebookRepoItemUtil extends BasePage { + private repoItemPage: NotebookRepoItemPage; + + constructor(page: Page, repoName: string) { + super(page); + this.repoItemPage = new NotebookRepoItemPage(page, repoName); + } + + async verifyDisplayMode(): Promise { + await expect(this.repoItemPage.editButton).toBeVisible(); + const isEditMode = await this.repoItemPage.isEditMode(); + expect(isEditMode).toBe(false); + } + + async verifyEditMode(): Promise { + await expect(this.repoItemPage.saveButton).toBeVisible(); + await expect(this.repoItemPage.cancelButton).toBeVisible(); + const isEditMode = await this.repoItemPage.isEditMode(); + expect(isEditMode).toBe(true); + } +} diff --git a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts index 66befc4d2b5..3272df477de 100644 --- a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts @@ -15,26 +15,24 @@ import { waitForZeppelinReady } from '../utils'; import { BasePage } from './base-page'; export class NotebookReposPage extends BasePage { - readonly pageHeader: Locator; readonly pageDescription: Locator; readonly repositoryItems: Locator; constructor(page: Page) { super(page); - this.pageHeader = page.locator('zeppelin-page-header[title="Notebook Repository"]'); this.pageDescription = page.locator("text=Manage your Notebook Repositories' settings."); this.repositoryItems = page.locator('zeppelin-notebook-repo-item'); } async navigate(): Promise { - await this.page.goto('/#/notebook-repos', { waitUntil: 'load' }); - await this.page.waitForURL('**/#/notebook-repos', { timeout: 15000 }); + await this.navigateToRoute('/notebook-repos', { timeout: 60000 }); + await this.page.waitForURL('**/#/notebook-repos', { timeout: 60000 }); await waitForZeppelinReady(this.page); await this.page.waitForLoadState('networkidle', { timeout: 15000 }); - await this.page.waitForSelector('zeppelin-notebook-repo-item, zeppelin-page-header[title="Notebook Repository"]', { - state: 'visible', - timeout: 20000 - }); + await Promise.race([ + this.zeppelinPageHeader.filter({ hasText: 'Notebook Repository' }).waitFor({ state: 'visible' }), + this.page.waitForSelector('zeppelin-notebook-repo-item', { state: 'visible' }) + ]); } async getRepositoryItemCount(): Promise { @@ -42,8 +40,7 @@ export class NotebookReposPage extends BasePage { } } -export class NotebookRepoItemPage { - readonly page: Page; +export class NotebookRepoItemPage extends BasePage { readonly repositoryCard: Locator; readonly repositoryName: Locator; readonly editButton: Locator; @@ -53,7 +50,7 @@ export class NotebookRepoItemPage { readonly settingRows: Locator; constructor(page: Page, repoName: string) { - this.page = page; + super(page); this.repositoryCard = page.locator('nz-card').filter({ hasText: repoName }); this.repositoryName = this.repositoryCard.locator('.ant-card-head-title'); this.editButton = this.repositoryCard.locator('button:has-text("Edit")'); @@ -64,15 +61,15 @@ export class NotebookRepoItemPage { } async clickEdit(): Promise { - await this.editButton.click(); + await this.editButton.click({ timeout: 15000 }); } async clickSave(): Promise { - await this.saveButton.click(); + await this.saveButton.click({ timeout: 15000 }); } async clickCancel(): Promise { - await this.cancelButton.click(); + await this.cancelButton.click({ timeout: 15000 }); } async isEditMode(): Promise { @@ -99,8 +96,8 @@ export class NotebookRepoItemPage { async selectSettingDropdown(settingName: string, optionValue: string): Promise { const row = this.repositoryCard.locator('tbody tr').filter({ hasText: settingName }); const select = row.locator('nz-select'); - await select.click(); - await this.page.locator(`nz-option[nzvalue="${optionValue}"]`).click(); + await select.click({ timeout: 15000 }); + await this.page.locator(`nz-option[nzvalue="${optionValue}"]`).click({ timeout: 15000 }); } async getSettingInputValue(settingName: string): Promise { diff --git a/zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts b/zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts deleted file mode 100644 index d2b0b1f2044..00000000000 --- a/zeppelin-web-angular/e2e/models/notebook-repos-page.util.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { expect, Page } from '@playwright/test'; -import { NotebookReposPage, NotebookRepoItemPage } from './notebook-repos-page'; - -export class NotebookReposPageUtil { - private notebookReposPage: NotebookReposPage; - private page: Page; - - constructor(page: Page) { - this.page = page; - this.notebookReposPage = new NotebookReposPage(page); - } - - async verifyPageStructure(): Promise { - await expect(this.notebookReposPage.pageHeader).toBeVisible(); - await expect(this.notebookReposPage.pageDescription).toBeVisible(); - } - - async verifyRepositoryListDisplayed(): Promise { - const count = await this.notebookReposPage.getRepositoryItemCount(); - expect(count).toBeGreaterThan(0); - } - - async verifyAllRepositoriesRendered(): Promise { - const count = await this.notebookReposPage.getRepositoryItemCount(); - expect(count).toBeGreaterThan(0); - return count; - } - - async getRepositoryItem(repoName: string): Promise { - return new NotebookRepoItemPage(this.page, repoName); - } - - async verifyRepositoryCardDisplayed(repoName: string): Promise { - const repoItem = await this.getRepositoryItem(repoName); - await expect(repoItem.repositoryCard).toBeVisible(); - await expect(repoItem.repositoryName).toContainText(repoName); - } -} - -export class NotebookRepoItemUtil { - private repoItemPage: NotebookRepoItemPage; - - constructor(page: Page, repoName: string) { - this.repoItemPage = new NotebookRepoItemPage(page, repoName); - } - - async verifyDisplayMode(): Promise { - await expect(this.repoItemPage.editButton).toBeVisible(); - const isEditMode = await this.repoItemPage.isEditMode(); - expect(isEditMode).toBe(false); - } - - async verifyEditMode(): Promise { - await expect(this.repoItemPage.saveButton).toBeVisible(); - await expect(this.repoItemPage.cancelButton).toBeVisible(); - const isEditMode = await this.repoItemPage.isEditMode(); - expect(isEditMode).toBe(true); - } - - async enterEditMode(): Promise { - await this.repoItemPage.clickEdit(); - await this.verifyEditMode(); - } - - async exitEditModeByCancel(): Promise { - await this.repoItemPage.clickCancel(); - await this.verifyDisplayMode(); - } - - async exitEditModeBySave(): Promise { - await this.repoItemPage.clickSave(); - await this.verifyDisplayMode(); - } - - async verifySettingsDisplayed(): Promise { - const settingCount = await this.repoItemPage.getSettingCount(); - expect(settingCount).toBeGreaterThan(0); - } - - async verifyInputTypeSettingInEditMode(settingName: string): Promise { - const isVisible = await this.repoItemPage.isInputVisible(settingName); - expect(isVisible).toBe(true); - } - - async verifyDropdownTypeSettingInEditMode(settingName: string): Promise { - const isVisible = await this.repoItemPage.isDropdownVisible(settingName); - expect(isVisible).toBe(true); - } - - async updateInputSetting(settingName: string, value: string): Promise { - await this.repoItemPage.fillSettingInput(settingName, value); - const inputValue = await this.repoItemPage.getSettingInputValue(settingName); - expect(inputValue).toBe(value); - } - - async updateDropdownSetting(settingName: string, optionValue: string): Promise { - await this.repoItemPage.selectSettingDropdown(settingName, optionValue); - } - - async verifySaveButtonDisabled(): Promise { - const isEnabled = await this.repoItemPage.isSaveButtonEnabled(); - expect(isEnabled).toBe(false); - } - - async verifySaveButtonEnabled(): Promise { - const isEnabled = await this.repoItemPage.isSaveButtonEnabled(); - expect(isEnabled).toBe(true); - } - - async verifyFormReset(settingName: string, originalValue: string): Promise { - const currentValue = await this.repoItemPage.getSettingValue(settingName); - expect(currentValue.trim()).toBe(originalValue.trim()); - } - - async performCompleteEditWorkflow(settingName: string, newValue: string, isInput: boolean = true): Promise { - await this.enterEditMode(); - if (isInput) { - await this.updateInputSetting(settingName, newValue); - } else { - await this.updateDropdownSetting(settingName, newValue); - } - await this.verifySaveButtonEnabled(); - await this.exitEditModeBySave(); - } -} diff --git a/zeppelin-web-angular/e2e/models/notebook.util.ts b/zeppelin-web-angular/e2e/models/notebook.util.ts index 5495a1dfef7..00e8dbc1831 100644 --- a/zeppelin-web-angular/e2e/models/notebook.util.ts +++ b/zeppelin-web-angular/e2e/models/notebook.util.ts @@ -11,6 +11,7 @@ */ import { expect, Page } from '@playwright/test'; +import { performLoginIfRequired, waitForZeppelinReady } from '../utils'; import { BasePage } from './base-page'; import { HomePage } from './home-page'; @@ -24,21 +25,20 @@ export class NotebookUtil extends BasePage { async createNotebook(notebookName: string): Promise { await this.homePage.navigateToHome(); - await this.homePage.createNewNoteButton.click(); - // Wait for the modal to appear and fill the notebook name - const notebookNameInput = this.page.locator('input[name="noteName"]'); - await expect(notebookNameInput).toBeVisible({ timeout: 10000 }); + // Perform login if required + await performLoginIfRequired(this.page); - // Fill notebook name - await notebookNameInput.fill(notebookName); + // Wait for Zeppelin to be fully ready + await waitForZeppelinReady(this.page); - // Click the 'Create' button in the modal - const createButton = this.page.locator('button', { hasText: 'Create' }); - await createButton.click(); + // Wait for URL to not contain 'login' and for the notebook list to appear + await this.page.waitForFunction( + () => !window.location.href.includes('#/login') && document.querySelector('zeppelin-node-list') !== null, + { timeout: 30000 } + ); - // Wait for the notebook to be created and navigate to it - await this.page.waitForURL(url => url.toString().includes('/notebook/'), { timeout: 30000 }); - await this.waitForPageLoad(); + await expect(this.homePage.zeppelinNodeList).toBeVisible({ timeout: 90000 }); + await this.homePage.createNote(notebookName); } } diff --git a/zeppelin-web-angular/e2e/models/published-paragraph-page.ts b/zeppelin-web-angular/e2e/models/published-paragraph-page.ts index 73f37b17982..0bc6997cfdf 100644 --- a/zeppelin-web-angular/e2e/models/published-paragraph-page.ts +++ b/zeppelin-web-angular/e2e/models/published-paragraph-page.ts @@ -11,58 +11,36 @@ */ import { Locator, Page } from '@playwright/test'; +import { navigateToNotebookWithFallback } from '../utils'; import { BasePage } from './base-page'; export class PublishedParagraphPage extends BasePage { - readonly publishedParagraphContainer: Locator; - readonly dynamicForms: Locator; readonly paragraphResult: Locator; - readonly errorModal: Locator; - readonly errorModalTitle: Locator; readonly errorModalContent: Locator; readonly errorModalOkButton: Locator; readonly confirmationModal: Locator; - readonly modalTitle: Locator; - readonly runButton: Locator; constructor(page: Page) { super(page); - this.publishedParagraphContainer = page.locator('zeppelin-publish-paragraph'); - this.dynamicForms = page.locator('zeppelin-notebook-paragraph-dynamic-forms'); this.paragraphResult = page.locator('zeppelin-notebook-paragraph-result'); - this.errorModal = page.locator('.ant-modal').last(); - this.errorModalTitle = page.locator('.ant-modal-title'); this.errorModalContent = this.page.locator('.ant-modal-body', { hasText: 'Paragraph Not Found' }).last(); this.errorModalOkButton = page.getByRole('button', { name: 'OK' }).last(); this.confirmationModal = page.locator('div.ant-modal-confirm').last(); - this.modalTitle = this.confirmationModal.locator('.ant-modal-confirm-title'); - this.runButton = this.confirmationModal.locator('button', { hasText: 'Run' }); } async navigateToNotebook(noteId: string): Promise { - await this.page.goto(`/#/notebook/${noteId}`); - await this.waitForPageLoad(); + await navigateToNotebookWithFallback(this.page, noteId); } async navigateToPublishedParagraph(noteId: string, paragraphId: string): Promise { - await this.page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`); - await this.waitForPageLoad(); + await this.navigateToRoute(`/notebook/${noteId}/paragraph/${paragraphId}`); } async getErrorModalContent(): Promise { - return (await this.errorModalContent.textContent()) || ''; + return await this.getElementText(this.errorModalContent); } async clickErrorModalOk(): Promise { - await this.errorModalOkButton.click(); - } - - async getCurrentUrl(): Promise { - return this.page.url(); - } - - async isOnHomePage(): Promise { - const url = await this.getCurrentUrl(); - return url.includes('/#/') && !url.includes('/notebook/'); + await this.errorModalOkButton.click({ timeout: 15000 }); } } diff --git a/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts b/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts index 8f91c02094e..a10cce38da4 100644 --- a/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts +++ b/zeppelin-web-angular/e2e/models/published-paragraph-page.util.ts @@ -10,230 +10,28 @@ * limitations under the License. */ -import { expect, Page } from '@playwright/test'; -import { NotebookUtil } from './notebook.util'; +import { Page } from '@playwright/test'; +import { BasePage } from './base-page'; import { PublishedParagraphPage } from './published-paragraph-page'; -export class PublishedParagraphTestUtil { - private page: Page; +export class PublishedParagraphTestUtil extends BasePage { private publishedParagraphPage: PublishedParagraphPage; - private notebookUtil: NotebookUtil; constructor(page: Page) { - this.page = page; + super(page); this.publishedParagraphPage = new PublishedParagraphPage(page); - this.notebookUtil = new NotebookUtil(page); } - async verifyNonExistentParagraphError(validNoteId: string, invalidParagraphId: string): Promise { - await this.publishedParagraphPage.navigateToPublishedParagraph(validNoteId, invalidParagraphId); - - // Try different possible error modal texts - const possibleModals = [ - this.page.locator('.ant-modal', { hasText: 'Paragraph Not Found' }), - this.page.locator('.ant-modal', { hasText: 'not found' }), - this.page.locator('.ant-modal', { hasText: 'Error' }), - this.page.locator('.ant-modal').filter({ hasText: /not found|error|paragraph/i }) - ]; - - let modal; - for (const possibleModal of possibleModals) { - const count = await possibleModal.count(); - - for (let i = 0; i < count; i++) { - const m = possibleModal.nth(i); - - if (await m.isVisible()) { - modal = m; - break; - } - } - - if (modal) { - break; - } - } - - if (!modal) { - // If no modal is found, check if we're redirected to home - await expect(this.page).toHaveURL(/\/#\/$/, { timeout: 10000 }); - return; - } - - await expect(modal).toBeVisible({ timeout: 10000 }); - - // Try to get content and check if available - try { - const content = await this.publishedParagraphPage.getErrorModalContent(); - if (content && content.includes(invalidParagraphId)) { - expect(content).toContain(invalidParagraphId); - } - } catch { - throw Error('Content check failed, continue with OK button click'); - } - - await this.publishedParagraphPage.clickErrorModalOk(); - - // Wait for redirect to home page instead of checking modal state - await expect(this.page).toHaveURL(/\/#\/$/, { timeout: 10000 }); - - expect(await this.publishedParagraphPage.isOnHomePage()).toBe(true); + async navigateToPublishedParagraph(noteId: string, paragraphId: string): Promise { + await this.publishedParagraphPage.navigateToPublishedParagraph(noteId, paragraphId); } - async verifyClickLinkThisParagraphBehavior(noteId: string, paragraphId: string): Promise { - // 1. Navigate to the normal notebook view - await this.page.goto(`/#/notebook/${noteId}`); - await this.page.waitForLoadState('networkidle'); - - // 2. Find the correct paragraph result element and go up to the parent paragraph container - // First try with data-testid, then fallback to first paragraph if not found - let paragraphElement = this.page.locator(`zeppelin-notebook-paragraph[data-testid="${paragraphId}"]`); - - if ((await paragraphElement.count()) === 0) { - // Fallback to first paragraph if specific ID not found - paragraphElement = this.page.locator('zeppelin-notebook-paragraph').first(); - } - - await expect(paragraphElement).toBeVisible({ timeout: 10000 }); - - // 3. Click the settings button to open the dropdown - const settingsButton = paragraphElement.locator('a[nz-dropdown]'); - await settingsButton.click(); - - // 4. Click "Link this paragraph" in the dropdown menu - const linkParagraphButton = this.page.locator('li.list-item:has-text("Link this paragraph")'); - await expect(linkParagraphButton).toBeVisible(); - - // 5. Handle the new page/tab that opens - const [newPage] = await Promise.all([this.page.waitForEvent('popup'), linkParagraphButton.click()]); - await newPage.waitForLoadState(); - - // 6. Verify the new page URL shows published paragraph (not redirected) - await expect(newPage).toHaveURL(new RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 10000 }); - - const codeEditor = newPage.locator('zeppelin-notebook-paragraph-code-editor'); - await expect(codeEditor).toBeHidden(); - - const controlPanel = newPage.locator('zeppelin-notebook-paragraph-control'); - await expect(controlPanel).toBeHidden(); + async getErrorModalContent(): Promise { + return this.publishedParagraphPage.getErrorModalContent(); } - async createTestNotebook(): Promise<{ noteId: string; paragraphId: string }> { - const notebookName = `Test Notebook ${Date.now()}`; - - // Use existing NotebookUtil to create notebook - await this.notebookUtil.createNotebook(notebookName); - - // Extract noteId from URL - const url = this.page.url(); - const noteIdMatch = url.match(/\/notebook\/([^\/\?]+)/); - if (!noteIdMatch) { - throw new Error(`Failed to extract notebook ID from URL: ${url}`); - } - const noteId = noteIdMatch[1]; - - // Get first paragraph ID - await this.page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 'visible', timeout: 10000 }); - const paragraphContainer = this.page.locator('zeppelin-notebook-paragraph').first(); - const dropdownTrigger = paragraphContainer.locator('a[nz-dropdown]'); - await dropdownTrigger.click(); - - const paragraphLink = this.page.locator('li.paragraph-id a').first(); - await paragraphLink.waitFor({ state: 'attached', timeout: 5000 }); - - const paragraphId = await paragraphLink.textContent(); - - if (!paragraphId || !paragraphId.startsWith('paragraph_')) { - throw new Error(`Failed to find a valid paragraph ID. Found: ${paragraphId}`); - } - - // Navigate back to home - await this.page.goto('/'); - await this.page.waitForLoadState('networkidle'); - await this.page.waitForSelector('text=Welcome to Zeppelin!', { timeout: 5000 }); - - return { noteId, paragraphId }; - } - - async deleteTestNotebook(noteId: string): Promise { - try { - // Navigate to home page - await this.page.goto('/'); - await this.page.waitForLoadState('networkidle'); - - // Find the notebook in the tree by noteId and get its parent tree node - const notebookLink = this.page.locator(`a[href*="/notebook/${noteId}"]`); - - if ((await notebookLink.count()) > 0) { - // Hover over the tree node to make delete button visible - const treeNode = notebookLink.locator('xpath=ancestor::nz-tree-node[1]'); - await treeNode.hover(); - - // Wait a bit for hover effects - await this.page.waitForTimeout(1000); - - // Try multiple selectors for the delete button - const deleteButtonSelectors = [ - 'a[nz-tooltip] i[nztype="delete"]', - 'i[nztype="delete"]', - '[nz-popconfirm] i[nztype="delete"]', - 'i.anticon-delete' - ]; - - let deleteClicked = false; - for (const selector of deleteButtonSelectors) { - const deleteButton = treeNode.locator(selector); - try { - if (await deleteButton.isVisible({ timeout: 2000 })) { - await deleteButton.click({ timeout: 5000 }); - deleteClicked = true; - break; - } - } catch (e) { - // Continue to next selector - continue; - } - } - - if (!deleteClicked) { - console.warn(`Delete button not found for notebook ${noteId}`); - return; - } - - // Confirm deletion in popconfirm with timeout - try { - const confirmButton = this.page.locator('button:has-text("OK")'); - await confirmButton.click({ timeout: 5000 }); - - // Wait for the notebook to be removed with timeout - await expect(treeNode).toBeHidden({ timeout: 10000 }); - } catch (e) { - // If confirmation fails, try alternative OK button selectors - const altConfirmButtons = [ - '.ant-popover button:has-text("OK")', - '.ant-popconfirm button:has-text("OK")', - 'button.ant-btn-primary:has-text("OK")' - ]; - - for (const selector of altConfirmButtons) { - try { - const button = this.page.locator(selector); - if (await button.isVisible({ timeout: 1000 })) { - await button.click({ timeout: 3000 }); - await expect(treeNode).toBeHidden({ timeout: 10000 }); - break; - } - } catch (altError) { - // Continue to next selector - continue; - } - } - } - } - } catch (error) { - console.warn(`Failed to delete test notebook ${noteId}:`, error); - // Don't throw error to avoid failing the test cleanup - } + async clickErrorModalOk(): Promise { + await this.publishedParagraphPage.clickErrorModalOk(); } generateNonExistentIds(): { noteId: string; paragraphId: string } { diff --git a/zeppelin-web-angular/e2e/models/workspace-page.ts b/zeppelin-web-angular/e2e/models/workspace-page.ts index 57c0da8796b..1fdcf9e5a78 100644 --- a/zeppelin-web-angular/e2e/models/workspace-page.ts +++ b/zeppelin-web-angular/e2e/models/workspace-page.ts @@ -14,19 +14,10 @@ import { Locator, Page } from '@playwright/test'; import { BasePage } from './base-page'; export class WorkspacePage extends BasePage { - readonly workspaceComponent: Locator; - readonly header: Locator; readonly routerOutlet: Locator; constructor(page: Page) { super(page); - this.workspaceComponent = page.locator('zeppelin-workspace'); - this.header = page.locator('zeppelin-header'); this.routerOutlet = page.locator('zeppelin-workspace router-outlet'); } - - async navigateToWorkspace(): Promise { - await this.page.goto('/', { waitUntil: 'load' }); - await this.waitForPageLoad(); - } } diff --git a/zeppelin-web-angular/e2e/models/workspace-page.util.ts b/zeppelin-web-angular/e2e/models/workspace-page.util.ts index 7ff706f93a2..fd6d9c3f450 100644 --- a/zeppelin-web-angular/e2e/models/workspace-page.util.ts +++ b/zeppelin-web-angular/e2e/models/workspace-page.util.ts @@ -11,54 +11,28 @@ */ import { expect, Page } from '@playwright/test'; -import { performLoginIfRequired, waitForZeppelinReady } from '../utils'; +import { BasePage } from './base-page'; import { WorkspacePage } from './workspace-page'; -export class WorkspaceTestUtil { - private page: Page; +export class WorkspaceUtil extends BasePage { private workspacePage: WorkspacePage; constructor(page: Page) { - this.page = page; + super(page); this.workspacePage = new WorkspacePage(page); } - async navigateAndWaitForLoad(): Promise { - await this.workspacePage.navigateToWorkspace(); - await waitForZeppelinReady(this.page); - await performLoginIfRequired(this.page); - } - - async verifyWorkspaceLayout(): Promise { - await expect(this.workspacePage.workspaceComponent).toBeVisible(); - await expect(this.workspacePage.routerOutlet).toBeAttached(); - } - async verifyHeaderVisibility(shouldBeVisible: boolean): Promise { if (shouldBeVisible) { - await expect(this.workspacePage.header).toBeVisible(); + await expect(this.workspacePage.zeppelinHeader).toBeVisible(); } else { - await expect(this.workspacePage.header).toBeHidden(); + await expect(this.workspacePage.zeppelinHeader).toBeHidden(); } } - async verifyWorkspaceContainer(): Promise { - await expect(this.workspacePage.workspaceComponent).toBeVisible(); - const contentElements = await this.page.locator('.content').count(); - expect(contentElements).toBeGreaterThan(0); - } - async verifyRouterOutletActivation(): Promise { await expect(this.workspacePage.routerOutlet).toBeAttached(); - - await this.page.waitForFunction( - () => { - const workspace = document.querySelector('zeppelin-workspace'); - const outlet = workspace?.querySelector('router-outlet'); - return outlet && outlet.nextElementSibling !== null; - }, - { timeout: 10000 } - ); + await this.waitForRouterOutletChild(); } async waitForComponentActivation(): Promise { diff --git a/zeppelin-web-angular/e2e/tests/app.spec.ts b/zeppelin-web-angular/e2e/tests/app.spec.ts index 5a02c87f388..5d956c747f2 100644 --- a/zeppelin-web-angular/e2e/tests/app.spec.ts +++ b/zeppelin-web-angular/e2e/tests/app.spec.ts @@ -12,8 +12,7 @@ import { expect, test } from '@playwright/test'; import { BasePage } from '../models/base-page'; -import { LoginTestUtil } from '../models/login-page.util'; -import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES, performLoginIfRequired } from '../utils'; test.describe('Zeppelin App Component', () => { addPageAnnotationBeforeEach(PAGES.APP); @@ -23,6 +22,8 @@ test.describe('Zeppelin App Component', () => { basePage = new BasePage(page); await page.goto('/', { waitUntil: 'load' }); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); }); test('should have correct component selector and structure', async ({ page }) => { @@ -56,12 +57,8 @@ test.describe('Zeppelin App Component', () => { test('should display workspace after loading', async ({ page }) => { await waitForZeppelinReady(page); - const isShiroEnabled = await LoginTestUtil.isShiroEnabled(); - if (isShiroEnabled) { - await expect(page.locator('zeppelin-login')).toBeVisible(); - } else { - await expect(page.locator('zeppelin-workspace')).toBeVisible(); - } + // After the `beforeEach` hook, which handles login, the workspace should be visible. + await expect(basePage.zeppelinWorkspace).toBeVisible(); }); test('should handle navigation events correctly', async ({ page }) => { @@ -142,6 +139,7 @@ test.describe('Zeppelin App Component', () => { test('should maintain component integrity during navigation', async ({ page }) => { await waitForZeppelinReady(page); + await performLoginIfRequired(page); const zeppelinRoot = page.locator('zeppelin-root'); const routerOutlet = zeppelinRoot.locator('router-outlet').first(); diff --git a/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts b/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts index 1c0905c282b..5e73dc036d4 100644 --- a/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts +++ b/zeppelin-web-angular/e2e/tests/authentication/anonymous-login-redirect.spec.ts @@ -11,10 +11,12 @@ */ import { expect, test } from '@playwright/test'; -import { HomePageUtil } from '../../models/home-page.util'; +import { BasePage } from '../../models/base-page'; +import { HomePage } from '../../models/home-page'; import { LoginTestUtil } from '../../models/login-page.util'; import { addPageAnnotationBeforeEach, + getBasicPageMetadata, getCurrentPath, waitForUrlNotContaining, waitForZeppelinReady, @@ -24,7 +26,8 @@ import { test.describe('Anonymous User Login Redirect', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); - let homePageUtil: HomePageUtil; + let homePage: HomePage; + let basePage: BasePage; test.beforeAll(async () => { const isShiroEnabled = await LoginTestUtil.isShiroEnabled(); @@ -34,74 +37,90 @@ test.describe('Anonymous User Login Redirect', () => { }); test.beforeEach(async ({ page }) => { - homePageUtil = new HomePageUtil(page); + homePage = new HomePage(page); + basePage = new BasePage(page); }); test.describe('Given an anonymous user is already logged in', () => { test.beforeEach(async ({ page }) => { - await page.goto('/', { waitUntil: 'load' }); + await page.goto('/#/'); await waitForZeppelinReady(page); }); - test('When accessing login page directly, Then should redirect to home with proper URL change', async () => { - const redirectResult = await homePageUtil.verifyAnonymousUserRedirectFromLogin(); - - expect(redirectResult.isLoginUrlMaintained).toBe(false); - expect(redirectResult.isHomeContentDisplayed).toBe(true); - expect(redirectResult.isAnonymousUser).toBe(true); - expect(redirectResult.currentPath).toContain('#/'); - expect(redirectResult.currentPath).not.toContain('#/login'); + test('When accessing login page directly, Then should redirect to home with proper URL change', async ({ + page + }) => { + await homePage.navigateToLogin(); + + const currentPath = getCurrentPath(page); + const isLoginUrlMaintained = currentPath.includes('#/login'); + const isHomeContentDisplayed = await homePage.isHomeContentDisplayed(); + const isAnonymousUser = await homePage.isAnonymousUser(); + + expect(isLoginUrlMaintained).toBe(false); + expect(isHomeContentDisplayed).toBe(true); + expect(isAnonymousUser).toBe(true); + expect(currentPath).toContain('#/'); + expect(currentPath).not.toContain('#/login'); }); test('When accessing login page directly, Then should display all home page elements correctly', async ({ page }) => { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); - await homePageUtil.verifyHomePageElements(); + await expect(homePage.welcomeTitle).toBeVisible(); + await expect(homePage.notebookSection).toBeVisible(); + await expect(homePage.helpSection).toBeVisible(); + await expect(homePage.communitySection).toBeVisible(); }); test('When clicking Zeppelin logo after redirect, Then should maintain home URL and content', async ({ page }) => { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); - const navigationResult = await homePageUtil.testNavigationConsistency(); + const pathBeforeClick = getCurrentPath(page); + await homePage.clickZeppelinLogo(); + await basePage.waitForPageLoad(); + const pathAfterClick = getCurrentPath(page); + const homeContentMaintained = await homePage.isHomeContentDisplayed(); - expect(navigationResult.pathBeforeClick).toContain('#/'); - expect(navigationResult.pathBeforeClick).not.toContain('#/login'); - expect(navigationResult.pathAfterClick).toContain('#/'); - expect(navigationResult.homeContentMaintained).toBe(true); + expect(pathBeforeClick).toContain('#/'); + expect(pathBeforeClick).not.toContain('#/login'); + expect(pathAfterClick).toContain('#/'); + expect(homeContentMaintained).toBe(true); }); test('When accessing login page, Then should redirect and maintain anonymous user state', async ({ page }) => { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); - const metadata = await homePageUtil.getHomePageMetadata(); + const basicMetadata = await getBasicPageMetadata(page); + const isAnonymous = await homePage.isAnonymousUser(); - expect(metadata.title).toContain('Zeppelin'); - expect(metadata.path).toContain('#/'); - expect(metadata.path).not.toContain('#/login'); - expect(metadata.isAnonymous).toBe(true); + expect(basicMetadata.title).toContain('Zeppelin'); + expect(basicMetadata.path).toContain('#/'); + expect(basicMetadata.path).not.toContain('#/login'); + expect(isAnonymous).toBe(true); }); test('When accessing login page, Then should display welcome heading and main sections', async ({ page }) => { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); - await expect(page.locator('h1', { hasText: 'Welcome to Zeppelin!' })).toBeVisible(); + await expect(basePage.welcomeTitle).toBeVisible(); await expect(page.locator('text=Notebook').first()).toBeVisible(); await expect(page.locator('text=Help').first()).toBeVisible(); await expect(page.locator('text=Community').first()).toBeVisible(); }); test('When accessing login page, Then should display notebook functionalities', async ({ page }) => { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); @@ -117,7 +136,7 @@ test.describe('Anonymous User Login Redirect', () => { test('When accessing login page, Then should display external links in help and community sections', async ({ page }) => { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); @@ -143,33 +162,36 @@ test.describe('Anonymous User Login Redirect', () => { test('When navigating between home and login URLs, Then should maintain consistent user experience', async ({ page }) => { - await page.goto('/', { waitUntil: 'load' }); + await page.goto('/#/'); await waitForZeppelinReady(page); - const homeMetadata = await homePageUtil.getHomePageMetadata(); + const homeMetadata = await getBasicPageMetadata(page); + const isHomeAnonymous = await homePage.isAnonymousUser(); expect(homeMetadata.path).toContain('#/'); - expect(homeMetadata.isAnonymous).toBe(true); + expect(isHomeAnonymous).toBe(true); - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await page.waitForURL(url => !url.toString().includes('#/login')); - const loginMetadata = await homePageUtil.getHomePageMetadata(); + const loginMetadata = await getBasicPageMetadata(page); + const isLoginAnonymous = await homePage.isAnonymousUser(); expect(loginMetadata.path).toContain('#/'); expect(loginMetadata.path).not.toContain('#/login'); - expect(loginMetadata.isAnonymous).toBe(true); + expect(isLoginAnonymous).toBe(true); - const isHomeContentDisplayed = await homePageUtil.verifyAnonymousUserRedirectFromLogin(); - expect(isHomeContentDisplayed.isHomeContentDisplayed).toBe(true); + await homePage.navigateToLogin(); + const isHomeContentDisplayed = await homePage.isHomeContentDisplayed(); + expect(isHomeContentDisplayed).toBe(true); }); test('When multiple page loads occur on login URL, Then should consistently redirect to home', async ({ page }) => { for (let i = 0; i < 3; i++) { - await page.goto('/#/login', { waitUntil: 'load' }); + await page.goto('/#/login'); await waitForZeppelinReady(page); await waitForUrlNotContaining(page, '#/login'); - await expect(page.locator('h1', { hasText: 'Welcome to Zeppelin!' })).toBeVisible(); + await expect(basePage.welcomeTitle).toBeVisible(); await expect(page.locator('text=anonymous')).toBeVisible(); const path = getCurrentPath(page); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts index f9f27d59e5d..f41c00c544e 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts @@ -12,13 +12,15 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { HomePageUtil } from '../../models/home-page.util'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Home Page - Core Elements', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); + let homePage: HomePage; + test.beforeEach(async ({ page }) => { + homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); @@ -26,10 +28,7 @@ test.describe('Home Page - Core Elements', () => { test.describe('Welcome Section', () => { test('should display welcome section with correct content', async ({ page }) => { - const homePageUtil = new HomePageUtil(page); - await test.step('Given I am on the home page', async () => { - const homePage = new HomePage(page); await homePage.navigateToHome(); }); @@ -38,13 +37,18 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then I should see the welcome section with correct content', async () => { - await homePageUtil.verifyWelcomeSection(); + await expect(homePage.welcomeSection).toBeVisible(); + await expect(homePage.welcomeTitle).toBeVisible(); + const headingText = await homePage.getWelcomeHeadingText(); + expect(headingText.trim()).toBe('Welcome to Zeppelin!'); + await expect(homePage.welcomeDescription).toBeVisible(); + const welcomeText = await homePage.welcomeDescription.textContent(); + expect(welcomeText).toContain('web-based notebook'); + expect(welcomeText).toContain('interactive data analytics'); }); }); - test('should have proper welcome message structure', async ({ page }) => { - const homePage = new HomePage(page); - + test('should have proper welcome message structure', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -54,7 +58,7 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then I should see the welcome heading', async () => { - await expect(homePage.welcomeHeading).toBeVisible(); + await expect(homePage.welcomeTitle).toBeVisible(); const headingText = await homePage.getWelcomeHeadingText(); expect(headingText.trim()).toBe('Welcome to Zeppelin!'); }); @@ -70,10 +74,7 @@ test.describe('Home Page - Core Elements', () => { test.describe('Notebook Section', () => { test('should display notebook section with all components', async ({ page }) => { - const homePageUtil = new HomePageUtil(page); - await test.step('Given I am on the home page', async () => { - const homePage = new HomePage(page); await homePage.navigateToHome(); }); @@ -82,14 +83,15 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then I should see all notebook section components', async () => { - await homePageUtil.verifyNotebookSection(); + await expect(homePage.notebookSection).toBeVisible(); + await expect(homePage.notebookHeading).toBeVisible(); + await expect(homePage.refreshNoteButton).toBeVisible(); + await page.waitForSelector('zeppelin-node-list', { timeout: 10000 }); + await expect(homePage.zeppelinNodeList).toBeVisible(); }); }); - test('should have functional refresh notes button', async ({ page }) => { - const homePage = new HomePage(page); - const homePageUtil = new HomePageUtil(page); - + test('should have functional refresh notes button', async () => { await test.step('Given I am on the home page with notebook section visible', async () => { await homePage.navigateToHome(); await expect(homePage.refreshNoteButton).toBeVisible(); @@ -100,13 +102,14 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then the notebook list should still be visible', async () => { - await homePageUtil.verifyNotebookRefreshFunctionality(); + await homePage.waitForRefreshToComplete(); + await expect(homePage.zeppelinNodeList).toBeVisible(); + const isStillVisible = await homePage.zeppelinNodeList.isVisible(); + expect(isStillVisible).toBe(true); }); }); test('should display notebook list component', async ({ page }) => { - const homePage = new HomePage(page); - await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -116,7 +119,7 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then I should see the notebook list component', async () => { - await expect(homePage.notebookList).toBeVisible(); + await expect(homePage.zeppelinNodeList).toBeVisible(); const isVisible = await homePage.isNotebookListVisible(); expect(isVisible).toBe(true); }); @@ -125,10 +128,7 @@ test.describe('Home Page - Core Elements', () => { test.describe('Help Section', () => { test('should display help section with documentation link', async ({ page }) => { - const homePageUtil = new HomePageUtil(page); - await test.step('Given I am on the home page', async () => { - const homePage = new HomePage(page); await homePage.navigateToHome(); }); @@ -137,11 +137,11 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then I should see the help section', async () => { - await homePageUtil.verifyHelpSection(); + await expect(homePage.helpSection).toBeVisible(); + await expect(homePage.helpHeading).toBeVisible(); }); await test.step('And I should see the documentation link', async () => { - const homePage = new HomePage(page); await expect(homePage.externalLinks.documentation).toBeVisible(); }); }); @@ -149,10 +149,7 @@ test.describe('Home Page - Core Elements', () => { test.describe('Community Section', () => { test('should display community section with all links', async ({ page }) => { - const homePageUtil = new HomePageUtil(page); - await test.step('Given I am on the home page', async () => { - const homePage = new HomePage(page); await homePage.navigateToHome(); }); @@ -161,11 +158,15 @@ test.describe('Home Page - Core Elements', () => { }); await test.step('Then I should see the community section', async () => { - await homePageUtil.verifyCommunitySection(); + await expect(homePage.communitySection).toBeVisible(); + await expect(homePage.communityHeading).toBeVisible(); }); await test.step('And I should see all community links', async () => { - await homePageUtil.verifyExternalLinks(); + await expect(homePage.externalLinks.documentation).toBeVisible(); + await expect(homePage.externalLinks.mailingList).toBeVisible(); + await expect(homePage.externalLinks.issuesTracking).toBeVisible(); + await expect(homePage.externalLinks.github).toBeVisible(); }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts index 1025a48e4fd..fb3a56cbc20 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-enhanced-functionality.spec.ts @@ -11,54 +11,82 @@ */ import { expect, test } from '@playwright/test'; -import { HomePageUtil } from '../../models/home-page.util'; +import { HomePage } from '../../models/home-page'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); test.describe('Home Page Enhanced Functionality', () => { - let homeUtil: HomePageUtil; + let homePage: HomePage; test.beforeEach(async ({ page }) => { - homeUtil = new HomePageUtil(page); - await page.goto('/'); + homePage = new HomePage(page); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); }); test.describe('Given documentation links are displayed', () => { test('When documentation link is checked Then should have correct version in URL', async () => { - await homeUtil.verifyDocumentationVersionLink(); + const href = await homePage.getDocumentationLinkHref(); + expect(href).toContain('zeppelin.apache.org/docs'); + expect(href).toMatch(/\/docs\/\d+\.\d+\.\d+(-SNAPSHOT)?\//); }); test('When external links are checked Then should all open in new tab', async () => { - await homeUtil.verifyAllExternalLinksTargetBlank(); + const links = [ + homePage.externalLinks.documentation, + homePage.externalLinks.mailingList, + homePage.externalLinks.issuesTracking, + homePage.externalLinks.github + ]; + + for (const link of links) { + const target = await link.getAttribute('target'); + expect(target).toBe('_blank'); + } }); }); test.describe('Given welcome section display', () => { test('When page loads Then should show welcome content with proper text', async () => { - await homeUtil.verifyWelcomeSection(); + await expect(homePage.welcomeSection).toBeVisible(); + await expect(homePage.welcomeTitle).toBeVisible(); + const headingText = await homePage.getWelcomeHeadingText(); + expect(headingText.trim()).toBe('Welcome to Zeppelin!'); + await expect(homePage.welcomeDescription).toBeVisible(); + const welcomeText = await homePage.welcomeDescription.textContent(); + expect(welcomeText).toContain('web-based notebook'); + expect(welcomeText).toContain('interactive data analytics'); }); - test('When welcome section is displayed Then should contain interactive elements', async () => { - await homeUtil.verifyNotebookSection(); + test('When welcome section is displayed Then should contain interactive elements', async ({ page }) => { + await expect(homePage.notebookSection).toBeVisible(); + await expect(homePage.notebookHeading).toBeVisible(); + await expect(homePage.refreshNoteButton).toBeVisible(); + await page.waitForSelector('zeppelin-node-list', { timeout: 10000 }); + await expect(homePage.zeppelinNodeList).toBeVisible(); }); }); test.describe('Given community section content', () => { test('When community section loads Then should display help and community headings', async () => { - await homeUtil.verifyHelpSection(); - await homeUtil.verifyCommunitySection(); + await expect(homePage.helpSection).toBeVisible(); + await expect(homePage.helpHeading).toBeVisible(); + await expect(homePage.communitySection).toBeVisible(); + await expect(homePage.communityHeading).toBeVisible(); }); test('When external links are displayed Then should show correct targets', async () => { - const linkTargets = await homeUtil.testExternalLinkTargets(); + const docHref = await homePage.externalLinks.documentation.getAttribute('href'); + const mailHref = await homePage.externalLinks.mailingList.getAttribute('href'); + const issuesHref = await homePage.externalLinks.issuesTracking.getAttribute('href'); + const githubHref = await homePage.externalLinks.github.getAttribute('href'); - expect(linkTargets.documentationHref).toContain('zeppelin.apache.org/docs'); - expect(linkTargets.mailingListHref).toContain('community.html'); - expect(linkTargets.issuesTrackingHref).toContain('issues.apache.org'); - expect(linkTargets.githubHref).toContain('github.com/apache/zeppelin'); + expect(docHref).toContain('zeppelin.apache.org/docs'); + expect(mailHref).toContain('community.html'); + expect(issuesHref).toContain('issues.apache.org'); + expect(githubHref).toContain('github.com/apache/zeppelin'); }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts index 34e7e27de0f..ce44eb967bf 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts @@ -12,23 +12,22 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { HomePageUtil } from '../../models/home-page.util'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Home Page - External Links', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); + let homePage: HomePage; + test.beforeEach(async ({ page }) => { + homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); }); test.describe('Documentation Link', () => { - test('should have correct documentation link with dynamic version', async ({ page }) => { - const homePage = new HomePage(page); - const homePageUtil = new HomePageUtil(page); - + test('should have correct documentation link with dynamic version', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -38,9 +37,9 @@ test.describe('Home Page - External Links', () => { }); await test.step('Then it should have the correct href pattern', async () => { - const linkTargets = await homePageUtil.testExternalLinkTargets(); - expect(linkTargets.documentationHref).toContain('zeppelin.apache.org/docs'); - expect(linkTargets.documentationHref).toContain('index.html'); + const href = await homePage.externalLinks.documentation.getAttribute('href'); + expect(href).toContain('zeppelin.apache.org/docs'); + expect(href).toContain('index.html'); }); await test.step('And it should open in a new tab', async () => { @@ -51,10 +50,7 @@ test.describe('Home Page - External Links', () => { }); test.describe('Community Links', () => { - test('should have correct mailing list link', async ({ page }) => { - const homePage = new HomePage(page); - const homePageUtil = new HomePageUtil(page); - + test('should have correct mailing list link', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -64,8 +60,8 @@ test.describe('Home Page - External Links', () => { }); await test.step('Then it should have the correct href', async () => { - const linkTargets = await homePageUtil.testExternalLinkTargets(); - expect(linkTargets.mailingListHref).toBe('http://zeppelin.apache.org/community.html'); + const href = await homePage.externalLinks.mailingList.getAttribute('href'); + expect(href).toBe('http://zeppelin.apache.org/community.html'); }); await test.step('And it should open in a new tab', async () => { @@ -79,10 +75,7 @@ test.describe('Home Page - External Links', () => { }); }); - test('should have correct issues tracking link', async ({ page }) => { - const homePage = new HomePage(page); - const homePageUtil = new HomePageUtil(page); - + test('should have correct issues tracking link', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -92,10 +85,8 @@ test.describe('Home Page - External Links', () => { }); await test.step('Then it should have the correct href', async () => { - const linkTargets = await homePageUtil.testExternalLinkTargets(); - expect(linkTargets.issuesTrackingHref).toBe( - 'https://issues.apache.org/jira/projects/ZEPPELIN/issues/filter=allopenissues' - ); + const href = await homePage.externalLinks.issuesTracking.getAttribute('href'); + expect(href).toBe('https://issues.apache.org/jira/projects/ZEPPELIN/issues/filter=allopenissues'); }); await test.step('And it should open in a new tab', async () => { @@ -109,10 +100,7 @@ test.describe('Home Page - External Links', () => { }); }); - test('should have correct GitHub link', async ({ page }) => { - const homePage = new HomePage(page); - const homePageUtil = new HomePageUtil(page); - + test('should have correct GitHub link', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -122,8 +110,8 @@ test.describe('Home Page - External Links', () => { }); await test.step('Then it should have the correct href', async () => { - const linkTargets = await homePageUtil.testExternalLinkTargets(); - expect(linkTargets.githubHref).toBe('https://github.com/apache/zeppelin'); + const href = await homePage.externalLinks.github.getAttribute('href'); + expect(href).toBe('https://github.com/apache/zeppelin'); }); await test.step('And it should open in a new tab', async () => { @@ -139,9 +127,7 @@ test.describe('Home Page - External Links', () => { }); test.describe('Link Verification', () => { - test('should have all external links with proper attributes', async ({ page }) => { - const homePage = new HomePage(page); - + test('should have all external links with proper attributes', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts index b830f8ab038..e960c3c6cb5 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts @@ -17,7 +17,10 @@ import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinRea test.describe('Home Page - Layout and Grid', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); + let homePage: HomePage; + test.beforeEach(async ({ page }) => { + homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); @@ -26,7 +29,6 @@ test.describe('Home Page - Layout and Grid', () => { test.describe('Responsive Grid Layout', () => { test('should display responsive grid structure', async ({ page }) => { await test.step('Given I am on the home page', async () => { - const homePage = new HomePage(page); await homePage.navigateToHome(); }); @@ -35,9 +37,7 @@ test.describe('Home Page - Layout and Grid', () => { }); }); - test('should have proper column distribution', async ({ page }) => { - const homePage = new HomePage(page); - + test('should have proper column distribution', async () => { await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); @@ -66,15 +66,12 @@ test.describe('Home Page - Layout and Grid', () => { }); test('should maintain layout structure across different viewport sizes', async ({ page }) => { - const homePage = new HomePage(page); - await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); await test.step('When I resize to tablet view', async () => { await page.setViewportSize({ width: 768, height: 1024 }); - await page.waitForTimeout(500); }); await test.step('Then the grid should still be visible and functional', async () => { @@ -85,7 +82,6 @@ test.describe('Home Page - Layout and Grid', () => { await test.step('When I resize to mobile view', async () => { await page.setViewportSize({ width: 375, height: 667 }); - await page.waitForTimeout(500); }); await test.step('Then the grid should adapt to mobile layout', async () => { @@ -104,8 +100,6 @@ test.describe('Home Page - Layout and Grid', () => { test.describe('Content Organization', () => { test('should organize content in logical sections', async ({ page }) => { - const homePage = new HomePage(page); - await test.step('Given I am on the home page', async () => { await homePage.navigateToHome(); }); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts index 23a6888054d..018bfbf40e3 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts @@ -11,16 +11,21 @@ */ import { expect, test } from '@playwright/test'; +import { HomePage } from '../../models/home-page'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); test.describe('Home Page Note Operations', () => { + let homePage: HomePage; + test.beforeEach(async ({ page }) => { - await page.goto('/'); + homePage = new HomePage(page); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); - await page.waitForSelector('zeppelin-node-list', { timeout: 15000 }); + const noteListLocator = page.locator('zeppelin-node-list'); + await expect(noteListLocator).toBeVisible({ timeout: 15000 }); }); test.describe('Given note operations are available', () => { @@ -31,9 +36,9 @@ test.describe('Home Page Note Operations', () => { const firstNote = page.locator('.node .file').first(); await firstNote.hover(); - await expect(page.locator('.file .operation a[nztooltiptitle*="Rename note"]').first()).toBeVisible(); - await expect(page.locator('.file .operation a[nztooltiptitle*="Clear output"]').first()).toBeVisible(); - await expect(page.locator('.file .operation a[nztooltiptitle*="Move note to Trash"]').first()).toBeVisible(); + await expect(homePage.nodeList.noteActions.renameNote.first()).toBeVisible(); + await expect(homePage.nodeList.noteActions.clearOutput.first()).toBeVisible(); + await expect(homePage.nodeList.noteActions.moveToTrash.first()).toBeVisible(); } else { console.log('No notes available for testing operations'); } @@ -50,22 +55,18 @@ test.describe('Home Page Note Operations', () => { const firstNote = page.locator('.node .file').first(); await firstNote.hover(); - const renameIcon = page.locator('.file .operation a[nztooltiptitle*="Rename note"]').first(); - const clearIcon = page.locator('.file .operation a[nztooltiptitle*="Clear output"]').first(); - const deleteIcon = page.locator('.file .operation a[nztooltiptitle*="Move note to Trash"]').first(); - - await expect(renameIcon).toBeVisible(); - await expect(clearIcon).toBeVisible(); - await expect(deleteIcon).toBeVisible(); + await expect(homePage.nodeList.noteActions.renameNote).toBeVisible(); + await expect(homePage.nodeList.noteActions.clearOutput).toBeVisible(); + await expect(homePage.nodeList.noteActions.moveToTrash).toBeVisible(); // Test tooltip visibility by hovering over each icon - await renameIcon.hover(); + await homePage.nodeList.noteActions.renameNote.hover(); await expect(page.locator('.ant-tooltip', { hasText: 'Rename note' })).toBeVisible(); - await clearIcon.hover(); + await homePage.nodeList.noteActions.clearOutput.hover(); await expect(page.locator('.ant-tooltip', { hasText: 'Clear output' })).toBeVisible(); - await deleteIcon.hover(); + await homePage.nodeList.noteActions.moveToTrash.hover(); await expect(page.locator('.ant-tooltip', { hasText: 'Move note to Trash' })).toBeVisible(); } }); @@ -83,7 +84,7 @@ test.describe('Home Page Note Operations', () => { const noteItem = page.locator('.node .file').first(); await noteItem.hover(); - const renameButton = page.locator('.file .operation a[nztooltiptitle*="Rename note"]').first(); + const renameButton = homePage.nodeList.noteActions.renameNote.first(); await expect(renameButton).toBeVisible(); await renameButton.click(); @@ -114,7 +115,7 @@ test.describe('Home Page Note Operations', () => { const noteItem = page.locator('.node .file').first(); await noteItem.hover(); - const clearButton = page.locator('.file .operation a[nztooltiptitle*="Clear output"]').first(); + const clearButton = homePage.nodeList.noteActions.clearOutput.first(); await expect(clearButton).toBeVisible(); await clearButton.click(); @@ -133,7 +134,7 @@ test.describe('Home Page Note Operations', () => { const noteItem = page.locator('.node .file').first(); await noteItem.hover(); - const clearButton = page.locator('.file .operation a[nztooltiptitle*="Clear output"]').first(); + const clearButton = homePage.nodeList.noteActions.clearOutput.first(); await expect(clearButton).toBeVisible(); await clearButton.click(); @@ -157,7 +158,7 @@ test.describe('Home Page Note Operations', () => { const noteItem = page.locator('.node .file').first(); await noteItem.hover(); - const deleteButton = page.locator('.file .operation a[nztooltiptitle*="Move note to Trash"]').first(); + const deleteButton = homePage.nodeList.noteActions.moveToTrash.first(); await expect(deleteButton).toBeVisible(); await deleteButton.click(); @@ -176,7 +177,7 @@ test.describe('Home Page Note Operations', () => { const noteItem = page.locator('.node .file').first(); await noteItem.hover(); - const deleteButton = page.locator('.file .operation a[nztooltiptitle*="Move note to Trash"]').first(); + const deleteButton = homePage.nodeList.noteActions.moveToTrash.first(); await expect(deleteButton).toBeVisible(); await deleteButton.click(); @@ -184,8 +185,6 @@ test.describe('Home Page Note Operations', () => { if (await confirmButton.isVisible()) { await confirmButton.click(); - await page.waitForTimeout(2000); - const trashFolder = page.locator('.node .folder').filter({ hasText: 'Trash' }); await expect(trashFolder).toBeVisible(); } diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts index c323573b289..3cb9725dcb4 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts @@ -10,59 +10,80 @@ * limitations under the License. */ -import { test } from '@playwright/test'; -import { HomePageUtil } from '../../models/home-page.util'; +import { expect, test } from '@playwright/test'; +import { HomePage } from '../../models/home-page'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); test.describe('Home Page Notebook Actions', () => { - let homeUtil: HomePageUtil; + let homePage: HomePage; test.beforeEach(async ({ page }) => { - homeUtil = new HomePageUtil(page); - await page.goto('/'); + homePage = new HomePage(page); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); }); test.describe('Given notebook list is displayed', () => { test('When page loads Then should show notebook actions', async () => { - await homeUtil.verifyNotebookActions(); + await expect(homePage.nodeList.createNewNoteLink).toBeVisible(); + await expect(homePage.nodeList.importNoteLink).toBeVisible(); + await expect(homePage.nodeList.filterInput).toBeVisible(); + await expect(homePage.nodeList.tree).toBeVisible(); }); - test('When refresh button is clicked Then should trigger reload with loading state', async () => { - await homeUtil.testNotebookRefreshLoadingState(); + test('When refresh button is clicked Then should trigger reload with loading state', async ({ page }) => { + const refreshButton = page.locator('a.refresh-note'); + const refreshIcon = page.locator('a.refresh-note i[nz-icon]'); + + await expect(refreshButton).toBeVisible(); + await expect(refreshIcon).toBeVisible(); + + await homePage.clickRefreshNotes(); + + await page.waitForTimeout(500); + + await expect(refreshIcon).toBeVisible(); }); - test('When filter is used Then should filter notebook list', async () => { - await homeUtil.testFilterFunctionality('test'); + test('When filter is used Then should filter notebook list', async ({ page }) => { + // Note (ZEPPELIN-6386): + // The Notebook search filter in the New UI is currently too slow, + // so this test is temporarily skipped. The skip will be removed + // once the performance issue is resolved. + test.skip(); + await homePage.filterNotes('test'); + await page.waitForLoadState('networkidle', { timeout: 15000 }); + const filteredResults = await page.locator('nz-tree .node').count(); + expect(filteredResults).toBeGreaterThanOrEqual(0); }); }); test.describe('Given create new note action', () => { - test('When create new note is clicked Then should open note creation modal', async () => { - try { - await homeUtil.verifyCreateNewNoteWorkflow(); - } catch (error) { - console.log('Note creation modal might not appear immediately'); - } + test('When create new note is clicked Then should open note creation modal', async ({ page }) => { + await homePage.clickCreateNewNote(); + await page.waitForSelector('zeppelin-note-create', { timeout: 10000 }); + await expect(page.locator('zeppelin-note-create')).toBeVisible(); }); }); test.describe('Given import note action', () => { - test('When import note is clicked Then should open import modal', async () => { - try { - await homeUtil.verifyImportNoteWorkflow(); - } catch (error) { - console.log('Import modal might not appear immediately'); - } + test('When import note is clicked Then should open import modal', async ({ page }) => { + await homePage.clickImportNote(); + await page.waitForSelector('zeppelin-note-import', { timeout: 10000 }); + await expect(page.locator('zeppelin-note-import')).toBeVisible(); }); }); test.describe('Given notebook refresh functionality', () => { test('When refresh is triggered Then should maintain notebook list visibility', async () => { - await homeUtil.verifyNotebookRefreshFunctionality(); + await homePage.clickRefreshNotes(); + await homePage.waitForRefreshToComplete(); + await expect(homePage.zeppelinNodeList).toBeVisible(); + const isStillVisible = await homePage.zeppelinNodeList.isVisible(); + expect(isStillVisible).toBe(true); }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts index b3388cd0875..2c35369bd0c 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts @@ -13,7 +13,14 @@ import { expect, test } from '@playwright/test'; import { PublishedParagraphPage } from 'e2e/models/published-paragraph-page'; import { PublishedParagraphTestUtil } from '../../../models/published-paragraph-page.util'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { + addPageAnnotationBeforeEach, + performLoginIfRequired, + waitForNotebookLinks, + waitForZeppelinReady, + PAGES, + createTestNotebook +} from '../../../utils'; test.describe('Published Paragraph', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.PUBLISHED_PARAGRAPH); @@ -24,24 +31,18 @@ test.describe('Published Paragraph', () => { test.beforeEach(async ({ page }) => { publishedParagraphPage = new PublishedParagraphPage(page); - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); + await waitForNotebookLinks(page); - // Handle the welcome modal if it appears - const cancelButton = page.locator('.ant-modal-root button', { hasText: 'Cancel' }); - if ((await cancelButton.count()) > 0) { - await cancelButton.click(); + if ((await publishedParagraphPage.cancelButton.count()) > 0) { + await publishedParagraphPage.cancelButton.click(); + await publishedParagraphPage.cancelButton.waitFor({ state: 'detached', timeout: 5000 }); } testUtil = new PublishedParagraphTestUtil(page); - testNotebook = await testUtil.createTestNotebook(); - }); - - test.afterEach(async () => { - if (testNotebook?.noteId) { - await testUtil.deleteTestNotebook(testNotebook.noteId); - } + testNotebook = await createTestNotebook(page); }); test.describe('Error Handling', () => { @@ -50,22 +51,33 @@ test.describe('Published Paragraph', () => { await publishedParagraphPage.navigateToPublishedParagraph(nonExistentIds.noteId, nonExistentIds.paragraphId); + // Directly assert that the modal appears and contains the expected text const modal = page.locator('.ant-modal:has-text("Notebook not found")').last(); - const isModalVisible = await modal.isVisible({ timeout: 10000 }); + await expect(modal).toBeVisible({ timeout: 10000 }); // Expect the modal to be visible - if (isModalVisible) { - const modalContent = await modal.textContent(); - expect(modalContent?.toLowerCase()).toContain('not found'); - } else { - await expect(page).toHaveURL(/\/#\/$/, { timeout: 5000 }); - } + const modalContent = await modal.textContent(); + expect(modalContent?.toLowerCase()).toContain('not found'); }); - test('should show error modal when paragraph does not exist in valid notebook', async () => { + test('should show error modal when paragraph does not exist in valid notebook', async ({ page }) => { const validNoteId = testNotebook.noteId; const nonExistentParagraphId = testUtil.generateNonExistentIds().paragraphId; - await testUtil.verifyNonExistentParagraphError(validNoteId, nonExistentParagraphId); + await testUtil.navigateToPublishedParagraph(validNoteId, nonExistentParagraphId); + + // Expect a specific error modal + const errorModal = page.locator('.ant-modal', { hasText: /Paragraph Not Found|not found|Error/i }); + await expect(errorModal).toBeVisible({ timeout: 10000 }); + + // Verify modal content includes the invalid paragraph ID + const content = await testUtil.getErrorModalContent(); + expect(content).toBeDefined(); + expect(content).toContain(nonExistentParagraphId); + + await testUtil.clickErrorModalOk(); + + // Wait for redirect to home page + await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 }); }); test('should redirect to home page after error modal dismissal', async ({ page }) => { @@ -77,8 +89,7 @@ test.describe('Published Paragraph', () => { const isModalVisible = await modal.isVisible(); if (isModalVisible) { - const okButton = page.locator('button:has-text("OK"), button:has-text("확인"), [role="button"]:has-text("OK")'); - await okButton.click(); + await publishedParagraphPage.okButton.click(); await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 }); } else { @@ -87,55 +98,193 @@ test.describe('Published Paragraph', () => { }); }); - test.describe('Valid Paragraph Display', () => { - test('should enter published paragraph by clicking', async () => { - await testUtil.verifyClickLinkThisParagraphBehavior(testNotebook.noteId, testNotebook.paragraphId); + test.describe('Navigation and URL Patterns', () => { + test('should enter published paragraph by clicking link', async ({ page }) => { + const { noteId, paragraphId } = testNotebook; + + // Navigate to the normal notebook view + await page.goto(`/#/notebook/${noteId}`); + await page.waitForLoadState('networkidle'); + + // Find the first paragraph + let paragraphElement = page.locator(`zeppelin-notebook-paragraph[data-testid="${paragraphId}"]`); + if ((await paragraphElement.count()) === 0) { + paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); + } + + await expect(paragraphElement).toBeVisible({ timeout: 10000 }); + + // Click the settings button to open the dropdown + const settingsButton = paragraphElement.locator('a[nz-dropdown]'); + await settingsButton.click(); + + // Click "Link this paragraph" in the dropdown menu + const linkParagraphButton = page.locator('li.list-item:has-text("Link this paragraph")'); + await expect(linkParagraphButton).toBeVisible(); + + // Handle the new page/tab that opens + const [newPage] = await Promise.all([page.waitForEvent('popup'), linkParagraphButton.click()]); + await newPage.waitForLoadState(); + + // Verify the new page URL shows published paragraph + await expect(newPage).toHaveURL(new RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 10000 }); + + const codeEditor = newPage.locator('zeppelin-notebook-paragraph-code-editor'); + await expect(codeEditor).toBeHidden(); + + const controlPanel = newPage.locator('zeppelin-notebook-paragraph-control'); + await expect(controlPanel).toBeHidden(); }); - test('should enter published paragraph by URL', async ({ page }) => { + test('should enter published paragraph by direct URL navigation', async ({ page }) => { await page.goto(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`); await page.waitForLoadState('networkidle'); await expect(page).toHaveURL(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`, { timeout: 10000 }); }); + + test('should allow running paragraph via confirmation modal in published mode', async ({ page }) => { + const { noteId, paragraphId } = testNotebook; + + // Given: Navigate to a specific paragraph's published URL + await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`); + await page.waitForLoadState('networkidle'); + + // Then: URL should correctly preserve both notebook and paragraph identifiers + await expect(page).toHaveURL(new RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 15000 }); + + // Verify URL contains the specific notebook and paragraph context + expect(page.url()).toContain(noteId); + expect(page.url()).toContain(paragraphId); + + // Then: Published paragraph component should be loaded (indicating published mode is active) + const publishedContainer = page.locator('zeppelin-publish-paragraph'); + await publishedContainer.waitFor({ state: 'attached', timeout: 10000 }); + + // Then: Confirmation modal should appear for paragraph execution + const modal = page.locator('.ant-modal'); + await expect(modal).toBeVisible({ timeout: 20000 }); + + // Handle the execution confirmation to complete the published mode setup + await expect(publishedParagraphPage.runButton).toBeVisible(); + await publishedParagraphPage.runButton.click(); + await expect(modal).not.toBeVisible({ timeout: 10000 }); + + // Then: Published container should remain attached and page should be in published mode + await expect(publishedContainer).toBeAttached({ timeout: 10000 }); + + // Verify we're in published mode by checking for the published component + const isPublishedMode = await page.evaluate(() => document.querySelector('zeppelin-publish-paragraph') !== null); + expect(isPublishedMode).toBe(true); + + const paragraphContainer = page.locator('zeppelin-publish-paragraph'); + + // Published component should be present + await expect(paragraphContainer).toBeAttached(); + }); }); - test('should show confirmation modal and allow running the paragraph', async ({ page }) => { - const { noteId, paragraphId } = testNotebook; + test.describe('Published Mode Functionality', () => { + test('should hide editing controls in published mode', async ({ page }) => { + const { noteId, paragraphId } = testNotebook; + + await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`); + await page.waitForLoadState('networkidle'); + + // In published mode, code editor and control panel should be hidden + const codeEditor = page.locator('zeppelin-notebook-paragraph-code-editor'); + const controlPanel = page.locator('zeppelin-notebook-paragraph-control'); + + await expect(codeEditor).toBeHidden(); + await expect(controlPanel).toBeHidden(); + }); + }); + + test.describe('Confirmation Modal and Execution', () => { + test('should show confirmation modal and allow running the paragraph', async ({ page }) => { + const { noteId, paragraphId } = testNotebook; + + await publishedParagraphPage.navigateToNotebook(noteId); - await publishedParagraphPage.navigateToNotebook(noteId); + const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); + const paragraphResult = paragraphElement.locator('zeppelin-notebook-paragraph-result'); - const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); - const paragraphResult = paragraphElement.locator('zeppelin-notebook-paragraph-result'); + // Only clear output if result exists + if (await paragraphResult.isVisible()) { + const settingsButton = paragraphElement.locator('a[nz-dropdown]'); + await settingsButton.click(); - // Only clear output if result exists - if (await paragraphResult.isVisible()) { + const clearOutputButton = page.locator('li.list-item:has-text("Clear output")'); + await clearOutputButton.click(); + await expect(paragraphResult).toBeHidden(); + } + + await publishedParagraphPage.navigateToPublishedParagraph(noteId, paragraphId); + + await expect(page).toHaveURL(new RegExp(`/paragraph/${paragraphId}`)); + + const modal = publishedParagraphPage.confirmationModal; + await expect(modal).toBeVisible(); + + // Check for the enhanced modal content + await expect(publishedParagraphPage.modalTitle).toHaveText('Run Paragraph?'); + + // Verify that the modal shows code preview + await expect(publishedParagraphPage.modalBody.locator('.ant-modal-confirm-content')).toContainText( + 'This paragraph contains the following code:' + ); + await expect(publishedParagraphPage.modalBody.locator('.ant-modal-confirm-content')).toContainText( + 'Would you like to execute this code?' + ); + + // Click the Run button in the modal (OK button in confirmation modal) + const runButton = modal.locator('.ant-modal-confirm-btns .ant-btn-primary'); + await expect(runButton).toBeVisible(); + await runButton.click(); + await expect(modal).toBeHidden(); + }); + + test('should show confirmation modal for paragraphs without results', async ({ page }) => { + const { noteId, paragraphId } = testNotebook; + + await publishedParagraphPage.navigateToNotebook(noteId); + + const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); const settingsButton = paragraphElement.locator('a[nz-dropdown]'); await settingsButton.click(); const clearOutputButton = page.locator('li.list-item:has-text("Clear output")'); await clearOutputButton.click(); - await expect(paragraphResult).toBeHidden(); - } + await expect(paragraphElement.locator('[data-testid="paragraph-result"]')).toBeHidden(); - await publishedParagraphPage.navigateToPublishedParagraph(noteId, paragraphId); + await publishedParagraphPage.navigateToPublishedParagraph(noteId, paragraphId); - const modal = publishedParagraphPage.confirmationModal; - await expect(modal).toBeVisible(); + const modal = publishedParagraphPage.confirmationModal; + await expect(modal).toBeVisible(); - // Check for the new enhanced modal content - await expect(publishedParagraphPage.modalTitle).toHaveText('Run Paragraph?'); + // Check for the enhanced modal content + await expect(publishedParagraphPage.modalTitle).toContainText('Run Paragraph?'); - // Verify that the modal shows code preview - const modalContent = publishedParagraphPage.confirmationModal.locator('.ant-modal-confirm-content'); - await expect(modalContent).toContainText('This paragraph contains the following code:'); - await expect(modalContent).toContainText('Would you like to execute this code?'); + // Check that code preview is shown + await expect(publishedParagraphPage.modalBody.first()).toContainText( + 'This paragraph contains the following code:' + ); + await expect(publishedParagraphPage.modalBody.first()).toContainText('Would you like to execute this code?'); - // Click the Run button in the modal (OK button in confirmation modal) - const runButton = modal.locator('.ant-modal-confirm-btns .ant-btn-primary'); - await expect(runButton).toBeVisible(); - await runButton.click(); - await expect(modal).toBeHidden(); + // Verify that the code preview area exists + const codePreview = publishedParagraphPage.modalBody + .locator('pre, code, .code-preview, .highlight, [class*="code"]') + .first(); + await expect(codePreview).toBeVisible(); + + // Check for Run and Cancel buttons + await expect(publishedParagraphPage.runButton).toBeVisible(); + await expect(publishedParagraphPage.cancelButton).toBeVisible(); + + // Click the Run button in the modal + await publishedParagraphPage.runButton.click(); + await expect(modal).toBeHidden(); + }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts index 20991806327..76e9f77e614 100644 --- a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts +++ b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts @@ -11,79 +11,65 @@ */ import { expect, test } from '@playwright/test'; -import { ThemePage } from '../../models/theme.page'; +import { DarkModePage } from '../../models/dark-mode-page'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Dark Mode Theme Switching', () => { addPageAnnotationBeforeEach(PAGES.SHARE.THEME_TOGGLE); - let themePage: ThemePage; + let darkModePage: DarkModePage; test.beforeEach(async ({ page }) => { - themePage = new ThemePage(page); - await page.goto('/'); + darkModePage = new DarkModePage(page); + await page.goto('/#/'); await waitForZeppelinReady(page); // Handle authentication if shiro.ini exists await performLoginIfRequired(page); // Ensure a clean localStorage for each test - await themePage.clearLocalStorage(); + await darkModePage.clearLocalStorage(); }); - test('Scenario: User can switch to dark mode and persistence is maintained', async ({ page, context }) => { - let currentPage = page; - + test('Scenario: User can switch to dark mode and persistence is maintained', async ({ page }) => { // GIVEN: User is on the main page, which starts in 'system' mode by default (localStorage cleared). await test.step('GIVEN the page starts in system mode', async () => { - await themePage.assertSystemTheme(); // Robot icon for system theme + await darkModePage.assertSystemTheme(); // Robot icon for system theme }); // WHEN: Explicitly set theme to light mode for the rest of the test. await test.step('WHEN the user explicitly sets theme to light mode', async () => { - await themePage.setThemeInLocalStorage('light'); + await darkModePage.setThemeInLocalStorage('light'); + await page.waitForTimeout(500); + // Reload the page to apply localStorage theme changes await page.reload(); await waitForZeppelinReady(page); - await themePage.assertLightTheme(); // Now it should be light mode with sun icon + await darkModePage.assertLightTheme(); // Now it should be light mode with sun icon }); // WHEN: User switches to dark mode by setting localStorage and reloading. - await test.step('WHEN the user switches to dark mode', async () => { - await themePage.setThemeInLocalStorage('dark'); - const newPage = await context.newPage(); - await newPage.goto(currentPage.url()); - await waitForZeppelinReady(newPage); - - // Update themePage to use newPage and verify dark mode - themePage = new ThemePage(newPage); - currentPage = newPage; - await themePage.assertDarkTheme(); - }); - - // AND: User refreshes the page. - await test.step('AND the user refreshes the page', async () => { - await currentPage.reload(); - await waitForZeppelinReady(currentPage); - }); - - // THEN: Dark mode is maintained after refresh. - await test.step('THEN dark mode is maintained after refresh', async () => { - await themePage.assertDarkTheme(); + await test.step('WHEN the user explicitly sets theme to dark mode', async () => { + await darkModePage.setThemeInLocalStorage('dark'); + await page.waitForTimeout(500); + // Reload the page to apply localStorage theme changes + await page.reload(); + await waitForZeppelinReady(page); + await darkModePage.assertDarkTheme(); }); // AND: User clicks the toggle again to switch back to light mode. await test.step('AND the user clicks the toggle to switch back to light mode', async () => { - await themePage.toggleTheme(); + await darkModePage.toggleTheme(); }); // THEN: The theme switches to system mode. await test.step('THEN the theme switches to system mode', async () => { - await themePage.assertSystemTheme(); + await darkModePage.assertSystemTheme(); }); }); test('Scenario: System Theme and Local Storage Interaction', async ({ page }) => { // Ensure localStorage is clear for each sub-scenario - await themePage.clearLocalStorage(); + await darkModePage.clearLocalStorage(); await test.step('GIVEN: No localStorage, System preference is Light', async () => { await page.emulateMedia({ colorScheme: 'light' }); @@ -91,44 +77,44 @@ test.describe('Dark Mode Theme Switching', () => { await waitForZeppelinReady(page); // When no explicit theme is set, it defaults to 'system' mode // Even in system mode with light preference, the icon should be robot - await expect(themePage.rootElement).toHaveClass(/light/); - await expect(themePage.rootElement).toHaveAttribute('data-theme', 'light'); - await themePage.assertSystemTheme(); // Should show robot icon + await expect(darkModePage.rootElement).toHaveClass(/light/); + await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'light'); + await darkModePage.assertSystemTheme(); // Should show robot icon }); await test.step('GIVEN: No localStorage, System preference is Dark (initial system state)', async () => { - await themePage.setThemeInLocalStorage('system'); + await darkModePage.setThemeInLocalStorage('system'); await page.goto('/'); await waitForZeppelinReady(page); - await themePage.assertSystemTheme(); // Robot icon for system theme + await darkModePage.assertSystemTheme(); // Robot icon for system theme }); await test.step("GIVEN: localStorage is 'dark', System preference is Light", async () => { - await themePage.setThemeInLocalStorage('dark'); + await darkModePage.setThemeInLocalStorage('dark'); await page.emulateMedia({ colorScheme: 'light' }); await page.goto('/'); await waitForZeppelinReady(page); - await themePage.assertDarkTheme(); // localStorage should override system + await darkModePage.assertDarkTheme(); // localStorage should override system }); await test.step("GIVEN: localStorage is 'system', THEN: Emulate system preference change to Light", async () => { - await themePage.setThemeInLocalStorage('system'); + await darkModePage.setThemeInLocalStorage('system'); await page.emulateMedia({ colorScheme: 'light' }); await page.goto('/'); await waitForZeppelinReady(page); - await expect(themePage.rootElement).toHaveClass(/light/); - await expect(themePage.rootElement).toHaveAttribute('data-theme', 'light'); - await themePage.assertSystemTheme(); // Robot icon for system theme + await expect(darkModePage.rootElement).toHaveClass(/light/); + await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'light'); + await darkModePage.assertSystemTheme(); // Robot icon for system theme }); await test.step("GIVEN: localStorage is 'system', THEN: Emulate system preference change to Dark", async () => { - await themePage.setThemeInLocalStorage('system'); + await darkModePage.setThemeInLocalStorage('system'); await page.emulateMedia({ colorScheme: 'dark' }); await page.goto('/'); await waitForZeppelinReady(page); - await expect(themePage.rootElement).toHaveClass(/dark/); - await expect(themePage.rootElement).toHaveAttribute('data-theme', 'dark'); - await themePage.assertSystemTheme(); // Robot icon for system theme + await expect(darkModePage.rootElement).toHaveClass(/dark/); + await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'dark'); + await darkModePage.assertSystemTheme(); // Robot icon for system theme }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts index 342c67e7a8d..6e887b1924e 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts @@ -22,7 +22,7 @@ test.describe('Notebook Repository Item - Display Mode', () => { let firstRepoName: string; test.beforeEach(async ({ page }) => { - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts index 13c870df387..1ee350c21dc 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; -import { NotebookRepoItemUtil } from '../../../models/notebook-repos-page.util'; +import { NotebookRepoItemUtil } from '../../../models/notebook-repo-item.util'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Edit Mode', () => { @@ -24,7 +24,7 @@ test.describe('Notebook Repository Item - Edit Mode', () => { let firstRepoName: string; test.beforeEach(async ({ page }) => { - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); @@ -66,22 +66,13 @@ test.describe('Notebook Repository Item - Edit Mode', () => { }); test('should reset form when cancel is clicked', async () => { - const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } - const firstRow = repoItemPage.settingRows.first(); const settingName = (await firstRow.locator('td').first().textContent()) || ''; const originalValue = await repoItemPage.getSettingValue(settingName); await repoItemPage.clickEdit(); - const isInputVisible = await repoItemPage.isInputVisible(settingName); - if (isInputVisible) { - await repoItemPage.fillSettingInput(settingName, 'temp-value'); - } + await repoItemPage.fillSettingInput(settingName, 'temp-value'); await repoItemPage.clickCancel(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts index 51f5d232c10..aedf7e16751 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts @@ -22,7 +22,7 @@ test.describe('Notebook Repository Item - Form Validation', () => { let firstRepoName: string; test.beforeEach(async ({ page }) => { - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); @@ -34,58 +34,32 @@ test.describe('Notebook Repository Item - Form Validation', () => { }); test('should disable save button when form is invalid', async () => { - const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } - await repoItemPage.clickEdit(); const firstRow = repoItemPage.settingRows.first(); const settingName = (await firstRow.locator('td').first().textContent()) || ''; - const isInputVisible = await repoItemPage.isInputVisible(settingName); - if (isInputVisible) { - await repoItemPage.fillSettingInput(settingName, ''); + await repoItemPage.fillSettingInput(settingName, ''); - const isSaveEnabled = await repoItemPage.isSaveButtonEnabled(); - expect(isSaveEnabled).toBe(false); - } else { - test.skip(); - } + const isSaveEnabled = await repoItemPage.isSaveButtonEnabled(); + expect(isSaveEnabled).toBe(false); }); test('should enable save button when form is valid', async () => { - const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } - await repoItemPage.clickEdit(); const firstRow = repoItemPage.settingRows.first(); const settingName = (await firstRow.locator('td').first().textContent()) || ''; - const isInputVisible = await repoItemPage.isInputVisible(settingName); - if (isInputVisible) { - const originalValue = await repoItemPage.getSettingInputValue(settingName); - await repoItemPage.fillSettingInput(settingName, originalValue || 'valid-value'); + const originalValue = await repoItemPage.getSettingInputValue(settingName); + await repoItemPage.fillSettingInput(settingName, originalValue || 'valid-value'); - const isSaveEnabled = await repoItemPage.isSaveButtonEnabled(); - expect(isSaveEnabled).toBe(true); - } else { - test.skip(); - } + const isSaveEnabled = await repoItemPage.isSaveButtonEnabled(); + expect(isSaveEnabled).toBe(true); }); test('should validate required fields on form controls', async () => { const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } await repoItemPage.clickEdit(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts index e25fbfd9111..68cc608bb3c 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts @@ -22,7 +22,7 @@ test.describe('Notebook Repository Item - Settings', () => { let firstRepoName: string; test.beforeEach(async ({ page }) => { - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); @@ -48,10 +48,6 @@ test.describe('Notebook Repository Item - Settings', () => { test('should show input controls for INPUT type settings in edit mode', async () => { const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } await repoItemPage.clickEdit(); @@ -70,10 +66,6 @@ test.describe('Notebook Repository Item - Settings', () => { test('should show dropdown controls for DROPDOWN type settings in edit mode', async () => { const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } await repoItemPage.clickEdit(); @@ -91,14 +83,9 @@ test.describe('Notebook Repository Item - Settings', () => { test('should update input value in edit mode', async () => { const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } await repoItemPage.clickEdit(); - let foundInput = false; for (let i = 0; i < settingRows; i++) { const row = repoItemPage.settingRows.nth(i); const settingName = (await row.locator('td').first().textContent()) || ''; @@ -109,23 +96,12 @@ test.describe('Notebook Repository Item - Settings', () => { await repoItemPage.fillSettingInput(settingName, testValue); const inputValue = await repoItemPage.getSettingInputValue(settingName); expect(inputValue).toBe(testValue); - foundInput = true; break; } } - - if (!foundInput) { - test.skip(); - } }); test('should display setting name and value in display mode', async () => { - const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } - const firstRow = repoItemPage.settingRows.first(); const nameCell = firstRow.locator('td').first(); const valueCell = firstRow.locator('td').nth(1); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts index a765eb82dd1..52f3e429096 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; -import { NotebookRepoItemUtil } from '../../../models/notebook-repos-page.util'; +import { NotebookRepoItemUtil } from '../../../models/notebook-repo-item.util'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Edit Workflow', () => { @@ -24,7 +24,7 @@ test.describe('Notebook Repository Item - Edit Workflow', () => { let firstRepoName: string; test.beforeEach(async ({ page }) => { - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); @@ -36,19 +36,14 @@ test.describe('Notebook Repository Item - Edit Workflow', () => { repoItemUtil = new NotebookRepoItemUtil(page, firstRepoName); }); - test('should complete full edit workflow with save', async ({ page }) => { + test('should complete full edit workflow with save', async () => { const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } await repoItemUtil.verifyDisplayMode(); await repoItemPage.clickEdit(); await repoItemUtil.verifyEditMode(); - let foundSetting = false; for (let i = 0; i < settingRows; i++) { const row = repoItemPage.settingRows.nth(i); const settingName = (await row.locator('td').first().textContent()) || ''; @@ -57,33 +52,19 @@ test.describe('Notebook Repository Item - Edit Workflow', () => { if (isInputVisible) { const originalValue = await repoItemPage.getSettingInputValue(settingName); await repoItemPage.fillSettingInput(settingName, originalValue || 'test-value'); - foundSetting = true; break; } } - if (!foundSetting) { - test.skip(); - return; - } - const isSaveEnabled = await repoItemPage.isSaveButtonEnabled(); expect(isSaveEnabled).toBe(true); await repoItemPage.clickSave(); - await page.waitForTimeout(1000); - await repoItemUtil.verifyDisplayMode(); }); test('should complete full edit workflow with cancel', async () => { - const settingRows = await repoItemPage.settingRows.count(); - if (settingRows === 0) { - test.skip(); - return; - } - await repoItemUtil.verifyDisplayMode(); const firstRow = repoItemPage.settingRows.first(); @@ -93,13 +74,7 @@ test.describe('Notebook Repository Item - Edit Workflow', () => { await repoItemPage.clickEdit(); await repoItemUtil.verifyEditMode(); - const isInputVisible = await repoItemPage.isInputVisible(settingName); - if (isInputVisible) { - await repoItemPage.fillSettingInput(settingName, 'temp-modified-value'); - } else { - test.skip(); - return; - } + await repoItemPage.fillSettingInput(settingName, 'temp-modified-value'); await repoItemPage.clickCancel(); await repoItemUtil.verifyDisplayMode(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts index 957a7a8a3d6..747037ef47f 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts @@ -12,26 +12,23 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage } from '../../../models/notebook-repos-page'; -import { NotebookReposPageUtil } from '../../../models/notebook-repos-page.util'; import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Page - Structure', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS); let notebookReposPage: NotebookReposPage; - let notebookReposUtil: NotebookReposPageUtil; test.beforeEach(async ({ page }) => { - await page.goto('/'); + await page.goto('/#/'); await waitForZeppelinReady(page); await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); - notebookReposUtil = new NotebookReposPageUtil(page); await notebookReposPage.navigate(); }); test('should display page header with correct title and description', async () => { - await expect(notebookReposPage.pageHeader).toBeVisible(); + await expect(notebookReposPage.zeppelinPageHeader).toBeVisible(); await expect(notebookReposPage.pageDescription).toBeVisible(); }); @@ -42,10 +39,6 @@ test.describe('Notebook Repository Page - Structure', () => { test('should display all repository items', async () => { const count = await notebookReposPage.getRepositoryItemCount(); - if (count === 0) { - test.skip(); - return; - } - await notebookReposUtil.verifyAllRepositoriesRendered(); + expect(count).toBeGreaterThan(0); }); }); diff --git a/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts index c6292cbaecc..a3e42474c02 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts @@ -10,58 +10,57 @@ * limitations under the License. */ -import { test } from '@playwright/test'; -import { WorkspaceTestUtil } from '../../models/workspace-page.util'; -import { addPageAnnotationBeforeEach, PAGES } from '../../utils'; +import { expect, test } from '@playwright/test'; +import { WorkspacePage } from 'e2e/models/workspace-page'; +import { WorkspaceUtil } from '../../models/workspace-page.util'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.MAIN); test.describe('Workspace Main Component', () => { - let workspaceUtil: WorkspaceTestUtil; + let workspaceUtil: WorkspaceUtil; + let workspacePage: WorkspacePage; test.beforeEach(async ({ page }) => { - workspaceUtil = new WorkspaceTestUtil(page); + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + + workspacePage = new WorkspacePage(page); + workspaceUtil = new WorkspaceUtil(page); }); test.describe('Given user accesses workspace container', () => { - test('When workspace loads Then should display main container structure', async () => { - await workspaceUtil.navigateAndWaitForLoad(); + test('When workspace loads Then should display main container structure', async ({ page }) => { + await expect(workspacePage.zeppelinWorkspace).toBeVisible(); + await expect(workspacePage.routerOutlet).toBeAttached(); - await workspaceUtil.verifyWorkspaceLayout(); - await workspaceUtil.verifyWorkspaceContainer(); + await expect(workspacePage.zeppelinWorkspace).toBeVisible(); + const contentElements = await page.locator('.content').count(); + expect(contentElements).toBeGreaterThan(0); }); test('When workspace loads Then should display header component', async () => { - await workspaceUtil.navigateAndWaitForLoad(); - await workspaceUtil.verifyHeaderVisibility(true); }); test('When workspace loads Then should activate router outlet', async () => { - await workspaceUtil.navigateAndWaitForLoad(); - await workspaceUtil.verifyRouterOutletActivation(); }); test('When component activates Then should trigger onActivate event', async () => { - await workspaceUtil.navigateAndWaitForLoad(); - await workspaceUtil.waitForComponentActivation(); }); }); test.describe('Given workspace header visibility', () => { test('When not in publish mode Then should show header', async () => { - await workspaceUtil.navigateAndWaitForLoad(); - await workspaceUtil.verifyHeaderVisibility(true); }); }); test.describe('Given router outlet functionality', () => { test('When navigating to workspace Then should load child components', async () => { - await workspaceUtil.navigateAndWaitForLoad(); - await workspaceUtil.verifyRouterOutletActivation(); await workspaceUtil.waitForComponentActivation(); }); diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index bc57c353526..dab04a13256 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -374,7 +374,7 @@ const navigateViaHomePageFallback = async (page: Page, baseNotebookName: string) }; const extractFirstParagraphId = async (page: Page): Promise => { - await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 'visible', timeout: 10000 }); + await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 'visible', timeout: 20000 }); const paragraphContainer = page.locator('zeppelin-notebook-paragraph').first(); const dropdownTrigger = paragraphContainer.locator('a[nz-dropdown]'); From 776e29c89f4e1d47a89bd09c9a467acb0dce3767 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Thu, 26 Feb 2026 00:19:36 +0900 Subject: [PATCH 002/179] [ZEPPELIN-6398] Fix Selenium-based integration tests ### What is this PR for? Selenium-based integration tests have been failing recently. There were several issues: - The Chrome/Edge driver had a bug related to calling window.maximize(). Since a fixed window size is sufficient for our tests, I replaced it with a method that sets a fixed window size instead. - The element wait logic was not properly separated by intent, which caused unintended test failures. I refactored the wait methods to distinguish between presence, visibility, and clickability. - Browser built-in features such as the password manager could trigger alert dialogs that block test execution, so these have been disabled. Previously, we switched to EdgeDriver (also Chromium-based) to work around the window.maximize() bug, but the same issue occurred. Therefore, I reverted back to ChromeDriver. ### What type of PR is it? Bug Fix ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6398 ### How should this be tested? - Check `test-selenium-with-spark-module-for-spark-3-5` job ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5160 from tbonelee/fix-selenium-edge. Signed-off-by: ChanHo Lee --- .github/workflows/frontend.yml | 18 --------- .../apache/zeppelin/AbstractZeppelinIT.java | 39 ++++++++++--------- .../org/apache/zeppelin/WebDriverManager.java | 10 ++++- .../integration/AuthenticationIT.java | 30 +++++++------- .../integration/InterpreterModeActionsIT.java | 34 ++++++++-------- .../integration/PersonalizeActionsIT.java | 26 ++++++------- .../zeppelin/integration/ZeppelinIT.java | 4 +- 7 files changed, 77 insertions(+), 84 deletions(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 2f99846e696..7eecf57638d 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -149,29 +149,11 @@ jobs: defaults: run: shell: bash -l {0} - env: - ZEPPELIN_SELENIUM_BROWSER: "edge" steps: - name: Checkout uses: actions/checkout@v4 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - - name: Install Microsoft Edge - run: | - curl -fsSL https://packages.microsoft.com/keys/microsoft.asc | sudo gpg --dearmor -o /usr/share/keyrings/microsoft-edge.gpg - echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft-edge.gpg] https://packages.microsoft.com/repos/edge stable main" | sudo tee /etc/apt/sources.list.d/microsoft-edge.list - sudo apt-get update - sudo apt-get install -y microsoft-edge-stable - - name: Install msedgedriver - run: | - EDGE_VERSION=$(microsoft-edge --version | awk '{print $3}') - wget -q "https://msedgedriver.microsoft.com/${EDGE_VERSION}/edgedriver_linux64.zip" -O edgedriver.zip - unzip -q edgedriver.zip - sudo mv msedgedriver /usr/local/bin/ - sudo chmod +x /usr/local/bin/msedgedriver - rm edgedriver.zip - - name: Print Edge version - run: msedgedriver --version - name: Set up JDK 11 uses: actions/setup-java@v4 with: diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java index cfffe5051d4..6d2746eeab9 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/AbstractZeppelinIT.java @@ -18,12 +18,10 @@ package org.apache.zeppelin; -import com.google.common.base.Function; import java.io.File; import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; -import java.time.temporal.ChronoUnit; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; import org.openqa.selenium.By; @@ -38,8 +36,6 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import org.openqa.selenium.support.ui.ExpectedConditions; -import org.openqa.selenium.support.ui.FluentWait; -import org.openqa.selenium.support.ui.Wait; import org.openqa.selenium.support.ui.WebDriverWait; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,15 +51,13 @@ abstract public class AbstractZeppelinIT { protected static final long MAX_PARAGRAPH_TIMEOUT_SEC = 120; protected void authenticationUser(String userName, String password) { - pollingWait( + clickableWait( By.xpath("//div[contains(@class, 'navbar-collapse')]//li//button[contains(.,'Login')]"), MAX_BROWSER_TIMEOUT_SEC).click(); - ZeppelinITUtils.sleep(1000, false); - - pollingWait(By.xpath("//*[@id='userName']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys(userName); - pollingWait(By.xpath("//*[@id='password']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys(password); - pollingWait( + visibilityWait(By.xpath("//*[@id='userName']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys(userName); + visibilityWait(By.xpath("//*[@id='password']"), MAX_BROWSER_TIMEOUT_SEC).sendKeys(password); + clickableWait( By.xpath("//*[@id='loginModalContent']//button[contains(.,'Login')]"), MAX_BROWSER_TIMEOUT_SEC).click(); @@ -132,7 +126,7 @@ protected static String getNoteFormsXPath() { protected boolean waitForParagraph(final int paragraphNo, final String state) { By locator = By.xpath(getParagraphXPath(paragraphNo) + "//div[contains(@class, 'control')]//span[2][contains(.,'" + state + "')]"); - WebElement element = pollingWait(locator, MAX_PARAGRAPH_TIMEOUT_SEC); + WebElement element = visibilityWait(locator, MAX_PARAGRAPH_TIMEOUT_SEC); return element.isDisplayed(); } @@ -145,7 +139,7 @@ protected String getParagraphStatus(final int paragraphNo) { protected boolean waitForText(final String txt, final By locator) { try { - WebElement element = pollingWait(locator, MAX_BROWSER_TIMEOUT_SEC); + WebElement element = visibilityWait(locator, MAX_BROWSER_TIMEOUT_SEC); return txt.equals(element.getText()); } catch (TimeoutException e) { return false; @@ -153,12 +147,21 @@ protected boolean waitForText(final String txt, final By locator) { } protected WebElement pollingWait(final By locator, final long timeWait) { - Wait wait = new FluentWait<>(manager.getWebDriver()) - .withTimeout(Duration.of(timeWait, ChronoUnit.SECONDS)) - .pollingEvery(Duration.of(1, ChronoUnit.SECONDS)) - .ignoring(NoSuchElementException.class); + WebDriverWait wait = new WebDriverWait(manager.getWebDriver(), + Duration.ofSeconds(timeWait)); + return wait.until(ExpectedConditions.presenceOfElementLocated(locator)); + } + + protected WebElement visibilityWait(final By locator, final long timeWait) { + WebDriverWait wait = new WebDriverWait(manager.getWebDriver(), + Duration.ofSeconds(timeWait)); + return wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); + } - return wait.until((Function) driver -> driver.findElement(locator)); + protected WebElement clickableWait(final By locator, final long timeWait) { + WebDriverWait wait = new WebDriverWait(manager.getWebDriver(), + Duration.ofSeconds(timeWait)); + return wait.until(ExpectedConditions.elementToBeClickable(locator)); } protected void createNewNote() { @@ -193,7 +196,7 @@ protected void deleteTrashNotebook(final WebDriver driver) { } protected void clickAndWait(final By locator) { - WebElement element = pollingWait(locator, MAX_IMPLICIT_WAIT); + WebElement element = clickableWait(locator, MAX_IMPLICIT_WAIT); try { element.click(); ZeppelinITUtils.sleep(1000, false); diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java index f2e1c91d808..a6aa0341a2b 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/WebDriverManager.java @@ -30,6 +30,7 @@ import org.apache.commons.lang3.SystemUtils; import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; import org.openqa.selenium.TimeoutException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; @@ -84,6 +85,12 @@ private WebDriver constructWebDriver(int port) { Supplier chromeDriverSupplier = () -> { try { ChromeOptions options = new ChromeOptions(); + options.addArguments("--disable-search-engine-choice-screen"); + options.setExperimentalOption("prefs", Map.of( + "credentials_enable_service", false, + "profile.password_manager_enabled", false, + "profile.password_manager_leak_detection", false + )); return new ChromeDriver(options); } catch (Exception e) { LOG.error("Exception in WebDriverManager while ChromeDriver ", e); @@ -169,7 +176,8 @@ public Boolean apply(WebDriver d) { assertTrue(loaded); try { - driver.manage().window().maximize(); + // Manually setting fixed window size since `maximize()` crashes for Chrome/Edge driver on linux with xvfb. + driver.manage().window().setSize(new Dimension(1920, 1080)); } catch (Exception e) { LOG.warn("Failed to maximize browser window. Consider using setSize() instead.", e); } diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java index 64713b8062a..0eb414327e2 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/AuthenticationIT.java @@ -109,11 +109,11 @@ void testAnyOfRolesUser() throws Exception { try { authenticationUser("admin", "password1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); - assertTrue(pollingWait(By.xpath( + assertTrue(visibilityWait(By.xpath( "//div[@id='main']/div/div[2]"), MIN_IMPLICIT_WAIT).isDisplayed(), "Check is user has permission to view this page"); @@ -121,25 +121,25 @@ void testAnyOfRolesUser() throws Exception { authenticationUser("finance1", "finance1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); assertTrue( - pollingWait(By.xpath("//div[@id='main']/div/div[2]"), MIN_IMPLICIT_WAIT).isDisplayed(), + visibilityWait(By.xpath("//div[@id='main']/div/div[2]"), MIN_IMPLICIT_WAIT).isDisplayed(), "Check is user has permission to view this page"); logoutUser("finance1"); authenticationUser("hr1", "hr1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); try { assertTrue( - pollingWait(By.xpath("//li[contains(@class, 'ng-toast__message')]//span/span"), + visibilityWait(By.xpath("//li[contains(@class, 'ng-toast__message')]//span/span"), MIN_IMPLICIT_WAIT).isDisplayed(), "Check is user has permission to view this page"); } catch (TimeoutException e) { @@ -161,27 +161,27 @@ void testGroupPermission() throws Exception { String noteId = manager.getWebDriver().getCurrentUrl() .substring(manager.getWebDriver().getCurrentUrl().lastIndexOf("/") + 1); - pollingWait(By.xpath("//span[@uib-tooltip='Note permissions']"), + clickableWait(By.xpath("//span[@uib-tooltip='Note permissions']"), MAX_BROWSER_TIMEOUT_SEC).click(); - pollingWait(By.xpath(".//*[@id='selectOwners']/following::span//input"), + visibilityWait(By.xpath(".//*[@id='selectOwners']/following::span//input"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance "); - pollingWait(By.xpath(".//*[@id='selectReaders']/following::span//input"), + visibilityWait(By.xpath(".//*[@id='selectReaders']/following::span//input"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance "); - pollingWait(By.xpath(".//*[@id='selectRunners']/following::span//input"), + visibilityWait(By.xpath(".//*[@id='selectRunners']/following::span//input"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance "); - pollingWait(By.xpath(".//*[@id='selectWriters']/following::span//input"), + visibilityWait(By.xpath(".//*[@id='selectWriters']/following::span//input"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("finance "); - pollingWait(By.xpath("//button[@ng-click='savePermissions()']"), MAX_BROWSER_TIMEOUT_SEC) + visibilityWait(By.xpath("//button[@ng-click='savePermissions()']"), MAX_BROWSER_TIMEOUT_SEC) .sendKeys(Keys.ENTER); - pollingWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Permissions Saved ')]" + + clickableWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Permissions Saved ')]" + "//div[@class='modal-footer']//button[contains(.,'OK')]"), MAX_BROWSER_TIMEOUT_SEC).click(); logoutUser("finance1"); authenticationUser("hr1", "hr1"); try { - WebElement element = pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), + WebElement element = visibilityWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC); assertFalse(element.isDisplayed(), "Check is user has permission to view this note link"); } catch (Exception e) { @@ -202,7 +202,7 @@ void testGroupPermission() throws Exception { authenticationUser("finance2", "finance2"); try { - WebElement element = pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), + WebElement element = visibilityWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC); assertTrue(element.isDisplayed(), "Check is user has permission to view this note link"); } catch (Exception e) { diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java index 35b98046c39..2dfb87d2e0b 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java @@ -111,10 +111,10 @@ void testGloballyAction() throws Exception { try { //step 1: (admin) login, set 'globally in shared' mode of python interpreter, logout authenticationUser("admin", "password1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); - pollingWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), + visibilityWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("python"); ZeppelinITUtils.sleep(500, false); clickAndWait(By.xpath("//div[contains(@id, 'python')]//button[contains(@ng-click, 'valueform.$show();\n" + @@ -206,7 +206,7 @@ void testGloballyAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } waitForParagraph(2, "FINISHED"); @@ -265,11 +265,11 @@ void testPerUserScopedAction() throws Exception { try { //step 1: (admin) login, set 'Per user in scoped' mode of python interpreter, logout authenticationUser("admin", "password1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); - pollingWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), + visibilityWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("python"); ZeppelinITUtils.sleep(500, false); @@ -370,7 +370,7 @@ void testPerUserScopedAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } runParagraph(2); @@ -467,7 +467,7 @@ void testPerUserScopedAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } waitForParagraph(1, "FINISHED"); @@ -486,7 +486,7 @@ void testPerUserScopedAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user2noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user2noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } runParagraph(1); @@ -510,11 +510,11 @@ void testPerUserScopedAction() throws Exception { //System: Check if the number of python interpreter process is 0 //System: Check if the number of python process is 0 authenticationUser("admin", "password1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); - pollingWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), + visibilityWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("python"); ZeppelinITUtils.sleep(500, false); @@ -553,10 +553,10 @@ void testPerUserIsolatedAction() throws Exception { try { //step 1: (admin) login, set 'Per user in isolated' mode of python interpreter, logout authenticationUser("admin", "password1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); - pollingWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), + visibilityWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("python"); ZeppelinITUtils.sleep(500, false); clickAndWait(By.xpath("//div[contains(@id, 'python')]//button[contains(@ng-click, 'valueform.$show();\n" + @@ -653,7 +653,7 @@ void testPerUserIsolatedAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } runParagraph(2); @@ -752,7 +752,7 @@ void testPerUserIsolatedAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user1noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } waitForParagraph(1, "FINISHED"); @@ -771,7 +771,7 @@ void testPerUserIsolatedAction() throws Exception { (new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC))) .until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user2noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + user2noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } runParagraph(1); @@ -795,11 +795,11 @@ void testPerUserIsolatedAction() throws Exception { //System: Check if the number of python interpreter process is 0 //System: Check if the number of python process is 0 authenticationUser("admin", "password1"); - pollingWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), + clickableWait(By.xpath("//div/button[contains(@class, 'nav-btn dropdown-toggle ng-scope')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//li/a[contains(@href, '#/interpreter')]")); - pollingWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), + visibilityWait(By.xpath("//input[contains(@ng-model, 'searchInterpreter')]"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("python"); ZeppelinITUtils.sleep(500, false); diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java index bc4e0277c01..ea3ad80e319 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/PersonalizeActionsIT.java @@ -117,7 +117,7 @@ void testSimpleAction() throws Exception { .findElement( By.xpath(getParagraphXPath(1) + "//div[contains(@class, 'markdown-body')]")) .getText()); - pollingWait(By.xpath("//*[@id='actionbar']" + + clickableWait(By.xpath("//*[@id='actionbar']" + "//button[contains(@uib-tooltip, 'Switch to personal mode')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Do you want to personalize your analysis?')" + "]//div[@class='modal-footer']//button[contains(.,'OK')]")); @@ -129,7 +129,7 @@ void testSimpleAction() throws Exception { wait = new WebDriverWait(manager.getWebDriver(), Duration.ofSeconds(MAX_BROWSER_TIMEOUT_SEC)); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } assertEquals("Switch to personal mode (owner can change)", @@ -149,7 +149,7 @@ void testSimpleAction() throws Exception { locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } waitForParagraph(1, "FINISHED"); setParagraphText("After"); @@ -164,7 +164,7 @@ void testSimpleAction() throws Exception { locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } assertEquals("Before", manager.getWebDriver() .findElement( @@ -205,12 +205,12 @@ void testGraphAction() throws Exception { "Exception in PersonalizeActionsIT while testGraphAction, status of 1st Spark Paragraph "); } - pollingWait(By.xpath("//*[@id='actionbar']" + + clickableWait(By.xpath("//*[@id='actionbar']" + "//button[contains(@uib-tooltip, 'Switch to personal mode')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Do you want to personalize your analysis?')" + "]//div[@class='modal-footer']//button[contains(.,'OK')]")); - pollingWait(By.xpath(getParagraphXPath(1) + + clickableWait(By.xpath(getParagraphXPath(1) + "//button[contains(@uib-tooltip, 'Bar Chart')]"), MAX_BROWSER_TIMEOUT_SEC).click(); assertEquals("fa fa-bar-chart", manager.getWebDriver().findElement(By.xpath(getParagraphXPath(1) @@ -226,7 +226,7 @@ void testGraphAction() throws Exception { locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } assertEquals("Switch to personal mode (owner can change)", @@ -238,7 +238,7 @@ void testGraphAction() throws Exception { + "//button[contains(@class," + "'btn btn-default btn-sm ng-binding ng-scope active')]//i")).getAttribute("class")); - pollingWait(By.xpath(getParagraphXPath(1) + + clickableWait(By.xpath(getParagraphXPath(1) + "//button[contains(@uib-tooltip, 'Table')]"), MAX_BROWSER_TIMEOUT_SEC).click(); ZeppelinITUtils.sleep(1000, false); assertEquals("fa fa-table", manager.getWebDriver().findElement(By.xpath(getParagraphXPath(1) @@ -252,7 +252,7 @@ void testGraphAction() throws Exception { locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } assertEquals("fa fa-bar-chart", @@ -293,7 +293,7 @@ void testDynamicFormAction() throws Exception { assertEquals("Before", manager.getWebDriver().findElement(By.xpath(getParagraphXPath(1) + "//input[contains(@name, 'name')]")).getAttribute("value")); - pollingWait(By.xpath("//*[@id='actionbar']" + + clickableWait(By.xpath("//*[@id='actionbar']" + "//button[contains(@uib-tooltip, 'Switch to personal mode')]"), MAX_BROWSER_TIMEOUT_SEC).click(); clickAndWait(By.xpath("//div[@class='modal-dialog'][contains(.,'Do you want to personalize your analysis?')" + "]//div[@class='modal-footer']//button[contains(.,'OK')]")); @@ -305,7 +305,7 @@ void testDynamicFormAction() throws Exception { locator = By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"); element = wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); if (element.isDisplayed()) { - pollingWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), + clickableWait(By.xpath("//*[@id='notebook-names']//a[contains(@href, '" + noteId + "')]"), MAX_BROWSER_TIMEOUT_SEC).click(); } assertEquals("Switch to personal mode (owner can change)", @@ -316,9 +316,9 @@ void testDynamicFormAction() throws Exception { assertEquals("Before", manager.getWebDriver().findElement(By.xpath(getParagraphXPath(1) + "//input[contains(@name, 'name')]")).getAttribute("value")); - pollingWait(By.xpath(getParagraphXPath(1) + + visibilityWait(By.xpath(getParagraphXPath(1) + "//input[contains(@name, 'name')]"), MAX_BROWSER_TIMEOUT_SEC).clear(); - pollingWait(By.xpath(getParagraphXPath(1) + + visibilityWait(By.xpath(getParagraphXPath(1) + "//input[contains(@name, 'name')]"), MAX_BROWSER_TIMEOUT_SEC).sendKeys("After"); runParagraph(1); diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java index 4d94ce69c71..003f7cc5376 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java @@ -236,7 +236,7 @@ void testSparkInterpreterDependencyLoading() throws Exception { manager.getWebDriver().findElement(By.xpath("//div[@id='spark']//button[contains(.,'edit')]")) .sendKeys(Keys.ENTER); - WebElement depArtifact = pollingWait(By.xpath("//input[@ng-model='setting.depArtifact']"), + WebElement depArtifact = visibilityWait(By.xpath("//input[@ng-model='setting.depArtifact']"), MAX_BROWSER_TIMEOUT_SEC); String artifact = "org.apache.commons:commons-csv:1.1"; depArtifact.sendKeys(artifact); @@ -279,7 +279,7 @@ void testSparkInterpreterDependencyLoading() throws Exception { interpreterLink.click(); manager.getWebDriver().findElement(By.xpath("//div[@id='spark']//button[contains(.,'edit')]")) .sendKeys(Keys.ENTER); - WebElement testDepRemoveBtn = pollingWait(By.xpath("//tr[descendant::text()[contains(.,'" + + WebElement testDepRemoveBtn = visibilityWait(By.xpath("//tr[descendant::text()[contains(.,'" + artifact + "')]]/td[3]/button"), MAX_IMPLICIT_WAIT); testDepRemoveBtn.sendKeys(Keys.ENTER); manager.getWebDriver().findElement(By.xpath("//div[@id='spark']//form//button[1]")).click(); From cf766dbcbc0373be73424b0ce8859d5bb747c948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Thu, 26 Feb 2026 09:52:16 +0900 Subject: [PATCH 003/179] [ZEPPELIN-6373] Add E2E tests about share area ### What is this PR for? ABOUT_ZEPPELIN:'src/app/share/about-zeppelin/about-zeppelin.component', CODE_EDITOR:'src/app/share/code-editor/code-editor.component', FOLDER_RENAME:'src/app/share/folder-rename/folder-rename.component', HEADER:'src/app/share/header/header.component', NODE_LIST:'src/app/share/node-list/node-list.component', NOTE_CREATE:'src/app/share/note-create/note-create.component', NOTE_IMPORT:'src/app/share/note-import/note-import.component', NOTE_RENAME:'src/app/share/note-rename/note-rename.component', NOTE_TOC:'src/app/share/note-toc/note-toc.component', PAGE_HEADER:'src/app/share/page-header/page-header.component', RESIZE_HANDLE:'src/app/share/resize-handle/resize-handle.component', SHORTCUT:'src/app/share/shortcut/shortcut.component', SPIN:'src/app/share/spin/spin.component', THEME_TOGGLE:'src/app/share/theme-toggle/theme-toggle.component' ### What type of PR is it? Improvement *Please leave your type of PR only* ### Todos ### What is the Jira issue? ZEPPELIN-6373 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5114 from dididy/e2e/share. Signed-off-by: ChanHo Lee --- .../e2e/models/about-zeppelin-modal.ts | 57 +++++++++ .../e2e/models/header-page.ts | 113 ++++++++++++++++++ .../e2e/models/header-page.util.ts | 109 +++++++++++++++++ .../e2e/models/node-list-page.ts | 78 ++++++++++++ .../e2e/models/note-create-modal.ts | 54 +++++++++ .../e2e/models/note-create-modal.util.ts | 40 +++++++ .../e2e/models/note-import-modal.ts | 95 +++++++++++++++ .../home/home-page-note-operations.spec.ts | 12 +- .../about-zeppelin-modal.spec.ts | 69 +++++++++++ .../share/header/header-navigation.spec.ts | 73 +++++++++++ .../tests/share/header/header-search.spec.ts | 42 +++++++ .../node-list/node-list-functionality.spec.ts | 113 ++++++++++++++++++ .../note-create/note-create-modal.spec.ts | 108 +++++++++++++++++ .../note-import/note-import-modal.spec.ts | 105 ++++++++++++++++ zeppelin-web-angular/e2e/utils.ts | 2 +- 15 files changed, 1063 insertions(+), 7 deletions(-) create mode 100644 zeppelin-web-angular/e2e/models/about-zeppelin-modal.ts create mode 100644 zeppelin-web-angular/e2e/models/header-page.ts create mode 100644 zeppelin-web-angular/e2e/models/header-page.util.ts create mode 100644 zeppelin-web-angular/e2e/models/node-list-page.ts create mode 100644 zeppelin-web-angular/e2e/models/note-create-modal.ts create mode 100644 zeppelin-web-angular/e2e/models/note-create-modal.util.ts create mode 100644 zeppelin-web-angular/e2e/models/note-import-modal.ts create mode 100644 zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts diff --git a/zeppelin-web-angular/e2e/models/about-zeppelin-modal.ts b/zeppelin-web-angular/e2e/models/about-zeppelin-modal.ts new file mode 100644 index 00000000000..d5a44add770 --- /dev/null +++ b/zeppelin-web-angular/e2e/models/about-zeppelin-modal.ts @@ -0,0 +1,57 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Locator, Page } from '@playwright/test'; +import { BasePage } from './base-page'; + +export class AboutZeppelinModal extends BasePage { + readonly modal: Locator; + readonly modalTitle: Locator; + readonly closeButton: Locator; + readonly logo: Locator; + readonly heading: Locator; + readonly versionText: Locator; + readonly getInvolvedLink: Locator; + readonly licenseLink: Locator; + + constructor(page: Page) { + super(page); + this.modal = page.locator('[role="dialog"]').filter({ has: page.getByText('About Zeppelin') }); + this.modalTitle = page.locator('.ant-modal-title', { hasText: 'About Zeppelin' }); + this.closeButton = page.getByRole('button', { name: 'Close' }); + this.logo = page.locator('img[alt="Apache Zeppelin"]'); + this.heading = page.locator('h3', { hasText: 'Apache Zeppelin' }); + this.versionText = page.locator('.about-version'); + this.getInvolvedLink = page.getByRole('link', { name: 'Get involved!' }); + this.licenseLink = page.getByRole('link', { name: 'Licensed under the Apache License, Version 2.0' }); + } + + async close(): Promise { + await this.closeButton.click(); + } + + async getVersionText(): Promise { + return (await this.versionText.textContent()) || ''; + } + + async isLogoVisible(): Promise { + return this.logo.isVisible(); + } + + async getGetInvolvedHref(): Promise { + return this.getInvolvedLink.getAttribute('href'); + } + + async getLicenseHref(): Promise { + return this.licenseLink.getAttribute('href'); + } +} diff --git a/zeppelin-web-angular/e2e/models/header-page.ts b/zeppelin-web-angular/e2e/models/header-page.ts new file mode 100644 index 00000000000..2f5c1c496fc --- /dev/null +++ b/zeppelin-web-angular/e2e/models/header-page.ts @@ -0,0 +1,113 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Locator, Page } from '@playwright/test'; +import { BasePage } from './base-page'; + +export class HeaderPage extends BasePage { + readonly header: Locator; + readonly brandLogo: Locator; + readonly brandLink: Locator; + readonly notebookMenuItem: Locator; + readonly notebookDropdownTrigger: Locator; + readonly notebookDropdown: Locator; + readonly jobMenuItem: Locator; + readonly userDropdownTrigger: Locator; + readonly userBadge: Locator; + readonly searchInput: Locator; + readonly themeToggleButton: Locator; + + readonly userMenuItems: { + aboutZeppelin: Locator; + interpreter: Locator; + notebookRepos: Locator; + credential: Locator; + configuration: Locator; + logout: Locator; + switchToClassicUI: Locator; + }; + + constructor(page: Page) { + super(page); + this.header = page.locator('.header'); + this.brandLogo = page.locator('.header .brand .logo'); + this.brandLink = page.locator('.header .brand'); + this.notebookMenuItem = page.locator('[nz-menu-item]').filter({ hasText: 'Notebook' }); + this.notebookDropdownTrigger = page.locator('.node-list-trigger'); + this.notebookDropdown = page.locator('zeppelin-node-list.ant-dropdown-menu'); + this.jobMenuItem = page.getByRole('link', { name: 'Job' }); + this.userDropdownTrigger = page.locator('.header .user .status'); + this.userBadge = page.locator('.header .user nz-badge'); + this.searchInput = page.locator('.header .search input[type="text"]'); + this.themeToggleButton = page.locator('zeppelin-theme-toggle button'); + + this.userMenuItems = { + aboutZeppelin: page.getByText('About Zeppelin', { exact: true }), + interpreter: page.getByRole('link', { name: 'Interpreter' }), + notebookRepos: page.getByRole('link', { name: 'Notebook Repos' }), + credential: page.getByRole('link', { name: 'Credential' }), + configuration: page.getByRole('link', { name: 'Configuration' }), + logout: page.getByText('Logout', { exact: true }), + switchToClassicUI: page.getByRole('link', { name: 'Switch to Classic UI' }) + }; + } + + async clickBrandLogo(): Promise { + await this.brandLink.waitFor({ state: 'visible', timeout: 10000 }); + await this.brandLink.click(); + } + + async clickNotebookMenu(): Promise { + await this.notebookDropdownTrigger.waitFor({ state: 'visible', timeout: 10000 }); + await this.notebookDropdownTrigger.click(); + } + + async clickJobMenu(): Promise { + await this.jobMenuItem.waitFor({ state: 'visible', timeout: 10000 }); + await this.jobMenuItem.click(); + } + + async clickUserDropdown(): Promise { + await this.userDropdownTrigger.waitFor({ state: 'visible', timeout: 10000 }); + await this.userDropdownTrigger.click(); + } + + async clickAboutZeppelin(): Promise { + await this.userMenuItems.aboutZeppelin.click(); + } + + async clickInterpreter(): Promise { + await this.userMenuItems.interpreter.click(); + } + + async clickNotebookRepos(): Promise { + await this.userMenuItems.notebookRepos.click(); + } + + async clickCredential(): Promise { + await this.userMenuItems.credential.click(); + } + + async clickConfiguration(): Promise { + await this.userMenuItems.configuration.click(); + } + + async getUsernameText(): Promise { + return (await this.userBadge.textContent()) || ''; + } + + async searchNote(query: string): Promise { + await this.searchInput.waitFor({ state: 'visible', timeout: 10000 }); + await this.searchInput.fill(query); + await this.page.keyboard.press('Enter'); + } +} diff --git a/zeppelin-web-angular/e2e/models/header-page.util.ts b/zeppelin-web-angular/e2e/models/header-page.util.ts new file mode 100644 index 00000000000..14a369eb0ec --- /dev/null +++ b/zeppelin-web-angular/e2e/models/header-page.util.ts @@ -0,0 +1,109 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page } from '@playwright/test'; +import { HeaderPage } from './header-page'; +import { NodeListPage } from './node-list-page'; + +export class HeaderPageUtil { + constructor( + private readonly page: Page, + private readonly headerPage: HeaderPage + ) {} + + async verifyHeaderIsDisplayed(): Promise { + await expect(this.headerPage.header).toBeVisible(); + await expect(this.headerPage.brandLogo).toBeVisible(); + await expect(this.headerPage.notebookMenuItem).toBeVisible(); + await expect(this.headerPage.jobMenuItem).toBeVisible(); + await expect(this.headerPage.userDropdownTrigger).toBeVisible(); + await expect(this.headerPage.searchInput).toBeVisible(); + await expect(this.headerPage.themeToggleButton).toBeVisible(); + } + + async verifyNavigationToHomePage(): Promise { + await this.headerPage.clickBrandLogo(); + await this.page.waitForURL(/\/(#\/)?$/); + const url = this.page.url(); + expect(url).toMatch(/\/(#\/)?$/); + } + + async verifyNavigationToJobManager(): Promise { + await this.headerPage.clickJobMenu(); + await this.page.waitForURL(/jobmanager/); + expect(this.page.url()).toContain('jobmanager'); + } + + async verifyUserDropdownOpens(): Promise { + await this.headerPage.clickUserDropdown(); + await expect(this.headerPage.userMenuItems.aboutZeppelin).toBeVisible(); + } + + async verifyNotebookDropdownOpens(): Promise { + await this.headerPage.clickNotebookMenu(); + await expect(this.headerPage.notebookDropdown).toBeVisible(); + + const nodeList = new NodeListPage(this.page); + await expect(nodeList.createNewNoteButton).toBeVisible(); + } + + async verifySearchNavigation(query: string): Promise { + await this.headerPage.searchNote(query); + await this.page.waitForURL(/search/); + expect(this.page.url()).toContain('search'); + expect(this.page.url()).toContain(query); + } + + async verifyUserMenuItemsVisible(isLoggedIn: boolean): Promise { + await this.headerPage.clickUserDropdown(); + await expect(this.headerPage.userMenuItems.aboutZeppelin).toBeVisible(); + await expect(this.headerPage.userMenuItems.interpreter).toBeVisible(); + await expect(this.headerPage.userMenuItems.notebookRepos).toBeVisible(); + await expect(this.headerPage.userMenuItems.credential).toBeVisible(); + await expect(this.headerPage.userMenuItems.configuration).toBeVisible(); + await expect(this.headerPage.userMenuItems.switchToClassicUI).toBeVisible(); + + if (isLoggedIn) { + const username = await this.headerPage.getUsernameText(); + expect(username).not.toBe('anonymous'); + await expect(this.headerPage.userMenuItems.logout).toBeVisible(); + } + } + + async navigateToInterpreterSettings(): Promise { + await this.headerPage.clickUserDropdown(); + await this.headerPage.clickInterpreter(); + await this.page.waitForURL(/interpreter/); + expect(this.page.url()).toContain('interpreter'); + } + + async navigateToNotebookRepos(): Promise { + await this.headerPage.clickUserDropdown(); + await this.headerPage.clickNotebookRepos(); + await this.page.waitForURL(/notebook-repos/); + expect(this.page.url()).toContain('notebook-repos'); + } + + async navigateToCredential(): Promise { + await this.headerPage.clickUserDropdown(); + await this.headerPage.clickCredential(); + await this.page.waitForURL(/credential/); + expect(this.page.url()).toContain('credential'); + } + + async navigateToConfiguration(): Promise { + await this.headerPage.clickUserDropdown(); + await this.headerPage.clickConfiguration(); + await this.page.waitForURL(/configuration/); + expect(this.page.url()).toContain('configuration'); + } +} diff --git a/zeppelin-web-angular/e2e/models/node-list-page.ts b/zeppelin-web-angular/e2e/models/node-list-page.ts new file mode 100644 index 00000000000..17bd93de33d --- /dev/null +++ b/zeppelin-web-angular/e2e/models/node-list-page.ts @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Locator, Page } from '@playwright/test'; +import { BasePage } from './base-page'; + +export class NodeListPage extends BasePage { + readonly nodeListContainer: Locator; + readonly importNoteButton: Locator; + readonly createNewNoteButton: Locator; + readonly filterInput: Locator; + readonly treeView: Locator; + readonly notes: Locator; + readonly trashFolder: Locator; + + constructor(page: Page) { + super(page); + this.nodeListContainer = page.locator('zeppelin-node-list'); + this.importNoteButton = page.getByText('Import Note', { exact: true }).first(); + this.createNewNoteButton = page.getByText('Create new Note', { exact: true }).first(); + this.filterInput = page.locator('zeppelin-node-list input[placeholder*="Filter"]'); + this.treeView = page.locator('zeppelin-node-list nz-tree'); + this.notes = page.locator('nz-tree-node').filter({ has: page.locator('.ant-tree-node-content-wrapper .file') }); + this.trashFolder = page.locator('nz-tree-node').filter({ hasText: '~Trash' }); + } + + async clickImportNote(): Promise { + await this.importNoteButton.click(); + } + + async clickCreateNewNote(): Promise { + await this.createNewNoteButton.click(); + } + + getFolderByName(folderName: string): Locator { + return this.page.locator('nz-tree-node').filter({ hasText: folderName }).first(); + } + + getNoteByName(noteName: string): Locator { + return this.page.locator('nz-tree-node').filter({ hasText: noteName }).first(); + } + + async clickNote(noteName: string): Promise { + const note = this.getNoteByName(noteName); + // Target the specific link that navigates to the notebook (has href with "#/notebook/") + const noteLink = note.locator('a[href*="#/notebook/"]'); + await noteLink.click(); + } + + async isFilterInputVisible(): Promise { + return this.filterInput.isVisible(); + } + + async isTrashFolderVisible(): Promise { + return this.trashFolder.isVisible(); + } + + async getAllVisibleNoteNames(): Promise { + const noteElements = await this.notes.all(); + const names: string[] = []; + for (const note of noteElements) { + const text = await note.textContent(); + if (text) { + names.push(text.trim()); + } + } + return names; + } +} diff --git a/zeppelin-web-angular/e2e/models/note-create-modal.ts b/zeppelin-web-angular/e2e/models/note-create-modal.ts new file mode 100644 index 00000000000..1e1a0c4808d --- /dev/null +++ b/zeppelin-web-angular/e2e/models/note-create-modal.ts @@ -0,0 +1,54 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Locator, Page } from '@playwright/test'; +import { BasePage } from './base-page'; + +export class NoteCreateModal extends BasePage { + readonly modal: Locator; + readonly closeButton: Locator; + readonly noteNameInput: Locator; + readonly interpreterDropdown: Locator; + readonly folderInfoAlert: Locator; + readonly createButton: Locator; + + constructor(page: Page) { + super(page); + this.modal = page.locator('[role="dialog"]').filter({ has: page.locator('input[name="noteName"]') }); + this.closeButton = page.getByRole('button', { name: 'Close' }); + this.noteNameInput = page.locator('input[name="noteName"]'); + this.interpreterDropdown = page.locator('nz-select[name="defaultInterpreter"]'); + this.folderInfoAlert = page.getByText("Use '/' to create folders"); + this.createButton = page.getByRole('button', { name: 'Create' }); + } + + async close(): Promise { + await this.closeButton.click(); + } + + async getNoteName(): Promise { + return (await this.noteNameInput.inputValue()) || ''; + } + + async setNoteName(name: string): Promise { + await this.noteNameInput.clear(); + await this.noteNameInput.fill(name); + } + + async clickCreate(): Promise { + await this.createButton.click(); + } + + async isFolderInfoVisible(): Promise { + return this.folderInfoAlert.isVisible(); + } +} diff --git a/zeppelin-web-angular/e2e/models/note-create-modal.util.ts b/zeppelin-web-angular/e2e/models/note-create-modal.util.ts new file mode 100644 index 00000000000..7553325c1e2 --- /dev/null +++ b/zeppelin-web-angular/e2e/models/note-create-modal.util.ts @@ -0,0 +1,40 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect } from '@playwright/test'; +import { NoteCreateModal } from './note-create-modal'; + +export class NoteCreateModalUtil { + constructor(private readonly modal: NoteCreateModal) {} + + async verifyModalIsOpen(): Promise { + await expect(this.modal.modal).toBeVisible(); + await expect(this.modal.noteNameInput).toBeVisible(); + await expect(this.modal.createButton).toBeVisible(); + } + + async verifyDefaultNoteName(expectedPattern: RegExp): Promise { + const noteName = await this.modal.getNoteName(); + expect(noteName).toMatch(expectedPattern); + } + + async verifyFolderCreationInfo(): Promise { + await expect(this.modal.folderInfoAlert).toBeVisible(); + const text = await this.modal.folderInfoAlert.textContent(); + expect(text).toContain('/'); + } + + async verifyModalClose(): Promise { + await this.modal.close(); + await expect(this.modal.modal).not.toBeVisible(); + } +} diff --git a/zeppelin-web-angular/e2e/models/note-import-modal.ts b/zeppelin-web-angular/e2e/models/note-import-modal.ts new file mode 100644 index 00000000000..11db6d5da41 --- /dev/null +++ b/zeppelin-web-angular/e2e/models/note-import-modal.ts @@ -0,0 +1,95 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Locator, Page } from '@playwright/test'; +import { BasePage } from './base-page'; + +export class NoteImportModal extends BasePage { + readonly modal: Locator; + readonly modalTitle: Locator; + readonly closeButton: Locator; + readonly importAsInput: Locator; + readonly jsonFileTab: Locator; + readonly urlTab: Locator; + readonly uploadArea: Locator; + readonly uploadText: Locator; + readonly fileSizeLimit: Locator; + readonly urlInput: Locator; + readonly importNoteButton: Locator; + readonly errorAlert: Locator; + + constructor(page: Page) { + super(page); + this.modal = page.locator('[role="dialog"]').filter({ has: page.locator('input[name="noteImportName"]') }); + this.modalTitle = page.locator('.ant-modal-title', { hasText: 'Import New Note' }); + this.closeButton = page.getByRole('button', { name: 'Close' }); + this.importAsInput = page.locator('input[name="noteImportName"]'); + this.jsonFileTab = page.getByRole('tab', { name: 'Import From JSON File' }); + this.urlTab = page.getByRole('tab', { name: 'Import From URL' }); + this.uploadArea = page.locator('nz-upload[nztype="drag"]'); + this.uploadText = page.getByText('Click or drag JSON file to this area to upload'); + this.fileSizeLimit = page.locator('.ant-upload-hint strong'); + this.urlInput = page.locator('input[name="importUrl"]'); + this.importNoteButton = page.getByRole('button', { name: 'Import Note' }); + this.errorAlert = page.locator('nz-alert[nztype="error"]'); + } + + async close(): Promise { + await this.closeButton.click(); + } + + async setImportAsName(name: string): Promise { + await this.importAsInput.fill(name); + } + + async getImportAsName(): Promise { + return (await this.importAsInput.inputValue()) || ''; + } + + async switchToUrlTab(): Promise { + await this.urlTab.click(); + } + + async isJsonFileTabSelected(): Promise { + const ariaSelected = await this.jsonFileTab.getAttribute('aria-selected'); + return ariaSelected === 'true'; + } + + async isUrlTabSelected(): Promise { + const ariaSelected = await this.urlTab.getAttribute('aria-selected'); + return ariaSelected === 'true'; + } + + async setImportUrl(url: string): Promise { + await this.urlInput.fill(url); + } + + async clickImportNote(): Promise { + await this.importNoteButton.click(); + } + + async isImportNoteButtonDisabled(): Promise { + return this.importNoteButton.isDisabled(); + } + + async getFileSizeLimit(): Promise { + return (await this.fileSizeLimit.textContent()) || ''; + } + + async isErrorAlertVisible(): Promise { + return this.errorAlert.isVisible(); + } + + async getErrorMessage(): Promise { + return (await this.errorAlert.textContent()) || ''; + } +} diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts index 018bfbf40e3..f385de5f585 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts @@ -55,18 +55,18 @@ test.describe('Home Page Note Operations', () => { const firstNote = page.locator('.node .file').first(); await firstNote.hover(); - await expect(homePage.nodeList.noteActions.renameNote).toBeVisible(); - await expect(homePage.nodeList.noteActions.clearOutput).toBeVisible(); - await expect(homePage.nodeList.noteActions.moveToTrash).toBeVisible(); + await expect(homePage.nodeList.noteActions.renameNote.first()).toBeVisible(); + await expect(homePage.nodeList.noteActions.clearOutput.first()).toBeVisible(); + await expect(homePage.nodeList.noteActions.moveToTrash.first()).toBeVisible(); // Test tooltip visibility by hovering over each icon - await homePage.nodeList.noteActions.renameNote.hover(); + await homePage.nodeList.noteActions.renameNote.first().hover(); await expect(page.locator('.ant-tooltip', { hasText: 'Rename note' })).toBeVisible(); - await homePage.nodeList.noteActions.clearOutput.hover(); + await homePage.nodeList.noteActions.clearOutput.first().hover(); await expect(page.locator('.ant-tooltip', { hasText: 'Clear output' })).toBeVisible(); - await homePage.nodeList.noteActions.moveToTrash.hover(); + await homePage.nodeList.noteActions.moveToTrash.first().hover(); await expect(page.locator('.ant-tooltip', { hasText: 'Move note to Trash' })).toBeVisible(); } }); diff --git a/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts new file mode 100644 index 00000000000..2e8ab234a78 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts @@ -0,0 +1,69 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect } from '@playwright/test'; +import { HeaderPage } from '../../../models/header-page'; +import { AboutZeppelinModal } from '../../../models/about-zeppelin-modal'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +test.describe('About Zeppelin Modal', () => { + let headerPage: HeaderPage; + let aboutModal: AboutZeppelinModal; + + addPageAnnotationBeforeEach(PAGES.SHARE.ABOUT_ZEPPELIN); + + test.beforeEach(async ({ page }) => { + headerPage = new HeaderPage(page); + aboutModal = new AboutZeppelinModal(page); + + await page.goto('/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + + await headerPage.clickUserDropdown(); + await headerPage.clickAboutZeppelin(); + }); + + test('Given user clicks About Zeppelin menu item, When modal opens, Then modal should display all required elements', async () => { + await expect(aboutModal.modal).toBeVisible(); + await expect(aboutModal.modalTitle).toBeVisible(); + await expect(aboutModal.heading).toBeVisible(); + await expect(aboutModal.logo).toBeVisible(); + await expect(aboutModal.versionText).toBeVisible(); + await expect(aboutModal.getInvolvedLink).toBeVisible(); + await expect(aboutModal.licenseLink).toBeVisible(); + }); + + test('Given About Zeppelin modal is open, When viewing version information, Then version should be displayed', async () => { + const version = await aboutModal.getVersionText(); + expect(version).toBeTruthy(); + expect(version.length).toBeGreaterThan(0); + }); + + test('Given About Zeppelin modal is open, When checking external links, Then links should have correct URLs', async () => { + const getInvolvedHref = await aboutModal.getGetInvolvedHref(); + const licenseHref = await aboutModal.getLicenseHref(); + + expect(getInvolvedHref).toContain('zeppelin.apache.org'); + expect(licenseHref).toContain('apache.org/licenses'); + }); + + test('Given About Zeppelin modal is open, When clicking close button, Then modal should close', async () => { + await aboutModal.close(); + await expect(aboutModal.modal).not.toBeVisible(); + }); + + test('Given About Zeppelin modal is open, When checking logo, Then logo should be visible and properly loaded', async () => { + const isLogoVisible = await aboutModal.isLogoVisible(); + expect(isLogoVisible).toBe(true); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts new file mode 100644 index 00000000000..18ae43faba6 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts @@ -0,0 +1,73 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test } from '@playwright/test'; +import { HeaderPage } from '../../../models/header-page'; +import { HeaderPageUtil } from '../../../models/header-page.util'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +test.describe('Header Navigation', () => { + let headerPage: HeaderPage; + let headerUtil: HeaderPageUtil; + + addPageAnnotationBeforeEach(PAGES.SHARE.HEADER); + + test.beforeEach(async ({ page }) => { + headerPage = new HeaderPage(page); + headerUtil = new HeaderPageUtil(page, headerPage); + + await page.goto('/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + }); + + test('Given user is on any page, When viewing the header, Then all header elements should be visible', async () => { + await headerUtil.verifyHeaderIsDisplayed(); + }); + + test('Given user is on any page, When clicking the Zeppelin logo, Then user should navigate to home page', async () => { + await headerUtil.verifyNavigationToHomePage(); + }); + + test('Given user is on home page, When clicking the Job menu item, Then user should navigate to Job Manager page', async () => { + await headerUtil.verifyNavigationToJobManager(); + }); + + test('Given user is on home page, When clicking the Notebook dropdown, Then dropdown with node list should open', async () => { + await headerUtil.verifyNotebookDropdownOpens(); + }); + + test('Given user is on home page, When clicking the user dropdown, Then user menu should open', async () => { + await headerUtil.verifyUserDropdownOpens(); + }); + + test('Given user opens user dropdown, When all menu items are displayed, Then menu items should include settings and configuration options', async () => { + const isAnonymous = (await headerPage.getUsernameText()).includes('anonymous'); + await headerUtil.verifyUserMenuItemsVisible(!isAnonymous); + }); + + test('Given user opens user dropdown, When clicking Interpreter menu item, Then user should navigate to Interpreter settings page', async () => { + await headerUtil.navigateToInterpreterSettings(); + }); + + test('Given user opens user dropdown, When clicking Notebook Repos menu item, Then user should navigate to Notebook Repos page', async () => { + await headerUtil.navigateToNotebookRepos(); + }); + + test('Given user opens user dropdown, When clicking Credential menu item, Then user should navigate to Credential page', async () => { + await headerUtil.navigateToCredential(); + }); + + test('Given user opens user dropdown, When clicking Configuration menu item, Then user should navigate to Configuration page', async () => { + await headerUtil.navigateToConfiguration(); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts b/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts new file mode 100644 index 00000000000..171f2d52558 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts @@ -0,0 +1,42 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect } from '@playwright/test'; +import { HeaderPage } from '../../../models/header-page'; +import { HeaderPageUtil } from '../../../models/header-page.util'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +test.describe('Header Search Functionality', () => { + let headerPage: HeaderPage; + let headerUtil: HeaderPageUtil; + + addPageAnnotationBeforeEach(PAGES.SHARE.HEADER); + + test.beforeEach(async ({ page }) => { + headerPage = new HeaderPage(page); + headerUtil = new HeaderPageUtil(page, headerPage); + + await page.goto('/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + }); + + test('Given user is on home page, When entering search query and pressing Enter, Then user should navigate to search results page', async () => { + const searchQuery = 'test'; + await headerUtil.verifySearchNavigation(searchQuery); + }); + + test('Given user is on home page, When viewing search input, Then search input should be visible and accessible', async () => { + await expect(headerPage.searchInput).toBeVisible(); + await expect(headerPage.searchInput).toBeEditable(); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts new file mode 100644 index 00000000000..111d01011f7 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts @@ -0,0 +1,113 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect } from '@playwright/test'; +import { HomePage } from '../../../models/home-page'; +import { NodeListPage } from '../../../models/node-list-page'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +test.describe('Node List Functionality', () => { + let nodeListPage: NodeListPage; + + addPageAnnotationBeforeEach(PAGES.SHARE.NODE_LIST); + + test.beforeEach(async ({ page }) => { + nodeListPage = new NodeListPage(page); + + await page.goto('/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + }); + + test('Given user is on home page, When viewing node list, Then node list should display tree structure', async () => { + await expect(nodeListPage.nodeListContainer).toBeVisible(); + await expect(nodeListPage.treeView).toBeVisible(); + }); + + test('Given user is on home page, When viewing node list, Then action buttons should be visible', async () => { + await expect(nodeListPage.createNewNoteButton).toBeVisible(); + await expect(nodeListPage.importNoteButton).toBeVisible(); + }); + + test('Given user is on home page, When viewing node list, Then filter input should be visible', async () => { + const isFilterVisible = await nodeListPage.isFilterInputVisible(); + expect(isFilterVisible).toBe(true); + }); + + test('Given a note has been moved to trash, When viewing node list, Then trash folder should be visible', async ({ + page + }) => { + const homePage = new HomePage(page); + + // Create a test note to ensure there is something to trash + await homePage.createNote('_e2e_trash_test'); + + // Navigate back to home + await page.goto('/'); + await waitForZeppelinReady(page); + + // Wait for the created note to appear in the node list, then hover + const testNote = page.locator('.node .file').filter({ hasText: '_e2e_trash_test' }); + await expect(testNote).toBeVisible({ timeout: 15000 }); + await testNote.hover(); + + // Click the delete icon (nz-popconfirm is on the element) + const deleteIcon = testNote.locator('.operation i[nztype="delete"]'); + await deleteIcon.click(); + + // Confirm the popconfirm dialog (ng-zorro en_US default is "OK", not "Yes") + await expect(page.locator('text=This note will be moved to trash.')).toBeVisible(); + const confirmButton = page.locator('.ant-popover button:has-text("OK")'); + await confirmButton.click(); + + // Wait for the trash folder to appear and verify + await expect(nodeListPage.trashFolder).toBeVisible({ timeout: 10000 }); + const isTrashVisible = await nodeListPage.isTrashFolderVisible(); + expect(isTrashVisible).toBe(true); + }); + + test('Given there are notes in node list, When clicking a note, Then user should navigate to that note', async ({ + page + }) => { + await expect(nodeListPage.treeView).toBeVisible(); + const notes = await nodeListPage.getAllVisibleNoteNames(); + + if (notes.length > 0 && notes[0]) { + const noteName = notes[0].trim(); + + await nodeListPage.clickNote(noteName); + await page.waitForURL(/notebook\//); + + expect(page.url()).toContain('notebook/'); + } + }); + + test('Given user clicks Create New Note button, When modal opens, Then note create modal should be displayed', async ({ + page + }) => { + await nodeListPage.clickCreateNewNote(); + await page.waitForSelector('input[name="noteName"]'); + + const noteNameInput = page.locator('input[name="noteName"]'); + await expect(noteNameInput).toBeVisible(); + }); + + test('Given user clicks Import Note button, When modal opens, Then note import modal should be displayed', async ({ + page + }) => { + await nodeListPage.clickImportNote(); + await page.waitForSelector('input[name="noteImportName"]'); + + const importNameInput = page.locator('input[name="noteImportName"]'); + await expect(importNameInput).toBeVisible(); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts new file mode 100644 index 00000000000..a2674b4c4ae --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts @@ -0,0 +1,108 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect } from '@playwright/test'; +import { HomePage } from '../../../models/home-page'; +import { NoteCreateModal } from '../../../models/note-create-modal'; +import { NoteCreateModalUtil } from '../../../models/note-create-modal.util'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +test.describe('Note Create Modal', () => { + let homePage: HomePage; + let noteCreateModal: NoteCreateModal; + let noteCreateUtil: NoteCreateModalUtil; + + addPageAnnotationBeforeEach(PAGES.SHARE.NOTE_CREATE); + + test.beforeEach(async ({ page }) => { + homePage = new HomePage(page); + noteCreateModal = new NoteCreateModal(page); + noteCreateUtil = new NoteCreateModalUtil(noteCreateModal); + + await page.goto('/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + + await homePage.clickCreateNewNote(); + await page.waitForSelector('input[name="noteName"]'); + }); + + test('Given user clicks Create New Note, When modal opens, Then modal should display all required elements', async () => { + await noteCreateUtil.verifyModalIsOpen(); + await expect(noteCreateModal.interpreterDropdown).toBeVisible(); + await noteCreateUtil.verifyFolderCreationInfo(); + }); + + test('Given Create Note modal is open, When checking default note name, Then auto-generated name should follow pattern', async () => { + await noteCreateUtil.verifyDefaultNoteName(/Untitled Note \d+/); + }); + + test('Given Create Note modal is open, When entering custom note name and creating, Then new note should be created successfully', async ({ + page + }) => { + const uniqueName = `Test Note ${Date.now()}`; + await noteCreateModal.setNoteName(uniqueName); + await noteCreateModal.clickCreate(); + + // Wait for modal to disappear + await expect(noteCreateModal.modal).not.toBeVisible(); + + await page.waitForURL(/notebook\//); + expect(page.url()).toContain('notebook/'); + + // Verify the note was created with the correct name + const notebookTitle = page.locator('p, .notebook-title, .note-title, h1, [data-testid="notebook-title"]').first(); + await expect(notebookTitle).toContainText(uniqueName); + + // Verify in the navigation tree if available + await page.goto('/'); + await page.waitForLoadState('networkidle'); + const noteInTree = page.getByRole('link', { name: uniqueName }); + await expect(noteInTree).toBeVisible(); + }); + + test('Given Create Note modal is open, When entering note name with folder path, Then note should be created in folder', async ({ + page + }) => { + const folderPath = `/TestFolder/SubFolder`; + const noteName = `Note ${Date.now()}`; + const fullPath = `${folderPath}/${noteName}`; + + await noteCreateModal.setNoteName(fullPath); + await noteCreateModal.clickCreate(); + + // Wait for modal to disappear + await expect(noteCreateModal.modal).not.toBeVisible(); + + await page.waitForURL(/notebook\//); + expect(page.url()).toContain('notebook/'); + + // Verify the note was created with the correct name (without folder path) + const notebookTitle = page.locator('p, .notebook-title, .note-title, h1, [data-testid="notebook-title"]').first(); + await expect(notebookTitle).toContainText(noteName); + + // Verify the folder structure was created + await page.goto('/'); + await page.waitForLoadState('networkidle'); + const folder = page.locator('nz-tree-node').filter({ hasText: 'TestFolder' }); + await expect(folder).toBeVisible(); + }); + + test('Given Create Note modal is open, When clicking close button, Then modal should close', async () => { + await noteCreateUtil.verifyModalClose(); + }); + + test('Given Create Note modal is open, When viewing folder info alert, Then alert should contain folder creation instructions', async () => { + const isInfoVisible = await noteCreateModal.isFolderInfoVisible(); + expect(isInfoVisible).toBe(true); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts new file mode 100644 index 00000000000..b20bee0902a --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts @@ -0,0 +1,105 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test, expect } from '@playwright/test'; +import { HomePage } from '../../../models/home-page'; +import { NoteImportModal } from '../../../models/note-import-modal'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +test.describe('Note Import Modal', () => { + let homePage: HomePage; + let noteImportModal: NoteImportModal; + + addPageAnnotationBeforeEach(PAGES.SHARE.NOTE_IMPORT); + + test.beforeEach(async ({ page }) => { + homePage = new HomePage(page); + noteImportModal = new NoteImportModal(page); + + await page.goto('/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + + await homePage.clickImportNote(); + await page.waitForSelector('input[name="noteImportName"]'); + }); + + test('Given user clicks Import Note, When modal opens, Then modal should display all required elements', async () => { + await expect(noteImportModal.modal).toBeVisible(); + await expect(noteImportModal.modalTitle).toBeVisible(); + await expect(noteImportModal.importAsInput).toBeVisible(); + await expect(noteImportModal.jsonFileTab).toBeVisible(); + await expect(noteImportModal.urlTab).toBeVisible(); + }); + + test('Given Import Note modal is open, When viewing default tab, Then JSON File tab should be selected', async () => { + const isJsonTabSelected = await noteImportModal.isJsonFileTabSelected(); + expect(isJsonTabSelected).toBe(true); + + await expect(noteImportModal.uploadArea).toBeVisible(); + await expect(noteImportModal.uploadText).toBeVisible(); + }); + + test('Given Import Note modal is open, When switching to URL tab, Then URL input should be visible', async () => { + await noteImportModal.switchToUrlTab(); + + const isUrlTabSelected = await noteImportModal.isUrlTabSelected(); + expect(isUrlTabSelected).toBe(true); + + await expect(noteImportModal.urlInput).toBeVisible(); + await expect(noteImportModal.importNoteButton).toBeVisible(); + }); + + test('Given URL tab is selected, When URL is empty, Then import button should be disabled', async () => { + await noteImportModal.switchToUrlTab(); + + const isDisabled = await noteImportModal.isImportNoteButtonDisabled(); + expect(isDisabled).toBe(true); + }); + + test('Given URL tab is selected, When entering URL, Then import button should be enabled', async () => { + await noteImportModal.switchToUrlTab(); + await noteImportModal.setImportUrl('https://example.com/note.json'); + + const isDisabled = await noteImportModal.isImportNoteButtonDisabled(); + expect(isDisabled).toBe(false); + }); + + test('Given Import Note modal is open, When entering import name, Then name should be set', async () => { + const importName = `Imported Note ${Date.now()}`; + await noteImportModal.setImportAsName(importName); + + const actualName = await noteImportModal.getImportAsName(); + expect(actualName).toBe(importName); + }); + + test('Given JSON File tab is selected, When viewing file size limit, Then limit should be displayed', async () => { + const fileSizeLimit = await noteImportModal.getFileSizeLimit(); + expect(fileSizeLimit).toBeTruthy(); + expect(fileSizeLimit.length).toBeGreaterThan(0); + }); + + test('Given Import Note modal is open, When clicking close button, Then modal should close', async () => { + await noteImportModal.close(); + await expect(noteImportModal.modal).not.toBeVisible(); + }); + + test('Given URL tab is selected, When entering invalid URL and clicking import, Then error should be displayed', async () => { + await noteImportModal.switchToUrlTab(); + await noteImportModal.setImportUrl('invalid-url'); + await noteImportModal.clickImportNote(); + + await expect(noteImportModal.errorAlert).toBeVisible(); + const errorMessage = await noteImportModal.getErrorMessage(); + expect(errorMessage).toBeTruthy(); + }); +}); diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index dab04a13256..d4fd455a972 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -215,7 +215,7 @@ export const waitForZeppelinReady = async (page: Page): Promise => { if (isOnLoginPage) { console.log('On login page - checking if authentication is enabled'); - // If we're on login dlpage, this is expected when authentication is required + // If we're on login page, this is expected when authentication is required // Just wait for login elements to be ready instead of waiting for app content await page.waitForFunction( () => { From c3ccd9b4dd40eac2fc7500ae15b71cbee9384cd5 Mon Sep 17 00:00:00 2001 From: Prabhjyot Singh Date: Sun, 1 Mar 2026 08:54:45 -0500 Subject: [PATCH 004/179] [ZEPPELIN-6162] Implement revisions comparator for New UI ### What is this PR for? Port the revision comparison feature from the legacy AngularJS UI to the new Angular 13 frontend. Users can now select two revisions and view paragraph-by-paragraph diffs with color-coded additions and deletions. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6162 ### How should this be tested? * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ![ZEPPELIN-6162](https://github.com/user-attachments/assets/483c05e1-9fa0-4347-8f50-21d0fbd90db2) ### Questions: * Does the license files need to update? no * Is there breaking changes for older versions? no * Does this needs documentation? no Closes #5155 from prabhjyotsingh/ZEPPELIN-6162. Signed-off-by: ChanHo Lee --- .../message-data-type-map.interface.ts | 2 + .../interfaces/message-notebook.interface.ts | 7 + .../notebook/notebook.component.html | 6 +- .../workspace/notebook/notebook.module.ts | 6 +- .../revisions-comparator.component.html | 111 +++++++++- .../revisions-comparator.component.less | 146 +++++++++++++ .../revisions-comparator.component.ts | 198 +++++++++++++++++- .../src/styles/theme/dark-theme-overrides.css | 15 ++ 8 files changed, 479 insertions(+), 12 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts index 25786552697..6c6088c73ae 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-data-type-map.interface.ts @@ -34,6 +34,7 @@ import { NoteRename, NoteRevision, NoteRevisionForCompare, + NoteRevisionForCompareReceived, NoteRunningStatus, NoteUpdate, NoteUpdated, @@ -118,6 +119,7 @@ export interface MessageReceiveDataTypeMap { [OP.ANGULAR_OBJECT_UPDATE]: AngularObjectUpdate; [OP.ANGULAR_OBJECT_REMOVE]: AngularObjectRemove; [OP.PARAS_INFO]: ParasInfo; + [OP.NOTE_REVISION_FOR_COMPARE]: NoteRevisionForCompareReceived; } export interface MessageSendDataTypeMap { diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts index a07d52d372b..986aed0b910 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts @@ -125,6 +125,13 @@ export interface NoteRevisionForCompare { position: string; } +export interface NoteRevisionForCompareReceived { + noteId: string; + revisionId: string; + position: string; + note: Note['note']; +} + export interface CollaborativeModeStatus { status: boolean; users: string[]; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html index ed0bddd2f2c..8541afc964a 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -56,7 +56,11 @@ [(activatedExtension)]="activatedExtension" [permissions]="permissions" > - +
-
-
-

Revisions comparator

+
+
+
+ + + + Revision name + Date + + + + + {{ revision.message }} + {{ formatRevisionDate(revision.time) }} + + + +
+ +
+ + + + compare with + + + +
+ +
+
+
+
+ {{ p.paragraph.id }} + ({{ p.paragraph.title }}) + added + deleted + differences + identical + {{ p.firstString }} +
+
+
+ Please select a revision +
+
+
+
+ +
+ + Revision: + {{ currentFirstRevisionLabel }} --> {{ currentSecondRevisionLabel }} + +
{{
+      currentParagraphDiffDisplay?.paragraph?.text
+    }}
+
{{
+      currentParagraphDiffDisplay?.paragraph?.text
+    }}
+
{{ seg.text }}
+
+      
Nothing to display
+
- -
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less index 019b5ca53b5..8eae3f0cc4b 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.less @@ -9,4 +9,150 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import "theme-mixin"; +.themeMixin({ + .revisions-comparator { + padding: 10px 15px 15px; + } + + .commit-tree { + margin-bottom: 10px; + + ::ng-deep .ant-table-body { + overflow-y: auto !important; + } + } + + .cursor-hand { + cursor: pointer; + } + + .selected-revision { + background-color: fade(@primary-6, 15%) !important; + } + + .revisions-comparator-bar { + display: flex; + align-items: center; + gap: 8px; + padding-bottom: 12px; + flex-wrap: wrap; + + .revision-select { + flex: 1; + min-width: 100px; + display: block; + } + + .compare-label { + white-space: nowrap; + } + } + + .diff-panel { + border: 1px solid @border-color-base; + border-radius: 4px; + } + + .paragraphs-div { + overflow: auto; + max-height: 35vh; + } + + .paragraph-item { + transition: background-color 200ms ease-out; + border-bottom: 1px solid @border-color-split; + cursor: pointer; + + &:hover { + background-color: fade(@primary-6, 8%); + } + + &.paragraph-item-selected { + background-color: fade(@primary-6, 15%); + } + } + + .paragraph-item-heading { + padding: 8px 12px; + } + + .paragraph-id { + font-family: monospace; + font-size: 12px; + color: @text-color-secondary; + } + + .paragraph-title { + padding: 0 5px; + } + + .paragraph-first-string { + display: block; + height: 1.8em; + overflow: hidden; + padding-top: 4px; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 12px; + color: @text-color-secondary; + } + + .empty-paragraph-message { + font-size: 1.5em; + color: @text-color-secondary; + text-align: center; + padding: 40px 0; + } + + .code-panel-col { + display: flex; + flex-direction: column; + } + + .code-panel-title { + font-size: 14px; + padding: 5px 0 8px; + } + + .code-panel { + flex: 1; + width: 100%; + min-height: 50vh; + max-height: 70vh; + overflow-y: auto; + border: 1px solid @border-color-base; + border-radius: 4px; + padding: 8px; + margin: 0; + font-size: 13px; + } + + .empty-code-panel { + text-align: center; + display: flex; + align-items: center; + justify-content: center; + font-size: 24px; + color: @text-color-secondary; + } + + ::ng-deep { + .color-green-row { + background-color: fade(@green-6, 15%); + display: block; + color: @green-6; + } + + .color-red-row { + background-color: fade(@red-6, 15%); + display: block; + color: @red-6; + } + + .color-black { + color: inherit; + } + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts index 1876b3cbbdb..3b45e77d44d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts @@ -10,16 +10,204 @@ * limitations under the License. */ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { DatePipe } from '@angular/common'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; +import * as DiffMatchPatch from 'diff-match-patch'; +import { Subscription } from 'rxjs'; + +import { NoteRevisionForCompareReceived, OP, ParagraphItem, RevisionListItem } from '@zeppelin/sdk'; +import { MessageService } from '@zeppelin/services'; + +interface DiffSegment { + type: 'insert' | 'delete' | 'equal'; + text: string; +} + +interface MergedParagraphDiff { + paragraph: ParagraphItem; + firstString: string; + type: 'added' | 'deleted' | 'compared'; + segments?: DiffSegment[]; + identical?: boolean; +} @Component({ selector: 'zeppelin-notebook-revisions-comparator', templateUrl: './revisions-comparator.component.html', styleUrls: ['./revisions-comparator.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [DatePipe] }) -export class NotebookRevisionsComparatorComponent implements OnInit { - constructor() {} +export class NotebookRevisionsComparatorComponent implements OnInit, OnDestroy { + @Input() noteRevisions: RevisionListItem[] = []; + @Input() noteId!: string; + + firstNoteRevisionForCompare: NoteRevisionForCompareReceived | null = null; + secondNoteRevisionForCompare: NoteRevisionForCompareReceived | null = null; + currentFirstRevisionLabel = 'Choose...'; + currentSecondRevisionLabel = 'Choose...'; + mergeNoteRevisionsDiff: MergedParagraphDiff[] = []; + currentParagraphDiffDisplay: MergedParagraphDiff | null = null; + selectedFirstRevisionId: string | null = null; + selectedSecondRevisionId: string | null = null; + private subscription: Subscription | null = null; + private dmp = new DiffMatchPatch(); + + get sortedRevisions(): RevisionListItem[] { + return [...this.noteRevisions].sort((a, b) => (b.time || 0) - (a.time || 0)); + } + + constructor( + private messageService: MessageService, + private cdr: ChangeDetectorRef, + private datePipe: DatePipe + ) {} + + ngOnInit(): void { + this.subscription = this.messageService + .receive(OP.NOTE_REVISION_FOR_COMPARE) + .subscribe((data: NoteRevisionForCompareReceived) => { + if (data.note && data.position) { + if (data.position === 'first') { + this.firstNoteRevisionForCompare = data; + } else { + this.secondNoteRevisionForCompare = data; + } + + if ( + this.firstNoteRevisionForCompare !== null && + this.secondNoteRevisionForCompare !== null && + this.firstNoteRevisionForCompare.revisionId !== this.secondNoteRevisionForCompare.revisionId + ) { + this.compareRevisions(); + } + this.cdr.markForCheck(); + } + }); + } + + getNoteRevisionForReview(revision: RevisionListItem, position: 'first' | 'second'): void { + if (!revision) { + return; + } + if (position === 'first') { + this.currentFirstRevisionLabel = revision.message; + this.selectedFirstRevisionId = revision.id; + } else { + this.currentSecondRevisionLabel = revision.message; + this.selectedSecondRevisionId = revision.id; + } + this.messageService.noteRevisionForCompare(this.noteId, revision.id, position); + } + + onFirstRevisionSelect(revisionId: string): void { + const revision = this.noteRevisions.find(r => r.id === revisionId); + if (revision) { + this.getNoteRevisionForReview(revision, 'first'); + } + } + + onSecondRevisionSelect(revisionId: string): void { + const revision = this.noteRevisions.find(r => r.id === revisionId); + if (revision) { + this.getNoteRevisionForReview(revision, 'second'); + } + } + + onRevisionRowClick(index: number): void { + const sorted = this.sortedRevisions; + if (index < sorted.length - 1) { + this.getNoteRevisionForReview(sorted[index + 1], 'first'); + this.getNoteRevisionForReview(sorted[index], 'second'); + } + } + + compareRevisions(): void { + if (!this.firstNoteRevisionForCompare || !this.secondNoteRevisionForCompare) { + return; + } + const baseParagraphs = this.secondNoteRevisionForCompare.note?.paragraphs || []; + const compareParagraphs = this.firstNoteRevisionForCompare.note?.paragraphs || []; + const paragraphDiffs: MergedParagraphDiff[] = []; + + for (const p1 of baseParagraphs) { + const p2 = compareParagraphs.find((p: ParagraphItem) => p.id === p1.id) || null; + if (p2 === null) { + paragraphDiffs.push({ + paragraph: p1, + firstString: (p1.text || '').split('\n')[0], + type: 'added' + }); + } else { + const text1 = p1.text || ''; + const text2 = p2.text || ''; + const diffResult = this.buildLineDiff(text1, text2); + paragraphDiffs.push({ + paragraph: p1, + segments: diffResult.segments, + identical: diffResult.identical, + firstString: (p1.text || '').split('\n')[0], + type: 'compared' + }); + } + } + + for (const p2 of compareParagraphs) { + const p1 = baseParagraphs.find((p: ParagraphItem) => p.id === p2.id) || null; + if (p1 === null) { + paragraphDiffs.push({ + paragraph: p2, + firstString: (p2.text || '').split('\n')[0], + type: 'deleted' + }); + } + } + + this.mergeNoteRevisionsDiff = paragraphDiffs; + + if (this.currentParagraphDiffDisplay !== null) { + this.changeCurrentParagraphDiffDisplay(this.currentParagraphDiffDisplay.paragraph.id); + } + } + + changeCurrentParagraphDiffDisplay(paragraphId: string): void { + const found = this.mergeNoteRevisionsDiff.find(p => p.paragraph.id === paragraphId); + this.currentParagraphDiffDisplay = found || null; + } + + formatRevisionDate(time: number | undefined): string { + if (!time) { + return ''; + } + return this.datePipe.transform(time * 1000, 'MMMM d yyyy, h:mm:ss a') || ''; + } + + private buildLineDiff(text1: string, text2: string): { segments: DiffSegment[]; identical: boolean } { + const { chars1, chars2, lineArray } = this.dmp.diff_linesToChars_(text1, text2); + const diffs = this.dmp.diff_main(chars1, chars2, false); + this.dmp.diff_charsToLines_(diffs, lineArray); + + let identical = true; + const segments: DiffSegment[] = []; + + for (const [op, text] of diffs) { + if (op === DiffMatchPatch.DIFF_INSERT) { + segments.push({ type: 'insert', text }); + identical = false; + } else if (op === DiffMatchPatch.DIFF_DELETE) { + segments.push({ type: 'delete', text }); + identical = false; + } else { + segments.push({ type: 'equal', text }); + } + } + + return { segments, identical }; + } - ngOnInit() {} + ngOnDestroy(): void { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } } diff --git a/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css b/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css index 6b762b23152..df1106ec293 100644 --- a/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css +++ b/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css @@ -166,6 +166,21 @@ html.dark .ant-menu-submenu-title:hover { color: rgba(255, 255, 255, 0.95) !important; } +html.dark .ant-select-selector { + background-color: #262626 !important; + border-color: #434343 !important; + color: rgba(255, 255, 255, 0.85) !important; +} + +html.dark .ant-select-selector:hover, +html.dark .ant-select-selector:focus { + border-color: #177ddc !important; +} + +html.dark .ant-select-item-option-active:not(html.dark .ant-select-item-option-disabled) { + background-color: #262626 !important; +} + html.dark .ant-dropdown-menu-item-selected, html.dark .ant-dropdown-menu-submenu-title-selected, html.dark .ant-dropdown-menu-item-selected > a, From 4bde6b27dd8f0b6a79479a84532759d358bc2bd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Sat, 7 Mar 2026 01:30:16 +0900 Subject: [PATCH 005/179] [ZEPPELIN-6371] Convert published paragraph rendering to Micro Frontend(Angular to React) in New UI ### What is this PR for? [Micro Frontend Migration(Angular to React) Proposal](https://cwiki.apache.org/confluence/display/ZEPPELIN/Micro+Frontend+Migration%28Angular+to+React%29+Proposal) --- #### Summary * Implement React-based micro-frontend architecture using Module Federation. * Convert published paragraph component to support React rendering. * Add environment-based configuration for development and production builds. #### Changes **1. React Micro-Frontend Project Setup** * Created new React project at `projects/zeppelin-react/`. * Configured Webpack Module Federation for micro-frontend architecture. * Set up React 18 with TypeScript support. **2. Component Implementation** *New React Components:* * `PublishedParagraph`: Main entry point for published paragraph rendering. * `SingleResultRenderer`: Template for rendering single paragraph results. *Renderers:* * `HTMLRenderer`: Renders HTML content with sanitization. * `TextRenderer`: Renders plain text with ANSI support. * `ImageRenderer`: Renders image outputs. *Visualizations:* * `TableVisualization`: Table rendering with sorting, filtering, and export. * `VisualizationControls`: Control panel for table operations. *Common Components:* * `Loading`: Loading state indicator. * `Empty`: Empty state display. **3. Angular Integration** * `paragraph.component.ts`: Added React widget loading logic via Module Federation. * `paragraph.component.html`: Added React container element. * `environment.ts` / `environment.prod.ts`: Added `reactRemoteEntryUrl` configuration. * Development: `http://localhost:3001/remoteEntry.js` * Production: `/assets/react/remoteEntry.js` **4. Build Configuration** * `angular.json`: Copy React build output to `/assets/react/`. * `webpack.config.js`: Configured Module Federation plugin: * Dev server: port 3001 * CORS headers for cross-origin requests * Environment-specific `publicPath` * `proxy.conf.js`: Updated proxy configuration. **5. Package** * Added React and React-DOM dependencies. * Added Webpack and Module Federation plugins. * Added Ant Design for React UI components. * Added antv/g2plot for data visualization (also used in Angular version with G2). #### License This PR uses several open-source libraries. The `xlsx` (v0.18.5) and `typescript` (v4.6.4) packages are licensed under **Apache-2.0**, while all other dependencies and devDependencies (such as `react`, `react-dom`, `antd`, `ant-design/icons`, etc.) are licensed under **MIT**. The MIT license is more permissive than Apache-2.0, so including MIT-licensed packages does not violate Apache-2.0 terms. All packages may be used commercially, and license notices should be included when distributing the project. #### Technical Details **Module Federation Configuration** ```ts // Development: http://localhost:3001/remoteEntry.js // Production: /assets/react/remoteEntry.js new ModuleFederationPlugin({ name: 'reactApp', filename: 'remoteEntry.js', exposes: { './PublishedParagraph': './src/pages/PublishedParagraph' } }) ``` #### Usage * Render published paragraph with React: `/notebook/{noteId}/paragraph/{paragraphId}?react=true` ### What type of PR is it? Improvement ### Todos ### What is the Jira issue? ZEPPELIN-6371 ### How should this be tested? ```sh // Start Zeppelin Server ./mvnw clean install -DskipTests ./mvnw clean package -DskipTests ./bin/zeppelin-daemon.sh start // Start Zeppelin New UI Client cd zeppelin-web-angular nvm use npm i npm run start ``` #### TextRenderer http://localhost:4200/#/notebook/2EYDJKFFY/paragraph/20180118-122136_1299905608?react=true #### TableVisualization http://localhost:4200/#/notebook/2EYDJKFFY/paragraph/20180118-122136_1299905608?react=true #### ImageRenderer http://localhost:4200/#/notebook/2F1S9ZY8Z/paragraph/20180117-220535_590781730?react=true #### HTMLRenderer - Table http://localhost:4200/#/notebook/2F1S9ZY8Z/paragraph/paragraph_1580885453474_1167659991?react=true #### HTMLRenderer - Script(Bokeh JS) http://localhost:4200/#/notebook/2F1S9ZY8Z/paragraph/paragraph_1580885707198_-1652524072?react=true ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5111 from dididy/feature/micro-frontend. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/.gitignore | 4 +- zeppelin-web-angular/angular.json | 24 +- zeppelin-web-angular/e2e/models/home-page.ts | 12 + .../e2e/models/published-paragraph-page.ts | 6 +- .../e2e/models/workspace-page.util.ts | 12 + .../published/published-paragraph.spec.ts | 205 +- .../e2e/tests/theme/dark-mode.spec.ts | 31 +- zeppelin-web-angular/e2e/utils.ts | 4 +- zeppelin-web-angular/package-lock.json | 632 + zeppelin-web-angular/package.json | 13 +- zeppelin-web-angular/playwright.config.js | 4 +- .../projects/zeppelin-react/.eslintrc.json | 53 + .../projects/zeppelin-react/.gitignore | 2 + .../projects/zeppelin-react/README.md | 100 + .../projects/zeppelin-react/package-lock.json | 10100 ++++++++++++++++ .../projects/zeppelin-react/package.json | 45 + .../src/components/common/Empty.tsx | 17 + .../src/components/common/Loading.tsx | 24 + .../src/components/common/index.ts | 14 + .../zeppelin-react/src/components/index.ts | 15 + .../src/components/renderers/HTMLRenderer.css | 59 + .../src/components/renderers/HTMLRenderer.tsx | 61 + .../components/renderers/ImageRenderer.tsx | 23 + .../src/components/renderers/TextRenderer.tsx | 26 + .../src/components/renderers/index.ts | 15 + .../visualizations/TableVisualization.tsx | 153 + .../visualizations/VisualizationControls.tsx | 67 + .../src/components/visualizations/index.ts | 14 + .../projects/zeppelin-react/src/index.html | 23 + .../projects/zeppelin-react/src/main.ts | 13 + .../src/pages/PublishedParagraph.tsx | 68 + .../zeppelin-react/src/pages/index.ts | 13 + .../src/templates/SingleResultRenderer.tsx | 48 + .../zeppelin-react/src/templates/index.ts | 13 + .../zeppelin-react/src/utils/exportFile.ts | 48 + .../zeppelin-react/src/utils/index.ts | 15 + .../zeppelin-react/src/utils/tableUtils.ts | 26 + .../zeppelin-react/src/utils/textUtils.ts | 35 + .../projects/zeppelin-react/tsconfig.json | 28 + .../projects/zeppelin-react/webpack.config.js | 130 + zeppelin-web-angular/proxy.conf.js | 8 +- .../paragraph/paragraph.component.html | 39 +- .../paragraph/paragraph.component.ts | 101 +- .../src/environments/environment.prod.ts | 3 +- .../src/environments/environment.ts | 3 +- .../{webpack.partial.js => webpack.config.js} | 22 + 46 files changed, 12199 insertions(+), 172 deletions(-) create mode 100644 zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json create mode 100644 zeppelin-web-angular/projects/zeppelin-react/.gitignore create mode 100644 zeppelin-web-angular/projects/zeppelin-react/README.md create mode 100644 zeppelin-web-angular/projects/zeppelin-react/package-lock.json create mode 100644 zeppelin-web-angular/projects/zeppelin-react/package.json create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/common/Empty.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/common/Loading.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/common/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.css create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/ImageRenderer.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/TextRenderer.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/VisualizationControls.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/index.html create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/main.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/pages/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/templates/SingleResultRenderer.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/templates/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/utils/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/utils/tableUtils.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/utils/textUtils.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/tsconfig.json create mode 100644 zeppelin-web-angular/projects/zeppelin-react/webpack.config.js rename zeppelin-web-angular/{webpack.partial.js => webpack.config.js} (68%) diff --git a/zeppelin-web-angular/.gitignore b/zeppelin-web-angular/.gitignore index 906a7afcfe4..f285d87e9b1 100644 --- a/zeppelin-web-angular/.gitignore +++ b/zeppelin-web-angular/.gitignore @@ -1,12 +1,12 @@ # See http://help.github.com/ignore-files/ for more about ignoring files. # compiled output -/dist +**/dist /tmp /out-tsc # dependencies -/node_modules +**/node_modules # profiling files chrome-profiler-events.json diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json index dcd3bb2afc3..dbd234a7ff7 100644 --- a/zeppelin-web-angular/angular.json +++ b/zeppelin-web-angular/angular.json @@ -38,13 +38,16 @@ }, "architect": { "build": { - "builder": "ngx-build-plus:browser", + "builder": "@angular-builders/custom-webpack:browser", "options": { "outputPath": "dist/zeppelin", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "src/tsconfig.json", + "customWebpackConfig": { + "path": "./webpack.config.js" + }, "assets": [ "src/favicon.ico", "src/assets", @@ -62,6 +65,11 @@ "glob": "**/*", "input": "./WEB-INF", "output": "/WEB-INF/" + }, + { + "glob": "**/*", + "input": "./projects/zeppelin-react/dist", + "output": "/assets/react/" } ], "styles": [ @@ -100,7 +108,6 @@ "optimization": true, "outputHashing": "all", "sourceMap": false, - "extractCss": true, "namedChunks": false, "aot": true, "extractLicenses": true, @@ -108,19 +115,22 @@ "buildOptimizer": false }, "development": { - "buildOptimizer": false, "optimization": false, - "vendorChunk": true, "extractLicenses": false, "namedChunks": true, "sourceMap": true } - } + }, + "defaultConfiguration": "production" }, "serve": { - "builder": "ngx-build-plus:dev-server", + "builder": "@angular-builders/custom-webpack:dev-server", "options": { - "browserTarget": "zeppelin:build" + "browserTarget": "zeppelin:build", + "port": 4200, + "host": "localhost", + "liveReload": true, + "hmr": true }, "configurations": { "production": { diff --git a/zeppelin-web-angular/e2e/models/home-page.ts b/zeppelin-web-angular/e2e/models/home-page.ts index 52c39df8b33..81f5085790e 100644 --- a/zeppelin-web-angular/e2e/models/home-page.ts +++ b/zeppelin-web-angular/e2e/models/home-page.ts @@ -89,6 +89,11 @@ export class HomePage extends BasePage { }; } + async navigateToHome(): Promise { + await this.page.goto('/'); + await this.waitForPageLoad(); + } + async navigateToLogin(): Promise { await this.navigateToRoute('/login'); // Wait for potential redirect to complete by checking URL change @@ -152,9 +157,16 @@ export class HomePage extends BasePage { } async filterNotes(searchTerm: string): Promise { + await this.page.waitForLoadState('domcontentloaded', { timeout: 10000 }); + await this.nodeList.filterInput.waitFor({ state: 'visible', timeout: 5000 }); await this.nodeList.filterInput.fill(searchTerm, { timeout: 15000 }); } + async isRefreshIconSpinning(): Promise { + const spinAttribute = await this.refreshIcon.getAttribute('nzSpin'); + return spinAttribute === 'true' || spinAttribute === ''; + } + async waitForRefreshToComplete(): Promise { await this.waitForElementAttribute('a.refresh-note i[nz-icon]', 'nzSpin', false); } diff --git a/zeppelin-web-angular/e2e/models/published-paragraph-page.ts b/zeppelin-web-angular/e2e/models/published-paragraph-page.ts index 0bc6997cfdf..13293c528e5 100644 --- a/zeppelin-web-angular/e2e/models/published-paragraph-page.ts +++ b/zeppelin-web-angular/e2e/models/published-paragraph-page.ts @@ -15,14 +15,12 @@ import { navigateToNotebookWithFallback } from '../utils'; import { BasePage } from './base-page'; export class PublishedParagraphPage extends BasePage { - readonly paragraphResult: Locator; - readonly errorModalContent: Locator; - readonly errorModalOkButton: Locator; + private readonly errorModalContent: Locator; + private readonly errorModalOkButton: Locator; readonly confirmationModal: Locator; constructor(page: Page) { super(page); - this.paragraphResult = page.locator('zeppelin-notebook-paragraph-result'); this.errorModalContent = this.page.locator('.ant-modal-body', { hasText: 'Paragraph Not Found' }).last(); this.errorModalOkButton = page.getByRole('button', { name: 'OK' }).last(); this.confirmationModal = page.locator('div.ant-modal-confirm').last(); diff --git a/zeppelin-web-angular/e2e/models/workspace-page.util.ts b/zeppelin-web-angular/e2e/models/workspace-page.util.ts index fd6d9c3f450..8ed557b66de 100644 --- a/zeppelin-web-angular/e2e/models/workspace-page.util.ts +++ b/zeppelin-web-angular/e2e/models/workspace-page.util.ts @@ -13,6 +13,7 @@ import { expect, Page } from '@playwright/test'; import { BasePage } from './base-page'; import { WorkspacePage } from './workspace-page'; +import { performLoginIfRequired, waitForZeppelinReady } from '../utils'; export class WorkspaceUtil extends BasePage { private workspacePage: WorkspacePage; @@ -22,6 +23,17 @@ export class WorkspaceUtil extends BasePage { this.workspacePage = new WorkspacePage(page); } + async navigateAndWaitForLoad(): Promise { + await this.workspacePage.navigateToWorkspace(); + await performLoginIfRequired(this.page); + await waitForZeppelinReady(this.page); + } + + async verifyWorkspaceLayout(): Promise { + await expect(this.workspacePage.workspaceComponent).toBeVisible(); + await expect(this.workspacePage.routerOutlet).toBeAttached(); + } + async verifyHeaderVisibility(shouldBeVisible: boolean): Promise { if (shouldBeVisible) { await expect(this.workspacePage.zeppelinHeader).toBeVisible(); diff --git a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts index 2c35369bd0c..b15facedc77 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts @@ -51,12 +51,9 @@ test.describe('Published Paragraph', () => { await publishedParagraphPage.navigateToPublishedParagraph(nonExistentIds.noteId, nonExistentIds.paragraphId); - // Directly assert that the modal appears and contains the expected text - const modal = page.locator('.ant-modal:has-text("Notebook not found")').last(); - await expect(modal).toBeVisible({ timeout: 10000 }); // Expect the modal to be visible - - const modalContent = await modal.textContent(); - expect(modalContent?.toLowerCase()).toContain('not found'); + const modal = page.locator('.ant-modal', { hasText: /not found/i }).last(); + await expect(modal).toBeVisible({ timeout: 10000 }); + await expect(modal).toContainText(/not found/i); }); test('should show error modal when paragraph does not exist in valid notebook', async ({ page }) => { @@ -65,18 +62,12 @@ test.describe('Published Paragraph', () => { await testUtil.navigateToPublishedParagraph(validNoteId, nonExistentParagraphId); - // Expect a specific error modal const errorModal = page.locator('.ant-modal', { hasText: /Paragraph Not Found|not found|Error/i }); await expect(errorModal).toBeVisible({ timeout: 10000 }); - - // Verify modal content includes the invalid paragraph ID - const content = await testUtil.getErrorModalContent(); - expect(content).toBeDefined(); - expect(content).toContain(nonExistentParagraphId); + await expect(errorModal).toContainText(nonExistentParagraphId); await testUtil.clickErrorModalOk(); - // Wait for redirect to home page await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 }); }); @@ -85,16 +76,13 @@ test.describe('Published Paragraph', () => { await publishedParagraphPage.navigateToPublishedParagraph(nonExistentIds.noteId, nonExistentIds.paragraphId); - const modal = page.locator('.ant-modal', { hasText: 'Paragraph Not Found' }).last(); - const isModalVisible = await modal.isVisible(); + // Modal must appear — we navigated to non-existent IDs + const modal = page.locator('.ant-modal').last(); + await expect(modal).toBeVisible({ timeout: 10000 }); - if (isModalVisible) { - await publishedParagraphPage.okButton.click(); + await publishedParagraphPage.okButton.click(); - await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 }); - } else { - await expect(page).toHaveURL(/\/#\/$/, { timeout: 5000 }); - } + await expect(page).toHaveURL(/\/#\/$/, { timeout: 10000 }); }); }); @@ -102,86 +90,74 @@ test.describe('Published Paragraph', () => { test('should enter published paragraph by clicking link', async ({ page }) => { const { noteId, paragraphId } = testNotebook; - // Navigate to the normal notebook view await page.goto(`/#/notebook/${noteId}`); await page.waitForLoadState('networkidle'); - // Find the first paragraph - let paragraphElement = page.locator(`zeppelin-notebook-paragraph[data-testid="${paragraphId}"]`); - if ((await paragraphElement.count()) === 0) { - paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); - } - + // createTestNotebook creates a single paragraph, so .first() is the target + const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); await expect(paragraphElement).toBeVisible({ timeout: 10000 }); - // Click the settings button to open the dropdown const settingsButton = paragraphElement.locator('a[nz-dropdown]'); await settingsButton.click(); - // Click "Link this paragraph" in the dropdown menu - const linkParagraphButton = page.locator('li.list-item:has-text("Link this paragraph")'); + const linkParagraphButton = page.locator('li.list-item', { hasText: 'Link this paragraph' }); await expect(linkParagraphButton).toBeVisible(); - // Handle the new page/tab that opens const [newPage] = await Promise.all([page.waitForEvent('popup'), linkParagraphButton.click()]); await newPage.waitForLoadState(); - // Verify the new page URL shows published paragraph await expect(newPage).toHaveURL(new RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 10000 }); - const codeEditor = newPage.locator('zeppelin-notebook-paragraph-code-editor'); - await expect(codeEditor).toBeHidden(); - - const controlPanel = newPage.locator('zeppelin-notebook-paragraph-control'); - await expect(controlPanel).toBeHidden(); + // Published mode hides editing controls + await expect(newPage.locator('zeppelin-notebook-paragraph-code-editor')).toBeHidden(); + await expect(newPage.locator('zeppelin-notebook-paragraph-control')).toBeHidden(); }); - test('should enter published paragraph by direct URL navigation', async ({ page }) => { + test('should load published paragraph component by direct URL navigation', async ({ page }) => { await page.goto(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`); await page.waitForLoadState('networkidle'); - await expect(page).toHaveURL(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`, { - timeout: 10000 - }); + + await expect(page).toHaveURL( + new RegExp(`/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}`) + ); + await expect(page.locator('zeppelin-publish-paragraph')).toBeAttached({ timeout: 10000 }); }); - test('should allow running paragraph via confirmation modal in published mode', async ({ page }) => { + test('should load published paragraph and keep component attached after modal confirmation', async ({ page }) => { const { noteId, paragraphId } = testNotebook; - // Given: Navigate to a specific paragraph's published URL await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`); await page.waitForLoadState('networkidle'); - // Then: URL should correctly preserve both notebook and paragraph identifiers - await expect(page).toHaveURL(new RegExp(`/notebook/${noteId}/paragraph/${paragraphId}`), { timeout: 15000 }); - - // Verify URL contains the specific notebook and paragraph context - expect(page.url()).toContain(noteId); - expect(page.url()).toContain(paragraphId); - - // Then: Published paragraph component should be loaded (indicating published mode is active) const publishedContainer = page.locator('zeppelin-publish-paragraph'); - await publishedContainer.waitFor({ state: 'attached', timeout: 10000 }); + await expect(publishedContainer).toBeAttached({ timeout: 10000 }); - // Then: Confirmation modal should appear for paragraph execution + // Confirmation modal should appear for paragraph execution const modal = page.locator('.ant-modal'); await expect(modal).toBeVisible({ timeout: 20000 }); - // Handle the execution confirmation to complete the published mode setup - await expect(publishedParagraphPage.runButton).toBeVisible(); await publishedParagraphPage.runButton.click(); await expect(modal).not.toBeVisible({ timeout: 10000 }); - // Then: Published container should remain attached and page should be in published mode + // Published container should remain attached after modal dismissal await expect(publishedContainer).toBeAttached({ timeout: 10000 }); + }); - // Verify we're in published mode by checking for the published component - const isPublishedMode = await page.evaluate(() => document.querySelector('zeppelin-publish-paragraph') !== null); - expect(isPublishedMode).toBe(true); + test('should render React micro-frontend instead of Angular result component', async ({ page }) => { + await test.step('Given I navigate to React mode URL', async () => { + await page.goto(`/#/notebook/${testNotebook.noteId}/paragraph/${testNotebook.paragraphId}?react=true`); + await waitForZeppelinReady(page); + }); - const paragraphContainer = page.locator('zeppelin-publish-paragraph'); + await test.step('Then Angular result component should not be rendered', async () => { + await expect(page.locator('zeppelin-notebook-paragraph-result')).toHaveCount(0, { timeout: 10000 }); + }); - // Published component should be present - await expect(paragraphContainer).toBeAttached(); + await test.step('And React widget should be mounted in the container', async () => { + // React mount() renders
or (Alert) + const reactContent = page.locator('[data-testid="react-published-paragraph"], .ant-alert'); + await expect(reactContent).toBeAttached({ timeout: 15000 }); + }); }); }); @@ -192,33 +168,21 @@ test.describe('Published Paragraph', () => { await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}`); await page.waitForLoadState('networkidle'); - // In published mode, code editor and control panel should be hidden - const codeEditor = page.locator('zeppelin-notebook-paragraph-code-editor'); - const controlPanel = page.locator('zeppelin-notebook-paragraph-control'); - - await expect(codeEditor).toBeHidden(); - await expect(controlPanel).toBeHidden(); + await expect(page.locator('zeppelin-publish-paragraph')).toBeAttached({ timeout: 10000 }); + await expect(page.locator('zeppelin-notebook-paragraph-code-editor')).toBeHidden(); + await expect(page.locator('zeppelin-notebook-paragraph-control')).toBeHidden(); }); }); test.describe('Confirmation Modal and Execution', () => { - test('should show confirmation modal and allow running the paragraph', async ({ page }) => { + test('should show confirmation modal with code preview and allow running', async ({ page }) => { const { noteId, paragraphId } = testNotebook; await publishedParagraphPage.navigateToNotebook(noteId); + // Verify paragraph has no results yet const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); - const paragraphResult = paragraphElement.locator('zeppelin-notebook-paragraph-result'); - - // Only clear output if result exists - if (await paragraphResult.isVisible()) { - const settingsButton = paragraphElement.locator('a[nz-dropdown]'); - await settingsButton.click(); - - const clearOutputButton = page.locator('li.list-item:has-text("Clear output")'); - await clearOutputButton.click(); - await expect(paragraphResult).toBeHidden(); - } + await expect(paragraphElement.locator('zeppelin-notebook-paragraph-result')).toBeHidden(); await publishedParagraphPage.navigateToPublishedParagraph(noteId, paragraphId); @@ -227,64 +191,55 @@ test.describe('Published Paragraph', () => { const modal = publishedParagraphPage.confirmationModal; await expect(modal).toBeVisible(); - // Check for the enhanced modal content + // Modal title await expect(publishedParagraphPage.modalTitle).toHaveText('Run Paragraph?'); - // Verify that the modal shows code preview - await expect(publishedParagraphPage.modalBody.locator('.ant-modal-confirm-content')).toContainText( - 'This paragraph contains the following code:' - ); - await expect(publishedParagraphPage.modalBody.locator('.ant-modal-confirm-content')).toContainText( - 'Would you like to execute this code?' - ); + // Code preview content + const modalContent = modal.locator('.ant-modal-confirm-content'); + await expect(modalContent).toContainText('This paragraph contains the following code:'); + await expect(modalContent).toContainText('Would you like to execute this code?'); + + // Code preview element + const codePreview = modalContent.locator('pre, code, .code-preview, [class*="code"]').first(); + await expect(codePreview).toBeVisible(); - // Click the Run button in the modal (OK button in confirmation modal) - const runButton = modal.locator('.ant-modal-confirm-btns .ant-btn-primary'); - await expect(runButton).toBeVisible(); - await runButton.click(); + // Run and Cancel buttons + await expect(publishedParagraphPage.runButton).toBeVisible(); + await expect(publishedParagraphPage.cancelButton).toBeVisible(); + + // Execute and verify modal dismissal + await publishedParagraphPage.runButton.click(); await expect(modal).toBeHidden(); }); - test('should show confirmation modal for paragraphs without results', async ({ page }) => { + test('should show confirmation modal in React mode and allow running', async ({ page }) => { const { noteId, paragraphId } = testNotebook; - await publishedParagraphPage.navigateToNotebook(noteId); - - const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); - const settingsButton = paragraphElement.locator('a[nz-dropdown]'); - await settingsButton.click(); - - const clearOutputButton = page.locator('li.list-item:has-text("Clear output")'); - await clearOutputButton.click(); - await expect(paragraphElement.locator('[data-testid="paragraph-result"]')).toBeHidden(); - - await publishedParagraphPage.navigateToPublishedParagraph(noteId, paragraphId); + await test.step('Given paragraph has no results in normal notebook view', async () => { + await publishedParagraphPage.navigateToNotebook(noteId); - const modal = publishedParagraphPage.confirmationModal; - await expect(modal).toBeVisible(); + const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); + await expect(paragraphElement.locator('zeppelin-notebook-paragraph-result')).toBeHidden(); + }); - // Check for the enhanced modal content - await expect(publishedParagraphPage.modalTitle).toContainText('Run Paragraph?'); + await test.step('When I navigate to React mode published paragraph URL', async () => { + await page.goto(`/#/notebook/${noteId}/paragraph/${paragraphId}?react=true`); + await waitForZeppelinReady(page); + }); - // Check that code preview is shown - await expect(publishedParagraphPage.modalBody.first()).toContainText( - 'This paragraph contains the following code:' - ); - await expect(publishedParagraphPage.modalBody.first()).toContainText('Would you like to execute this code?'); + await test.step('Then confirmation modal should appear and allow execution', async () => { + const modal = publishedParagraphPage.confirmationModal; + await expect(modal).toBeVisible({ timeout: 30000 }); - // Verify that the code preview area exists - const codePreview = publishedParagraphPage.modalBody - .locator('pre, code, .code-preview, .highlight, [class*="code"]') - .first(); - await expect(codePreview).toBeVisible(); + await expect(publishedParagraphPage.modalTitle).toHaveText('Run Paragraph?'); - // Check for Run and Cancel buttons - await expect(publishedParagraphPage.runButton).toBeVisible(); - await expect(publishedParagraphPage.cancelButton).toBeVisible(); + const modalContent = modal.locator('.ant-modal-confirm-content'); + await expect(modalContent).toContainText('This paragraph contains the following code:'); + await expect(modalContent).toContainText('Would you like to execute this code?'); - // Click the Run button in the modal - await publishedParagraphPage.runButton.click(); - await expect(modal).toBeHidden(); + await publishedParagraphPage.runButton.click(); + await expect(modal).toBeHidden(); + }); }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts index 76e9f77e614..61a15e26d1b 100644 --- a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts +++ b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts @@ -18,7 +18,11 @@ test.describe('Dark Mode Theme Switching', () => { addPageAnnotationBeforeEach(PAGES.SHARE.THEME_TOGGLE); let darkModePage: DarkModePage; - test.beforeEach(async ({ page }) => { + test.beforeEach(async ({ page, browserName }) => { + // TODO: This crash occurs only on WebKit. The root cause should be investigated and addressed. + if (browserName === 'webkit') { + test.skip(); + } darkModePage = new DarkModePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); @@ -30,7 +34,7 @@ test.describe('Dark Mode Theme Switching', () => { await darkModePage.clearLocalStorage(); }); - test('Scenario: User can switch to dark mode and persistence is maintained', async ({ page }) => { + test('Scenario: User can switch to dark mode and persistence is maintained', async ({ page, browserName }) => { // GIVEN: User is on the main page, which starts in 'system' mode by default (localStorage cleared). await test.step('GIVEN the page starts in system mode', async () => { await darkModePage.assertSystemTheme(); // Robot icon for system theme @@ -41,7 +45,12 @@ test.describe('Dark Mode Theme Switching', () => { await darkModePage.setThemeInLocalStorage('light'); await page.waitForTimeout(500); // Reload the page to apply localStorage theme changes - await page.reload(); + if (browserName === 'webkit') { + const currentUrl = page.url(); + await page.goto(currentUrl, { waitUntil: 'load' }); + } else { + await page.reload(); + } await waitForZeppelinReady(page); await darkModePage.assertLightTheme(); // Now it should be light mode with sun icon }); @@ -51,8 +60,24 @@ test.describe('Dark Mode Theme Switching', () => { await darkModePage.setThemeInLocalStorage('dark'); await page.waitForTimeout(500); // Reload the page to apply localStorage theme changes + if (browserName === 'webkit') { + const currentUrl = page.url(); + await page.goto(currentUrl, { waitUntil: 'load' }); + } else { + await page.reload(); + } + await waitForZeppelinReady(page); + await darkModePage.assertDarkTheme(); + }); + + // AND: User refreshes the page. + await test.step('AND the user refreshes the page', async () => { await page.reload(); await waitForZeppelinReady(page); + }); + + // THEN: Dark mode is maintained after refresh. + await test.step('THEN dark mode is maintained after refresh', async () => { await darkModePage.assertDarkTheme(); }); diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index d4fd455a972..efd60965320 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -142,7 +142,8 @@ export const flattenPageComponents = (pages: PageStructureType): string[] => { export const getCoverageTransformPaths = (): string[] => flattenPageComponents(PAGES); export const waitForUrlNotContaining = async (page: Page, fragment: string) => { - await page.waitForURL(url => !url.toString().includes(fragment)); + await page.waitForLoadState('domcontentloaded', { timeout: 10000 }); + await page.waitForURL(url => !url.toString().includes(fragment), { timeout: 15000 }); }; export const getCurrentPath = (page: Page): string => { @@ -194,6 +195,7 @@ export const performLoginIfRequired = async (page: Page): Promise => { try { await page.waitForSelector('zeppelin-login', { state: 'hidden', timeout: 30000 }); await page.waitForSelector('text=Welcome to Zeppelin!', { timeout: 30000 }); + await page.waitForLoadState('networkidle'); await page.waitForSelector('zeppelin-node-list', { timeout: 30000 }); await waitForZeppelinReady(page); return true; diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index 5ab8288a0f0..d1514207327 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -43,6 +43,8 @@ "zone.js": "~0.11.4" }, "devDependencies": { + "@angular-architects/module-federation": "13.0.1", + "@angular-builders/custom-webpack": "13.1.0", "@angular-devkit/build-angular": "^13.3.11", "@angular-eslint/builder": "13.5.0", "@angular-eslint/eslint-plugin": "13.5.0", @@ -64,6 +66,7 @@ "@types/webpack-env": "^1.18.8", "@typescript-eslint/eslint-plugin": "5.62.0", "@typescript-eslint/parser": "5.62.0", + "concurrently": "9.2.1", "cross-env": "^10.1.0", "dotenv": "^17.2.3", "eslint": "^8.57.1", @@ -99,6 +102,139 @@ "node": ">=6.0.0" } }, + "node_modules/@angular-architects/module-federation": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@angular-architects/module-federation/-/module-federation-13.0.1.tgz", + "integrity": "sha512-NFf/UOsP/MjyzaqgDynVYvtoaBKogXTQNAVYGNra/dKwrr2O9gJ7njrjzUih5M2KuG6oJaOvl0D/Dop4PES1FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-architects/module-federation-runtime": "^13.0.1", + "callsite": "^1.0.0", + "ngx-build-plus": "^13.0.0", + "node-fetch": "^2.6.1", + "rxjs": "~6.6.3", + "semver": "^7.3.5", + "word-wrap": "^1.2.3" + } + }, + "node_modules/@angular-architects/module-federation-runtime": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@angular-architects/module-federation-runtime/-/module-federation-runtime-13.0.1.tgz", + "integrity": "sha512-lvXmdCN+/JJMDm3h+FlNPc+lwFgNC3/J7Dr5h6ZHXT6sGgelcUQPpGxO1QUiE87XmUG8/Gdo57CebS0TKCklyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=12.0.0", + "@angular/core": ">=12.0.0" + } + }, + "node_modules/@angular-architects/module-federation/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-architects/module-federation/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/@angular-builders/custom-webpack": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-13.1.0.tgz", + "integrity": "sha512-qhtnAv1i7agk14zeKZZfXjrckYt37OZ+3tsTBLhf3ZFbwREK8L1SNi8xhZ1j1JLGsf2Dp0GEcZrSYeFDweo0WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": ">=0.1300.0 < 0.1400.0", + "@angular-devkit/build-angular": "^13.0.0", + "@angular-devkit/core": "^13.0.0", + "lodash": "^4.17.15", + "ts-node": "^10.0.0", + "tsconfig-paths": "^3.9.0", + "webpack-merge": "^5.7.3" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/@angular-builders/custom-webpack/node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/@angular-devkit/architect": { "version": "0.1303.11", "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.11.tgz", @@ -3014,6 +3150,30 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@csstools/postcss-progressive-custom-properties": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", @@ -4174,6 +4334,34 @@ "node": ">= 6" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/angular": { "version": "1.8.9", "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.9.tgz", @@ -5243,6 +5431,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", @@ -5527,6 +5728,13 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -6232,6 +6440,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -6675,6 +6892,87 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", @@ -6921,6 +7219,13 @@ "node": ">=0.8" } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/critters": { "version": "0.0.16", "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", @@ -12794,6 +13099,27 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-forge": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", @@ -15863,6 +16189,19 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -16813,6 +17152,13 @@ "topoquantize": "bin/topoquantize" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -17255,6 +17601,13 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/validate-npm-package-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", @@ -17326,6 +17679,13 @@ "defaults": "^1.0.3" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/webpack": { "version": "5.102.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", @@ -17600,6 +17960,17 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -17989,6 +18360,97 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, + "@angular-architects/module-federation": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@angular-architects/module-federation/-/module-federation-13.0.1.tgz", + "integrity": "sha512-NFf/UOsP/MjyzaqgDynVYvtoaBKogXTQNAVYGNra/dKwrr2O9gJ7njrjzUih5M2KuG6oJaOvl0D/Dop4PES1FQ==", + "dev": true, + "requires": { + "@angular-architects/module-federation-runtime": "^13.0.1", + "callsite": "^1.0.0", + "ngx-build-plus": "^13.0.0", + "node-fetch": "^2.6.1", + "rxjs": "~6.6.3", + "semver": "^7.3.5", + "word-wrap": "^1.2.3" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-architects/module-federation-runtime": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@angular-architects/module-federation-runtime/-/module-federation-runtime-13.0.1.tgz", + "integrity": "sha512-lvXmdCN+/JJMDm3h+FlNPc+lwFgNC3/J7Dr5h6ZHXT6sGgelcUQPpGxO1QUiE87XmUG8/Gdo57CebS0TKCklyQ==", + "dev": true, + "requires": { + "tslib": "^2.0.0" + } + }, + "@angular-builders/custom-webpack": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-13.1.0.tgz", + "integrity": "sha512-qhtnAv1i7agk14zeKZZfXjrckYt37OZ+3tsTBLhf3ZFbwREK8L1SNi8xhZ1j1JLGsf2Dp0GEcZrSYeFDweo0WA==", + "dev": true, + "requires": { + "@angular-devkit/architect": ">=0.1300.0 < 0.1400.0", + "@angular-devkit/build-angular": "^13.0.0", + "@angular-devkit/core": "^13.0.0", + "lodash": "^4.17.15", + "ts-node": "^10.0.0", + "tsconfig-paths": "^3.9.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } + }, "@angular-devkit/architect": { "version": "0.1303.11", "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.11.tgz", @@ -20127,6 +20589,27 @@ "@babel/helper-validator-identifier": "^7.28.5" } }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, "@csstools/postcss-progressive-custom-properties": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", @@ -20978,6 +21461,30 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, "@types/angular": { "version": "1.8.9", "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.9.tgz", @@ -21832,6 +22339,15 @@ "dev": true, "requires": {} }, + "acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "requires": { + "acorn": "^8.11.0" + } + }, "adjust-sourcemap-loader": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", @@ -22033,6 +22549,12 @@ "readable-stream": "^3.6.0" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -22538,6 +23060,12 @@ "get-intrinsic": "^1.3.0" } }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -22859,6 +23387,61 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "requires": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "connect-history-api-fallback": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", @@ -23033,6 +23616,12 @@ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "critters": { "version": "0.0.16", "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", @@ -27257,6 +27846,15 @@ "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true }, + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-forge": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.2.tgz", @@ -29452,6 +30050,12 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true + }, "side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -30129,6 +30733,12 @@ "commander": "2" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, "tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -30454,6 +31064,12 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "validate-npm-package-name": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", @@ -30513,6 +31129,12 @@ "defaults": "^1.0.3" } }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, "webpack": { "version": "5.102.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.102.1.tgz", @@ -30697,6 +31319,16 @@ "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 43333365308..2bf5deaff5a 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -3,10 +3,14 @@ "version": "0.0.0", "scripts": { "prepare": "cd .. && husky", - "postinstall": "npm run build:projects && npx playwright install --with-deps", + "postinstall": "npm run build:projects && npx playwright install --with-deps && cd projects/zeppelin-react && npm install", "ng": "./node_modules/.bin/ng", - "start": "ng serve --proxy-config proxy.conf.js --extra-webpack-config webpack.partial.js", - "build": "ng build --configuration production --extra-webpack-config webpack.partial.js", + "start": "concurrently \"npm run start:react\" \"npm run start:angular\"", + "start:angular": "ng serve --proxy-config proxy.conf.js", + "start:react": "cd projects/zeppelin-react && npm run dev", + "build": "npm run build:projects && npm run build:react && npm run build:angular", + "build:angular": "ng build --configuration production", + "build:react": "cd projects/zeppelin-react && npm run build", "build:projects": "npm run build-project:sdk && npm run build-project:vis", "build-project:sdk": "ng build --project zeppelin-sdk", "build-project:vis": "ng build --project zeppelin-visualization", @@ -61,6 +65,8 @@ "zone.js": "~0.11.4" }, "devDependencies": { + "@angular-architects/module-federation": "13.0.1", + "@angular-builders/custom-webpack": "13.1.0", "@angular-devkit/build-angular": "^13.3.11", "@angular-eslint/builder": "13.5.0", "@angular-eslint/eslint-plugin": "13.5.0", @@ -82,6 +88,7 @@ "@types/webpack-env": "^1.18.8", "@typescript-eslint/eslint-plugin": "5.62.0", "@typescript-eslint/parser": "5.62.0", + "concurrently": "9.2.1", "cross-env": "^10.1.0", "dotenv": "^17.2.3", "eslint": "^8.57.1", diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index 496383e139e..6e3e664bf07 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -19,8 +19,8 @@ module.exports = defineConfig({ globalTeardown: require.resolve('./e2e/global-teardown'), fullyParallel: true, forbidOnly: !!process.env.CI, - retries: 1, - workers: 10, + retries: process.env.CI ? 2 : 1, + workers: process.env.CI ? 2 : 10, timeout: 300000, expect: { timeout: 60000 diff --git a/zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json b/zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json new file mode 100644 index 00000000000..8be6028ca02 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json @@ -0,0 +1,53 @@ +{ + "root": true, + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaFeatures": { + "jsx": true + }, + "ecmaVersion": "latest", + "sourceType": "module", + "project": true + }, + "plugins": ["@typescript-eslint", "react", "react-hooks"], + "settings": { + "react": { + "version": "detect" + } + }, + "rules": { + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": [ + "error", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ], + "@typescript-eslint/no-for-in-array": "error", + "@typescript-eslint/no-this-alias": "error", + "no-duplicate-imports": "error", + "no-invalid-this": "error", + "no-irregular-whitespace": "error", + "no-param-reassign": "error", + "no-redeclare": "error", + "no-sparse-arrays": "error", + "no-template-curly-in-string": "error", + "prefer-object-spread": "error", + "prefer-template": "error", + "yoda": "error", + "react-hooks/exhaustive-deps": "error" + }, + "ignorePatterns": ["dist", "node_modules", "webpack.config.js"] +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/.gitignore b/zeppelin-web-angular/projects/zeppelin-react/.gitignore new file mode 100644 index 00000000000..de4d1f007dd --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules diff --git a/zeppelin-web-angular/projects/zeppelin-react/README.md b/zeppelin-web-angular/projects/zeppelin-react/README.md new file mode 100644 index 00000000000..e3acdb68b2f --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/README.md @@ -0,0 +1,100 @@ + + +# Zeppelin React + +React micro-frontend that runs alongside the Angular host via [Webpack Module Federation](https://webpack.js.org/concepts/module-federation/). + +- Design Document: [Micro Frontend Migration (Angular to React) Proposal](https://cwiki.apache.org/confluence/display/ZEPPELIN/Micro+Frontend+Migration%28Angular+to+React%29+Proposal) + +## Migration roadmap + +| Phase | Scope | Status | +|-------|-------|--------| +| 1 | Webpack 5 + Module Federation setup | Done | +| 1.5 | Published paragraph (pilot) | Done | +| 2 | Notebook and interpreter modules | Planned | + +The published paragraph was picked as pilot because it's read-only and has almost no coupling to other modules. + +## Architecture + +``` +Angular host (port 4200) React remote (port 3001) +┌─────────────────────────┐ ┌─────────────────────────┐ +│ paragraph.component.ts │ │ webpack.config.js │ +│ loads remoteEntry.js ──┼──────>│ ModuleFederationPlugin │ +│ calls mount(el, props) │ │ name: 'reactApp' │ +└─────────────────────────┘ │ exposes: │ + │ ./PublishedParagraph │ + └─────────────────────────┘ +``` + +1. Angular loads `remoteEntry.js` from the React dev server or production assets. +2. The script registers `window.reactApp` as a Module Federation container. +3. Angular calls `container.get('./PublishedParagraph')` to get the module. +4. The module exports `mount(element, props)`, which calls `createRoot()` and renders into the DOM element. + +Append `?react=true` to any published paragraph URL to activate React mode. + +## Setup + +Run `npm install` then `npm run dev` to start the dev server on `http://localhost:3001`. + +The Angular host must be running on port 4200. From `zeppelin-web-angular/`, `npm start` runs both servers together. + +## Build + +From `projects/zeppelin-react/`, run `npm run build`. Output goes to `dist/`. In production, Angular loads `remoteEntry.js` from `/assets/react/` (see `environment.prod.ts`). + +## Linting + +From `projects/zeppelin-react/`, run `npm run lint` to check, `npm run lint:fix` to auto-fix. See `.eslintrc.json` for rules. + +## Project structure + +``` +src/ +├── components/ +│ ├── common/ # Empty, Loading +│ ├── renderers/ # HTMLRenderer, ImageRenderer, TextRenderer +│ └── visualizations/ # TableVisualization, VisualizationControls +├── pages/ +│ └── PublishedParagraph.tsx # entry component + mount() +├── templates/ +│ └── SingleResultRenderer.tsx # routes result types to renderers +├── utils/ # tableUtils, textUtils, exportFile +└── main.ts # re-exports for Module Federation +``` + +## Adding a new React module + +1. Create a component (e.g. `src/pages/ExampleFeature.tsx`). +2. Export a `mount(element, props)` function that creates a React root and renders the component. +3. Register in `webpack.config.js` under `exposes`: + ```js + exposes: { + './PublishedParagraph': './src/pages/PublishedParagraph', + './ExampleFeature': './src/pages/ExampleFeature' + } + ``` +4. Re-export from `main.ts`: + ```ts + export { ExampleFeature, mount as mountExampleFeature } from './pages/ExampleFeature'; + ``` +5. Load from Angular (same pattern as `paragraph.component.ts`): + ```ts + const factory = await container.get('./ExampleFeature'); + const { mount } = factory(); + mount(hostElement, props); + ``` + diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json new file mode 100644 index 00000000000..2ae973b693e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -0,0 +1,10100 @@ +{ + "name": "@zeppelin/react", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@zeppelin/react", + "version": "0.0.1", + "dependencies": { + "@ant-design/icons": "5.4.0", + "@antv/g2plot": "2.4.35", + "@zeppelin/sdk": "file:../zeppelin-sdk", + "ansi-to-react": "6.2.6", + "antd": "5.21.0", + "file-saver": "2.0.5", + "react": "18.3.1", + "react-dom": "18.3.1", + "xlsx": "0.18.5" + }, + "devDependencies": { + "@types/file-saver": "2.0.7", + "@types/node": "18.19.64", + "@types/react": "18.3.26", + "@types/react-dom": "18.3.7", + "@types/xlsx": "0.0.36", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", + "css-loader": "6.8.0", + "eslint": "^8.57.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^4.6.2", + "html-webpack-plugin": "5.5.0", + "style-loader": "3.3.0", + "ts-loader": "9.4.0", + "typescript": "4.9.5", + "webpack": "5.88.0", + "webpack-cli": "5.1.4", + "webpack-dev-server": "4.15.0" + } + }, + "../zeppelin-sdk": { + "name": "@zeppelin/sdk", + "version": "0.0.1", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": "^8.2.9", + "@angular/core": "^8.2.9" + } + }, + "node_modules/@ant-design/colors": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.2.1.tgz", + "integrity": "sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==", + "license": "MIT", + "dependencies": { + "@ant-design/fast-color": "^2.0.6" + } + }, + "node_modules/@ant-design/cssinjs": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.24.0.tgz", + "integrity": "sha512-K4cYrJBsgvL+IoozUXYjbT6LHHNt+19a9zkvpBPxLjFHas1UpPM2A5MlhROb0BT8N8WoavM5VsP9MeSeNK/3mg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "@emotion/hash": "^0.8.0", + "@emotion/unitless": "^0.7.5", + "classnames": "^2.3.1", + "csstype": "^3.1.3", + "rc-util": "^5.35.0", + "stylis": "^4.3.4" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/cssinjs-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ant-design/cssinjs-utils/-/cssinjs-utils-1.1.3.tgz", + "integrity": "sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg==", + "license": "MIT", + "dependencies": { + "@ant-design/cssinjs": "^1.21.0", + "@babel/runtime": "^7.23.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@ant-design/icons": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.4.0.tgz", + "integrity": "sha512-QZbWC5xQYexCI5q4/fehSEkchJr5UGtvAJweT743qKUQQGs9IH2DehNLP49DJ3Ii9m9CijD2HN6fNy3WKhIFdA==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.24.8", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/@ant-design/icons-svg": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz", + "integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==", + "license": "MIT" + }, + "node_modules/@ant-design/react-slick": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz", + "integrity": "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.4", + "classnames": "^2.2.5", + "json2mq": "^0.2.0", + "resize-observer-polyfill": "^1.5.1", + "throttle-debounce": "^5.0.0" + }, + "peerDependencies": { + "react": ">=16.9.0" + } + }, + "node_modules/@antv/adjust": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.2.5.tgz", + "integrity": "sha512-MfWZOkD9CqXRES6MBGRNe27Q577a72EIwyMnE29wIlPliFvJfWwsrONddpGU7lilMpVKecS3WAzOoip3RfPTRQ==", + "license": "MIT", + "dependencies": { + "@antv/util": "~2.0.0", + "tslib": "^1.10.0" + } + }, + "node_modules/@antv/adjust/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@antv/attr": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.3.5.tgz", + "integrity": "sha512-wuj2gUo6C8Q2ASSMrVBuTcb5LcV+Tc0Egiy6bC42D0vxcQ+ta13CLxgMmHz8mjD0FxTPJDXSciyszRSC5TdLsg==", + "license": "MIT", + "dependencies": { + "@antv/color-util": "^2.0.1", + "@antv/scale": "^0.3.0", + "@antv/util": "~2.0.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@antv/color-util": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@antv/color-util/-/color-util-2.0.6.tgz", + "integrity": "sha512-KnPEaAH+XNJMjax9U35W67nzPI+QQ2x27pYlzmSIWrbj4/k8PGrARXfzDTjwoozHJY8qG62Z+Ww6Alhu2FctXQ==", + "license": "ISC", + "dependencies": { + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/component": { + "version": "0.8.35", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.8.35.tgz", + "integrity": "sha512-VnRa5X77nBPI952o2xePEEMSNZ6g2mcUDrQY8mVL2kino/8TFhqDq5fTRmDXZyWyIYd4ulJTz5zgeSwAnX/INQ==", + "license": "MIT", + "dependencies": { + "@antv/color-util": "^2.0.3", + "@antv/dom-util": "~2.0.1", + "@antv/g-base": "^0.5.9", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.7", + "@antv/scale": "~0.3.1", + "@antv/util": "~2.0.0", + "fecha": "~4.2.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/component/node_modules/@antv/path-util": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", + "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", + "license": "ISC", + "dependencies": { + "@antv/matrix-util": "^3.0.4", + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/component/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", + "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", + "license": "ISC", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.3.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/coord": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.3.1.tgz", + "integrity": "sha512-rFE94C8Xzbx4xmZnHh2AnlB3Qm1n5x0VT3OROy257IH6Rm4cuzv1+tZaUBATviwZd99S+rOY9telw/+6C9GbRw==", + "license": "MIT", + "dependencies": { + "@antv/matrix-util": "^3.1.0-beta.2", + "@antv/util": "~2.0.12", + "tslib": "^2.1.0" + } + }, + "node_modules/@antv/dom-util": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.4.tgz", + "integrity": "sha512-2shXUl504fKwt82T3GkuT4Uoc6p9qjCKnJ8gXGLSW4T1W37dqf9AV28aCfoVPHp2BUXpSsB+PAJX2rG/jLHsLQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/event-emitter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@antv/event-emitter/-/event-emitter-0.1.3.tgz", + "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==", + "license": "MIT" + }, + "node_modules/@antv/g-base": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@antv/g-base/-/g-base-0.5.16.tgz", + "integrity": "sha512-jP06wggTubDPHXoKwFg3/f1lyxBX9ywwN3E/HG74Nd7DXqOXQis8tsIWW+O6dS/h9vyuXLd1/wDWkMMm3ZzXdg==", + "license": "ISC", + "dependencies": { + "@antv/event-emitter": "^0.1.1", + "@antv/g-math": "^0.1.9", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.5", + "@antv/util": "~2.0.13", + "@types/d3-timer": "^2.0.0", + "d3-ease": "^1.0.5", + "d3-interpolate": "^3.0.1", + "d3-timer": "^1.0.9", + "detect-browser": "^5.1.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-base/node_modules/@antv/path-util": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", + "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", + "license": "ISC", + "dependencies": { + "@antv/matrix-util": "^3.0.4", + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-base/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", + "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", + "license": "ISC", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.3.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-canvas": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-0.5.17.tgz", + "integrity": "sha512-sXYJMWTOlb/Ycb6sTKu00LcJqInXJY4t99+kSM40u2OfqrXYmaXDjHR7D2V0roMkbK/QWiWS9UnEidCR1VtMOA==", + "license": "ISC", + "dependencies": { + "@antv/g-base": "^0.5.12", + "@antv/g-math": "^0.1.9", + "@antv/matrix-util": "^3.1.0-beta.1", + "@antv/path-util": "~2.0.5", + "@antv/util": "~2.0.0", + "gl-matrix": "^3.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-canvas/node_modules/@antv/path-util": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", + "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", + "license": "ISC", + "dependencies": { + "@antv/matrix-util": "^3.0.4", + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-canvas/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", + "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", + "license": "ISC", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.3.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g-math": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-0.1.9.tgz", + "integrity": "sha512-KHMSfPfZ5XHM1PZnG42Q2gxXfOitYveNTA7L61lR6mhZ8Y/aExsYmHqaKBsSarU0z+6WLrl9C07PQJZaw0uljQ==", + "license": "ISC", + "dependencies": { + "@antv/util": "~2.0.0", + "gl-matrix": "^3.0.0" + } + }, + "node_modules/@antv/g-svg": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-0.5.7.tgz", + "integrity": "sha512-jUbWoPgr4YNsOat2Y/rGAouNQYGpw4R0cvlN0YafwOyacFFYy2zC8RslNd6KkPhhR3XHNSqJOuCYZj/YmLUwYw==", + "license": "ISC", + "dependencies": { + "@antv/g-base": "^0.5.12", + "@antv/g-math": "^0.1.9", + "@antv/util": "~2.0.0", + "detect-browser": "^5.0.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g2": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-4.2.12.tgz", + "integrity": "sha512-kTg6ftJol+0hYRM2eMwJKq3JThdq4UAKgCoQalUPjwyF6SSKkWz2QdrIAxfLE7LSTwcIE+L8So1jMaOVVbEi6w==", + "license": "MIT", + "dependencies": { + "@antv/adjust": "^0.2.1", + "@antv/attr": "^0.3.1", + "@antv/color-util": "^2.0.2", + "@antv/component": "^0.8.27", + "@antv/coord": "^0.3.0", + "@antv/dom-util": "^2.0.2", + "@antv/event-emitter": "~0.1.0", + "@antv/g-base": "~0.5.6", + "@antv/g-canvas": "~0.5.10", + "@antv/g-svg": "~0.5.6", + "@antv/matrix-util": "^3.1.0-beta.3", + "@antv/path-util": "^2.0.15", + "@antv/scale": "^0.3.14", + "@antv/util": "~2.0.5", + "tslib": "^2.0.0" + } + }, + "node_modules/@antv/g2/node_modules/@antv/path-util": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", + "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", + "license": "ISC", + "dependencies": { + "@antv/matrix-util": "^3.0.4", + "@antv/util": "^2.0.9", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g2/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", + "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", + "license": "ISC", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.3.0", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/g2plot": { + "version": "2.4.35", + "resolved": "https://registry.npmjs.org/@antv/g2plot/-/g2plot-2.4.35.tgz", + "integrity": "sha512-jpfgUqC2ch1kkrSSiY8qsFZ5/cYGcwMA9MAgqZXHdNBDcClrLzdakHyc5RN2na9LwZTY3qoj6AawZzAQSiJ58w==", + "license": "MIT", + "dependencies": { + "@antv/color-util": "^2.0.6", + "@antv/event-emitter": "^0.1.2", + "@antv/g-base": "^0.5.11", + "@antv/g2": "^4.2.12", + "@antv/matrix-util": "^3.1.0-beta.2", + "@antv/path-util": "^3.0.1", + "@antv/scale": "^0.3.18", + "@antv/util": "^2.0.17", + "d3-hierarchy": "^2.0.0", + "d3-regression": "^1.3.5", + "fmin": "^0.0.2", + "pdfast": "^0.2.0", + "size-sensor": "^1.0.1", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/matrix-util": { + "version": "3.1.0-beta.3", + "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.1.0-beta.3.tgz", + "integrity": "sha512-W2R6Za3A6CmG51Y/4jZUM/tFgYSq7vTqJL1VD9dKrvwxS4sE0ZcXINtkp55CdyBwJ6Cwm8pfoRpnD4FnHahN0A==", + "license": "ISC", + "dependencies": { + "@antv/util": "^2.0.9", + "gl-matrix": "^3.4.3", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/path-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-3.0.1.tgz", + "integrity": "sha512-tpvAzMpF9Qm6ik2YSMqICNU5tco5POOW7S4XoxZAI/B0L26adU+Md/SmO0BBo2SpuywKvzPH3hPT3xmoyhr04Q==", + "license": "MIT", + "dependencies": { + "gl-matrix": "^3.1.0", + "lodash-es": "^4.17.21", + "tslib": "^2.0.3" + } + }, + "node_modules/@antv/scale": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.18.tgz", + "integrity": "sha512-GHwE6Lo7S/Q5fgaLPaCsW+CH+3zl4aXpnN1skOiEY0Ue9/u+s2EySv6aDXYkAqs//i0uilMDD/0/4n8caX9U9w==", + "license": "MIT", + "dependencies": { + "@antv/util": "~2.0.3", + "fecha": "~4.2.0", + "tslib": "^2.0.0" + } + }, + "node_modules/@antv/util": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz", + "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==", + "license": "ISC", + "dependencies": { + "csstype": "^3.0.8", + "tslib": "^2.0.3" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "license": "MIT" + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ljharb/resumer": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.0.1.tgz", + "integrity": "sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==", + "license": "MIT", + "dependencies": { + "@ljharb/through": "^2.3.9" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@ljharb/through": { + "version": "2.3.14", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.14.tgz", + "integrity": "sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rc-component/async-validator": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", + "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.4" + }, + "engines": { + "node": ">=14.x" + } + }, + "node_modules/@rc-component/color-picker": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-2.0.1.tgz", + "integrity": "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q==", + "license": "MIT", + "dependencies": { + "@ant-design/fast-color": "^2.0.6", + "@babel/runtime": "^7.23.6", + "classnames": "^2.2.6", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/context": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz", + "integrity": "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/mini-decimal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", + "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0" + }, + "engines": { + "node": ">=8.x" + } + }, + "node_modules/@rc-component/mutate-observer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz", + "integrity": "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/portal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz", + "integrity": "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/qrcode": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rc-component/qrcode/-/qrcode-1.0.1.tgz", + "integrity": "sha512-g8eeeaMyFXVlq8cZUeaxCDhfIYjpao0l9cvm5gFwKXy/Vm1yDWV7h2sjH5jHYzdFedlVKBpATFB1VKMrHzwaWQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "classnames": "^2.3.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/tour": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.1.tgz", + "integrity": "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/portal": "^1.0.0-9", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.2", + "rc-util": "^5.24.4" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@rc-component/trigger": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.3.0.tgz", + "integrity": "sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2", + "@rc-component/portal": "^1.1.0", + "classnames": "^2.3.2", + "rc-motion": "^2.0.0", + "rc-resize-observer": "^1.3.1", + "rc-util": "^5.44.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/d3-timer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-2.0.3.tgz", + "integrity": "sha512-jhAJzaanK5LqyLQ50jJNIrB8fjL9gwWZTgYjevPvkDLMU+kTAZkYsobI59nYoeSrH1PucuyJEi247Pb90t6XUg==", + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.24.tgz", + "integrity": "sha512-Mbrt4SRlXSTWryOnHAh2d4UQ/E7n9lZyGSi6KgX+4hkuL9soYbLOVXVhnk/ODp12YsGc95f4pOvqywJ6kngUwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", + "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.7", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", + "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/file-saver": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", + "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.19.64", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.26", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz", + "integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/xlsx": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz", + "integrity": "sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw==", + "deprecated": "This is a stub types definition for xlsx (https://github.com/sheetjs/js-xlsx). xlsx provides its own type definitions, so you don't need @types/xlsx installed!", + "dev": true, + "license": "MIT", + "dependencies": { + "xlsx": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/project-service/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@zeppelin/sdk": { + "resolved": "../zeppelin-sdk", + "link": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "deprecated": "package has been renamed to acorn-import-attributes", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/align-text/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "license": "BSD-3-Clause OR MIT", + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/anser": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/anser/-/anser-2.3.5.tgz", + "integrity": "sha512-vcZjxvvVoxTeR5XBNJB38oTu/7eDCZlwdz32N1eNgpyPF7j/Z7Idf+CUwQOkKKpJ7RJyjxgLHCM7vdIK0iCNMQ==", + "license": "MIT" + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-to-react": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/ansi-to-react/-/ansi-to-react-6.2.6.tgz", + "integrity": "sha512-Eqi0iaMK5OZ3jsVFxWvU2B74UZBnGuHlkflKMX6wTOeH+luy9KE2O0gUkc2PxhIP1R4IO0xohv62UMFInQOSeg==", + "license": "BSD-3-Clause", + "dependencies": { + "anser": "^2.3.2", + "escape-carriage": "^1.3.1", + "linkify-it": "^3.0.3" + }, + "peerDependencies": { + "react": "^16.3.2 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.3.2 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/antd": { + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/antd/-/antd-5.21.0.tgz", + "integrity": "sha512-eoY3LruXq/8MRCXG46O2cwc+Q8HW8Bhc+pWw7loIt6Dn22tLHckxYF/663kn55JTIOVUnJdmJDP9njdJmLXJsQ==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.1.0", + "@ant-design/cssinjs": "^1.21.1", + "@ant-design/cssinjs-utils": "^1.1.0", + "@ant-design/icons": "^5.5.1", + "@ant-design/react-slick": "~1.1.2", + "@babel/runtime": "^7.25.6", + "@ctrl/tinycolor": "^3.6.1", + "@rc-component/color-picker": "~2.0.1", + "@rc-component/mutate-observer": "^1.1.0", + "@rc-component/qrcode": "~1.0.0", + "@rc-component/tour": "~1.15.1", + "@rc-component/trigger": "^2.2.3", + "classnames": "^2.5.1", + "copy-to-clipboard": "^3.3.3", + "dayjs": "^1.11.11", + "rc-cascader": "~3.28.1", + "rc-checkbox": "~3.3.0", + "rc-collapse": "~3.8.0", + "rc-dialog": "~9.6.0", + "rc-drawer": "~7.2.0", + "rc-dropdown": "~4.2.0", + "rc-field-form": "~2.4.0", + "rc-image": "~7.11.0", + "rc-input": "~1.6.3", + "rc-input-number": "~9.2.0", + "rc-mentions": "~2.16.1", + "rc-menu": "~9.15.1", + "rc-motion": "^2.9.3", + "rc-notification": "~5.6.1", + "rc-pagination": "~4.3.0", + "rc-picker": "~4.6.14", + "rc-progress": "~4.0.0", + "rc-rate": "~2.13.0", + "rc-resize-observer": "^1.4.0", + "rc-segmented": "~2.5.0", + "rc-select": "~14.15.2", + "rc-slider": "~11.1.6", + "rc-steps": "~6.0.1", + "rc-switch": "~4.1.0", + "rc-table": "~7.47.5", + "rc-tabs": "~15.2.0", + "rc-textarea": "~1.8.2", + "rc-tooltip": "~6.2.1", + "rc-tree": "~5.9.0", + "rc-tree-select": "~5.23.0", + "rc-upload": "~4.8.1", + "rc-util": "^5.43.0", + "scroll-into-view-if-needed": "^3.1.0", + "throttle-debounce": "^5.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ant-design" + } + }, + "node_modules/antd/node_modules/@ant-design/icons": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.6.1.tgz", + "integrity": "sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg==", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^7.0.0", + "@ant-design/icons-svg": "^4.4.0", + "@babel/runtime": "^7.24.8", + "classnames": "^2.2.6", + "rc-util": "^5.31.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-tree-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", + "integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==", + "license": "MIT" + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", + "integrity": "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", + "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.19", + "caniuse-lite": "^1.0.30001751", + "electron-to-chromium": "^1.5.238", + "node-releases": "^2.0.26", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001751", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", + "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", + "license": "MIT", + "dependencies": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", + "license": "ISC", + "dependencies": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", + "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/contour_plot": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", + "integrity": "sha512-Nil2HI76Xux6sVGORvhSS8v66m+/h5CwFkBJDO+U5vWaMdNC0yXNCsGDPbzPhvqOEU5koebhdEvD372LI+IyLw==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.0.tgz", + "integrity": "sha512-oBmqObfEW1tAmLoKjxz8wlUxwvnea21GyplYqZUuMpeNC5I1EW0S0y3/pk0adzUW8oxMlhbA1X2fgOpRxDNDqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.21", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.3", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-hierarchy": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz", + "integrity": "sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-regression": { + "version": "1.3.10", + "resolved": "https://registry.npmjs.org/d3-regression/-/d3-regression-1.3.10.tgz", + "integrity": "sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", + "license": "BSD-3-Clause" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dayjs": { + "version": "1.11.18", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", + "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "license": "MIT", + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "license": "MIT" + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dotignore": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", + "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.4" + }, + "bin": { + "ignored": "bin/ignored" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.240", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.240.tgz", + "integrity": "sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.19.0.tgz", + "integrity": "sha512-DoSM9VyG6O3vqBf+p3Gjgr/Q52HYBBtO3v+4koAxt1MnWr+zEnxE+nke/yXS4lt2P4SYCHQ4V3f1i88LQVOpAw==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-abstract": { + "version": "1.24.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", + "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "license": "MIT", + "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.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract/node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", + "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "dev": true, + "license": "MIT", + "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-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.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", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-carriage": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/escape-carriage/-/escape-carriage-1.3.1.tgz", + "integrity": "sha512-GwBr6yViW3ttx1kb7/Oh+gKQ1/TrhYwxKqVmg5gS+BK+Qe2KrOa/Vh7w3HPBvgGf0LfcDGoY9I6NHKoA5Hozhw==", + "license": "MIT" + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", + "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fmin": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", + "integrity": "sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A==", + "license": "BSD-3-Clause", + "dependencies": { + "contour_plot": "^0.0.1", + "json2module": "^0.0.3", + "rollup": "^0.25.8", + "tape": "^4.5.1", + "uglify-js": "^2.6.2" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gl-matrix": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", + "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true, + "license": "MIT" + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-webpack-plugin": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz", + "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/html-minifier-terser": "^6.0.0", + "html-minifier-terser": "^6.0.2", + "lodash": "^4.17.21", + "pretty-error": "^4.0.0", + "tapable": "^2.0.0" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/html-webpack-plugin" + }, + "peerDependencies": { + "webpack": "^5.20.0" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json2module": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", + "integrity": "sha512-qYGxqrRrt4GbB8IEOy1jJGypkNsjWoIMlZt4bAsmUScCA507Hbc2p1JOhBzqn45u3PWafUgH2OnzyNU7udO/GA==", + "license": "BSD-3-Clause", + "dependencies": { + "rw": "^1.3.2" + }, + "bin": { + "json2module": "bin/json2module" + } + }, + "node_modules/json2mq": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", + "integrity": "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==", + "license": "MIT", + "dependencies": { + "string-convert": "^0.2.0" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/launch-editor": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", + "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "license": "MIT", + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mock-property": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.3.tgz", + "integrity": "sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.1", + "functions-have-names": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "hasown": "^2.0.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", + "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pdfast": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/pdfast/-/pdfast-0.2.0.tgz", + "integrity": "sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz", + "integrity": "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^3.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc-cascader": { + "version": "3.28.2", + "resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.28.2.tgz", + "integrity": "sha512-8f+JgM83iLTvjgdkgU7GfI4qY8icXOBP0cGZjOdx2iJAkEe8ucobxDQAVE69UD/c3ehCxZlcgEHeD5hFmypbUw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "array-tree-filter": "^2.1.0", + "classnames": "^2.3.1", + "rc-select": "~14.15.0", + "rc-tree": "~5.9.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-checkbox": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz", + "integrity": "sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.25.2" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-collapse": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.8.0.tgz", + "integrity": "sha512-YVBkssrKPBG09TGfcWWGj8zJBYD9G3XuTy89t5iUmSXrIXEAnO1M+qjUxRW6b4Qi0+wNWG6MHJF/+US+nmIlzA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.3.4", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dialog": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.6.0.tgz", + "integrity": "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/portal": "^1.0.0-8", + "classnames": "^2.2.6", + "rc-motion": "^2.3.0", + "rc-util": "^5.21.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-drawer": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.2.0.tgz", + "integrity": "sha512-9lOQ7kBekEJRdEpScHvtmEtXnAsy+NGDXiRWc2ZVC7QXAazNVbeT4EraQKYwCME8BJLa8Bxqxvs5swwyOepRwg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@rc-component/portal": "^1.1.1", + "classnames": "^2.2.6", + "rc-motion": "^2.6.1", + "rc-util": "^5.38.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-dropdown": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.1.tgz", + "integrity": "sha512-YDAlXsPv3I1n42dv1JpdM7wJ+gSUBfeyPK59ZpBD9jQhK9jVuxpjj3NmWQHOBceA1zEPVX84T2wbdb2SD0UjmA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-util": "^5.44.1" + }, + "peerDependencies": { + "react": ">=16.11.0", + "react-dom": ">=16.11.0" + } + }, + "node_modules/rc-field-form": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.4.0.tgz", + "integrity": "sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.0", + "@rc-component/async-validator": "^5.0.3", + "rc-util": "^5.32.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-image": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.11.1.tgz", + "integrity": "sha512-XuoWx4KUXg7hNy5mRTy1i8c8p3K8boWg6UajbHpDXS5AlRVucNfTi5YxTtPBTBzegxAZpvuLfh3emXFt6ybUdA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/portal": "^1.0.2", + "classnames": "^2.2.6", + "rc-dialog": "~9.6.0", + "rc-motion": "^2.6.2", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-input": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.6.4.tgz", + "integrity": "sha512-lBZhfRD4NSAUW0zOKLUeI6GJuXkxeZYi0hr8VcJgJpyTNOvHw1ysrKWAHcEOAAHj7guxgmWYSi6xWrEdfrSAsA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.18.1" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-input-number": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.2.0.tgz", + "integrity": "sha512-5XZFhBCV5f9UQ62AZ2hFbEY8iZT/dm23Q1kAg0H8EvOgD3UDbYYJAayoVIkM3lQaCqYAW5gV0yV3vjw1XtzWHg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/mini-decimal": "^1.0.1", + "classnames": "^2.2.5", + "rc-input": "~1.6.0", + "rc-util": "^5.40.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-mentions": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.16.1.tgz", + "integrity": "sha512-GnhSTGP9Mtv6pqFFGQze44LlrtWOjHNrUUAcsdo9DnNAhN4pwVPEWy4z+2jpjkiGlJ3VoXdvMHcNDQdfI9fEaw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.22.5", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.6", + "rc-input": "~1.6.0", + "rc-menu": "~9.15.1", + "rc-textarea": "~1.8.0", + "rc-util": "^5.34.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-menu": { + "version": "9.15.1", + "resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.15.1.tgz", + "integrity": "sha512-UKporqU6LPfHnpPmtP6hdEK4iO5Q+b7BRv/uRpxdIyDGplZy9jwUjsnpev5bs3PQKB0H0n34WAPDfjAfn3kAPA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.0.0", + "classnames": "2.x", + "rc-motion": "^2.4.3", + "rc-overflow": "^1.3.1", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-motion": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.5.tgz", + "integrity": "sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-util": "^5.44.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-notification": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-5.6.4.tgz", + "integrity": "sha512-KcS4O6B4qzM3KH7lkwOB7ooLPZ4b6J+VMmQgT51VZCeEcmghdeR4IrMcFq0LG+RPdnbe/ArT086tGM8Snimgiw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.9.0", + "rc-util": "^5.20.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-overflow": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.5.0.tgz", + "integrity": "sha512-Lm/v9h0LymeUYJf0x39OveU52InkdRXqnn2aYXfWmo8WdOonIKB2kfau+GF0fWq6jPgtdO9yMqveGcK6aIhJmg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.37.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-pagination": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.3.0.tgz", + "integrity": "sha512-UubEWA0ShnroQ1tDa291Fzw6kj0iOeF26IsUObxYTpimgj4/qPCWVFl18RLZE+0Up1IZg0IK4pMn6nB3mjvB7g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.3.2", + "rc-util": "^5.38.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-picker": { + "version": "4.6.15", + "resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.6.15.tgz", + "integrity": "sha512-OWZ1yrMie+KN2uEUfYCfS4b2Vu6RC1FWwNI0s+qypsc3wRt7g+peuZKVIzXCTaJwyyZruo80+akPg2+GmyiJjw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.24.7", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.2.1", + "rc-overflow": "^1.3.2", + "rc-resize-observer": "^1.4.0", + "rc-util": "^5.43.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "date-fns": ">= 2.x", + "dayjs": ">= 1.x", + "luxon": ">= 3.x", + "moment": ">= 2.x", + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + }, + "peerDependenciesMeta": { + "date-fns": { + "optional": true + }, + "dayjs": { + "optional": true + }, + "luxon": { + "optional": true + }, + "moment": { + "optional": true + } + } + }, + "node_modules/rc-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz", + "integrity": "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.6", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-rate": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.13.1.tgz", + "integrity": "sha512-QUhQ9ivQ8Gy7mtMZPAjLbxBt5y9GRp65VcUyGUMF3N3fhiftivPHdpuDIaWIMOTEprAjZPC08bls1dQB+I1F2Q==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.0.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-resize-observer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.3.tgz", + "integrity": "sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.7", + "classnames": "^2.2.1", + "rc-util": "^5.44.1", + "resize-observer-polyfill": "^1.5.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-segmented": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.5.0.tgz", + "integrity": "sha512-B28Fe3J9iUFOhFJET3RoXAPFJ2u47QvLSYcZWC4tFYNGPEjug5LAxEasZlA/PpAxhdOPqGWsGbSj7ftneukJnw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.1", + "classnames": "^2.2.1", + "rc-motion": "^2.4.4", + "rc-util": "^5.17.0" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/rc-select": { + "version": "14.15.2", + "resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.15.2.tgz", + "integrity": "sha512-oNoXlaFmpqXYcQDzcPVLrEqS2J9c+/+oJuGrlXeVVX/gVgrbHa5YcyiRUXRydFjyuA7GP3elRuLF7Y3Tfwltlw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/trigger": "^2.1.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-overflow": "^1.3.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-slider": { + "version": "11.1.9", + "resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-11.1.9.tgz", + "integrity": "sha512-h8IknhzSh3FEM9u8ivkskh+Ef4Yo4JRIY2nj7MrH6GQmrwV6mcpJf5/4KgH5JaVI1H3E52yCdpOlVyGZIeph5A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.5", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-steps": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz", + "integrity": "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.16.7", + "classnames": "^2.2.3", + "rc-util": "^5.16.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-switch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz", + "integrity": "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0", + "classnames": "^2.2.1", + "rc-util": "^5.30.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-table": { + "version": "7.47.5", + "resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.47.5.tgz", + "integrity": "sha512-fzq+V9j/atbPIcvs3emuclaEoXulwQpIiJA6/7ey52j8+9cJ4P8DGmp4YzfUVDrb3qhgedcVeD6eRgUrokwVEQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.4.0", + "classnames": "^2.2.5", + "rc-resize-observer": "^1.1.0", + "rc-util": "^5.41.0", + "rc-virtual-list": "^3.14.2" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tabs": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.2.0.tgz", + "integrity": "sha512-ZfHdGw0krK4walBYNOgPWCcBImSp5NtzJR5+oI4rN9Z44FYDQKozBFfuAQHhumIUtx4EmGaYCFjywwgca/Rs1g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "classnames": "2.x", + "rc-dropdown": "~4.2.0", + "rc-menu": "~9.15.1", + "rc-motion": "^2.6.2", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.34.1" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-textarea": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.8.2.tgz", + "integrity": "sha512-UFAezAqltyR00a8Lf0IPAyTd29Jj9ee8wt8DqXyDMal7r/Cg/nDt3e1OOv3Th4W6mKaZijjgwuPXhAfVNTN8sw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "^2.2.1", + "rc-input": "~1.6.0", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.27.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tooltip": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.1.tgz", + "integrity": "sha512-rws0duD/3sHHsD905Nex7FvoUGy2UBQRhTkKxeEvr2FB+r21HsOxcDJI0TzyO8NHhnAA8ILr8pfbSBg5Jj5KBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.11.2", + "@rc-component/trigger": "^2.0.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-tree": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.9.0.tgz", + "integrity": "sha512-CPrgOvm9d/9E+izTONKSngNzQdIEjMox2PBufWjS1wf7vxtvmCWzK1SlpHbRY6IaBfJIeZ+88RkcIevf729cRg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-motion": "^2.0.1", + "rc-util": "^5.16.1", + "rc-virtual-list": "^3.5.1" + }, + "engines": { + "node": ">=10.x" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-tree-select": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.23.0.tgz", + "integrity": "sha512-aQGi2tFSRw1WbXv0UVXPzHm09E0cSvUVZMLxQtMv3rnZZpNmdRXWrnd9QkLNlVH31F+X5rgghmdSFF3yZW0N9A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.10.1", + "classnames": "2.x", + "rc-select": "~14.15.0", + "rc-tree": "~5.9.0", + "rc-util": "^5.16.1" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/rc-upload": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.8.1.tgz", + "integrity": "sha512-toEAhwl4hjLAI1u8/CgKWt30BR06ulPa4iGQSMvSXoHzO88gPCslxqV/mnn4gJU7PDoltGIC9Eh+wkeudqgHyw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "classnames": "^2.2.5", + "rc-util": "^5.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-util": { + "version": "5.44.4", + "resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.44.4.tgz", + "integrity": "sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "react-is": "^18.2.0" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/rc-virtual-list": { + "version": "3.19.2", + "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.19.2.tgz", + "integrity": "sha512-Ys6NcjwGkuwkeaWBDqfI3xWuZ7rDiQXlH1o2zLfFzATfEgXcqpk8CkgMfbJD81McqjcJVez25a3kPxCR807evA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.0", + "classnames": "^2.2.6", + "rc-resize-observer": "^1.0.0", + "rc-util": "^5.36.0" + }, + "engines": { + "node": ">=8.x" + }, + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/renderkid": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz", + "integrity": "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^6.0.1" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", + "license": "MIT", + "dependencies": { + "align-text": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", + "integrity": "sha512-a2S4Bh3bgrdO4BhKr2E4nZkjTvrJ2m2bWjMTzVYtoqSCn0HnuxosXnaJUHrMEziOWr3CzL9GjilQQKcyCQpJoA==", + "license": "MIT", + "dependencies": { + "chalk": "^1.1.1", + "minimist": "^1.2.0", + "source-map-support": "^0.3.2" + }, + "bin": { + "rollup": "bin/rollup" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test/node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true, + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list/node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map/node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap/node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel/node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/size-sensor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.2.tgz", + "integrity": "sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==", + "license": "ISC" + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", + "license": "MIT", + "dependencies": { + "source-map": "0.1.32" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-convert": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", + "integrity": "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==", + "license": "MIT" + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-loader": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.0.tgz", + "integrity": "sha512-szANub7ksJtQioJYtpbWwh1hUl99uK15n5HDlikeCRil/zYMZgSxucHddyF/4A3qJMUiAjPhFowrrQuNMA7jwQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tape": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/tape/-/tape-4.17.0.tgz", + "integrity": "sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw==", + "license": "MIT", + "dependencies": { + "@ljharb/resumer": "~0.0.1", + "@ljharb/through": "~2.3.9", + "call-bind": "~1.0.2", + "deep-equal": "~1.1.1", + "defined": "~1.0.1", + "dotignore": "~0.1.2", + "for-each": "~0.3.3", + "glob": "~7.2.3", + "has": "~1.0.3", + "inherits": "~2.0.4", + "is-regex": "~1.1.4", + "minimist": "~1.2.8", + "mock-property": "~1.0.0", + "object-inspect": "~1.12.3", + "resolve": "~1.22.6", + "string.prototype.trim": "~1.2.8" + }, + "bin": { + "tape": "bin/tape" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/throttle-debounce": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", + "integrity": "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==", + "license": "MIT", + "engines": { + "node": ">=12.22" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-loader": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.0.tgz", + "integrity": "sha512-0G3UMhk1bjgsgiwF4rnZRAeTi69j9XMDtmDDMghGSqlWESIAS3LFgJe//GYfE4vcjbyzuURLB9Us2RZIWp2clQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", + "license": "BSD-2-Clause", + "dependencies": { + "source-map": "~0.5.1", + "yargs": "~3.10.0" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + }, + "optionalDependencies": { + "uglify-to-browserify": "~1.0.0" + } + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", + "license": "MIT", + "optional": true + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", + "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.88.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.0.tgz", + "integrity": "sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", + "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack-dev-server/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", + "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "license": "MIT/X11", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, + "license": "MIT", + "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 + } + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", + "license": "MIT", + "dependencies": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json new file mode 100644 index 00000000000..41816ddc779 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -0,0 +1,45 @@ +{ + "name": "@zeppelin/react", + "version": "0.0.1", + "sideEffects": [ + "*.css" + ], + "scripts": { + "start": "webpack serve --config webpack.config.js --mode development", + "build": "webpack --config webpack.config.js --mode production", + "dev": "webpack serve --config webpack.config.js --mode development", + "lint": "eslint src --ext .ts,.tsx", + "lint:fix": "eslint src --ext .ts,.tsx --fix" + }, + "dependencies": { + "@ant-design/icons": "5.4.0", + "@antv/g2plot": "2.4.35", + "@zeppelin/sdk": "file:../zeppelin-sdk", + "ansi-to-react": "6.2.6", + "antd": "5.21.0", + "file-saver": "2.0.5", + "react": "18.3.1", + "react-dom": "18.3.1", + "xlsx": "0.18.5" + }, + "devDependencies": { + "@types/file-saver": "2.0.7", + "@types/node": "18.19.64", + "@types/react": "18.3.26", + "@types/react-dom": "18.3.7", + "@types/xlsx": "0.0.36", + "@typescript-eslint/eslint-plugin": "^8.56.1", + "@typescript-eslint/parser": "^8.56.1", + "css-loader": "6.8.0", + "eslint": "^8.57.1", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^4.6.2", + "html-webpack-plugin": "5.5.0", + "style-loader": "3.3.0", + "ts-loader": "9.4.0", + "typescript": "4.9.5", + "webpack": "5.88.0", + "webpack-cli": "5.1.4", + "webpack-dev-server": "4.15.0" + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/common/Empty.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/common/Empty.tsx new file mode 100644 index 00000000000..791d67a052d --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/common/Empty.tsx @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Alert } from 'antd'; + +export const Empty = () => { + return ; +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/common/Loading.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/common/Loading.tsx new file mode 100644 index 00000000000..101ab62f96e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/common/Loading.tsx @@ -0,0 +1,24 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Spin, Typography } from 'antd'; + +export const Loading = () => { + return ( +
+ + + Loading paragraph data... + +
+ ); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/common/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/components/common/index.ts new file mode 100644 index 00000000000..9a1fddcbc0e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/common/index.ts @@ -0,0 +1,14 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { Loading } from './Loading'; +export { Empty } from './Empty'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts new file mode 100644 index 00000000000..a9beee6fe3a --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './renderers'; +export * from './visualizations'; +export * from './common'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.css b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.css new file mode 100644 index 00000000000..2e2601fc7c6 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.css @@ -0,0 +1,59 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.inner-html table { + border: none; + border-collapse: collapse; + border-spacing: 0; + table-layout: fixed; +} + +.inner-html table thead { + border-bottom: 2px solid rgba(0, 0, 0, 0.65); + vertical-align: bottom; +} + +.inner-html table tr, +.inner-html table th, +.inner-html table td { + text-align: right; + vertical-align: middle; + padding: 0.5em 0.5em; + line-height: normal; + white-space: normal; + max-width: none; + border: none; +} + +.inner-html table th { + font-weight: bold; +} + +.inner-html table tbody tr:nth-child(odd) { + background: #fafafa; +} + +.inner-html table tbody tr:hover { + background: #e6f7ff; +} + +.inner-html .dataframe tbody tr th:only-of-type { + vertical-align: middle; +} + +.inner-html .dataframe tbody tr th { + vertical-align: top; +} + +.inner-html .dataframe thead th { + text-align: right; +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.tsx new file mode 100644 index 00000000000..45fbeec9d40 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/HTMLRenderer.tsx @@ -0,0 +1,61 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useEffect, useRef } from 'react'; +import './HTMLRenderer.css'; + +interface HTMLRendererProps { + html: string; +} + +export const HTMLRenderer = ({ html }: HTMLRendererProps) => { + const containerRef = useRef(null); + + useEffect(() => { + const container = containerRef.current; + if (container) { + // For security reasons, React's dangerouslySetInnerHTML does not execute script tags. + // To render HTML containing libraries like BokehJS, we must manually add script tags + // to the DOM to execute them. + container.innerHTML = html; + + // Highlight code blocks (matches Angular: result.component.ts renderHTML) + const codeEle = container.querySelector('pre code'); + if (codeEle) { + import('highlight.js').then(({ default: hljs }) => { + hljs.highlightBlock(codeEle as HTMLElement); + }); + } + + const scripts = Array.from(container.querySelectorAll('script')); + + scripts.forEach(script => { + const newScript = document.createElement('script'); + + for (const attr of Array.from(script.attributes)) { + newScript.setAttribute(attr.name, attr.value); + } + + newScript.textContent = script.textContent; + newScript.async = false; + + script.parentNode?.replaceChild(newScript, script); + }); + + return () => { + container.innerHTML = ''; + }; + } + }, [html]); + + return
; +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/ImageRenderer.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/ImageRenderer.tsx new file mode 100644 index 00000000000..a025a371791 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/ImageRenderer.tsx @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface ImageRendererProps { + imageData: string; +} + +export const ImageRenderer = ({ imageData }: ImageRendererProps) => { + const imgSrc = `data:image/png;base64,${imageData}`; + + return ( + Result + ); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/TextRenderer.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/TextRenderer.tsx new file mode 100644 index 00000000000..5b44a9704a9 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/TextRenderer.tsx @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Ansi from 'ansi-to-react'; + +export interface TextRendererProps { + text: string; +} + +// Matches Angular: result.component.ts renderText() +export const TextRenderer = ({ text }: TextRendererProps) => { + return ( +
+      {text}
+    
+ ); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/index.ts new file mode 100644 index 00000000000..d8340f89b1c --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/renderers/index.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { HTMLRenderer } from './HTMLRenderer'; +export { TextRenderer } from './TextRenderer'; +export { ImageRenderer } from './ImageRenderer'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx new file mode 100644 index 00000000000..4b34591c23a --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx @@ -0,0 +1,153 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useState, useEffect, useMemo, useRef } from 'react'; +import { Table } from 'antd'; +import type { Column, Line, Pie, Scatter } from '@antv/g2plot'; +import { VisualizationControls } from './VisualizationControls'; +import { parseTableData, exportFile } from '@/utils'; +import type { ParagraphConfigResult, ParagraphIResultsMsgItem, VisualizationMode } from '@zeppelin/sdk'; + +interface TableVisualizationProps { + result: ParagraphIResultsMsgItem; + config?: ParagraphConfigResult; +} + +export const TableVisualization = ({ result, config }: TableVisualizationProps) => { + const [currentMode, setCurrentMode] = useState(config?.graph.mode || 'table'); + const chartRef = useRef(null); + + const tableData = useMemo(() => parseTableData(result.data), [result.data]); + + const handleExport = (type: 'csv' | 'xlsx') => { + if (tableData) { + exportFile(tableData, type); + } + }; + + const renderVisualization = () => { + if (!tableData || tableData.rows.length === 0) return null; + + if (currentMode === 'table') { + const columns = tableData.columnNames.map((col, idx) => ({ + title: col, + dataIndex: idx, + key: idx, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + render: (text: any) => text + })); + + const dataSource = tableData.rows.map((row, idx) => ({ + key: idx, + ...row.reduce((acc, cell, cellIdx) => ({ ...acc, [cellIdx]: cell }), {}) + })); + + return ( + + ); + } + + return
; + }; + + useEffect(() => { + if (!chartRef.current || !tableData || tableData.rows.length === 0 || currentMode === 'table') return; + + const data = tableData.rows.map((row, idx) => ({ + category: row[0] || `Row ${idx + 1}`, + value: parseFloat(row[1] || '0') || 0, + x: idx, + y: parseFloat(row[1] || '0') || 0 + })); + + let chart: Column | Line | Pie | Scatter | null = null; + let cancelled = false; + + import('@antv/g2plot').then(g2plot => { + if (cancelled || !chartRef.current) return; + + switch (currentMode) { + case 'multiBarChart': + chart = new g2plot.Column(chartRef.current, { + data, + xField: 'category', + yField: 'value', + color: '#1890ff', + columnWidthRatio: 0.8 + }); + break; + case 'lineChart': + chart = new g2plot.Line(chartRef.current, { + data, + xField: 'category', + yField: 'value', + color: '#1890ff' + }); + break; + case 'pieChart': + chart = new g2plot.Pie(chartRef.current, { + data, + angleField: 'value', + colorField: 'category' + }); + break; + case 'scatterChart': + chart = new g2plot.Scatter(chartRef.current, { + data, + xField: 'x', + yField: 'y', + color: '#1890ff' + }); + break; + case 'stackedAreaChart': + chart = new g2plot.Line(chartRef.current, { + data, + xField: 'category', + yField: 'value', + color: '#1890ff', + point: { + size: 3, + shape: 'circle' + }, + lineStyle: { + lineWidth: 2 + } + }); + break; + } + + if (chart) { + chart.render(); + } + }); + + return () => { + cancelled = true; + if (chart) { + chart.destroy(); + } + }; + }, [currentMode, tableData]); + + return ( +
+ + {renderVisualization()} +
+ ); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/VisualizationControls.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/VisualizationControls.tsx new file mode 100644 index 00000000000..a05f2b39487 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/VisualizationControls.tsx @@ -0,0 +1,67 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Button, Space } from 'antd'; +import BarChartOutlined from '@ant-design/icons/BarChartOutlined'; +import PieChartOutlined from '@ant-design/icons/PieChartOutlined'; +import LineChartOutlined from '@ant-design/icons/LineChartOutlined'; +import DotChartOutlined from '@ant-design/icons/DotChartOutlined'; +import TableOutlined from '@ant-design/icons/TableOutlined'; +import AreaChartOutlined from '@ant-design/icons/AreaChartOutlined'; +import DownloadOutlined from '@ant-design/icons/DownloadOutlined'; +import FileExcelOutlined from '@ant-design/icons/FileExcelOutlined'; +import type { VisualizationMode } from '@zeppelin/sdk'; + +interface VisualizationControlsProps { + currentMode: VisualizationMode; + onModeChange: (mode: VisualizationMode) => void; + onExport: (type: 'csv' | 'xlsx') => void; +} + +export const VisualizationControls = ({ currentMode, onModeChange, onExport }: VisualizationControlsProps) => { + const visualizations = [ + { id: 'table', name: 'Table', icon: }, + { id: 'multiBarChart', name: 'Bar Chart', icon: }, + { id: 'pieChart', name: 'Pie Chart', icon: }, + { id: 'lineChart', name: 'Line Chart', icon: }, + { id: 'stackedAreaChart', name: 'Area Chart', icon: }, + { id: 'scatterChart', name: 'Scatter Chart', icon: } + ] as const; + + return ( +
+ + + {visualizations.map(viz => ( + + ))} + + + + + + +
+ ); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/index.ts new file mode 100644 index 00000000000..485503f8a51 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/index.ts @@ -0,0 +1,14 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { VisualizationControls } from './VisualizationControls'; +export { TableVisualization } from './TableVisualization'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/index.html b/zeppelin-web-angular/projects/zeppelin-react/src/index.html new file mode 100644 index 00000000000..3fcd3bb99cd --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/index.html @@ -0,0 +1,23 @@ + + + + + + + + Zeppelin - React by Micro Frontend + + +
+ + diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/main.ts b/zeppelin-web-angular/projects/zeppelin-react/src/main.ts new file mode 100644 index 00000000000..190f1978160 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/main.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { PublishedParagraph, mount } from './pages/PublishedParagraph'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx new file mode 100644 index 00000000000..c33b2b911e3 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx @@ -0,0 +1,68 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createRoot } from 'react-dom/client'; +import { ConfigProvider } from 'antd'; +import { Empty } from '@/components'; +import { SingleResultRenderer } from '@/templates'; +import type { ParagraphConfigResults, ParagraphIResultsMsgItem } from '@zeppelin/sdk'; + +export interface PublishedParagraphProps { + paragraphId: string; + results?: ParagraphIResultsMsgItem[]; + config?: ParagraphConfigResults; +} + +export const PublishedParagraph = ({ results, config }: PublishedParagraphProps) => { + if (!results || results.length === 0) { + return ; + } + + return ( + +
+ {results.map((result, index) => ( +
+ +
+ ))} +
+
+ ); +}; + +export const mount = (element: HTMLElement, props?: PublishedParagraphProps) => { + if (!element) { + throw new Error('Mount element is required'); + } + + const root = createRoot(element); + + root.render( + + ); + + return () => { + root.unmount(); + }; +}; + diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/pages/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/pages/index.ts new file mode 100644 index 00000000000..95bf317aaf4 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/pages/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './PublishedParagraph'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/templates/SingleResultRenderer.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/templates/SingleResultRenderer.tsx new file mode 100644 index 00000000000..5b4202ad1f7 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/templates/SingleResultRenderer.tsx @@ -0,0 +1,48 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Alert } from 'antd'; +import { HTMLRenderer, TextRenderer, ImageRenderer, TableVisualization } from '@/components'; +import { checkAndReplaceCarriageReturn } from '@/utils'; +import { DatasetType, ParagraphConfigResult, ParagraphConfigResults, ParagraphIResultsMsgItem } from '@zeppelin/sdk'; + +interface SingleResultRendererProps { + result: ParagraphIResultsMsgItem; + index: number; + config?: ParagraphConfigResults; +} + +export const SingleResultRenderer = ({ result, index, config }: SingleResultRendererProps) => { + const resultConfig: ParagraphConfigResult | undefined = config?.[index]; + + switch (result.type) { + case DatasetType.TABLE: + return ; + case DatasetType.HTML: + return ; + case DatasetType.TEXT: + return ; + case DatasetType.IMG: + return ; + case DatasetType.ANGULAR: + return ( + + ); + default: + return null; + } +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/templates/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/templates/index.ts new file mode 100644 index 00000000000..71ee4447a35 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/templates/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './SingleResultRenderer'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts b/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts new file mode 100644 index 00000000000..d048a738651 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts @@ -0,0 +1,48 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type { TableData } from './tableUtils'; + +const EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'; +const EXCEL_EXTENSION = '.xlsx'; + +export const exportFile = async (tableData: TableData, type: 'csv' | 'xlsx') => { + if (!tableData?.rows || tableData.rows.length === 0) { + return; + } + + const { saveAs } = await import('file-saver'); + + if (type === 'xlsx') { + const XLSX = await import('xlsx'); + + const wb = XLSX.utils.book_new(); + const ws = XLSX.utils.aoa_to_sheet([tableData.columnNames, ...tableData.rows]); + XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); + + const excelBuffer = XLSX.write(wb, { + bookType: 'xlsx', + type: 'array' + }); + + const blob = new Blob([excelBuffer], { type: EXCEL_TYPE }); + saveAs(blob, `export${EXCEL_EXTENSION}`); + } else { + const separator = ','; + const header = tableData.columnNames.join(separator); + const rows = tableData.rows.map(row => row.join(separator)); + const content = [header, ...rows].join('\n'); + + const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); + saveAs(blob, `export.${type}`); + } +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/utils/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/utils/index.ts new file mode 100644 index 00000000000..e66e6c7627f --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/utils/index.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './tableUtils'; +export * from './textUtils'; +export * from './exportFile'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/utils/tableUtils.ts b/zeppelin-web-angular/projects/zeppelin-react/src/utils/tableUtils.ts new file mode 100644 index 00000000000..31204c7a865 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/utils/tableUtils.ts @@ -0,0 +1,26 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface TableData { + columnNames: string[]; + rows: string[][]; +} + +export const parseTableData = (data: string): TableData => { + const lines = data.trim().split('\n'); + if (lines.length === 0) return { columnNames: [], rows: [] }; + + const columnNames = lines[0].split('\t'); + const rows = lines.slice(1).map(line => line.split('\t')); + + return { columnNames, rows }; +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/utils/textUtils.ts b/zeppelin-web-angular/projects/zeppelin-react/src/utils/textUtils.ts new file mode 100644 index 00000000000..8ad111ad386 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/utils/textUtils.ts @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Replicated from Angular: src/app/pages/workspace/share/result/result.component.ts +export const checkAndReplaceCarriageReturn = (data: string): string => { + const str = data.replace(/\r\n/g, '\n'); + if (/\r/.test(str)) { + const generatedLines = str.split('\n').map(line => { + if (!/\r/.test(line)) { + return line; + } + const parts = line.split('\r'); + let currentLine = parts[0]; + for (let i = 1; i < parts.length; i++) { + const part = parts[i]; + const partLength = part.length; + const overwritten = part + currentLine.substring(partLength); + currentLine = overwritten; + } + return currentLine; + }); + return generatedLines.join('\n'); + } else { + return str; + } +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/tsconfig.json b/zeppelin-web-angular/projects/zeppelin-react/tsconfig.json new file mode 100644 index 00000000000..3dba52c585b --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": false, + "outDir": "./dist", + "jsx": "react-jsx", + "baseUrl": "src", + "paths": { + "@/*": ["./*"], + "@zeppelin/sdk": ["../../zeppelin-sdk/src"], + "@zeppelin/sdk/*": ["../../zeppelin-sdk/src/*"] + } + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js b/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js new file mode 100644 index 00000000000..4facdadc09b --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js @@ -0,0 +1,130 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const path = require('path'); + +module.exports = (_env, argv) => { + const isProduction = argv.mode === 'production'; + const publicPath = isProduction ? '/assets/react/' : 'http://localhost:3001/'; + + return { + entry: './src/main.ts', + devServer: { + port: 3001, + historyApiFallback: true, + hot: false, + liveReload: false, + allowedHosts: 'all', + headers: { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS', + 'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization' + }, + client: false, + webSocketServer: false + }, + resolve: { + extensions: ['.tsx', '.ts', '.js', '.jsx'], + modules: ['node_modules', path.resolve(__dirname, '../../node_modules')], + alias: { + '@': path.resolve(__dirname, 'src'), + '@zeppelin/sdk': path.resolve(__dirname, '../zeppelin-sdk/src') + } + }, + resolveLoader: { + modules: ['node_modules', path.resolve(__dirname, '../../node_modules')] + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: { + loader: 'ts-loader', + options: { + transpileOnly: true, + configFile: 'tsconfig.json' + } + }, + exclude: /node_modules/ + }, + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + } + ] + }, + plugins: [ + new ModuleFederationPlugin({ + name: 'reactApp', + filename: 'remoteEntry.js', + exposes: { + './PublishedParagraph': './src/pages/PublishedParagraph' + }, + shared: { + react: { + singleton: true, + strictVersion: false, + requiredVersion: '18.3.1', + eager: true + }, + 'react-dom': { + singleton: true, + strictVersion: false, + requiredVersion: '18.3.1', + eager: true + } + } + }), + new HtmlWebpackPlugin({ + template: './src/index.html' + }), + { + apply: compiler => { + compiler.hooks.afterEmit.tap('GenerateRemoteEntryJson', () => { + const fs = require('fs'); + const path = require('path'); + + const remoteEntryJson = { + name: 'zeppelinReact', + type: 'module', + version: '1.0.0', + baseUrl: isProduction ? '/assets/react/' : 'http://localhost:3001/', + exposes: { + './PublishedParagraph': './PublishedParagraph.tsx' + } + }; + + const outputDir = path.resolve(__dirname, 'dist'); + const outputPath = path.resolve(outputDir, 'remoteEntry.json'); + + // Ensure directory exists + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + + fs.writeFileSync(outputPath, JSON.stringify(remoteEntryJson, null, 2)); + console.log('Generated remoteEntry.json for Native Federation'); + }); + } + } + ], + output: { + path: path.resolve(__dirname, 'dist'), + clean: true, + publicPath: publicPath, + uniqueName: 'reactApp', + scriptType: 'text/javascript' + } + }; +}; diff --git a/zeppelin-web-angular/proxy.conf.js b/zeppelin-web-angular/proxy.conf.js index b4d39e0d230..e4b8e53dfd2 100644 --- a/zeppelin-web-angular/proxy.conf.js +++ b/zeppelin-web-angular/proxy.conf.js @@ -16,14 +16,18 @@ dotenv.config(); const proxyConfig = [ { - context: ['/'], + // Changed from ['/'] to ['/api', '/app'] to avoid proxying React microfrontend routes + // Module Federation serves React app at /assets/react/, which should not be proxied + context: ['/api', '/app'], target: 'http://127.0.0.1:8080', secure: false, changeOrigin: true }, { context: '/ws', - target: 'ws://127.0.0.1:8080', + // Changed from 'ws://127.0.0.1:8080' to 'http://127.0.0.1:8080' + // http-proxy-middleware automatically upgrades to WebSocket protocol when ws: true + target: 'http://127.0.0.1:8080', secure: false, ws: true, changeOrigin: true diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html index 7e126e70280..f7d25f91020 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.html @@ -9,25 +9,28 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - - +
+
+ + + + +
diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts index 0e8ae766421..e4573c7c221 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts @@ -13,7 +13,8 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnInit, + ElementRef, + OnDestroy, QueryList, TemplateRef, ViewChild, @@ -33,6 +34,7 @@ import { SpellResult } from '@zeppelin/spell'; import { isNil } from 'lodash'; import { NzModalService } from 'ng-zorro-antd/modal'; import { NotebookParagraphResultComponent } from '../../share/result/result.component'; +import { environment } from '../../../../../environments/environment'; @Component({ selector: 'zeppelin-publish-paragraph', @@ -40,14 +42,20 @@ import { NotebookParagraphResultComponent } from '../../share/result/result.comp styleUrls: ['./paragraph.component.less'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class PublishedParagraphComponent extends ParagraphBase implements Published, OnInit { +export class PublishedParagraphComponent extends ParagraphBase implements Published, OnDestroy { readonly [publishedSymbol] = true; noteId: string | null = null; paragraphId: string | null = null; previewCode: string = ''; + useReact = false; + isLoading = true; + error: string | null = null; + private unmountReact: (() => void) | null = null; + private reactScriptLoaded = false; @ViewChild('codePreviewModal', { static: true }) codePreviewModal!: TemplateRef; + @ViewChild('reactContainer', { static: false }) reactContainer!: ElementRef; @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents!: QueryList; @@ -62,6 +70,10 @@ export class PublishedParagraphComponent extends ParagraphBase implements Publis cdr: ChangeDetectorRef ) { super(messageService, noteStatusService, ngZService, cdr); + this.activatedRoute.queryParams.subscribe(queryParams => { + this.useReact = queryParams.react === 'true' || queryParams.react === ''; + }); + this.activatedRoute.params.subscribe(params => { if (typeof params.noteId !== 'string') { throw new Error(`noteId path parameter should be string, but got ${typeof params.noteId} instead.`); @@ -72,7 +84,11 @@ export class PublishedParagraphComponent extends ParagraphBase implements Publis }); } - ngOnInit() {} + ngOnDestroy() { + if (this.useReact) { + this.cleanupReactWidget(); + } + } @MessageListener(OP.NOTE) getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) { @@ -83,6 +99,14 @@ export class PublishedParagraphComponent extends ParagraphBase implements Publis if (!this.paragraph.results) { this.showRunConfirmationModal(); } + if (this.useReact) { + this.setResults(this.paragraph); + this.isLoading = false; + this.cdr.markForCheck(); + this.loadReactWidget(); + return; + } + this.setResults(this.paragraph); this.originalText = this.paragraph.text; this.initializeDefault(this.paragraph.config, this.paragraph.settings); @@ -177,4 +201,75 @@ export class PublishedParagraphComponent extends ParagraphBase implements Publis }); }); } + + /** + * Loads the React micro-frontend via Webpack Module Federation. + * + * Flow: + * 1. Loads remoteEntry.js once (skips on subsequent calls via `reactScriptLoaded` flag). + * 2. remoteEntry.js registers `window.reactApp` as a federation container. + * 3. `container.get('./PublishedParagraph')` returns a module with a `mount(el, props)` function. + * 4. `mount()` calls `createRoot()` and renders into the given element. + * 5. `mount()` returns an `unmount` function, stored for cleanup in `ngOnDestroy`. + * + * See `projects/zeppelin-react/README.md` for the full guide. + * Append `?react=true` to a published paragraph URL to activate. + */ + private loadReactWidget() { + if (!this.reactContainer || !this.paragraph) { + return; + } + + const loadModule = async () => { + // @ts-ignore + const container = window.reactApp; + if (!container) { + throw new Error('window.reactApp not available'); + } + + const factory = await container.get('./PublishedParagraph'); + const { mount } = factory(); + + if (!mount || typeof mount !== 'function') { + throw new Error('mount function not found'); + } + + const mountPoint = this.reactContainer.nativeElement; + const props = { + paragraphId: this.paragraphId, + noteId: this.noteId, + results: this.paragraph?.results?.msg, + config: this.paragraph?.config?.results + }; + + this.unmountReact = mount(mountPoint, props); + }; + + if (this.reactScriptLoaded) { + loadModule(); + return; + } + + const script = document.createElement('script'); + script.src = environment.reactRemoteEntryUrl; + + script.onload = () => { + this.reactScriptLoaded = true; + loadModule(); + }; + + script.onerror = () => { + this.error = 'Failed to load React widget'; + this.cdr.markForCheck(); + }; + + document.head.appendChild(script); + } + + private cleanupReactWidget() { + if (this.unmountReact) { + this.unmountReact(); + this.unmountReact = null; + } + } } diff --git a/zeppelin-web-angular/src/environments/environment.prod.ts b/zeppelin-web-angular/src/environments/environment.prod.ts index a00527f83a1..8613a332bc6 100644 --- a/zeppelin-web-angular/src/environments/environment.prod.ts +++ b/zeppelin-web-angular/src/environments/environment.prod.ts @@ -11,5 +11,6 @@ */ export const environment = { - production: true + production: true, + reactRemoteEntryUrl: '/assets/react/remoteEntry.js' }; diff --git a/zeppelin-web-angular/src/environments/environment.ts b/zeppelin-web-angular/src/environments/environment.ts index 765af95bf30..c20bf371d28 100644 --- a/zeppelin-web-angular/src/environments/environment.ts +++ b/zeppelin-web-angular/src/environments/environment.ts @@ -15,7 +15,8 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, + reactRemoteEntryUrl: 'http://localhost:3001/remoteEntry.js' }; /* diff --git a/zeppelin-web-angular/webpack.partial.js b/zeppelin-web-angular/webpack.config.js similarity index 68% rename from zeppelin-web-angular/webpack.partial.js rename to zeppelin-web-angular/webpack.config.js index 0c5415cdc2e..3f7e7436bc2 100644 --- a/zeppelin-web-angular/webpack.partial.js +++ b/zeppelin-web-angular/webpack.config.js @@ -11,8 +11,24 @@ */ const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); +const webpack = require('@angular-devkit/build-angular/node_modules/webpack'); +const ModuleFederationPlugin = webpack.container.ModuleFederationPlugin; module.exports = { + output: { + // Unique name for this microfrontend to avoid collisions with other apps + uniqueName: 'shell', + publicPath: '/', + scriptType: 'text/javascript' + }, + optimization: { + // Disable runtime chunk to prevent conflicts with Module Federation's runtime + runtimeChunk: false + }, + experiments: { + // Enable top-level await for async Module Federation container initialization + topLevelAwait: true + }, // To avoid path conflict with websocket server path of ZeppelinServer devServer: { client: { @@ -28,6 +44,12 @@ module.exports = { } }, plugins: [ + new ModuleFederationPlugin({ + name: 'shell', + remotes: { + reactApp: 'reactApp@http://localhost:3001/remoteEntry.js' + } + }), new MonacoWebpackPlugin({ languages: [ 'bat', From aaa52286a36e18ee9747546a5c2089d50a402a9a Mon Sep 17 00:00:00 2001 From: Gyeongtae Park Date: Mon, 9 Mar 2026 22:24:30 +0900 Subject: [PATCH 006/179] [ZEPPELIN-6402] Update copyright year to 2026 in NOTICE file ### What is this PR for? This PR updates the copyright year range in the NOTICE file from 2015-2025 to 2015-2026 to reflect ongoing development and contributions in 2026. ### What type of PR is it? Documentation ### Todos * [x] - Update copyright year in NOTICE file ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6402 ### How should this be tested? * Verify that the NOTICE file contains the updated copyright year range "2015 - 2026" * Confirm that no other changes were made to the NOTICE file ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No. * Does this needs documentation? No. Closes #5177 from ParkGyeongTae/ZEPPELIN-6402. Signed-off-by: ParkGyeongTae --- NOTICE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NOTICE b/NOTICE index e583f549101..bd7844b811c 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache Zeppelin -Copyright 2015 - 2025 The Apache Software Foundation +Copyright 2015 - 2026 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (https://www.apache.org/). From 08fa86aeab2ccb4837c5b2d19820115acb206672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Mon, 9 Mar 2026 23:18:36 +0900 Subject: [PATCH 007/179] [ZEPPELIN-6401] Resolve all npm audit vulnerabilities in zeppelin-react MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Resolved all 16 npm audit vulnerabilities (8 high, 6 moderate, 2 low) in zeppelin-web-angular/projects/zeppelin-react. Direct dependency upgrades: - webpack 5.88.0 → 5.105.4 (moderate: DOM Clobbering XSS, SSRF) - webpack-dev-server 4.15.0 → 5.2.3 (moderate: source code theft vulnerability) - antv/g2plot 2.4.35 → 2.3.32 (high: XSS, Path Traversal) - g2plot 2.4.35 pulls in fmin → rollup2.x as transitive dependency, which has 2 high severity vulnerabilities - g2plot 2.3.32 does not depend on fmin, so rollup is removed entirely - No API breaking changes — Column, Line, Pie, Scatter all available in 2.3.32 - xlsx 0.18.5 → replaced with xlsx-js-style 1.2.0 (high: Prototype Pollution, ReDoS) - All versions of xlsx on npm are vulnerable with no patched version available - xlsx-js-style is an API-compatible community fork with the vulnerabilities fixed - types/xlsx 0.0.36 → removed (no longer needed after xlsx replacement) Transitive dependency fixes (via npm audit fix): - lodash 4.17.21 → 4.17.23 (moderate: Prototype Pollution) - lodash-es 4.17.21 → 4.17.23 (moderate: Prototype Pollution) - node-forge 1.3.1 → 1.3.3 (high: ASN.1 vulnerabilities) - serialize-javascript — resolved via webpack upgrade (high: RCE, dep removed in newer terser-webpack-plugin) - qs/express/body-parser — audit fix (moderate: DoS) - ajv — audit fix (moderate: ReDoS) Constraints: - Node 18 environment maintained (serialize-javascript 7.x requires Node >= 20, resolved by upgrading webpack instead) Verification: - npm audit → 0 vulnerabilities - npm run build → success Related Dependabot PRs (redundant, to be closed): - #5168, #5169, #5170, #5171, #5172, #5173 ### What type of PR is it? Hot Fix ### Todos ### What is the Jira issue? ZEPPELIN-6401 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5176 from dididy/fix/zeppelin-react-audit. Signed-off-by: ChanHo Lee --- .github/workflows/frontend.yml | 14 + .../projects/zeppelin-react/package-lock.json | 2595 +++++++++-------- .../projects/zeppelin-react/package.json | 9 +- .../zeppelin-react/src/utils/exportFile.ts | 2 +- 4 files changed, 1422 insertions(+), 1198 deletions(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 7eecf57638d..d91f2573e96 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -30,6 +30,20 @@ permissions: contents: read # to fetch code (actions/checkout) jobs: + npm-audit: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: 'zeppelin-web-angular/.nvmrc' + # TODO: Add zeppelin-web-angular root audit after Angular version upgrade and stabilization + - name: Run npm audit on zeppelin-react + working-directory: zeppelin-web-angular/projects/zeppelin-react + run: npm ci --ignore-scripts && npm audit --audit-level=high + run-e2e-tests-in-zeppelin-web: runs-on: ubuntu-24.04 steps: diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index 2ae973b693e..ff9ba13cd01 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -9,21 +9,20 @@ "version": "0.0.1", "dependencies": { "@ant-design/icons": "5.4.0", - "@antv/g2plot": "2.4.35", + "@antv/g2plot": "2.3.32", "@zeppelin/sdk": "file:../zeppelin-sdk", "ansi-to-react": "6.2.6", "antd": "5.21.0", "file-saver": "2.0.5", "react": "18.3.1", "react-dom": "18.3.1", - "xlsx": "0.18.5" + "xlsx-js-style": "1.2.0" }, "devDependencies": { "@types/file-saver": "2.0.7", "@types/node": "18.19.64", "@types/react": "18.3.26", "@types/react-dom": "18.3.7", - "@types/xlsx": "0.0.36", "@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/parser": "^8.56.1", "css-loader": "6.8.0", @@ -34,9 +33,9 @@ "style-loader": "3.3.0", "ts-loader": "9.4.0", "typescript": "4.9.5", - "webpack": "5.88.0", + "webpack": "5.105.4", "webpack-cli": "5.1.4", - "webpack-dev-server": "4.15.0" + "webpack-dev-server": "5.2.3" } }, "../zeppelin-sdk": { @@ -397,22 +396,15 @@ } }, "node_modules/@antv/g2plot": { - "version": "2.4.35", - "resolved": "https://registry.npmjs.org/@antv/g2plot/-/g2plot-2.4.35.tgz", - "integrity": "sha512-jpfgUqC2ch1kkrSSiY8qsFZ5/cYGcwMA9MAgqZXHdNBDcClrLzdakHyc5RN2na9LwZTY3qoj6AawZzAQSiJ58w==", + "version": "2.3.32", + "resolved": "https://registry.npmjs.org/@antv/g2plot/-/g2plot-2.3.32.tgz", + "integrity": "sha512-ksBCEAjd2pki3H3Ce0c26sOD5Z8v6v7hbFwux1se5H5YPpzf+Vq8FgWO8Tokur07wiOqnAJzuEDflxos2KxApw==", "license": "MIT", "dependencies": { - "@antv/color-util": "^2.0.6", "@antv/event-emitter": "^0.1.2", - "@antv/g-base": "^0.5.11", - "@antv/g2": "^4.2.12", - "@antv/matrix-util": "^3.1.0-beta.2", - "@antv/path-util": "^3.0.1", - "@antv/scale": "^0.3.18", - "@antv/util": "^2.0.17", + "@antv/g2": "^4.1.23", "d3-hierarchy": "^2.0.0", "d3-regression": "^1.3.5", - "fmin": "^0.0.2", "pdfast": "^0.2.0", "size-sensor": "^1.0.1", "tslib": "^2.0.3" @@ -429,17 +421,6 @@ "tslib": "^2.0.3" } }, - "node_modules/@antv/path-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-3.0.1.tgz", - "integrity": "sha512-tpvAzMpF9Qm6ik2YSMqICNU5tco5POOW7S4XoxZAI/B0L26adU+Md/SmO0BBo2SpuywKvzPH3hPT3xmoyhr04Q==", - "license": "MIT", - "dependencies": { - "gl-matrix": "^3.1.0", - "lodash-es": "^4.17.21", - "tslib": "^2.0.3" - } - }, "node_modules/@antv/scale": { "version": "0.3.18", "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.18.tgz", @@ -712,35 +693,454 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } }, - "node_modules/@ljharb/resumer": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.0.1.tgz", - "integrity": "sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==", - "license": "MIT", + "node_modules/@jsonjoy.com/buffers": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.56.11.tgz", + "integrity": "sha512-wThHjzUp01ImIjfCwhs+UnFkeGPFAymwLEkOtenHewaKe2pTP12p6r1UuwikA9NEvNf9Vlck92r8fb8n/MWM5w==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@ljharb/through": "^2.3.9" + "@jsonjoy.com/fs-node-builtins": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.56.11", + "thingies": "^2.5.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@ljharb/through": { - "version": "2.3.14", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.14.tgz", - "integrity": "sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A==", - "license": "MIT", + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.56.11.tgz", + "integrity": "sha512-ZYlF3XbMayyp97xEN8ZvYutU99PCHjM64mMZvnCseXkCJXJDVLAwlF8Q/7q/xiWQRsv3pQBj1WXHd9eEyYcaCQ==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "call-bind": "^1.0.8" + "@jsonjoy.com/fs-core": "4.56.11", + "@jsonjoy.com/fs-node-builtins": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.56.11", + "thingies": "^2.5.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.56.11.tgz", + "integrity": "sha512-D65YrnP6wRuZyEWoSFnBJSr5zARVpVBGctnhie4rCsMuGXNzX7IHKaOt85/Aj7SSoG1N2+/xlNjWmkLvZ2H3Tg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.56.11", + "@jsonjoy.com/fs-node-builtins": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/fs-print": "4.56.11", + "@jsonjoy.com/fs-snapshot": "4.56.11", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.56.11.tgz", + "integrity": "sha512-CNmt3a0zMCIhniFLXtzPWuUxXFU+U+2VyQiIrgt/rRVeEJNrMQUABaRbVxR0Ouw1LyR9RjaEkPM6nYpED+y43A==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.56.11.tgz", + "integrity": "sha512-5OzGdvJDgZVo+xXWEYo72u81zpOWlxlbG4d4nL+hSiW+LKlua/dldNgPrpWxtvhgyntmdFQad2UTxFyGjJAGhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-fsa": "4.56.11", + "@jsonjoy.com/fs-node-builtins": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.56.11" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.56.11.tgz", + "integrity": "sha512-JADOZFDA3wRfsuxkT0+MYc4F9hJO2PYDaY66kRTG6NqGX3+bqmKu66YFYAbII/tEmQWPZeHoClUB23rtQM9UPg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.56.11" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.56.11.tgz", + "integrity": "sha512-rnaKRgCRIn8JGTjxhS0JPE38YM3Pj/H7SW4/tglhIPbfKEkky7dpPayNKV2qy25SZSL15oFVgH/62dMZ/z7cyA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-utils": "4.56.11", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.56.11.tgz", + "integrity": "sha512-IIldPX+cIRQuUol9fQzSS3hqyECxVpYMJQMqdU3dCKZFRzEl1rkIkw4P6y7Oh493sI7YdxZlKr/yWdzEWZ1wGQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/util": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/@nodelib/fs.scandir": { @@ -781,6 +1181,165 @@ "node": ">= 8" } }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", + "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", + "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", + "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", + "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", + "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", + "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pfx": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", + "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", + "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", + "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@rc-component/async-validator": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", @@ -1007,16 +1566,16 @@ "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.24.tgz", - "integrity": "sha512-Mbrt4SRlXSTWryOnHAh2d4UQ/E7n9lZyGSi6KgX+4hkuL9soYbLOVXVhnk/ODp12YsGc95f4pOvqywJ6kngUwg==", + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", - "@types/serve-static": "*" + "@types/serve-static": "^1" } }, "node_modules/@types/express-serve-static-core": { @@ -1093,21 +1652,11 @@ "node_modules/@types/node": { "version": "18.19.64", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", - "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-forge": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", - "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/node": "*" + "undici-types": "~5.26.4" } }, "node_modules/@types/prop-types": { @@ -1153,9 +1702,9 @@ } }, "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "dev": true, "license": "MIT" }, @@ -1222,17 +1771,6 @@ "@types/node": "*" } }, - "node_modules/@types/xlsx": { - "version": "0.0.36", - "resolved": "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz", - "integrity": "sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw==", - "deprecated": "This is a stub types definition for xlsx (https://github.com/sheetjs/js-xlsx). xlsx provides its own type definitions, so you don't need @types/xlsx installed!", - "dev": true, - "license": "MIT", - "dependencies": { - "xlsx": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.56.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", @@ -1863,9 +2401,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -1875,15 +2413,17 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "deprecated": "package has been renamed to acorn-import-attributes", + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", "dev": true, "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, "peerDependencies": { - "acorn": "^8" + "acorn": "^8.14.0" } }, "node_modules/acorn-jsx": { @@ -1941,9 +2481,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -1964,51 +2504,6 @@ "dev": true, "license": "MIT" }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "license": "MIT", - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/align-text/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", - "license": "BSD-3-Clause OR MIT", - "engines": { - "node": ">=0.4.2" - } - }, "node_modules/anser": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/anser/-/anser-2.3.5.tgz", @@ -2028,24 +2523,6 @@ "ansi-html": "bin/ansi-html" } }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ansi-to-react": { "version": "6.2.6", "resolved": "https://registry.npmjs.org/ansi-to-react/-/ansi-to-react-6.2.6.tgz", @@ -2167,6 +2644,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -2295,6 +2773,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", @@ -2312,10 +2791,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2325,6 +2820,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -2340,16 +2836,20 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.20", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.20.tgz", - "integrity": "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", "dev": true, "license": "Apache-2.0", "bin": { - "baseline-browser-mapping": "dist/cli.js" + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" } }, "node_modules/batch": { @@ -2373,24 +2873,24 @@ } }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -2419,6 +2919,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -2439,9 +2940,9 @@ } }, "node_modules/browserslist": { - "version": "4.27.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.27.0.tgz", - "integrity": "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { @@ -2459,11 +2960,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.8.19", - "caniuse-lite": "^1.0.30001751", - "electron-to-chromium": "^1.5.238", - "node-releases": "^2.0.26", - "update-browserslist-db": "^1.1.4" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -2479,6 +2980,22 @@ "dev": true, "license": "MIT" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2489,10 +3006,21 @@ "node": ">= 0.8" } }, + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -2511,6 +3039,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2524,6 +3053,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -2557,19 +3087,10 @@ "tslib": "^2.0.3" } }, - "node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", - "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", "dev": true, "funding": [ { @@ -2587,19 +3108,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", - "license": "MIT", - "dependencies": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cfb": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", @@ -2613,34 +3121,6 @@ "node": ">=0.8" } }, - "node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/chalk/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -2695,17 +3175,6 @@ "node": ">= 10.0" } }, - "node_modules/cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", - "license": "ISC", - "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, "node_modules/clone-deep": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", @@ -2721,15 +3190,6 @@ "node": ">=6" } }, - "node_modules/codepage": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", - "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", - "license": "Apache-2.0", - "engines": { - "node": ">=0.8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2809,6 +3269,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/connect-history-api-fallback": { @@ -2844,16 +3305,10 @@ "node": ">= 0.6" } }, - "node_modules/contour_plot": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", - "integrity": "sha512-Nil2HI76Xux6sVGORvhSS8v66m+/h5CwFkBJDO+U5vWaMdNC0yXNCsGDPbzPhvqOEU5koebhdEvD372LI+IyLw==", - "license": "MIT" - }, "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -2861,9 +3316,9 @@ } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "dev": true, "license": "MIT" }, @@ -3035,6 +3490,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3052,6 +3508,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -3069,6 +3526,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3098,35 +3556,6 @@ "ms": "2.0.0" } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "license": "MIT", - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3134,23 +3563,41 @@ "dev": true, "license": "MIT" }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "execa": "^5.0.0" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -3165,19 +3612,23 @@ } }, "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -3191,15 +3642,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -3340,22 +3782,11 @@ "tslib": "^2.0.3" } }, - "node_modules/dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.4" - }, - "bin": { - "ignored": "bin/ignored" - } - }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -3374,9 +3805,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.240", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.240.tgz", - "integrity": "sha512-OBwbZjWgrCOH+g6uJsA2/7Twpas2OlepS9uvByJjR2datRDuKGYeD+nP8lBBks2qnB7bGJNHDUx7c/YLaT3QMQ==", + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", "dev": true, "license": "ISC" }, @@ -3391,14 +3822,14 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" + "tapable": "^2.3.0" }, "engines": { "node": ">=10.13.0" @@ -3431,6 +3862,7 @@ "version": "1.24.1", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "dev": true, "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.2", @@ -3499,6 +3931,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -3517,6 +3950,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3529,6 +3963,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3538,6 +3973,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3572,9 +4008,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, @@ -3582,6 +4018,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -3594,6 +4031,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3622,6 +4060,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7", @@ -3658,15 +4097,6 @@ "dev": true, "license": "MIT" }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/eslint": { "version": "8.57.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", @@ -4164,65 +4594,50 @@ "node": ">=0.8.x" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, + "node_modules/exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", + "license": "Apache-2.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">=0.8" } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -4312,6 +4727,12 @@ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", "license": "MIT" }, + "node_modules/fflate": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz", + "integrity": "sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A==", + "license": "MIT" + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -4345,18 +4766,18 @@ } }, "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -4409,19 +4830,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fmin": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", - "integrity": "sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A==", - "license": "BSD-3-Clause", - "dependencies": { - "contour_plot": "^0.0.1", - "json2module": "^0.0.3", - "rollup": "^0.25.8", - "tape": "^4.5.1", - "uglify-js": "^2.6.2" - } - }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -4447,6 +4855,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -4487,17 +4896,11 @@ "node": ">= 0.6" } }, - "node_modules/fs-monkey": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", - "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", - "dev": true, - "license": "Unlicense" - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -4519,6 +4922,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4528,6 +4932,7 @@ "version": "1.1.8", "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -4548,6 +4953,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4557,6 +4963,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4566,6 +4973,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -4590,32 +4998,21 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" }, "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.4" } }, "node_modules/get-symbol-description": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -4640,6 +5037,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -4669,6 +5067,23 @@ "node": ">= 6" } }, + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -4696,6 +5111,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, "license": "MIT", "dependencies": { "define-properties": "^1.2.1", @@ -4712,6 +5128,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4741,31 +5158,11 @@ "dev": true, "license": "MIT" }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4788,6 +5185,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -4800,6 +5198,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.0" @@ -4815,6 +5214,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4827,6 +5227,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -4842,6 +5243,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -4913,23 +5315,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -5004,20 +5389,24 @@ "license": "MIT" }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/http-parser-js": { @@ -5067,14 +5456,14 @@ } } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "engines": { - "node": ">=10.17.0" + "node": ">=10.18" } }, "node_modules/iconv-lite": { @@ -5175,6 +5564,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -5185,12 +5575,14 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, "license": "ISC" }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -5221,26 +5613,11 @@ "node": ">= 10" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -5258,6 +5635,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, "license": "MIT", "dependencies": { "async-function": "^1.0.0", @@ -5277,6 +5655,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, "license": "MIT", "dependencies": { "has-bigints": "^1.0.2" @@ -5305,6 +5684,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5317,16 +5697,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "license": "MIT" - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5339,6 +5714,7 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -5354,6 +5730,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5371,6 +5748,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5384,16 +5762,16 @@ } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5413,6 +5791,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -5428,6 +5807,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -5456,10 +5836,30 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5472,6 +5872,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5480,6 +5881,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-network-error": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz", + "integrity": "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5494,6 +5908,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5542,26 +5957,11 @@ "node": ">=0.10.0" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5574,6 +5974,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -5585,23 +5986,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-string": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5618,6 +6007,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -5635,6 +6025,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -5650,6 +6041,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5662,6 +6054,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3" @@ -5677,6 +6070,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -5690,22 +6084,26 @@ } }, "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", "dev": true, "license": "MIT", "dependencies": { - "is-docker": "^2.0.0" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, "license": "MIT" }, "node_modules/isexe": { @@ -5821,18 +6219,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json2module": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", - "integrity": "sha512-qYGxqrRrt4GbB8IEOy1jJGypkNsjWoIMlZt4bAsmUScCA507Hbc2p1JOhBzqn45u3PWafUgH2OnzyNU7udO/GA==", - "license": "BSD-3-Clause", - "dependencies": { - "rw": "^1.3.2" - }, - "bin": { - "json2module": "bin/json2module" - } - }, "node_modules/json2mq": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz", @@ -5889,15 +6275,6 @@ "shell-quote": "^1.8.3" } }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5949,18 +6326,12 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5968,15 +6339,6 @@ "dev": true, "license": "MIT" }, - "node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -6003,6 +6365,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6019,16 +6382,33 @@ } }, "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "version": "4.56.11", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.56.11.tgz", + "integrity": "sha512-/GodtwVeKVIHZKLUSr2ZdOxKBC5hHki4JNCU22DoCGPEHr5o2PD5U721zvESKyWwCfTfavFl9WZYgA13OAYK0g==", "dev": true, - "license": "Unlicense", + "license": "Apache-2.0", "dependencies": { - "fs-monkey": "^1.0.4" + "@jsonjoy.com/fs-core": "4.56.11", + "@jsonjoy.com/fs-fsa": "4.56.11", + "@jsonjoy.com/fs-node": "4.56.11", + "@jsonjoy.com/fs-node-builtins": "4.56.11", + "@jsonjoy.com/fs-node-to-fsa": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/fs-print": "4.56.11", + "@jsonjoy.com/fs-snapshot": "4.56.11", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" }, - "engines": { - "node": ">= 4.0.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, "node_modules/merge-descriptors": { @@ -6108,16 +6488,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -6129,6 +6499,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -6137,35 +6508,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mock-property": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.3.tgz", - "integrity": "sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.1", - "functions-have-names": "^1.2.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "hasown": "^2.0.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6270,20 +6612,10 @@ "semver": "bin/semver.js" } }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" - } - }, "node_modules/node-releases": { - "version": "2.0.26", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.26.tgz", - "integrity": "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "dev": true, "license": "MIT" }, @@ -6297,19 +6629,6 @@ "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -6333,35 +6652,11 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6371,6 +6666,7 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -6475,40 +6771,26 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "ISC", + "dependencies": { + "wrappy": "1" } }, "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", "dev": true, "license": "MIT", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6536,6 +6818,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.6", @@ -6579,17 +6862,21 @@ } }, "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/retry": "0.12.0", + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -6661,6 +6948,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -6680,6 +6968,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, "license": "MIT" }, "node_modules/path-to-regexp": { @@ -6728,10 +7017,29 @@ "node": ">=8" } }, + "node_modules/pkijs": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.3.3.tgz", + "integrity": "sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -6871,6 +7179,18 @@ "renderkid": "^3.0.0" } }, + "node_modules/printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", + "license": "Apache-2.0", + "bin": { + "printj": "bin/printj.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -6931,14 +7251,34 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -6968,16 +7308,6 @@ ], "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6989,16 +7319,16 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -7682,10 +8012,18 @@ "node": ">= 10.13.0" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7708,6 +8046,7 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7748,15 +8087,6 @@ "strip-ansi": "^6.0.1" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -7784,6 +8114,7 @@ "version": "1.22.11", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", @@ -7844,18 +8175,6 @@ "node": ">=0.10.0" } }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", - "license": "MIT", - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -7873,18 +8192,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", - "integrity": "sha512-a2S4Bh3bgrdO4BhKr2E4nZkjTvrJ2m2bWjMTzVYtoqSCn0HnuxosXnaJUHrMEziOWr3CzL9GjilQQKcyCQpJoA==", + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, "license": "MIT", - "dependencies": { - "chalk": "^1.1.1", - "minimist": "^1.2.0", - "source-map-support": "^0.3.2" + "engines": { + "node": ">=18" }, - "bin": { - "rollup": "bin/rollup" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/run-parallel": { @@ -7911,16 +8229,11 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" - }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -7961,6 +8274,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -7977,6 +8291,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -7994,6 +8309,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8025,15 +8341,16 @@ } }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { "node": ">= 10.13.0" @@ -8043,6 +8360,43 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/scroll-into-view-if-needed": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", @@ -8060,17 +8414,17 @@ "license": "MIT" }, "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", + "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", "dev": true, "license": "MIT", "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" + "@peculiar/x509": "^1.14.2", + "pkijs": "^3.3.3" }, "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/semver": { @@ -8087,40 +8441,30 @@ } }, "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -8128,16 +8472,6 @@ "dev": true, "license": "MIT" }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", @@ -8208,16 +8542,16 @@ } }, "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "dev": true, "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.19.0" + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" @@ -8227,6 +8561,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -8244,6 +8579,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -8259,6 +8595,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -8329,6 +8666,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8348,6 +8686,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8364,6 +8703,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8376,6 +8716,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8394,6 +8735,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8406,6 +8748,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8425,6 +8768,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8437,6 +8781,7 @@ "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8445,13 +8790,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, "node_modules/size-sensor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.2.tgz", @@ -8490,26 +8828,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", - "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", - "license": "MIT", - "dependencies": { - "source-map": "0.1.32" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -8605,9 +8923,9 @@ } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { @@ -8618,6 +8936,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -8686,6 +9005,7 @@ "version": "1.2.10", "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -8707,6 +9027,7 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -8725,6 +9046,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -8761,16 +9083,6 @@ "node": ">=8" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8807,19 +9119,11 @@ "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", "license": "MIT" }, - "node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8842,138 +9146,36 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/tape": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.17.0.tgz", - "integrity": "sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw==", - "license": "MIT", - "dependencies": { - "@ljharb/resumer": "~0.0.1", - "@ljharb/through": "~2.3.9", - "call-bind": "~1.0.2", - "deep-equal": "~1.1.1", - "defined": "~1.0.1", - "dotignore": "~0.1.2", - "for-each": "~0.3.3", - "glob": "~7.2.3", - "has": "~1.0.3", - "inherits": "~2.0.4", - "is-regex": "~1.1.4", - "minimist": "~1.2.8", - "mock-property": "~1.0.0", - "object-inspect": "~1.12.3", - "resolve": "~1.22.6", - "string.prototype.trim": "~1.2.8" - }, - "bin": { - "tape": "bin/tape" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/terser": { "version": "5.44.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", - "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", - "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "dependencies": { - "fast-deep-equal": "^3.1.3" + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" }, - "peerDependencies": { - "ajv": "^8.8.2" + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/terser-webpack-plugin": { + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.17.tgz", + "integrity": "sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" }, "engines": { "node": ">= 10.13.0" @@ -8981,6 +9183,20 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } } }, "node_modules/terser/node_modules/commander": { @@ -9008,6 +9224,23 @@ "dev": true, "license": "MIT" }, + "node_modules/thingies": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", + "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" + } + }, "node_modules/throttle-debounce": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.2.tgz", @@ -9101,6 +9334,23 @@ "node": ">=0.6" } }, + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -9186,6 +9436,26 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9230,6 +9500,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -9244,6 +9515,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -9263,6 +9535,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -9284,6 +9557,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.7", @@ -9320,45 +9594,11 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "license": "MIT" }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", - "license": "BSD-2-Clause", - "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" - } - }, - "node_modules/uglify-js/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "license": "MIT", - "optional": true - }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.3", @@ -9391,9 +9631,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", - "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -9476,9 +9716,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz", - "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "license": "MIT", "dependencies": { @@ -9500,36 +9740,37 @@ } }, "node_modules/webpack": { - "version": "5.88.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.0.tgz", - "integrity": "sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==", + "version": "5.105.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", + "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.20.0", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", + "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" }, "bin": { "webpack": "bin/webpack.js" @@ -9604,136 +9845,110 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", - "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", "dev": true, "license": "MIT", "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "webpack": "^5.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/webpack-dev-middleware/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "engines": { + "node": ">= 0.6" } }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/webpack-dev-middleware/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/express" } }, "node_modules/webpack-dev-server": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.0.tgz", - "integrity": "sha512-HmNB5QeSl1KpulTBQ8UT4FPrByYyaLxpJoQ0+s7EvUrMc16m0ZS1sgb1XGqzmgCPk0c9y+aaXxn11tbLzuM7NQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.3.tgz", + "integrity": "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.25", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", - "compression": "^1.7.4", + "compression": "^1.8.1", "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", + "express": "^4.22.1", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^5.5.0", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { "webpack": { @@ -9744,61 +9959,17 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/webpack-dev-server/node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, "node_modules/webpack-merge": { @@ -9817,9 +9988,9 @@ } }, "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", "dev": true, "license": "MIT", "engines": { @@ -9871,6 +10042,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, "license": "MIT", "dependencies": { "is-bigint": "^1.1.0", @@ -9890,6 +10062,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9917,6 +10090,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -9935,6 +10109,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, "license": "MIT", "dependencies": { "is-map": "^2.0.3", @@ -9953,6 +10128,7 @@ "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -9977,14 +10153,6 @@ "dev": true, "license": "MIT" }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/wmf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", @@ -10013,19 +10181,11 @@ "node": ">=0.10.0" } }, - "node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", - "license": "MIT/X11", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, "node_modules/ws": { @@ -10050,16 +10210,35 @@ } } }, - "node_modules/xlsx": { - "version": "0.18.5", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", - "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xlsx-js-style": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/xlsx-js-style/-/xlsx-js-style-1.2.0.tgz", + "integrity": "sha512-DDT4FXFSWfT4DXMSok/m3TvmP1gvO3dn0Eu/c+eXHW5Kzmp7IczNkxg/iEPnImbG9X0Vb8QhROda5eatSR/97Q==", "license": "Apache-2.0", "dependencies": { - "adler-32": "~1.3.0", - "cfb": "~1.2.1", - "codepage": "~1.15.0", - "crc-32": "~1.2.1", + "adler-32": "~1.2.0", + "cfb": "^1.1.4", + "codepage": "~1.14.0", + "commander": "~2.17.1", + "crc-32": "~1.2.0", + "exit-on-epipe": "~1.0.1", + "fflate": "^0.3.8", "ssf": "~0.11.2", "wmf": "~1.0.1", "word": "~0.3.0" @@ -10071,18 +10250,50 @@ "node": ">=0.8" } }, - "node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", - "license": "MIT", + "node_modules/xlsx-js-style/node_modules/adler-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", + "license": "Apache-2.0", + "dependencies": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + }, + "bin": { + "adler32": "bin/adler32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx-js-style/node_modules/codepage": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", + "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==", + "license": "Apache-2.0", "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "commander": "~2.14.1", + "exit-on-epipe": "~1.0.1" + }, + "bin": { + "codepage": "bin/codepage.njs" + }, + "engines": { + "node": ">=0.8" } }, + "node_modules/xlsx-js-style/node_modules/codepage/node_modules/commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", + "license": "MIT" + }, + "node_modules/xlsx-js-style/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "license": "MIT" + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json index 41816ddc779..aef56ba0573 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -13,21 +13,20 @@ }, "dependencies": { "@ant-design/icons": "5.4.0", - "@antv/g2plot": "2.4.35", + "@antv/g2plot": "2.3.32", "@zeppelin/sdk": "file:../zeppelin-sdk", "ansi-to-react": "6.2.6", "antd": "5.21.0", "file-saver": "2.0.5", "react": "18.3.1", "react-dom": "18.3.1", - "xlsx": "0.18.5" + "xlsx-js-style": "1.2.0" }, "devDependencies": { "@types/file-saver": "2.0.7", "@types/node": "18.19.64", "@types/react": "18.3.26", "@types/react-dom": "18.3.7", - "@types/xlsx": "0.0.36", "@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/parser": "^8.56.1", "css-loader": "6.8.0", @@ -38,8 +37,8 @@ "style-loader": "3.3.0", "ts-loader": "9.4.0", "typescript": "4.9.5", - "webpack": "5.88.0", + "webpack": "5.105.4", "webpack-cli": "5.1.4", - "webpack-dev-server": "4.15.0" + "webpack-dev-server": "5.2.3" } } diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts b/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts index d048a738651..c59525309f2 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts +++ b/zeppelin-web-angular/projects/zeppelin-react/src/utils/exportFile.ts @@ -23,7 +23,7 @@ export const exportFile = async (tableData: TableData, type: 'csv' | 'xlsx') => const { saveAs } = await import('file-saver'); if (type === 'xlsx') { - const XLSX = await import('xlsx'); + const XLSX = await import('xlsx-js-style'); const wb = XLSX.utils.book_new(); const ws = XLSX.utils.aoa_to_sheet([tableData.columnNames, ...tableData.rows]); From 1be5c3e70428eb757b9577f40a1a90f7ca82fce1 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Mon, 9 Mar 2026 23:20:44 +0900 Subject: [PATCH 008/179] [ZEPPELIN-6397] Bump Testcontainers version to 1.21.4 ### What is this PR for? This PR bumps the testcontainers minor/patch versions. image The interpreter-test-non-core job has been failing intermittently. Based on the error pattern, this appears related to a compatibility issue between older Testcontainers versions and newer Docker Engine APIs (see: https://github.com/testcontainers/testcontainers-java/issues/11212). Testcontainers released a patch to address this, so this PR updates Testcontainers to 1.21.4 (release notes: https://github.com/testcontainers/testcontainers-java/releases/tag/1.21.4). ### What type of PR is it? Bug Fix ### What is the Jira issue?[ * Open an issue on Jira https://issues.apache.org/jira/browse/ZEPPELIN-6397 ### How should this be tested? Check `interpreter-test-non-core` job. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5159 from tbonelee/bump-testcontainers-neo4j. Signed-off-by: ChanHo Lee --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cfe17f164f1..55a5a5a5380 100644 --- a/pom.xml +++ b/pom.xml @@ -179,7 +179,7 @@ 3.2.1 1.4.1.Final - 1.19.0 + 1.21.4 512m From c9fa525692911908fde47bf5fb9c3d8388220751 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:54:57 +0900 Subject: [PATCH 009/179] Bump immutable from 4.3.7 to 4.3.8 in /zeppelin-web-angular Bumps [immutable](https://github.com/immutable-js/immutable-js) from 4.3.7 to 4.3.8. - [Release notes](https://github.com/immutable-js/immutable-js/releases) - [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md) - [Commits](https://github.com/immutable-js/immutable-js/compare/v4.3.7...v4.3.8) --- updated-dependencies: - dependency-name: immutable dependency-version: 4.3.8 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- zeppelin-web-angular/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index d1514207327..0917d5c5853 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -10929,9 +10929,9 @@ } }, "node_modules/immutable": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", - "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", + "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", "dev": true }, "node_modules/import-fresh": { @@ -26301,9 +26301,9 @@ "optional": true }, "immutable": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", - "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==", + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", + "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", "dev": true }, "import-fresh": { From 5c35ad9ba2033419bf7e9e0343751d1ce2a360b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Tue, 10 Mar 2026 00:23:27 +0900 Subject: [PATCH 010/179] [ZEPPELIN-6358] Fix notebook UI bugs and add aria attributes and test IDs for selectors #5101 ### What is this PR for? This PR fixes several notebook-related UI issues and improves testability and accessibility. ### Changes - Fix an issue where the search menu trigger did not work correctly. - Prevent folder renaming when the input is empty by disabling the confirm button. - Add accessibility (ARIA) attributes and test-specific attributes to improve usability and E2E test stability. ### What type of PR is it? Bug Fix Refactoring ### Todos ### What is the Jira issue? ZEPPELIN-6358 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5133 from dididy/e2e/notebook-bug. Signed-off-by: ChanHo Lee --- .../notebook/action-bar/action-bar.component.html | 3 ++- .../workspace/notebook/action-bar/action-bar.component.ts | 6 ++++++ .../app/pages/workspace/notebook/notebook.component.html | 2 +- .../workspace/notebook/paragraph/paragraph.component.html | 1 + .../workspace/notebook/paragraph/paragraph.component.ts | 4 ++-- .../workspace/notebook/sidebar/sidebar.component.html | 8 +++++++- .../published/paragraph/paragraph.component.html | 2 +- .../app/share/folder-rename/folder-rename.component.html | 4 +++- .../src/app/share/node-list/node-list.component.html | 4 ++-- 9 files changed, 25 insertions(+), 9 deletions(-) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html index e2d354995ad..8e3bdea00b8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html @@ -11,7 +11,7 @@ -->
-
+
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html index 31249c94c4c..10917cc7999 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -107,6 +107,7 @@ (sizeChange)="onSizeChange($event)" (configChange)="onConfigChange($event, i)" [result]="result" + [attr.data-testid]="'paragraph-result'" > (); @Output() readonly selected = new EventEmitter(); @Output() readonly selectAtIndex = new EventEmitter(); - @Output() readonly searchCode = new EventEmitter(); + @Output() readonly openSearchMenu = new EventEmitter(); private destroy$ = new Subject(); @@ -700,7 +700,7 @@ export class NotebookParagraphComponent } handleFindInCode() { - this.searchCode.emit(); + this.openSearchMenu.emit(); } ngOnChanges(changes: SimpleChanges): void { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html index 9acfe35efab..fde35656973 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html @@ -15,6 +15,7 @@
-
- - - - - - - - - - - - - - - -
NameClassDescription
alluxio.master.hostnamelocalhostAlluxio master hostname
alluxio.master.port19998Alluxio master port
- -## Enabling Alluxio Interpreter -In a notebook, to enable the **Alluxio** interpreter, click on the **Gear** icon and select **Alluxio**. - -## Using the Alluxio Interpreter -In a paragraph, use `%alluxio` to select the **Alluxio** interpreter and then input all commands. - -```bash -%alluxio -help -``` - -> **Tip :** Use ( Ctrl + . ) for autocompletion. - -## Interpreter Commands -The **Alluxio** interpreter accepts the following commands. - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OperationSyntaxDescription
catcat "path"Print the content of the file to the console.
chgrpchgrp "group" "path"Change the group of the directory or file.
chmodchmod "permission" "path"Change the permission of the directory or file.
chownchown "owner" "path"Change the owner of the directory or file.
copyFromLocalcopyFromLocal "source path" "remote path"Copy the specified file specified by "source path" to the path specified by "remote path". - This command will fail if "remote path" already exists.
copyToLocalcopyToLocal "remote path" "local path"Copy the specified file from the path specified by "remote path" to a local destination.
countcount "path"Display the number of folders and files matching the specified prefix in "path".
dudu "path"Display the size of a file or a directory specified by the input path.
fileInfofileInfo "path"Print the information of the blocks of a specified file.
freefree "path"Free a file or all files under a directory from Alluxio. If the file/directory is also - in under storage, it will still be available there.
getCapacityBytesgetCapacityBytesGet the capacity of the AlluxioFS.
getUsedBytesgetUsedBytesGet number of bytes used in the AlluxioFS.
loadload "path"Load the data of a file or a directory from under storage into Alluxio.
loadMetadataloadMetadata "path"Load the metadata of a file or a directory from under storage into Alluxio.
locationlocation "path"Display a list of hosts that have the file data.
lsls "path"List all the files and directories directly under the given path with information such as - size.
mkdirmkdir "path1" ... "pathn"Create directory(ies) under the given paths, along with any necessary parent directories. - Multiple paths separated by spaces or tabs. This command will fail if any of the given paths - already exist.
mountmount "path" "uri"Mount the underlying file system path "uri" into the Alluxio namespace as "path". The "path" - is assumed not to exist and is created by the operation. No data or metadata is loaded from under - storage into Alluxio. After a path is mounted, operations on objects under the mounted path are - mirror to the mounted under storage.
mvmv "source" "destination"Move a file or directory specified by "source" to a new location "destination". This command - will fail if "destination" already exists.
persistpersist "path"Persist a file or directory currently stored only in Alluxio to the underlying file system.
pinpin "path"Pin the given file to avoid evicting it from memory. If the given path is a directory, it - recursively pins all the files contained and any new files created within this directory.
reportreport "path"Report to the master that a file is lost.
rmrm "path"Remove a file. This command will fail if the given path is a directory rather than a file.
setTtlsetTtl "time"Set the TTL (time to live) in milliseconds to a file.
tailtail "path"Print the last 1KB of the specified file to the console.
touchtouch "path"Create a 0-byte file at the specified location.
unmountunmount "path"Unmount the underlying file system path mounted in the Alluxio namespace as "path". Alluxio - objects under "path" are removed from Alluxio, but they still exist in the previously mounted - under storage.
unpinunpin "path"Unpin the given file to allow Alluxio to evict this file again. If the given path is a - directory, it recursively unpins all files contained and any new files created within this - directory.
unsetTtlunsetTtlRemove the TTL (time to live) setting from a file.
-
- -## How to test it's working -Be sure to have configured correctly the Alluxio interpreter, then open a new paragraph and type one of the above commands. - -Below a simple example to show how to interact with Alluxio interpreter. -Following steps are performed: - -* using sh interpreter a new text file is created on local machine -* using Alluxio interpreter: - * is listed the content of the afs (Alluxio File System) root - * the file previously created is copied to afs - * is listed again the content of the afs root to check the existence of the new copied file - * is showed the content of the copied file (using the tail command) - * the file previously copied to afs is copied to local machine -* using sh interpreter it's checked the existence of the new file copied from Alluxio and its content is showed - -
- ![Alluxio Interpreter Example]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/alluxio-example.png) -
diff --git a/docs/interpreter/hdfs.md b/docs/interpreter/hdfs.md index d7b7bf885d8..bec3785aad5 100644 --- a/docs/interpreter/hdfs.md +++ b/docs/interpreter/hdfs.md @@ -1,7 +1,7 @@ --- layout: page title: "HDFS File System Interpreter for Apache Zeppelin" -description: "Hadoop File System is a distributed, fault tolerant file system part of the hadoop project and is often used as storage for distributed processing engines like Hadoop MapReduce and Apache Spark or underlying file systems like Alluxio." +description: "Hadoop File System is a distributed, fault tolerant file system part of the hadoop project and is often used as storage for distributed processing engines like Hadoop MapReduce and Apache Spark or underlying file systems like S3." group: interpreter --- - ${flink1.17.version} + ${flink1.19.version} 2.12.7 2.12 ${flink.scala.version} @@ -55,19 +55,7 @@ org.apache.zeppelin - flink1.15-shims - ${project.version} - - - - org.apache.zeppelin - flink1.16-shims - ${project.version} - - - - org.apache.zeppelin - flink1.17-shims + flink1.20-shims ${project.version} @@ -1203,39 +1191,9 @@ - flink-115 - - ${flink1.15.version} - 2.12.7 - 2.12 - - - - org.apache.flink - flink-runtime - ${flink.version} - provided - - - org.apache.flink - flink-table-planner_${flink.scala.binary.version} - ${flink.version} - provided - - - org.apache.flink - flink-python_${flink.scala.binary.version} - ${flink.version} - provided - - - - - - flink-116 + flink-1.19 - ${flink1.16.version} - 2.12.7 + ${flink1.19.version} 2.12 @@ -1267,10 +1225,9 @@ - flink-117 + flink-1.20 - ${flink1.17.version} - 2.12.7 + ${flink1.20.version} 2.12 diff --git a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkBatchSqlInterpreter.java b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkBatchSqlInterpreter.java index f720ff255d4..67b2f2c3dad 100644 --- a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkBatchSqlInterpreter.java +++ b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkBatchSqlInterpreter.java @@ -37,7 +37,7 @@ public void open() throws InterpreterException { FlinkSqlContext flinkSqlContext = new FlinkSqlContext( flinkInterpreter.getExecutionEnvironment().getJavaEnv(), flinkInterpreter.getStreamExecutionEnvironment().getJavaEnv(), - flinkInterpreter.getJavaBatchTableEnvironment("blink"), + flinkInterpreter.getJavaBatchTableEnvironment(), flinkInterpreter.getJavaStreamTableEnvironment(), flinkInterpreter.getZeppelinContext(), null); diff --git a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkInterpreter.java b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkInterpreter.java index fa37e0fb30d..84881f84bda 100644 --- a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkInterpreter.java +++ b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkInterpreter.java @@ -158,8 +158,8 @@ TableEnvironment getStreamTableEnvironment() { return this.innerIntp.getStreamTableEnvironment(); } - org.apache.flink.table.api.TableEnvironment getJavaBatchTableEnvironment(String planner) { - return this.innerIntp.getJavaBatchTableEnvironment(planner); + org.apache.flink.table.api.TableEnvironment getJavaBatchTableEnvironment() { + return this.innerIntp.getJavaBatchTableEnvironment(); } TableEnvironment getJavaStreamTableEnvironment() { @@ -167,7 +167,7 @@ TableEnvironment getJavaStreamTableEnvironment() { } TableEnvironment getBatchTableEnvironment() { - return this.innerIntp.getBatchTableEnvironment("blink"); + return this.innerIntp.getBatchTableEnvironment(); } JobManager getJobManager() { diff --git a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkStreamSqlInterpreter.java b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkStreamSqlInterpreter.java index 087fa3a208e..21d7bbc7c45 100644 --- a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkStreamSqlInterpreter.java +++ b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/FlinkStreamSqlInterpreter.java @@ -18,6 +18,7 @@ package org.apache.zeppelin.flink; +import org.apache.zeppelin.flink.sql.AbstractStreamSqlJob; import org.apache.zeppelin.flink.sql.AppendStreamSqlJob; import org.apache.zeppelin.flink.sql.SingleRowStreamSqlJob; import org.apache.zeppelin.flink.sql.UpdateStreamSqlJob; @@ -42,7 +43,7 @@ public void open() throws InterpreterException { FlinkSqlContext flinkSqlContext = new FlinkSqlContext( flinkInterpreter.getExecutionEnvironment().getJavaEnv(), flinkInterpreter.getStreamExecutionEnvironment().getJavaEnv(), - flinkInterpreter.getJavaBatchTableEnvironment("blink"), + flinkInterpreter.getJavaBatchTableEnvironment(), flinkInterpreter.getJavaStreamTableEnvironment(), flinkInterpreter.getZeppelinContext(), sql -> callInnerSelect(sql)); @@ -53,48 +54,45 @@ public void open() throws InterpreterException { public void callInnerSelect(String sql) { InterpreterContext context = InterpreterContext.get(); String streamType = context.getLocalProperties().getOrDefault("type", "update"); + AbstractStreamSqlJob streamJob; if (streamType.equalsIgnoreCase("single")) { - SingleRowStreamSqlJob streamJob = new SingleRowStreamSqlJob( + streamJob = new SingleRowStreamSqlJob( flinkInterpreter.getStreamExecutionEnvironment(), flinkInterpreter.getJavaStreamTableEnvironment(), flinkInterpreter.getJobManager(), context, flinkInterpreter.getDefaultParallelism(), flinkInterpreter.getFlinkShims()); - try { - streamJob.run(sql); - } catch (IOException e) { - throw new RuntimeException("Fail to run single type stream job", e); - } } else if (streamType.equalsIgnoreCase("append")) { - AppendStreamSqlJob streamJob = new AppendStreamSqlJob( + streamJob = new AppendStreamSqlJob( flinkInterpreter.getStreamExecutionEnvironment(), flinkInterpreter.getStreamTableEnvironment(), flinkInterpreter.getJobManager(), context, flinkInterpreter.getDefaultParallelism(), flinkInterpreter.getFlinkShims()); - try { - streamJob.run(sql); - } catch (IOException e) { - throw new RuntimeException("Fail to run append type stream job", e); - } } else if (streamType.equalsIgnoreCase("update")) { - UpdateStreamSqlJob streamJob = new UpdateStreamSqlJob( + streamJob = new UpdateStreamSqlJob( flinkInterpreter.getStreamExecutionEnvironment(), flinkInterpreter.getStreamTableEnvironment(), flinkInterpreter.getJobManager(), context, flinkInterpreter.getDefaultParallelism(), flinkInterpreter.getFlinkShims()); - try { - streamJob.run(sql); - } catch (IOException e) { - throw new RuntimeException("Fail to run update type stream job", e); - } } else { throw new RuntimeException("Unrecognized stream type: " + streamType); } + + FlinkZeppelinContext z = + (FlinkZeppelinContext) flinkInterpreter.getZeppelinContext(); + z.setCurrentStreamJob(streamJob); + try { + streamJob.run(sql); + } catch (IOException e) { + throw new RuntimeException("Fail to run " + streamType + " type stream job", e); + } finally { + z.clearCurrentStreamJob(); + } } @Override diff --git a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/IPyFlinkInterpreter.java b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/IPyFlinkInterpreter.java index 1bc61821f85..ce12af0a241 100644 --- a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/IPyFlinkInterpreter.java +++ b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/IPyFlinkInterpreter.java @@ -146,8 +146,8 @@ public org.apache.flink.api.java.ExecutionEnvironment getJavaExecutionEnvironmen return flinkInterpreter.getStreamExecutionEnvironment().getJavaEnv(); } - public TableEnvironment getJavaBatchTableEnvironment(String planner) { - return flinkInterpreter.getJavaBatchTableEnvironment(planner); + public TableEnvironment getJavaBatchTableEnvironment() { + return flinkInterpreter.getJavaBatchTableEnvironment(); } public TableEnvironment getJavaStreamTableEnvironment() { diff --git a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/PyFlinkInterpreter.java b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/PyFlinkInterpreter.java index df203b71b84..7c9b7c539a0 100644 --- a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/PyFlinkInterpreter.java +++ b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/PyFlinkInterpreter.java @@ -195,8 +195,8 @@ public org.apache.flink.api.java.ExecutionEnvironment getJavaExecutionEnvironmen return flinkInterpreter.getStreamExecutionEnvironment().getJavaEnv(); } - public TableEnvironment getJavaBatchTableEnvironment(String planner) { - return flinkInterpreter.getJavaBatchTableEnvironment(planner); + public TableEnvironment getJavaBatchTableEnvironment() { + return flinkInterpreter.getJavaBatchTableEnvironment(); } public TableEnvironment getJavaStreamTableEnvironment() { diff --git a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/sql/AbstractStreamSqlJob.java b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/sql/AbstractStreamSqlJob.java index e5399865bfb..6994df13fe5 100644 --- a/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/sql/AbstractStreamSqlJob.java +++ b/flink/flink-scala-2.12/src/main/java/org/apache/zeppelin/flink/sql/AbstractStreamSqlJob.java @@ -28,6 +28,7 @@ import org.apache.flink.streaming.experimental.SocketStreamIterator; import org.apache.flink.table.api.Table; import org.apache.flink.table.api.TableEnvironment; +import org.apache.flink.table.api.TableResult; import org.apache.flink.table.api.TableSchema; import org.apache.flink.table.sinks.RetractStreamTableSink; import org.apache.flink.types.Row; @@ -43,12 +44,14 @@ import java.net.InetAddress; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; /** * Abstract class for all kinds of stream sql job @@ -65,6 +68,9 @@ public abstract class AbstractStreamSqlJob { protected InterpreterContext context; protected TableSchema schema; protected SocketStreamIterator> iterator; + private volatile TableResult insertResult; + private volatile boolean cancelled = false; + private volatile boolean cancelledWithSavepoint = false; protected Object resultLock = new Object(); protected volatile boolean enableToRefresh = true; protected int defaultParallelism; @@ -110,6 +116,7 @@ public String run(String st) throws IOException { } public String run(Table table, String tableName) throws IOException { + ResultRetrievalThread retrievalThread = null; try { this.table = table; int parallelism = Integer.parseInt(context.getLocalProperties() @@ -146,12 +153,43 @@ public String run(Table table, String tableName) throws IOException { context.getLocalProperties().getOrDefault("refreshInterval", "3000")); refreshScheduler.scheduleAtFixedRate(new RefreshTask(context), delay, period, MILLISECONDS); - ResultRetrievalThread retrievalThread = new ResultRetrievalThread(refreshScheduler); + retrievalThread = new ResultRetrievalThread(refreshScheduler); retrievalThread.start(); LOGGER.info("Run job: {}, parallelism: {}", tableName, parallelism); String jobName = context.getStringLocalProperty("jobName", tableName); - table.executeInsert(tableName).await(); + this.insertResult = table.executeInsert(tableName); + // Register the job with JobManager so that cancel (with savepoint) works properly + if (insertResult.getJobClient().isPresent()) { + jobManager.addJob(context, insertResult.getJobClient().get()); + } + // Use a CountDownLatch to wait for job completion while supporting cancellation + CountDownLatch jobDone = new CountDownLatch(1); + Thread jobThread = new Thread(() -> { + try { + insertResult.await(); + } catch (Exception e) { + LOGGER.debug("Job await interrupted or failed", e); + } finally { + jobDone.countDown(); + } + }, "flink-job-await"); + jobThread.setDaemon(true); + jobThread.start(); + + // Wait for either job completion or cancellation + while (!cancelled && !jobDone.await(1, SECONDS)) { + // keep waiting + } + if (cancelled) { + // Wait briefly for the job to finish (e.g. stopped with savepoint) + jobDone.await(10, SECONDS); + if (cancelledWithSavepoint) { + LOGGER.info("Stream sql job stopped with savepoint, jobName: {}", jobName); + return buildResult(); + } + throw new InterruptedException("Job was cancelled"); + } LOGGER.info("Flink Job is finished, jobName: {}", jobName); // wait for retrieve thread consume all data LOGGER.info("Waiting for retrieve thread to be done"); @@ -161,9 +199,30 @@ public String run(Table table, String tableName) throws IOException { LOGGER.info("Final Result: {}", finalResult); return finalResult; } catch (Exception e) { + if (cancelled) { + throw new IOException("Job was cancelled", e); + } LOGGER.error("Fail to run stream sql job", e); + if (e instanceof IOException) { + throw (IOException) e; + } throw new IOException("Fail to run stream sql job", e); } finally { + if (retrievalThread != null && retrievalThread.isAlive()) { + retrievalThread.cancel(); + try { + retrievalThread.join(5_000); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + if (insertResult != null && insertResult.getJobClient().isPresent()) { + try { + jobManager.removeJob(context.getParagraphId()); + } catch (Exception ex) { + LOGGER.warn("Failed to remove job from JobManager", ex); + } + } refreshScheduler.shutdownNow(); } } @@ -238,6 +297,12 @@ public void cancel() { } } + public void cancel(boolean withSavepoint) { + LOGGER.info("Canceling stream sql job, withSavepoint={}", withSavepoint); + this.cancelledWithSavepoint = withSavepoint; + this.cancelled = true; + } + protected abstract void refresh(InterpreterContext context) throws Exception; private class RefreshTask implements Runnable { diff --git a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py index 62cc81bef8d..18bab2111fa 100644 --- a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py +++ b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py @@ -49,7 +49,7 @@ if not intp.isAfterFlink114(): from pyflink.dataset import * b_env = pyflink.dataset.ExecutionEnvironment(intp.getJavaExecutionEnvironment()) - bt_env = BatchTableEnvironment(intp.getJavaBatchTableEnvironment("blink")) + bt_env = BatchTableEnvironment(intp.getJavaBatchTableEnvironment()) st_env = StreamTableEnvironment(intp.getJavaStreamTableEnvironment()) else: st_env = StreamTableEnvironment(intp.getJavaStreamTableEnvironment()) diff --git a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py index 2970c6d265e..88d1de6c59d 100644 --- a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py +++ b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py @@ -38,7 +38,7 @@ if not intp.isAfterFlink114(): from pyflink.dataset import * b_env = pyflink.dataset.ExecutionEnvironment(intp.getJavaExecutionEnvironment()) - bt_env = BatchTableEnvironment(intp.getJavaBatchTableEnvironment("blink")) + bt_env = BatchTableEnvironment(intp.getJavaBatchTableEnvironment()) st_env = StreamTableEnvironment(intp.getJavaStreamTableEnvironment()) else: st_env = StreamTableEnvironment(intp.getJavaStreamTableEnvironment()) diff --git a/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkScalaInterpreter.scala b/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkScalaInterpreter.scala index a11003b8bc2..0b84be68443 100644 --- a/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkScalaInterpreter.scala +++ b/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkScalaInterpreter.scala @@ -58,6 +58,7 @@ import scala.collection.JavaConversions import scala.collection.JavaConverters._ import scala.tools.nsc.Settings import scala.tools.nsc.interpreter.{Completion, IMain, IR, JPrintWriter, Results, SimpleReader} +import scala.util.control.NonFatal /** * It instantiate flink scala shell and create env, senv, btenv, stenv. @@ -86,18 +87,12 @@ abstract class FlinkScalaInterpreter(val properties: Properties, private var btenv: TableEnvironment = _ private var stenv: TableEnvironment = _ - // TableEnvironment of flink planner (used for convert Flink table to DataSet) - private var btenv_2: TableEnvironment = _ - // PyFlink depends on java version of TableEnvironment, // so need to create java version of TableEnvironment // java version of blink TableEnvironment private var java_btenv: TableEnvironment = _ private var java_stenv: TableEnvironment = _ - // java version TableEnvironment of old planner, used for converting Table to DataSet - private var java_btenv_2: TableEnvironment = _ - private var z: FlinkZeppelinContext = _ private var flinkVersion: FlinkVersion = _ private var flinkShims: FlinkShims = _ @@ -423,6 +418,26 @@ abstract class FlinkScalaInterpreter(val properties: Properties, setAsContext() } + private def bindWithRetry(name: String, tpe: String, value: AnyRef, modifiers: List[String]): Unit = { + // Workaround for Scala reflection issue with ImplicitExpressionConversions in Flink 1.19+. + // First bind attempt may fail due to unpickling error, but subsequent attempts succeed + // because the Scala reflection cache resolves the error state. + var success = false + for (attempt <- 1 to 2 if !success) { + try { + flinkILoop.bind(name, tpe, value, modifiers: List[String]) + success = true + } catch { + case NonFatal(e) => + if (attempt == 1) { + LOGGER.warn(s"Retrying bind for $name due to Scala reflection issue: ${e.getMessage}") + } else { + throw new InterpreterException(s"Failed to bind $name after retry", e) + } + } + } + } + private def createTableEnvs(): Unit = { val originalClassLoader = Thread.currentThread().getContextClassLoader try { @@ -438,8 +453,8 @@ abstract class FlinkScalaInterpreter(val properties: Properties, .asInstanceOf[EnvironmentSettings.Builder] .inBatchMode() .build() - this.btenv = tblEnvFactory.createJavaBlinkBatchTableEnvironment(btEnvSetting, getFlinkScalaShellLoader); - flinkILoop.bind("btenv", btenv.getClass().getCanonicalName(), btenv, List("@transient")) + this.btenv = tblEnvFactory.createJavaBlinkBatchTableEnvironment(btEnvSetting, getFlinkScalaShellLoader) + bindWithRetry("btenv", btenv.getClass().getCanonicalName(), btenv, List("@transient")) this.java_btenv = this.btenv val stEnvSetting = this.flinkShims.createBlinkPlannerEnvSettingBuilder() @@ -447,14 +462,8 @@ abstract class FlinkScalaInterpreter(val properties: Properties, .inStreamingMode() .build() this.stenv = tblEnvFactory.createScalaBlinkStreamTableEnvironment(stEnvSetting, getFlinkScalaShellLoader) - flinkILoop.bind("stenv", stenv.getClass().getCanonicalName(), stenv, List("@transient")) + bindWithRetry("stenv", stenv.getClass().getCanonicalName(), stenv, List("@transient")) this.java_stenv = tblEnvFactory.createJavaBlinkStreamTableEnvironment(stEnvSetting, getFlinkScalaShellLoader) - - if (!flinkVersion.isAfterFlink114()) { - // flink planner is not supported after flink 1.14 - this.btenv_2 = tblEnvFactory.createScalaFlinkBatchTableEnvironment() - this.java_btenv_2 = tblEnvFactory.createJavaFlinkBatchTableEnvironment() - } } finally { Thread.currentThread().setContextClassLoader(originalClassLoader) } @@ -718,6 +727,11 @@ abstract class FlinkScalaInterpreter(val properties: Properties, def cancel(context: InterpreterContext): Unit = { jobManager.cancelJob(context) + if (z != null) { + val savepointDir = context.getLocalProperties.get(JobManager.SAVEPOINT_DIR) + val withSavepoint = savepointDir != null && !savepointDir.isEmpty + z.asInstanceOf[FlinkZeppelinContext].cancelCurrentStreamJob(withSavepoint) + } } def getProgress(context: InterpreterContext): Int = { @@ -760,24 +774,11 @@ abstract class FlinkScalaInterpreter(val properties: Properties, def getStreamExecutionEnvironment(): StreamExecutionEnvironment = this.senv - def getBatchTableEnvironment(planner: String = "blink"): TableEnvironment = { - if (planner == "blink") - this.btenv - else - this.btenv_2 - } + def getBatchTableEnvironment(): TableEnvironment = this.btenv - def getStreamTableEnvironment(): TableEnvironment = { - this.stenv - } + def getStreamTableEnvironment(): TableEnvironment = this.stenv - def getJavaBatchTableEnvironment(planner: String): TableEnvironment = { - if (planner == "blink") { - this.java_btenv - } else { - this.java_btenv_2 - } - } + def getJavaBatchTableEnvironment(): TableEnvironment = this.java_btenv def getJavaStreamTableEnvironment(): TableEnvironment = { this.java_stenv diff --git a/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkZeppelinContext.scala b/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkZeppelinContext.scala index b5dba22307c..9e71531db84 100644 --- a/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkZeppelinContext.scala +++ b/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/FlinkZeppelinContext.scala @@ -29,7 +29,7 @@ import org.apache.flink.util.StringUtils import org.apache.zeppelin.annotation.ZeppelinApi import org.apache.zeppelin.display.AngularObjectWatcher import org.apache.zeppelin.display.ui.OptionInput.ParamOption -import org.apache.zeppelin.flink.sql.{AppendStreamSqlJob, SingleRowStreamSqlJob, UpdateStreamSqlJob} +import org.apache.zeppelin.flink.sql.{AbstractStreamSqlJob, AppendStreamSqlJob, SingleRowStreamSqlJob, UpdateStreamSqlJob} import org.apache.zeppelin.interpreter.{InterpreterContext, InterpreterHookRegistry, ResultMessages, ZeppelinContext} import org.apache.zeppelin.tabledata.TableDataUtils @@ -95,16 +95,7 @@ class FlinkZeppelinContext(val flinkInterpreter: FlinkScalaInterpreter, override def showData(obj: Any, maxResult: Int): String = { if (obj.isInstanceOf[DataSet[_]]) { - val ds = obj.asInstanceOf[DataSet[_]] - if (flinkInterpreter.getFlinkVersion.isAfterFlink114) { - "z.show(DataSet) is not supported after Flink 1.14" - } else { - val btenv = flinkInterpreter.getBatchTableEnvironment("flink") - val table = flinkInterpreter.getFlinkShims.fromDataSet(btenv, ds).asInstanceOf[Table] - val columnNames: Array[String] = table.getSchema.getFieldNames - val dsRows: DataSet[Row] = flinkInterpreter.getFlinkShims.toDataSet(btenv, table).asInstanceOf[DataSet[Row]] - showTable(columnNames, dsRows.first(maxResult + 1).collect()) - } + "Support for z.show(DataSet) has been removed." } else if (obj.isInstanceOf[Table]) { val rows = JavaConversions.asScalaBuffer( flinkInterpreter.getFlinkShims.collectToList(obj.asInstanceOf[TableImpl]).asInstanceOf[java.util.List[Row]]).toSeq @@ -115,13 +106,6 @@ class FlinkZeppelinContext(val flinkInterpreter: FlinkScalaInterpreter, } } - def showFlinkTable(table: Table): String = { - val columnNames: Array[String] = table.getSchema.getFieldNames - val btenv = flinkInterpreter.getJavaBatchTableEnvironment("flink") - val dsRows: DataSet[Row] = flinkInterpreter.getFlinkShims.toDataSet(btenv, table).asInstanceOf[DataSet[Row]] - showTable(columnNames, dsRows.first(maxResult + 1).collect()) - } - def showBlinkTable(table: Table): String = { val rows = JavaConversions.asScalaBuffer( flinkInterpreter.getFlinkShims.collectToList(table.asInstanceOf[TableImpl]).asInstanceOf[java.util.List[Row]]).toSeq @@ -129,29 +113,46 @@ class FlinkZeppelinContext(val flinkInterpreter: FlinkScalaInterpreter, showTable(columnNames, rows) } + @volatile private var currentStreamJob: AbstractStreamSqlJob = _ + + def cancelCurrentStreamJob(withSavepoint: Boolean): Unit = { + val job = currentStreamJob + if (job != null) job.cancel(withSavepoint) + } + + def setCurrentStreamJob(job: AbstractStreamSqlJob): Unit = { + currentStreamJob = job + } + + def clearCurrentStreamJob(): Unit = { + currentStreamJob = null + } + def show(table: Table, streamType: String, configs: Map[String, String] = Map.empty): Unit = { val context = InterpreterContext.get() configs.foreach(e => context.getLocalProperties.put(e._1, e._2)) val tableName = "UnnamedTable_" + context.getParagraphId.replace("-", "_") + "_" + SQL_INDEX.getAndIncrement() - if (streamType.equalsIgnoreCase("single")) { - val streamJob = new SingleRowStreamSqlJob(flinkInterpreter.getStreamExecutionEnvironment, + val streamJob: AbstractStreamSqlJob = if (streamType.equalsIgnoreCase("single")) { + new SingleRowStreamSqlJob(flinkInterpreter.getStreamExecutionEnvironment, table.asInstanceOf[TableImpl].getTableEnvironment, flinkInterpreter.getJobManager, context, flinkInterpreter.getDefaultParallelism, flinkInterpreter.getFlinkShims) - streamJob.run(table, tableName) - } - else if (streamType.equalsIgnoreCase("append")) { - val streamJob = new AppendStreamSqlJob(flinkInterpreter.getStreamExecutionEnvironment, + } else if (streamType.equalsIgnoreCase("append")) { + new AppendStreamSqlJob(flinkInterpreter.getStreamExecutionEnvironment, table.asInstanceOf[TableImpl].getTableEnvironment, flinkInterpreter.getJobManager, context, flinkInterpreter.getDefaultParallelism, flinkInterpreter.getFlinkShims) - streamJob.run(table, tableName) - } - else if (streamType.equalsIgnoreCase("update")) { - val streamJob = new UpdateStreamSqlJob(flinkInterpreter.getStreamExecutionEnvironment, + } else if (streamType.equalsIgnoreCase("update")) { + new UpdateStreamSqlJob(flinkInterpreter.getStreamExecutionEnvironment, table.asInstanceOf[TableImpl].getTableEnvironment, flinkInterpreter.getJobManager, context, flinkInterpreter.getDefaultParallelism, flinkInterpreter.getFlinkShims) + } else { + throw new IOException("Unrecognized stream type: " + streamType) + } + currentStreamJob = streamJob + try { streamJob.run(table, tableName) + } finally { + currentStreamJob = null } - else throw new IOException("Unrecognized stream type: " + streamType) } /** diff --git a/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/internal/FlinkILoop.scala b/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/internal/FlinkILoop.scala index b50135b91ed..b2a3d2d23b9 100644 --- a/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/internal/FlinkILoop.scala +++ b/flink/flink-scala-2.12/src/main/scala/org/apache/zeppelin/flink/internal/FlinkILoop.scala @@ -145,8 +145,7 @@ class FlinkILoop( "org.apache.flink.api.scala.utils._", "org.apache.flink.streaming.api.scala._", "org.apache.flink.streaming.api.windowing.time._", - "org.apache.flink.table.api._", - "org.apache.flink.table.api.bridge.scala._", + "org.apache.flink.table.api.{TableEnvironment, EnvironmentSettings, Table, TableResult, Schema, DataTypes, Expressions, FormatDescriptor, TableDescriptor}", "org.apache.flink.types.Row" ) diff --git a/flink/flink-scala-2.12/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java b/flink/flink-scala-2.12/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java index af2e7db1d30..d76081f0365 100644 --- a/flink/flink-scala-2.12/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java +++ b/flink/flink-scala-2.12/src/test/java/org/apache/zeppelin/flink/FlinkInterpreterTest.java @@ -227,7 +227,7 @@ void testZShow() throws InterpreterException, IOException { List resultMessages = context.out.toInterpreterResultMessage(); if (interpreter.getFlinkVersion().isAfterFlink114()) { assertEquals(InterpreterResult.Type.TEXT, resultMessages.get(0).getType()); - assertEquals("z.show(DataSet) is not supported after Flink 1.14", resultMessages.get(0).getData()); + assertEquals("Support for z.show(DataSet) has been removed.", resultMessages.get(0).getData()); } else { assertEquals(InterpreterResult.Type.TABLE, resultMessages.get(0).getType()); assertEquals("_1\t_2\n1\tjeff\n2\tandy\n3\tjames\n", resultMessages.get(0).getData()); @@ -264,13 +264,11 @@ void testBatchWordCount() throws InterpreterException, IOException { " .print()", context); assertEquals(InterpreterResult.Code.SUCCESS, result.code(), context.out.toString()); - String[] expectedCounts = {"(hello,3)", "(world,1)", "(flink,1)", "(hadoop,1)"}; - Arrays.sort(expectedCounts); - - String[] counts = context.out.toInterpreterResultMessage().get(0).getData().split("\n"); - Arrays.sort(counts); - - assertArrayEquals(expectedCounts, counts); + String output = context.out.toInterpreterResultMessage().get(0).getData(); + assertTrue(output.contains("(hello,3)"), output); + assertTrue(output.contains("(world,1)"), output); + assertTrue(output.contains("(flink,1)"), output); + assertTrue(output.contains("(hadoop,1)"), output); } @Test @@ -312,13 +310,10 @@ void testCancelStreamSql() InterpreterResult result2 = interpreter.interpret( "val table = stenv.sqlQuery(\"select url, count(1) as pv from " + "log group by url\")\nz.show(table, streamType=\"update\")", context); - LOGGER.info("---------------" + context.out.toString()); - LOGGER.info("---------------" + result2); waiter.assertTrue(context.out.toString().contains("Job was cancelled")); waiter.assertEquals(InterpreterResult.Code.ERROR, result2.code()); } catch (Exception e) { - e.printStackTrace(); - waiter.fail("Should not fail here"); + waiter.fail("Should not fail here: " + e.getClass().getName() + ": " + e.getMessage()); } waiter.resume(); }); diff --git a/flink/flink-shims/src/main/java/org/apache/zeppelin/flink/FlinkShims.java b/flink/flink-shims/src/main/java/org/apache/zeppelin/flink/FlinkShims.java index 11de5bd3b7e..1965375a13c 100644 --- a/flink/flink-shims/src/main/java/org/apache/zeppelin/flink/FlinkShims.java +++ b/flink/flink-shims/src/main/java/org/apache/zeppelin/flink/FlinkShims.java @@ -54,21 +54,10 @@ private static FlinkShims loadShims(FlinkVersion flinkVersion, Properties properties) throws Exception { Class flinkShimsClass; - if (flinkVersion.getMajorVersion() == 1 && flinkVersion.getMinorVersion() == 13) { - LOGGER.info("Initializing shims for Flink 1.13"); - flinkShimsClass = Class.forName("org.apache.zeppelin.flink.Flink113Shims"); - } else if (flinkVersion.getMajorVersion() == 1 && flinkVersion.getMinorVersion() == 14) { - LOGGER.info("Initializing shims for Flink 1.14"); - flinkShimsClass = Class.forName("org.apache.zeppelin.flink.Flink114Shims"); - } else if (flinkVersion.getMajorVersion() == 1 && flinkVersion.getMinorVersion() == 15) { - LOGGER.info("Initializing shims for Flink 1.15"); - flinkShimsClass = Class.forName("org.apache.zeppelin.flink.Flink115Shims"); - } else if (flinkVersion.getMajorVersion() == 1 && flinkVersion.getMinorVersion() == 16) { - LOGGER.info("Initializing shims for Flink 1.16"); - flinkShimsClass = Class.forName("org.apache.zeppelin.flink.Flink116Shims"); - } else if (flinkVersion.getMajorVersion() == 1 && flinkVersion.getMinorVersion() == 17) { - LOGGER.info("Initializing shims for Flink 1.17"); - flinkShimsClass = Class.forName("org.apache.zeppelin.flink.Flink117Shims"); + if (flinkVersion.getMajorVersion() == 1 + && (flinkVersion.getMinorVersion() == 19 || flinkVersion.getMinorVersion() == 20)) { + LOGGER.info("Initializing shims for Flink {}", flinkVersion); + flinkShimsClass = Class.forName("org.apache.zeppelin.flink.Flink120Shims"); } else { throw new Exception("Flink version: '" + flinkVersion + "' is not supported yet"); } @@ -120,10 +109,6 @@ public abstract Object getCollectStreamTableSink(InetAddress targetAddress, public abstract boolean rowEquals(Object row1, Object row2); - public abstract Object fromDataSet(Object btenv, Object ds); - - public abstract Object toDataSet(Object btenv, Object table); - public abstract void registerScalarFunction(Object btenv, String name, Object scalarFunction); public abstract void registerTableFunction(Object btenv, String name, Object tableFunction); diff --git a/flink/flink1.15-shims/pom.xml b/flink/flink1.15-shims/pom.xml deleted file mode 100644 index b8aab01b3a1..00000000000 --- a/flink/flink1.15-shims/pom.xml +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - flink-parent - org.apache.zeppelin - 0.13.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - flink1.15-shims - jar - Zeppelin: Flink1.15 Shims - - - ${flink1.15.version} - 2.12 - - - - - - org.apache.zeppelin - flink-shims - ${project.version} - - - - org.apache.flink - flink-core - ${flink.version} - provided - - - - org.apache.flink - flink-clients - ${flink.version} - provided - - - - org.apache.flink - flink-runtime - ${flink.version} - provided - - - - org.apache.flink - flink-table-api-scala_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-table-api-scala-bridge_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-table-api-java-bridge - ${flink.version} - provided - - - - org.apache.flink - flink-scala_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-streaming-java - ${flink.version} - provided - - - - org.apache.flink - flink-streaming-scala_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-java - ${flink.version} - provided - - - - org.apache.flink - flink-table-planner_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-python_${flink.scala.binary.version} - ${flink.version} - provided - - - - - - - - - net.alchim31.maven - scala-maven-plugin - - - eclipse-add-source - - add-source - - - - scala-compile-first - process-resources - - compile - - - - scala-test-compile-first - process-test-resources - - testCompile - - - - - ${flink.scala.version} - - -unchecked - -deprecation - -feature - -nobootcp - - - -Xms1024m - -Xmx1024m - -XX:MaxMetaspaceSize=${MaxMetaspace} - - - -source - ${java.version} - -target - ${java.version} - -Xlint:all,-serial,-path,-options - - - - - - maven-resources-plugin - - - copy-interpreter-setting - none - - true - - - - - - - - diff --git a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/Flink115Shims.java b/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/Flink115Shims.java deleted file mode 100644 index 4ed8abf3afe..00000000000 --- a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/Flink115Shims.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.flink.api.common.RuntimeExecutionMode; -import org.apache.flink.api.common.typeinfo.TypeInformation; -import org.apache.flink.api.common.typeutils.TypeSerializer; -import org.apache.flink.api.java.tuple.Tuple2; -import org.apache.flink.client.cli.CliFrontend; -import org.apache.flink.client.cli.CustomCommandLine; -import org.apache.flink.configuration.Configuration; -import org.apache.flink.configuration.ExecutionOptions; -import org.apache.flink.configuration.ReadableConfig; -import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; -import org.apache.flink.streaming.api.environment.StreamExecutionEnvironmentFactory; -import org.apache.flink.table.api.*; -import org.apache.flink.table.api.bridge.java.internal.StreamTableEnvironmentImpl; -import org.apache.flink.table.api.config.TableConfigOptions; -import org.apache.flink.table.catalog.CatalogManager; -import org.apache.flink.table.catalog.FunctionCatalog; -import org.apache.flink.table.catalog.GenericInMemoryCatalog; -import org.apache.flink.table.catalog.ResolvedSchema; -import org.apache.flink.table.delegation.Executor; -import org.apache.flink.table.delegation.ExecutorFactory; -import org.apache.flink.table.delegation.Planner; -import org.apache.flink.table.factories.FactoryUtil; -import org.apache.flink.table.factories.PlannerFactoryUtil; -import org.apache.flink.table.functions.AggregateFunction; -import org.apache.flink.table.functions.ScalarFunction; -import org.apache.flink.table.functions.TableAggregateFunction; -import org.apache.flink.table.functions.TableFunction; -import org.apache.flink.table.module.ModuleManager; -import org.apache.flink.table.planner.calcite.FlinkTypeFactory; -import org.apache.flink.table.sinks.TableSink; -import org.apache.flink.types.Row; -import org.apache.flink.types.RowKind; -import org.apache.flink.util.FlinkException; -import org.apache.zeppelin.flink.shims115.CollectStreamTableSink; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.URL; -import java.time.ZoneId; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - - -/** - * Shims for flink 1.15 - */ -public class Flink115Shims extends FlinkShims { - - private static final Logger LOGGER = LoggerFactory.getLogger(Flink115Shims.class); - - private Flink115SqlInterpreter batchSqlInterpreter; - private Flink115SqlInterpreter streamSqlInterpreter; - - public Flink115Shims(FlinkVersion flinkVersion, Properties properties) { - super(flinkVersion, properties); - } - - public void initInnerBatchSqlInterpreter(FlinkSqlContext flinkSqlContext) { - this.batchSqlInterpreter = new Flink115SqlInterpreter(flinkSqlContext, true); - } - - public void initInnerStreamSqlInterpreter(FlinkSqlContext flinkSqlContext) { - this.streamSqlInterpreter = new Flink115SqlInterpreter(flinkSqlContext, false); - } - - @Override - public Object createResourceManager(List jars, Object tableConfig) { - return null; - } - - @Override - public Object createFunctionCatalog(Object tableConfig, Object catalogManager, Object moduleManager, List jars) { - return new FunctionCatalog((TableConfig) tableConfig, (CatalogManager) catalogManager, (ModuleManager) moduleManager); - } - - @Override - public void disableSysoutLogging(Object batchConfig, Object streamConfig) { - // do nothing - } - - @Override - public Object createScalaBlinkStreamTableEnvironment(Object environmentSettingsObj, - Object senvObj, - Object tableConfigObj, - Object moduleManagerObj, - Object functionCatalogObj, - Object catalogManagerObj, - List jars, - ClassLoader classLoader) { - EnvironmentSettings environmentSettings = (EnvironmentSettings) environmentSettingsObj; - StreamExecutionEnvironment senv = (StreamExecutionEnvironment) senvObj; - TableConfig tableConfig = (TableConfig) tableConfigObj; - ModuleManager moduleManager = (ModuleManager) moduleManagerObj; - FunctionCatalog functionCatalog = (FunctionCatalog) functionCatalogObj; - CatalogManager catalogManager = (CatalogManager) catalogManagerObj; - ImmutablePair pair = createPlannerAndExecutor( - classLoader, environmentSettings, senv, - tableConfig, moduleManager, functionCatalog, catalogManager); - Planner planner = (Planner) pair.left; - Executor executor = (Executor) pair.right; - - return new org.apache.flink.table.api.bridge.scala.internal.StreamTableEnvironmentImpl(catalogManager, - moduleManager, - functionCatalog, tableConfig, new org.apache.flink.streaming.api.scala.StreamExecutionEnvironment(senv), - planner, executor, environmentSettings.isStreamingMode(), classLoader); - } - - @Override - public Object createJavaBlinkStreamTableEnvironment(Object environmentSettingsObj, - Object senvObj, - Object tableConfigObj, - Object moduleManagerObj, - Object functionCatalogObj, - Object catalogManagerObj, - List jars, - ClassLoader classLoader) { - EnvironmentSettings environmentSettings = (EnvironmentSettings) environmentSettingsObj; - StreamExecutionEnvironment senv = (StreamExecutionEnvironment) senvObj; - TableConfig tableConfig = (TableConfig) tableConfigObj; - ModuleManager moduleManager = (ModuleManager) moduleManagerObj; - FunctionCatalog functionCatalog = (FunctionCatalog) functionCatalogObj; - CatalogManager catalogManager = (CatalogManager) catalogManagerObj; - ImmutablePair pair = createPlannerAndExecutor( - classLoader, environmentSettings, senv, - tableConfig, moduleManager, functionCatalog, catalogManager); - Planner planner = (Planner) pair.left; - Executor executor = (Executor) pair.right; - - return new StreamTableEnvironmentImpl(catalogManager, moduleManager, - functionCatalog, tableConfig, senv, planner, executor, environmentSettings.isStreamingMode(), classLoader); - } - - @Override - public Object createStreamExecutionEnvironmentFactory(Object streamExecutionEnvironment) { - return new StreamExecutionEnvironmentFactory() { - @Override - public StreamExecutionEnvironment createExecutionEnvironment(Configuration configuration) { - return (StreamExecutionEnvironment) streamExecutionEnvironment; - } - }; - } - - @Override - public Object createCatalogManager(Object config) { - return CatalogManager.newBuilder() - .classLoader(Thread.currentThread().getContextClassLoader()) - .config((ReadableConfig) config) - .defaultCatalog("default_catalog", - new GenericInMemoryCatalog("default_catalog", "default_database")) - .build(); - } - - @Override - public String getPyFlinkPythonPath(Properties properties) throws IOException { - String mode = properties.getProperty("flink.execution.mode"); - if ("yarn-application".equalsIgnoreCase(mode)) { - // for yarn application mode, FLINK_HOME is container working directory - String flinkHome = new File(".").getAbsolutePath(); - return getPyFlinkPythonPath(new File(flinkHome + "/lib/python")); - } - - String flinkHome = System.getenv("FLINK_HOME"); - if (StringUtils.isNotBlank(flinkHome)) { - return getPyFlinkPythonPath(new File(flinkHome + "/opt/python")); - } else { - throw new IOException("No FLINK_HOME is specified"); - } - } - - private String getPyFlinkPythonPath(File pyFlinkFolder) throws IOException { - LOGGER.info("Getting pyflink lib from {}", pyFlinkFolder); - if (!pyFlinkFolder.exists() || !pyFlinkFolder.isDirectory()) { - throw new IOException(String.format("PyFlink folder %s does not exist or is not a folder", - pyFlinkFolder.getAbsolutePath())); - } - List depFiles = Arrays.asList(pyFlinkFolder.listFiles()); - StringBuilder builder = new StringBuilder(); - for (File file : depFiles) { - LOGGER.info("Adding extracted file {} to PYTHONPATH", file.getAbsolutePath()); - builder.append(file.getAbsolutePath() + ":"); - } - return builder.toString(); - } - - @Override - public Object getCollectStreamTableSink(InetAddress targetAddress, int targetPort, Object serializer) { - return new CollectStreamTableSink(targetAddress, targetPort, (TypeSerializer>) serializer); - } - - @Override - public List collectToList(Object table) throws Exception { - return Lists.newArrayList(((Table) table).execute().collect()); - } - - @Override - public boolean rowEquals(Object row1, Object row2) { - Row r1 = (Row) row1; - Row r2 = (Row) row2; - r1.setKind(RowKind.INSERT); - r2.setKind(RowKind.INSERT); - return r1.equals(r2); - } - - @Override - public Object fromDataSet(Object btenv, Object ds) { - throw new RuntimeException("Conversion from DataSet is not supported in Flink 1.15"); - } - - @Override - public Object toDataSet(Object btenv, Object table) { - throw new RuntimeException("Conversion to DataSet is not supported in Flink 1.15"); - } - - @Override - public void registerTableSink(Object stenv, String tableName, Object collectTableSink) { - ((org.apache.flink.table.api.internal.TableEnvironmentInternal) stenv) - .registerTableSinkInternal(tableName, (TableSink) collectTableSink); - } - - @Override - public void registerScalarFunction(Object btenv, String name, Object scalarFunction) { - ((StreamTableEnvironmentImpl) (btenv)).createTemporarySystemFunction(name, (ScalarFunction) scalarFunction); - } - - @Override - public void registerTableFunction(Object btenv, String name, Object tableFunction) { - ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (TableFunction) tableFunction); - } - - @Override - public void registerAggregateFunction(Object btenv, String name, Object aggregateFunction) { - ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (AggregateFunction) aggregateFunction); - } - - @Override - public void registerTableAggregateFunction(Object btenv, String name, Object tableAggregateFunction) { - ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (TableAggregateFunction) tableAggregateFunction); - } - - /** - * Flink 1.11 bind CatalogManager with parser which make blink and flink could not share the same CatalogManager. - * This is a workaround which always reset CatalogTableSchemaResolver before running any flink code. - * - * @param catalogManager - * @param parserObject - * @param environmentSetting - */ - @Override - public void setCatalogManagerSchemaResolver(Object catalogManager, - Object parserObject, - Object environmentSetting) { - - } - - @Override - public Object updateEffectiveConfig(Object cliFrontend, Object commandLine, Object effectiveConfig) { - CustomCommandLine customCommandLine = ((CliFrontend) cliFrontend).validateAndGetActiveCommandLine((CommandLine) commandLine); - try { - ((Configuration) effectiveConfig).addAll(customCommandLine.toConfiguration((CommandLine) commandLine)); - return effectiveConfig; - } catch (FlinkException e) { - throw new RuntimeException("Fail to call addAll", e); - } - } - - @Override - public void setBatchRuntimeMode(Object tableConfig) { - ((TableConfig) tableConfig).getConfiguration() - .set(ExecutionOptions.RUNTIME_MODE, RuntimeExecutionMode.BATCH); - } - - @Override - public void setOldPlanner(Object tableConfig) { - - } - - @Override - public String[] rowToString(Object row, Object table, Object tableConfig) { - final String zone = ((TableConfig) tableConfig).getConfiguration() - .get(TableConfigOptions.LOCAL_TIME_ZONE); - ZoneId zoneId = TableConfigOptions.LOCAL_TIME_ZONE.defaultValue().equals(zone) - ? ZoneId.systemDefault() - : ZoneId.of(zone); - - ResolvedSchema resolvedSchema = ((Table) table).getResolvedSchema(); - return PrintUtils.rowToString((Row) row, resolvedSchema, zoneId); - } - - @Override - public boolean isTimeIndicatorType(Object type) { - return FlinkTypeFactory.isTimeIndicatorType((TypeInformation) type); - } - - private Object lookupExecutor(ClassLoader classLoader, - Object settings, - Object sEnv) { - try { - final ExecutorFactory executorFactory = - FactoryUtil.discoverFactory( - classLoader, ExecutorFactory.class, ExecutorFactory.DEFAULT_IDENTIFIER); - final Method createMethod = - executorFactory - .getClass() - .getMethod("create", StreamExecutionEnvironment.class); - - return createMethod.invoke(executorFactory, sEnv); - } catch (Exception e) { - throw new TableException( - "Could not instantiate the executor. Make sure a planner module is on the classpath", - e); - } - } - - @Override - public ImmutablePair createPlannerAndExecutor( - ClassLoader classLoader, Object environmentSettings, Object sEnv, - Object tableConfig, Object moduleManager, Object functionCatalog, Object catalogManager) { - EnvironmentSettings settings = (EnvironmentSettings) environmentSettings; - Executor executor = (Executor) lookupExecutor(classLoader, environmentSettings, sEnv); - Planner planner = PlannerFactoryUtil.createPlanner(executor, - (TableConfig) tableConfig, - (ModuleManager) moduleManager, - (CatalogManager) catalogManager, - (FunctionCatalog) functionCatalog); - return ImmutablePair.of(planner, executor); - } - - @Override - public Object createBlinkPlannerEnvSettingBuilder() { - return EnvironmentSettings.newInstance(); - } - - @Override - public Object createOldPlannerEnvSettingBuilder() { - return EnvironmentSettings.newInstance(); - } - - public InterpreterResult runSqlList(String st, InterpreterContext context, boolean isBatch) { - if (isBatch) { - return batchSqlInterpreter.runSqlList(st, context); - } else { - return streamSqlInterpreter.runSqlList(st, context); - } - } -} diff --git a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/Flink115SqlInterpreter.java b/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/Flink115SqlInterpreter.java deleted file mode 100644 index 6c0c67fb2bc..00000000000 --- a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/Flink115SqlInterpreter.java +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.flink.api.common.JobExecutionResult; -import org.apache.flink.api.common.JobStatus; -import org.apache.flink.api.java.ExecutionEnvironment; -import org.apache.flink.configuration.PipelineOptions; -import org.apache.flink.core.execution.JobClient; -import org.apache.flink.core.execution.JobListener; -import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; -import org.apache.flink.table.api.SqlParserException; -import org.apache.flink.table.api.Table; -import org.apache.flink.table.api.TableEnvironment; -import org.apache.flink.table.api.TableResult; -import org.apache.flink.table.api.internal.TableEnvironmentInternal; -import org.apache.flink.table.delegation.Parser; -import org.apache.flink.table.operations.*; -import org.apache.flink.table.operations.command.HelpOperation; -import org.apache.flink.table.operations.command.SetOperation; -import org.apache.flink.table.operations.ddl.*; -import org.apache.flink.table.utils.EncodingUtils; -import org.apache.flink.types.Row; -import org.apache.flink.util.CloseableIterator; -import org.apache.flink.util.CollectionUtil; -import org.apache.flink.util.Preconditions; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.util.SqlSplitter; -import org.jline.utils.AttributedString; -import org.jline.utils.AttributedStringBuilder; -import org.jline.utils.AttributedStyle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.stream.Collectors; - -import static org.apache.flink.util.Preconditions.checkNotNull; -import static org.apache.flink.util.Preconditions.checkState; - - -public class Flink115SqlInterpreter { - - private static final Logger LOGGER = LoggerFactory.getLogger(Flink115SqlInterpreter.class); - private static final String CMD_DESC_DELIMITER = "\t\t"; - - /** - * SQL Client HELP command helper class. - */ - private static final class SQLCliCommandsDescriptions { - private int commandMaxLength; - private final Map commandsDescriptions; - - public SQLCliCommandsDescriptions() { - this.commandsDescriptions = new LinkedHashMap<>(); - this.commandMaxLength = -1; - } - - public SQLCliCommandsDescriptions commandDescription(String command, String description) { - Preconditions.checkState( - StringUtils.isNotBlank(command), "content of command must not be empty."); - Preconditions.checkState( - StringUtils.isNotBlank(description), - "content of command's description must not be empty."); - this.updateMaxCommandLength(command.length()); - this.commandsDescriptions.put(command, description); - return this; - } - - private void updateMaxCommandLength(int newLength) { - Preconditions.checkState(newLength > 0); - if (this.commandMaxLength < newLength) { - this.commandMaxLength = newLength; - } - } - - public AttributedString build() { - AttributedStringBuilder attributedStringBuilder = new AttributedStringBuilder(); - if (!this.commandsDescriptions.isEmpty()) { - this.commandsDescriptions.forEach( - (cmd, cmdDesc) -> { - attributedStringBuilder - .style(AttributedStyle.DEFAULT.bold()) - .append( - String.format( - String.format("%%-%ds", commandMaxLength), cmd)) - .append(CMD_DESC_DELIMITER) - .style(AttributedStyle.DEFAULT) - .append(cmdDesc) - .append('\n'); - }); - } - return attributedStringBuilder.toAttributedString(); - } - } - - private static final AttributedString SQL_CLI_COMMANDS_DESCRIPTIONS = - new SQLCliCommandsDescriptions() - .commandDescription("HELP", "Prints the available commands.") - .commandDescription( - "SET", - "Sets a session configuration property. Syntax: \"SET ''='';\". Use \"SET;\" for listing all properties.") - .commandDescription( - "RESET", - "Resets a session configuration property. Syntax: \"RESET '';\". Use \"RESET;\" for reset all session properties.") - .commandDescription( - "INSERT INTO", - "Inserts the results of a SQL SELECT query into a declared table sink.") - .commandDescription( - "INSERT OVERWRITE", - "Inserts the results of a SQL SELECT query into a declared table sink and overwrite existing data.") - .commandDescription( - "SELECT", "Executes a SQL SELECT query on the Flink cluster.") - .commandDescription( - "EXPLAIN", - "Describes the execution plan of a query or table with the given name.") - .commandDescription( - "BEGIN STATEMENT SET", - "Begins a statement set. Syntax: \"BEGIN STATEMENT SET;\"") - .commandDescription("END", "Ends a statement set. Syntax: \"END;\"") - // (TODO) zjffdu, ADD/REMOVE/SHOW JAR - .build(); - - // -------------------------------------------------------------------------------------------- - - public static final AttributedString MESSAGE_HELP = - new AttributedStringBuilder() - .append("The following commands are available:\n\n") - .append(SQL_CLI_COMMANDS_DESCRIPTIONS) - .style(AttributedStyle.DEFAULT.underline()) - .append("\nHint") - .style(AttributedStyle.DEFAULT) - .append( - ": Make sure that a statement ends with \";\" for finalizing (multi-line) statements.") - // About Documentation Link. - .style(AttributedStyle.DEFAULT) - .append( - "\nYou can also type any Flink SQL statement, please visit https://nightlies.apache.org/flink/flink-docs-stable/docs/dev/table/sql/overview/ for more details.") - .toAttributedString(); - - private static final String MESSAGE_NO_STATEMENT_IN_STATEMENT_SET = "No statement in the statement set, skip submit."; - - private FlinkSqlContext flinkSqlContext; - private TableEnvironment tbenv; - private ZeppelinContext z; - private Parser sqlParser; - private SqlSplitter sqlSplitter; - // paragraphId -> list of ModifyOperation, used for statement set in 2 syntax: - // 1. runAsOne= true - // 2. begin statement set; - // ... - // end; - private Map> statementOperationsMap = new HashMap<>(); - private boolean isBatch; - private ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock(); - - - public Flink115SqlInterpreter(FlinkSqlContext flinkSqlContext, boolean isBatch) { - this.flinkSqlContext = flinkSqlContext; - this.isBatch = isBatch; - if (isBatch) { - this.tbenv = (TableEnvironment) flinkSqlContext.getBtenv(); - } else { - this.tbenv = (TableEnvironment) flinkSqlContext.getStenv(); - } - this.z = (ZeppelinContext) flinkSqlContext.getZeppelinContext(); - this.sqlParser = ((TableEnvironmentInternal) tbenv).getParser(); - this.sqlSplitter = new SqlSplitter(); - JobListener jobListener = new JobListener() { - @Override - public void onJobSubmitted(@Nullable JobClient jobClient, @Nullable Throwable throwable) { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - LOGGER.info("UnLock JobSubmitLock"); - } - } - - @Override - public void onJobExecuted(@Nullable JobExecutionResult jobExecutionResult, @Nullable Throwable throwable) { - - } - }; - - ((ExecutionEnvironment) flinkSqlContext.getBenv()).registerJobListener(jobListener); - ((StreamExecutionEnvironment) flinkSqlContext.getSenv()).registerJobListener(jobListener); - } - - public InterpreterResult runSqlList(String st, InterpreterContext context) { - try { - boolean runAsOne = Boolean.parseBoolean(context.getStringLocalProperty("runAsOne", "false")); - if (runAsOne) { - statementOperationsMap.put(context.getParagraphId(), new ArrayList<>()); - } - - String jobName = context.getLocalProperties().get("jobName"); - if (StringUtils.isNotBlank(jobName)) { - tbenv.getConfig().getConfiguration().set(PipelineOptions.NAME, jobName); - } - - List sqls = sqlSplitter.splitSql(st).stream().map(String::trim).collect(Collectors.toList()); - for (String sql : sqls) { - List operations = null; - try { - operations = sqlParser.parse(sql); - } catch (SqlParserException e) { - context.out.write("%text Invalid Sql statement: " + sql + "\n"); - context.out.write(MESSAGE_HELP.toString()); - return new InterpreterResult(InterpreterResult.Code.ERROR, e.toString()); - } - - try { - callOperation(sql, operations.get(0), context); - context.out.flush(); - } catch (Throwable e) { - LOGGER.error("Fail to run sql:" + sql, e); - try { - context.out.write("%text Fail to run sql command: " + - sql + "\n" + ExceptionUtils.getStackTrace(e) + "\n"); - } catch (IOException ex) { - LOGGER.warn("Unexpected exception:", ex); - return new InterpreterResult(InterpreterResult.Code.ERROR, - ExceptionUtils.getStackTrace(e)); - } - return new InterpreterResult(InterpreterResult.Code.ERROR); - } - } - - if (runAsOne && !statementOperationsMap.getOrDefault(context.getParagraphId(), new ArrayList<>()).isEmpty()) { - try { - lock.lock(); - List modifyOperations = statementOperationsMap.getOrDefault(context.getParagraphId(), new ArrayList<>()); - if (!modifyOperations.isEmpty()) { - callInserts(modifyOperations, context); - } - } catch (Exception e) { - LOGGER.error("Fail to execute sql as one job", e); - return new InterpreterResult(InterpreterResult.Code.ERROR, ExceptionUtils.getStackTrace(e)); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - } catch (Exception e) { - LOGGER.error("Fail to execute sql", e); - return new InterpreterResult(InterpreterResult.Code.ERROR, ExceptionUtils.getStackTrace(e)); - } finally { - statementOperationsMap.remove(context.getParagraphId()); - } - - return new InterpreterResult(InterpreterResult.Code.SUCCESS); - } - - private void callOperation(String sql, Operation operation, InterpreterContext context) throws IOException { - if (operation instanceof HelpOperation) { - // HELP - callHelp(context); - } else if (operation instanceof SetOperation) { - // SET - callSet((SetOperation) operation, context); - } else if (operation instanceof ModifyOperation) { - // INSERT INTO/OVERWRITE - callInsert((ModifyOperation) operation, context); - } else if (operation instanceof QueryOperation) { - // SELECT - callSelect(sql, (QueryOperation) operation, context); - } else if (operation instanceof ExplainOperation) { - // EXPLAIN - callExplain((ExplainOperation) operation, context); - } else if (operation instanceof BeginStatementSetOperation) { - // BEGIN STATEMENT SET - callBeginStatementSet(context); - } else if (operation instanceof EndStatementSetOperation) { - // END - callEndStatementSet(context); - } else if (operation instanceof ShowCreateTableOperation) { - // SHOW CREATE TABLE - callShowCreateTable((ShowCreateTableOperation) operation, context); - } else if (operation instanceof ShowCatalogsOperation) { - callShowCatalogs(context); - } else if (operation instanceof ShowCurrentCatalogOperation) { - callShowCurrentCatalog(context); - } else if (operation instanceof UseCatalogOperation) { - callUseCatalog(((UseCatalogOperation) operation).getCatalogName(), context); - } else if (operation instanceof CreateCatalogOperation) { - callDDL(sql, context, "Catalog has been created."); - } else if (operation instanceof DropCatalogOperation) { - callDDL(sql, context, "Catalog has been dropped."); - } else if (operation instanceof UseDatabaseOperation) { - UseDatabaseOperation useDBOperation = (UseDatabaseOperation) operation; - callUseDatabase(useDBOperation.getDatabaseName(), context); - } else if (operation instanceof CreateDatabaseOperation) { - callDDL(sql, context, "Database has been created."); - } else if (operation instanceof DropDatabaseOperation) { - callDDL(sql, context, "Database has been removed."); - } else if (operation instanceof AlterDatabaseOperation) { - callDDL(sql, context, "Alter database succeeded!"); - } else if (operation instanceof ShowDatabasesOperation) { - callShowDatabases(context); - } else if (operation instanceof ShowCurrentDatabaseOperation) { - callShowCurrentDatabase(context); - } else if (operation instanceof CreateTableOperation || operation instanceof CreateTableASOperation) { - callDDL(sql, context, "Table has been created."); - } else if (operation instanceof AlterTableOperation) { - callDDL(sql, context, "Alter table succeeded!"); - } else if (operation instanceof DropTableOperation) { - callDDL(sql, context, "Table has been dropped."); - } else if (operation instanceof DescribeTableOperation) { - DescribeTableOperation describeTableOperation = (DescribeTableOperation) operation; - callDescribe(describeTableOperation.getSqlIdentifier().getObjectName(), context); - } else if (operation instanceof ShowTablesOperation) { - callShowTables(context); - } else if (operation instanceof CreateViewOperation) { - callDDL(sql, context, "View has been created."); - } else if (operation instanceof DropViewOperation) { - callDDL(sql, context, "View has been dropped."); - } else if (operation instanceof AlterViewOperation) { - callDDL(sql, context, "Alter view succeeded!"); - } else if (operation instanceof CreateCatalogFunctionOperation || operation instanceof CreateTempSystemFunctionOperation) { - callDDL(sql, context, "Function has been created."); - } else if (operation instanceof DropCatalogFunctionOperation || operation instanceof DropTempSystemFunctionOperation) { - callDDL(sql, context, "Function has been removed."); - } else if (operation instanceof AlterCatalogFunctionOperation) { - callDDL(sql, context, "Alter function succeeded!"); - } else if (operation instanceof ShowFunctionsOperation) { - callShowFunctions(context); - } else if (operation instanceof ShowModulesOperation) { - callShowModules(context); - } else if (operation instanceof ShowPartitionsOperation) { - ShowPartitionsOperation showPartitionsOperation = (ShowPartitionsOperation) operation; - callShowPartitions(showPartitionsOperation.asSummaryString(), context); - } else { - throw new IOException(operation.getClass().getName() + " is not supported"); - } - } - - - private void callHelp(InterpreterContext context) throws IOException { - context.out.write(MESSAGE_HELP.toString() + "\n"); - } - - private void callInsert(ModifyOperation operation, InterpreterContext context) throws IOException { - if (statementOperationsMap.containsKey(context.getParagraphId())) { - List modifyOperations = statementOperationsMap.get(context.getParagraphId()); - modifyOperations.add(operation); - } else { - callInserts(Collections.singletonList(operation), context); - } - } - - private void callInserts(List operations, InterpreterContext context) throws IOException { - if (!isBatch) { - context.getLocalProperties().put("flink.streaming.insert_into", "true"); - } - TableResult tableResult = ((TableEnvironmentInternal) tbenv).executeInternal(operations); - checkState(tableResult.getJobClient().isPresent()); - try { - tableResult.await(); - JobClient jobClient = tableResult.getJobClient().get(); - if (jobClient.getJobStatus().get() == JobStatus.FINISHED) { - context.out.write("Insertion successfully.\n"); - } else { - throw new IOException("Job is failed, " + jobClient.getJobExecutionResult().get().toString()); - } - } catch (InterruptedException e) { - throw new IOException("Flink job is interrupted", e); - } catch (ExecutionException e) { - throw new IOException("Flink job is failed", e); - } - } - - private void callShowCreateTable(ShowCreateTableOperation showCreateTableOperation, InterpreterContext context) throws IOException { - try { - lock.lock(); - TableResult tableResult = ((TableEnvironmentInternal) tbenv).executeInternal(showCreateTableOperation); - String explanation = - Objects.requireNonNull(tableResult.collect().next().getField(0)).toString(); - context.out.write(explanation + "\n"); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - - private void callExplain(ExplainOperation explainOperation, InterpreterContext context) throws IOException { - try { - lock.lock(); - TableResult tableResult = ((TableEnvironmentInternal) tbenv).executeInternal(explainOperation); - String explanation = - Objects.requireNonNull(tableResult.collect().next().getField(0)).toString(); - context.out.write(explanation + "\n"); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - - public void callSelect(String sql, QueryOperation queryOperation, InterpreterContext context) throws IOException { - try { - lock.lock(); - if (isBatch) { - callBatchInnerSelect(sql, context); - } else { - callStreamInnerSelect(sql, context); - } - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - - public void callBatchInnerSelect(String sql, InterpreterContext context) throws IOException { - Table table = this.tbenv.sqlQuery(sql); - String result = z.showData(table); - context.out.write(result); - } - - public void callStreamInnerSelect(String sql, InterpreterContext context) throws IOException { - flinkSqlContext.getStreamSqlSelectConsumer().accept(sql); - } - - public void callSet(SetOperation setOperation, InterpreterContext context) throws IOException { - if (setOperation.getKey().isPresent() && setOperation.getValue().isPresent()) { - // set a property - String key = setOperation.getKey().get().trim(); - String value = setOperation.getValue().get().trim(); - this.tbenv.getConfig().getConfiguration().setString(key, value); - LOGGER.info("Set table config: {}={}", key, value); - } else { - // show all properties - final Map properties = this.tbenv.getConfig().getConfiguration().toMap(); - List prettyEntries = new ArrayList<>(); - for (String key : properties.keySet()) { - prettyEntries.add( - String.format( - "'%s' = '%s'", - EncodingUtils.escapeSingleQuotes(key), - EncodingUtils.escapeSingleQuotes(properties.get(key)))); - } - prettyEntries.sort(String::compareTo); - prettyEntries.forEach(entry -> { - try { - context.out.write(entry + "\n"); - } catch (IOException e) { - LOGGER.warn("Fail to write output", e); - } - }); - } - } - - private void callBeginStatementSet(InterpreterContext context) throws IOException { - statementOperationsMap.put(context.getParagraphId(), new ArrayList<>()); - } - - private void callEndStatementSet(InterpreterContext context) throws IOException { - List modifyOperations = statementOperationsMap.get(context.getParagraphId()); - if (modifyOperations != null && !modifyOperations.isEmpty()) { - callInserts(modifyOperations, context); - } else { - context.out.write(MESSAGE_NO_STATEMENT_IN_STATEMENT_SET); - } - } - - private void callUseCatalog(String catalog, InterpreterContext context) throws IOException { - tbenv.executeSql("USE CATALOG `" + catalog + "`"); - } - - private void callUseDatabase(String databaseName, - InterpreterContext context) throws IOException { - this.tbenv.executeSql("USE `" + databaseName + "`"); - } - - private void callShowCatalogs(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Catalogs"); - List catalogs = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write("%table catalog\n" + StringUtils.join(catalogs, "\n") + "\n"); - } - - private void callShowCurrentCatalog(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Current Catalog"); - String catalog = tableResult.collect().next().getField(0).toString(); - context.out.write("%text current catalog: " + catalog + "\n"); - } - - private void callShowDatabases(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Databases"); - List databases = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write( - "%table database\n" + StringUtils.join(databases, "\n") + "\n"); - } - - private void callShowCurrentDatabase(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Current Database"); - String database = tableResult.collect().next().getField(0).toString(); - context.out.write("%text current database: " + database + "\n"); - } - - private void callShowTables(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Tables"); - List tables = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .filter(tbl -> !tbl.startsWith("UnnamedTable")) - .collect(Collectors.toList()); - context.out.write( - "%table table\n" + StringUtils.join(tables, "\n") + "\n"); - } - - private void callShowFunctions(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Functions"); - List functions = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write( - "%table function\n" + StringUtils.join(functions, "\n") + "\n"); - } - - private void callShowModules(InterpreterContext context) throws IOException { - String[] modules = this.tbenv.listModules(); - context.out.write("%table modules\n" + StringUtils.join(modules, "\n") + "\n"); - } - - private void callShowPartitions(String sql, InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql(sql); - List partions = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write( - "%table partitions\n" + StringUtils.join(partions, "\n") + "\n"); - } - - private void callDDL(String sql, InterpreterContext context, String message) throws IOException { - try { - lock.lock(); - this.tbenv.executeSql(sql); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - context.out.write(message + "\n"); - } - - private void callDescribe(String name, InterpreterContext context) throws IOException { - TableResult tableResult = null; - try { - tableResult = tbenv.executeSql("DESCRIBE " + name); - } catch (Exception e) { - throw new IOException("Fail to describe table: " + name, e); - } - CloseableIterator result = tableResult.collect(); - StringBuilder builder = new StringBuilder(); - builder.append("Column\tType\n"); - while (result.hasNext()) { - Row row = result.next(); - builder.append(row.getField(0) + "\t" + row.getField(1) + "\n"); - } - context.out.write("%table\n" + builder.toString()); - } -} diff --git a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/shims115/CollectStreamTableSink.java b/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/shims115/CollectStreamTableSink.java deleted file mode 100644 index 0025389b265..00000000000 --- a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/shims115/CollectStreamTableSink.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink.shims115; - -import org.apache.flink.api.common.typeinfo.TypeInformation; -import org.apache.flink.api.common.typeinfo.Types; -import org.apache.flink.api.common.typeutils.TypeSerializer; -import org.apache.flink.api.java.tuple.Tuple2; -import org.apache.flink.api.java.typeutils.TupleTypeInfo; -import org.apache.flink.streaming.api.datastream.DataStream; -import org.apache.flink.streaming.api.datastream.DataStreamSink; -import org.apache.flink.streaming.experimental.CollectSink; -import org.apache.flink.table.sinks.RetractStreamTableSink; -import org.apache.flink.types.Row; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; -import java.util.UUID; - -/** - * Table sink for collecting the results locally using sockets. - */ -public class CollectStreamTableSink implements RetractStreamTableSink { - - private static final Logger LOGGER = LoggerFactory.getLogger(CollectStreamTableSink.class); - - private final InetAddress targetAddress; - private final int targetPort; - private final TypeSerializer> serializer; - - private String[] fieldNames; - private TypeInformation[] fieldTypes; - - public CollectStreamTableSink(InetAddress targetAddress, - int targetPort, - TypeSerializer> serializer) { - LOGGER.info("Use address: " + targetAddress.getHostAddress() + ":" + targetPort); - this.targetAddress = targetAddress; - this.targetPort = targetPort; - this.serializer = serializer; - } - - @Override - public String[] getFieldNames() { - return fieldNames; - } - - @Override - public TypeInformation[] getFieldTypes() { - return fieldTypes; - } - - @Override - public CollectStreamTableSink configure(String[] fieldNames, TypeInformation[] fieldTypes) { - final CollectStreamTableSink copy = - new CollectStreamTableSink(targetAddress, targetPort, serializer); - copy.fieldNames = fieldNames; - copy.fieldTypes = fieldTypes; - return copy; - } - - @Override - public TypeInformation getRecordType() { - return Types.ROW_NAMED(fieldNames, fieldTypes); - } - - @Override - public DataStreamSink consumeDataStream(DataStream> stream) { - // add sink - return stream - .addSink(new CollectSink<>(targetAddress, targetPort, serializer)) - .name("Zeppelin Flink Sql Stream Collect Sink " + UUID.randomUUID()) - .setParallelism(1); - } - - @Override - public TupleTypeInfo> getOutputType() { - return new TupleTypeInfo<>(Types.BOOLEAN, getRecordType()); - } -} diff --git a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/Flink116SqlInterpreter.java b/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/Flink116SqlInterpreter.java deleted file mode 100644 index e4f098cea76..00000000000 --- a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/Flink116SqlInterpreter.java +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.flink.api.common.JobExecutionResult; -import org.apache.flink.api.common.JobStatus; -import org.apache.flink.api.java.ExecutionEnvironment; -import org.apache.flink.configuration.PipelineOptions; -import org.apache.flink.core.execution.JobClient; -import org.apache.flink.core.execution.JobListener; -import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; -import org.apache.flink.table.api.SqlParserException; -import org.apache.flink.table.api.Table; -import org.apache.flink.table.api.TableEnvironment; -import org.apache.flink.table.api.TableResult; -import org.apache.flink.table.api.internal.TableEnvironmentInternal; -import org.apache.flink.table.delegation.Parser; -import org.apache.flink.table.operations.*; -import org.apache.flink.table.operations.command.HelpOperation; -import org.apache.flink.table.operations.command.SetOperation; -import org.apache.flink.table.operations.ddl.*; -import org.apache.flink.table.utils.EncodingUtils; -import org.apache.flink.types.Row; -import org.apache.flink.util.CloseableIterator; -import org.apache.flink.util.CollectionUtil; -import org.apache.flink.util.Preconditions; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.util.SqlSplitter; -import org.jline.utils.AttributedString; -import org.jline.utils.AttributedStringBuilder; -import org.jline.utils.AttributedStyle; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.util.*; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.stream.Collectors; - -import static org.apache.flink.util.Preconditions.checkNotNull; -import static org.apache.flink.util.Preconditions.checkState; - - -public class Flink116SqlInterpreter { - - private static final Logger LOGGER = LoggerFactory.getLogger(Flink116SqlInterpreter.class); - private static final String CMD_DESC_DELIMITER = "\t\t"; - - /** - * SQL Client HELP command helper class. - */ - private static final class SQLCliCommandsDescriptions { - private int commandMaxLength; - private final Map commandsDescriptions; - - public SQLCliCommandsDescriptions() { - this.commandsDescriptions = new LinkedHashMap<>(); - this.commandMaxLength = -1; - } - - public SQLCliCommandsDescriptions commandDescription(String command, String description) { - Preconditions.checkState( - StringUtils.isNotBlank(command), "content of command must not be empty."); - Preconditions.checkState( - StringUtils.isNotBlank(description), - "content of command's description must not be empty."); - this.updateMaxCommandLength(command.length()); - this.commandsDescriptions.put(command, description); - return this; - } - - private void updateMaxCommandLength(int newLength) { - Preconditions.checkState(newLength > 0); - if (this.commandMaxLength < newLength) { - this.commandMaxLength = newLength; - } - } - - public AttributedString build() { - AttributedStringBuilder attributedStringBuilder = new AttributedStringBuilder(); - if (!this.commandsDescriptions.isEmpty()) { - this.commandsDescriptions.forEach( - (cmd, cmdDesc) -> { - attributedStringBuilder - .style(AttributedStyle.DEFAULT.bold()) - .append( - String.format( - String.format("%%-%ds", commandMaxLength), cmd)) - .append(CMD_DESC_DELIMITER) - .style(AttributedStyle.DEFAULT) - .append(cmdDesc) - .append('\n'); - }); - } - return attributedStringBuilder.toAttributedString(); - } - } - - private static final AttributedString SQL_CLI_COMMANDS_DESCRIPTIONS = - new SQLCliCommandsDescriptions() - .commandDescription("HELP", "Prints the available commands.") - .commandDescription( - "SET", - "Sets a session configuration property. Syntax: \"SET ''='';\". Use \"SET;\" for listing all properties.") - .commandDescription( - "RESET", - "Resets a session configuration property. Syntax: \"RESET '';\". Use \"RESET;\" for reset all session properties.") - .commandDescription( - "INSERT INTO", - "Inserts the results of a SQL SELECT query into a declared table sink.") - .commandDescription( - "INSERT OVERWRITE", - "Inserts the results of a SQL SELECT query into a declared table sink and overwrite existing data.") - .commandDescription( - "SELECT", "Executes a SQL SELECT query on the Flink cluster.") - .commandDescription( - "EXPLAIN", - "Describes the execution plan of a query or table with the given name.") - .commandDescription( - "BEGIN STATEMENT SET", - "Begins a statement set. Syntax: \"BEGIN STATEMENT SET;\"") - .commandDescription("END", "Ends a statement set. Syntax: \"END;\"") - // (TODO) zjffdu, ADD/REMOVE/SHOW JAR - .build(); - - // -------------------------------------------------------------------------------------------- - - public static final AttributedString MESSAGE_HELP = - new AttributedStringBuilder() - .append("The following commands are available:\n\n") - .append(SQL_CLI_COMMANDS_DESCRIPTIONS) - .style(AttributedStyle.DEFAULT.underline()) - .append("\nHint") - .style(AttributedStyle.DEFAULT) - .append( - ": Make sure that a statement ends with \";\" for finalizing (multi-line) statements.") - // About Documentation Link. - .style(AttributedStyle.DEFAULT) - .append( - "\nYou can also type any Flink SQL statement, please visit https://nightlies.apache.org/flink/flink-docs-stable/docs/dev/table/sql/overview/ for more details.") - .toAttributedString(); - - private static final String MESSAGE_NO_STATEMENT_IN_STATEMENT_SET = "No statement in the statement set, skip submit."; - - private FlinkSqlContext flinkSqlContext; - private TableEnvironment tbenv; - private ZeppelinContext z; - private Parser sqlParser; - private SqlSplitter sqlSplitter; - // paragraphId -> list of ModifyOperation, used for statement set in 2 syntax: - // 1. runAsOne= true - // 2. begin statement set; - // ... - // end; - private Map> statementOperationsMap = new HashMap<>(); - private boolean isBatch; - private ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock(); - - - public Flink116SqlInterpreter(FlinkSqlContext flinkSqlContext, boolean isBatch) { - this.flinkSqlContext = flinkSqlContext; - this.isBatch = isBatch; - if (isBatch) { - this.tbenv = (TableEnvironment) flinkSqlContext.getBtenv(); - } else { - this.tbenv = (TableEnvironment) flinkSqlContext.getStenv(); - } - this.z = (ZeppelinContext) flinkSqlContext.getZeppelinContext(); - this.sqlParser = ((TableEnvironmentInternal) tbenv).getParser(); - this.sqlSplitter = new SqlSplitter(); - JobListener jobListener = new JobListener() { - @Override - public void onJobSubmitted(@Nullable JobClient jobClient, @Nullable Throwable throwable) { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - LOGGER.info("UnLock JobSubmitLock"); - } - } - - @Override - public void onJobExecuted(@Nullable JobExecutionResult jobExecutionResult, @Nullable Throwable throwable) { - - } - }; - - ((ExecutionEnvironment) flinkSqlContext.getBenv()).registerJobListener(jobListener); - ((StreamExecutionEnvironment) flinkSqlContext.getSenv()).registerJobListener(jobListener); - } - - public InterpreterResult runSqlList(String st, InterpreterContext context) { - try { - boolean runAsOne = Boolean.parseBoolean(context.getStringLocalProperty("runAsOne", "false")); - if (runAsOne) { - statementOperationsMap.put(context.getParagraphId(), new ArrayList<>()); - } - - String jobName = context.getLocalProperties().get("jobName"); - if (StringUtils.isNotBlank(jobName)) { - tbenv.getConfig().getConfiguration().set(PipelineOptions.NAME, jobName); - } - - List sqls = sqlSplitter.splitSql(st).stream().map(String::trim).collect(Collectors.toList()); - for (String sql : sqls) { - List operations = null; - try { - operations = sqlParser.parse(sql); - } catch (SqlParserException e) { - context.out.write("%text Invalid Sql statement: " + sql + "\n"); - context.out.write(MESSAGE_HELP.toString()); - return new InterpreterResult(InterpreterResult.Code.ERROR, e.toString()); - } - - try { - callOperation(sql, operations.get(0), context); - context.out.flush(); - } catch (Throwable e) { - LOGGER.error("Fail to run sql:" + sql, e); - try { - context.out.write("%text Fail to run sql command: " + - sql + "\n" + ExceptionUtils.getStackTrace(e) + "\n"); - } catch (IOException ex) { - LOGGER.warn("Unexpected exception:", ex); - return new InterpreterResult(InterpreterResult.Code.ERROR, - ExceptionUtils.getStackTrace(e)); - } - return new InterpreterResult(InterpreterResult.Code.ERROR); - } - } - - if (runAsOne && !statementOperationsMap.getOrDefault(context.getParagraphId(), new ArrayList<>()).isEmpty()) { - try { - lock.lock(); - List modifyOperations = statementOperationsMap.getOrDefault(context.getParagraphId(), new ArrayList<>()); - if (!modifyOperations.isEmpty()) { - callInserts(modifyOperations, context); - } - } catch (Exception e) { - LOGGER.error("Fail to execute sql as one job", e); - return new InterpreterResult(InterpreterResult.Code.ERROR, ExceptionUtils.getStackTrace(e)); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - } catch (Exception e) { - LOGGER.error("Fail to execute sql", e); - return new InterpreterResult(InterpreterResult.Code.ERROR, ExceptionUtils.getStackTrace(e)); - } finally { - statementOperationsMap.remove(context.getParagraphId()); - } - - return new InterpreterResult(InterpreterResult.Code.SUCCESS); - } - - private void callOperation(String sql, Operation operation, InterpreterContext context) throws IOException { - if (operation instanceof HelpOperation) { - // HELP - callHelp(context); - } else if (operation instanceof SetOperation) { - // SET - callSet((SetOperation) operation, context); - } else if (operation instanceof ModifyOperation) { - // INSERT INTO/OVERWRITE - callInsert((ModifyOperation) operation, context); - } else if (operation instanceof QueryOperation) { - // SELECT - callSelect(sql, (QueryOperation) operation, context); - } else if (operation instanceof ExplainOperation) { - // EXPLAIN - callExplain((ExplainOperation) operation, context); - } else if (operation instanceof BeginStatementSetOperation) { - // BEGIN STATEMENT SET - callBeginStatementSet(context); - } else if (operation instanceof EndStatementSetOperation) { - // END - callEndStatementSet(context); - } else if (operation instanceof ShowCreateTableOperation) { - // SHOW CREATE TABLE - callShowCreateTable((ShowCreateTableOperation) operation, context); - } else if (operation instanceof ShowCatalogsOperation) { - callShowCatalogs(context); - } else if (operation instanceof ShowCurrentCatalogOperation) { - callShowCurrentCatalog(context); - } else if (operation instanceof UseCatalogOperation) { - callUseCatalog(((UseCatalogOperation) operation).getCatalogName(), context); - } else if (operation instanceof CreateCatalogOperation) { - callDDL(sql, context, "Catalog has been created."); - } else if (operation instanceof DropCatalogOperation) { - callDDL(sql, context, "Catalog has been dropped."); - } else if (operation instanceof UseDatabaseOperation) { - UseDatabaseOperation useDBOperation = (UseDatabaseOperation) operation; - callUseDatabase(useDBOperation.getDatabaseName(), context); - } else if (operation instanceof CreateDatabaseOperation) { - callDDL(sql, context, "Database has been created."); - } else if (operation instanceof DropDatabaseOperation) { - callDDL(sql, context, "Database has been removed."); - } else if (operation instanceof AlterDatabaseOperation) { - callDDL(sql, context, "Alter database succeeded!"); - } else if (operation instanceof ShowDatabasesOperation) { - callShowDatabases(context); - } else if (operation instanceof ShowCurrentDatabaseOperation) { - callShowCurrentDatabase(context); - } else if (operation instanceof CreateTableOperation || operation instanceof CreateTableASOperation) { - callDDL(sql, context, "Table has been created."); - } else if (operation instanceof AlterTableOperation) { - callDDL(sql, context, "Alter table succeeded!"); - } else if (operation instanceof DropTableOperation) { - callDDL(sql, context, "Table has been dropped."); - } else if (operation instanceof DescribeTableOperation) { - DescribeTableOperation describeTableOperation = (DescribeTableOperation) operation; - callDescribe(describeTableOperation.getSqlIdentifier().getObjectName(), context); - } else if (operation instanceof ShowTablesOperation) { - callShowTables(context); - } else if (operation instanceof CreateViewOperation) { - callDDL(sql, context, "View has been created."); - } else if (operation instanceof DropViewOperation) { - callDDL(sql, context, "View has been dropped."); - } else if (operation instanceof AlterViewOperation) { - callDDL(sql, context, "Alter view succeeded!"); - } else if (operation instanceof CreateCatalogFunctionOperation || operation instanceof CreateTempSystemFunctionOperation) { - callDDL(sql, context, "Function has been created."); - } else if (operation instanceof DropCatalogFunctionOperation || operation instanceof DropTempSystemFunctionOperation) { - callDDL(sql, context, "Function has been removed."); - } else if (operation instanceof AlterCatalogFunctionOperation) { - callDDL(sql, context, "Alter function succeeded!"); - } else if (operation instanceof ShowFunctionsOperation) { - callShowFunctions(context); - } else if (operation instanceof ShowModulesOperation) { - callShowModules(context); - } else if (operation instanceof ShowPartitionsOperation) { - ShowPartitionsOperation showPartitionsOperation = (ShowPartitionsOperation) operation; - callShowPartitions(showPartitionsOperation.asSummaryString(), context); - } else { - throw new IOException(operation.getClass().getName() + " is not supported"); - } - } - - - private void callHelp(InterpreterContext context) throws IOException { - context.out.write(MESSAGE_HELP.toString() + "\n"); - } - - private void callInsert(ModifyOperation operation, InterpreterContext context) throws IOException { - if (statementOperationsMap.containsKey(context.getParagraphId())) { - List modifyOperations = statementOperationsMap.get(context.getParagraphId()); - modifyOperations.add(operation); - } else { - callInserts(Collections.singletonList(operation), context); - } - } - - private void callInserts(List operations, InterpreterContext context) throws IOException { - if (!isBatch) { - context.getLocalProperties().put("flink.streaming.insert_into", "true"); - } - TableResult tableResult = ((TableEnvironmentInternal) tbenv).executeInternal(operations); - checkState(tableResult.getJobClient().isPresent()); - try { - tableResult.await(); - JobClient jobClient = tableResult.getJobClient().get(); - if (jobClient.getJobStatus().get() == JobStatus.FINISHED) { - context.out.write("Insertion successfully.\n"); - } else { - throw new IOException("Job is failed, " + jobClient.getJobExecutionResult().get().toString()); - } - } catch (InterruptedException e) { - throw new IOException("Flink job is interrupted", e); - } catch (ExecutionException e) { - throw new IOException("Flink job is failed", e); - } - } - - private void callShowCreateTable(ShowCreateTableOperation showCreateTableOperation, InterpreterContext context) throws IOException { - try { - lock.lock(); - TableResult tableResult = ((TableEnvironmentInternal) tbenv).executeInternal(showCreateTableOperation); - String explanation = - Objects.requireNonNull(tableResult.collect().next().getField(0)).toString(); - context.out.write(explanation + "\n"); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - - private void callExplain(ExplainOperation explainOperation, InterpreterContext context) throws IOException { - try { - lock.lock(); - TableResult tableResult = ((TableEnvironmentInternal) tbenv).executeInternal(explainOperation); - String explanation = - Objects.requireNonNull(tableResult.collect().next().getField(0)).toString(); - context.out.write(explanation + "\n"); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - - public void callSelect(String sql, QueryOperation queryOperation, InterpreterContext context) throws IOException { - try { - lock.lock(); - if (isBatch) { - callBatchInnerSelect(sql, context); - } else { - callStreamInnerSelect(sql, context); - } - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - } - - public void callBatchInnerSelect(String sql, InterpreterContext context) throws IOException { - Table table = this.tbenv.sqlQuery(sql); - String result = z.showData(table); - context.out.write(result); - } - - public void callStreamInnerSelect(String sql, InterpreterContext context) throws IOException { - flinkSqlContext.getStreamSqlSelectConsumer().accept(sql); - } - - public void callSet(SetOperation setOperation, InterpreterContext context) throws IOException { - if (setOperation.getKey().isPresent() && setOperation.getValue().isPresent()) { - // set a property - String key = setOperation.getKey().get().trim(); - String value = setOperation.getValue().get().trim(); - this.tbenv.getConfig().getConfiguration().setString(key, value); - LOGGER.info("Set table config: {}={}", key, value); - } else { - // show all properties - final Map properties = this.tbenv.getConfig().getConfiguration().toMap(); - List prettyEntries = new ArrayList<>(); - for (String key : properties.keySet()) { - prettyEntries.add( - String.format( - "'%s' = '%s'", - EncodingUtils.escapeSingleQuotes(key), - EncodingUtils.escapeSingleQuotes(properties.get(key)))); - } - prettyEntries.sort(String::compareTo); - prettyEntries.forEach(entry -> { - try { - context.out.write(entry + "\n"); - } catch (IOException e) { - LOGGER.warn("Fail to write output", e); - } - }); - } - } - - private void callBeginStatementSet(InterpreterContext context) throws IOException { - statementOperationsMap.put(context.getParagraphId(), new ArrayList<>()); - } - - private void callEndStatementSet(InterpreterContext context) throws IOException { - List modifyOperations = statementOperationsMap.get(context.getParagraphId()); - if (modifyOperations != null && !modifyOperations.isEmpty()) { - callInserts(modifyOperations, context); - } else { - context.out.write(MESSAGE_NO_STATEMENT_IN_STATEMENT_SET); - } - } - - private void callUseCatalog(String catalog, InterpreterContext context) throws IOException { - tbenv.executeSql("USE CATALOG `" + catalog + "`"); - } - - private void callUseDatabase(String databaseName, - InterpreterContext context) throws IOException { - this.tbenv.executeSql("USE `" + databaseName + "`"); - } - - private void callShowCatalogs(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Catalogs"); - List catalogs = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write("%table catalog\n" + StringUtils.join(catalogs, "\n") + "\n"); - } - - private void callShowCurrentCatalog(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Current Catalog"); - String catalog = tableResult.collect().next().getField(0).toString(); - context.out.write("%text current catalog: " + catalog + "\n"); - } - - private void callShowDatabases(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Databases"); - List databases = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write( - "%table database\n" + StringUtils.join(databases, "\n") + "\n"); - } - - private void callShowCurrentDatabase(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Current Database"); - String database = tableResult.collect().next().getField(0).toString(); - context.out.write("%text current database: " + database + "\n"); - } - - private void callShowTables(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Tables"); - List tables = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .filter(tbl -> !tbl.startsWith("UnnamedTable")) - .collect(Collectors.toList()); - context.out.write( - "%table table\n" + StringUtils.join(tables, "\n") + "\n"); - } - - private void callShowFunctions(InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql("SHOW Functions"); - List functions = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write( - "%table function\n" + StringUtils.join(functions, "\n") + "\n"); - } - - private void callShowModules(InterpreterContext context) throws IOException { - String[] modules = this.tbenv.listModules(); - context.out.write("%table modules\n" + StringUtils.join(modules, "\n") + "\n"); - } - - private void callShowPartitions(String sql, InterpreterContext context) throws IOException { - TableResult tableResult = this.tbenv.executeSql(sql); - List partions = CollectionUtil.iteratorToList(tableResult.collect()).stream() - .map(r -> checkNotNull(r.getField(0)).toString()) - .collect(Collectors.toList()); - context.out.write( - "%table partitions\n" + StringUtils.join(partions, "\n") + "\n"); - } - - private void callDDL(String sql, InterpreterContext context, String message) throws IOException { - try { - lock.lock(); - this.tbenv.executeSql(sql); - } finally { - if (lock.isHeldByCurrentThread()) { - lock.unlock(); - } - } - context.out.write(message + "\n"); - } - - private void callDescribe(String name, InterpreterContext context) throws IOException { - TableResult tableResult = null; - try { - tableResult = tbenv.executeSql("DESCRIBE " + name); - } catch (Exception e) { - throw new IOException("Fail to describe table: " + name, e); - } - CloseableIterator result = tableResult.collect(); - StringBuilder builder = new StringBuilder(); - builder.append("Column\tType\n"); - while (result.hasNext()) { - Row row = result.next(); - builder.append(row.getField(0) + "\t" + row.getField(1) + "\n"); - } - context.out.write("%table\n" + builder.toString()); - } -} diff --git a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java b/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java deleted file mode 100644 index a35ad3a6cd1..00000000000 --- a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - - -import org.apache.flink.table.catalog.ResolvedSchema; -import org.apache.flink.table.data.MapData; -import org.apache.flink.table.data.RowData; -import org.apache.flink.table.data.TimestampData; -import org.apache.flink.table.types.logical.*; -import org.apache.flink.types.Row; -import org.apache.flink.util.StringUtils; - -import java.sql.Time; -import java.sql.Timestamp; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.apache.flink.table.types.logical.utils.LogicalTypeChecks.getPrecision; -import static org.apache.zeppelin.flink.TimestampStringUtils.*; - -/** - * Copied from flink-project with minor modification. - * */ -public class PrintUtils { - - public static final String NULL_COLUMN = "(NULL)"; - private static final String COLUMN_TRUNCATED_FLAG = "..."; - - private PrintUtils() {} - - - public static String[] rowToString( - Row row, ResolvedSchema resolvedSchema, ZoneId sessionTimeZone) { - return rowToString(row, NULL_COLUMN, false, resolvedSchema, sessionTimeZone); - } - - public static String[] rowToString( - Row row, - String nullColumn, - boolean printRowKind, - ResolvedSchema resolvedSchema, - ZoneId sessionTimeZone) { - final int len = printRowKind ? row.getArity() + 1 : row.getArity(); - final List fields = new ArrayList<>(len); - if (printRowKind) { - fields.add(row.getKind().shortString()); - } - for (int i = 0; i < row.getArity(); i++) { - final Object field = row.getField(i); - final LogicalType fieldType = - resolvedSchema.getColumnDataTypes().get(i).getLogicalType(); - if (field == null) { - fields.add(nullColumn); - } else { - fields.add( - StringUtils.arrayAwareToString( - formattedTimestamp(field, fieldType, sessionTimeZone))); - } - } - return fields.toArray(new String[0]); - } - - /** - * Normalizes field that contains TIMESTAMP, TIMESTAMP_LTZ and TIME type data. - * - *

This method also supports nested type ARRAY, ROW, MAP. - */ - private static Object formattedTimestamp( - Object field, LogicalType fieldType, ZoneId sessionTimeZone) { - final LogicalTypeRoot typeRoot = fieldType.getTypeRoot(); - if (field == null) { - return "null"; - } - switch (typeRoot) { - case TIMESTAMP_WITHOUT_TIME_ZONE: - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - return formatTimestampField(field, fieldType, sessionTimeZone); - case TIME_WITHOUT_TIME_ZONE: - return formatTimeField(field); - case ARRAY: - LogicalType elementType = ((ArrayType) fieldType).getElementType(); - if (field instanceof List) { - List array = (List) field; - Object[] formattedArray = new Object[array.size()]; - for (int i = 0; i < array.size(); i++) { - formattedArray[i] = - formattedTimestamp(array.get(i), elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass().isArray()) { - // primitive type - if (field.getClass() == byte[].class) { - byte[] array = (byte[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == short[].class) { - short[] array = (short[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == int[].class) { - int[] array = (int[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == long[].class) { - long[] array = (long[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == float[].class) { - float[] array = (float[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == double[].class) { - double[] array = (double[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == boolean[].class) { - boolean[] array = (boolean[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == char[].class) { - char[] array = (char[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else { - // non-primitive type - Object[] array = (Object[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } - } else { - return field; - } - case ROW: - if (fieldType instanceof RowType && field instanceof Row) { - Row row = (Row) field; - Row formattedRow = new Row(row.getKind(), row.getArity()); - for (int i = 0; i < ((RowType) fieldType).getFields().size(); i++) { - LogicalType type = ((RowType) fieldType).getFields().get(i).getType(); - formattedRow.setField( - i, formattedTimestamp(row.getField(i), type, sessionTimeZone)); - } - return formattedRow; - - } else if (fieldType instanceof RowType && field instanceof RowData) { - RowData rowData = (RowData) field; - Row formattedRow = new Row(rowData.getRowKind(), rowData.getArity()); - for (int i = 0; i < ((RowType) fieldType).getFields().size(); i++) { - LogicalType type = ((RowType) fieldType).getFields().get(i).getType(); - RowData.FieldGetter fieldGetter = RowData.createFieldGetter(type, i); - formattedRow.setField( - i, - formattedTimestamp( - fieldGetter.getFieldOrNull(rowData), - type, - sessionTimeZone)); - } - return formattedRow; - } else { - return field; - } - case MAP: - LogicalType keyType = ((MapType) fieldType).getKeyType(); - LogicalType valueType = ((MapType) fieldType).getValueType(); - if (fieldType instanceof MapType && field instanceof Map) { - Map map = ((Map) field); - Map formattedMap = new HashMap<>(map.size()); - for (Object key : map.keySet()) { - formattedMap.put( - formattedTimestamp(key, keyType, sessionTimeZone), - formattedTimestamp(map.get(key), valueType, sessionTimeZone)); - } - return formattedMap; - } else if (fieldType instanceof MapType && field instanceof MapData) { - MapData map = ((MapData) field); - Map formattedMap = new HashMap<>(map.size()); - Object[] keyArray = - (Object[]) formattedTimestamp(map.keyArray(), keyType, sessionTimeZone); - Object[] valueArray = - (Object[]) - formattedTimestamp( - map.valueArray(), valueType, sessionTimeZone); - for (int i = 0; i < keyArray.length; i++) { - formattedMap.put(keyArray[i], valueArray[i]); - } - return formattedMap; - } else { - return field; - } - default: - return field; - } - } - - /** - * Formats the print content of TIMESTAMP and TIMESTAMP_LTZ type data, consider the user - * configured time zone. - */ - private static Object formatTimestampField( - Object timestampField, LogicalType fieldType, ZoneId sessionTimeZone) { - switch (fieldType.getTypeRoot()) { - case TIMESTAMP_WITHOUT_TIME_ZONE: - final int precision = getPrecision(fieldType); - if (timestampField instanceof java.sql.Timestamp) { - // conversion between java.sql.Timestamp and TIMESTAMP_WITHOUT_TIME_ZONE - return timestampToString( - ((Timestamp) timestampField).toLocalDateTime(), precision); - } else if (timestampField instanceof java.time.LocalDateTime) { - return timestampToString(((LocalDateTime) timestampField), precision); - } else if (timestampField instanceof TimestampData) { - return timestampToString( - ((TimestampData) timestampField).toLocalDateTime(), precision); - } else { - return timestampField; - } - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - Instant instant = null; - if (timestampField instanceof java.time.Instant) { - instant = ((Instant) timestampField); - } else if (timestampField instanceof java.sql.Timestamp) { - Timestamp timestamp = ((Timestamp) timestampField); - // conversion between java.sql.Timestamp and TIMESTAMP_WITH_LOCAL_TIME_ZONE - instant = - TimestampData.fromEpochMillis( - timestamp.getTime(), timestamp.getNanos() % 1000_000) - .toInstant(); - } else if (timestampField instanceof TimestampData) { - instant = ((TimestampData) timestampField).toInstant(); - } else if (timestampField instanceof Integer) { - instant = Instant.ofEpochSecond((Integer) timestampField); - } else if (timestampField instanceof Long) { - instant = Instant.ofEpochMilli((Long) timestampField); - } - if (instant != null) { - return timestampToString( - instant.atZone(sessionTimeZone).toLocalDateTime(), - getPrecision(fieldType)); - } else { - return timestampField; - } - default: - return timestampField; - } - } - - /** Formats the print content of TIME type data. */ - private static Object formatTimeField(Object timeField) { - if (timeField.getClass().isAssignableFrom(int.class) || timeField instanceof Integer) { - return unixTimeToString((int) timeField); - } else if (timeField.getClass().isAssignableFrom(long.class) || timeField instanceof Long) { - return unixTimeToString(((Long) timeField).intValue()); - } else if (timeField instanceof Time) { - return unixTimeToString(timeToInternal((Time) timeField)); - } else if (timeField instanceof LocalTime) { - return unixTimeToString(localTimeToUnixDate((LocalTime) timeField)); - } else { - return timeField; - } - } -} diff --git a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java b/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java deleted file mode 100644 index c52104e45af..00000000000 --- a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - -import java.sql.Time; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.TimeZone; - -/** - * Copied from flink-project with minor modification. - * */ -public class TimestampStringUtils { - - private static final TimeZone LOCAL_TZ = TimeZone.getDefault(); - - public TimestampStringUtils() { - } - - public static String timestampToString(LocalDateTime ldt, int precision) { - String fraction; - for(fraction = pad(9, (long)ldt.getNano()); fraction.length() > precision && fraction.endsWith("0"); fraction = fraction.substring(0, fraction.length() - 1)) { - } - - StringBuilder ymdhms = ymdhms(new StringBuilder(), ldt.getYear(), ldt.getMonthValue(), ldt.getDayOfMonth(), ldt.getHour(), ldt.getMinute(), ldt.getSecond()); - if (fraction.length() > 0) { - ymdhms.append(".").append(fraction); - } - - return ymdhms.toString(); - } - - private static String pad(int length, long v) { - StringBuilder s = new StringBuilder(Long.toString(v)); - - while(s.length() < length) { - s.insert(0, "0"); - } - - return s.toString(); - } - - private static StringBuilder hms(StringBuilder b, int h, int m, int s) { - int2(b, h); - b.append(':'); - int2(b, m); - b.append(':'); - int2(b, s); - return b; - } - - private static StringBuilder ymdhms(StringBuilder b, int year, int month, int day, int h, int m, int s) { - ymd(b, year, month, day); - b.append(' '); - hms(b, h, m, s); - return b; - } - - private static StringBuilder ymd(StringBuilder b, int year, int month, int day) { - int4(b, year); - b.append('-'); - int2(b, month); - b.append('-'); - int2(b, day); - return b; - } - - private static void int4(StringBuilder buf, int i) { - buf.append((char)(48 + i / 1000 % 10)); - buf.append((char)(48 + i / 100 % 10)); - buf.append((char)(48 + i / 10 % 10)); - buf.append((char)(48 + i % 10)); - } - - private static void int2(StringBuilder buf, int i) { - buf.append((char)(48 + i / 10 % 10)); - buf.append((char)(48 + i % 10)); - } - - public static String unixTimeToString(int time) { - StringBuilder buf = new StringBuilder(8); - unixTimeToString(buf, time, 0); - return buf.toString(); - } - - private static void unixTimeToString(StringBuilder buf, int time, int precision) { - while(time < 0) { - time = (int)((long)time + 86400000L); - } - - int h = time / 3600000; - int time2 = time % 3600000; - int m = time2 / '\uea60'; - int time3 = time2 % '\uea60'; - int s = time3 / 1000; - int ms = time3 % 1000; - int2(buf, h); - buf.append(':'); - int2(buf, m); - buf.append(':'); - int2(buf, s); - if (precision > 0) { - buf.append('.'); - - while(precision > 0) { - buf.append((char)(48 + ms / 100)); - ms %= 100; - ms *= 10; - if (ms == 0) { - break; - } - - --precision; - } - } - - } - - public static int timeToInternal(Time time) { - long ts = time.getTime() + (long)LOCAL_TZ.getOffset(time.getTime()); - return (int)(ts % 86400000L); - } - - public static int localTimeToUnixDate(LocalTime time) { - return time.getHour() * 3600000 + time.getMinute() * '\uea60' + time.getSecond() * 1000 + time.getNano() / 1000000; - } -} diff --git a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/shims116/CollectStreamTableSink.java b/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/shims116/CollectStreamTableSink.java deleted file mode 100644 index cf7968e7e65..00000000000 --- a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/shims116/CollectStreamTableSink.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink.shims116; - -import org.apache.flink.api.common.typeinfo.TypeInformation; -import org.apache.flink.api.common.typeinfo.Types; -import org.apache.flink.api.common.typeutils.TypeSerializer; -import org.apache.flink.api.java.tuple.Tuple2; -import org.apache.flink.api.java.typeutils.TupleTypeInfo; -import org.apache.flink.streaming.api.datastream.DataStream; -import org.apache.flink.streaming.api.datastream.DataStreamSink; -import org.apache.flink.streaming.experimental.CollectSink; -import org.apache.flink.table.sinks.RetractStreamTableSink; -import org.apache.flink.types.Row; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.InetAddress; -import java.util.UUID; - -/** - * Table sink for collecting the results locally using sockets. - */ -public class CollectStreamTableSink implements RetractStreamTableSink { - - private static final Logger LOGGER = LoggerFactory.getLogger(CollectStreamTableSink.class); - - private final InetAddress targetAddress; - private final int targetPort; - private final TypeSerializer> serializer; - - private String[] fieldNames; - private TypeInformation[] fieldTypes; - - public CollectStreamTableSink(InetAddress targetAddress, - int targetPort, - TypeSerializer> serializer) { - LOGGER.info("Use address: " + targetAddress.getHostAddress() + ":" + targetPort); - this.targetAddress = targetAddress; - this.targetPort = targetPort; - this.serializer = serializer; - } - - @Override - public String[] getFieldNames() { - return fieldNames; - } - - @Override - public TypeInformation[] getFieldTypes() { - return fieldTypes; - } - - @Override - public CollectStreamTableSink configure(String[] fieldNames, TypeInformation[] fieldTypes) { - final CollectStreamTableSink copy = - new CollectStreamTableSink(targetAddress, targetPort, serializer); - copy.fieldNames = fieldNames; - copy.fieldTypes = fieldTypes; - return copy; - } - - @Override - public TypeInformation getRecordType() { - return Types.ROW_NAMED(fieldNames, fieldTypes); - } - - @Override - public DataStreamSink consumeDataStream(DataStream> stream) { - // add sink - return stream - .addSink(new CollectSink<>(targetAddress, targetPort, serializer)) - .name("Zeppelin Flink Sql Stream Collect Sink " + UUID.randomUUID()) - .setParallelism(1); - } - - @Override - public TupleTypeInfo> getOutputType() { - return new TupleTypeInfo<>(Types.BOOLEAN, getRecordType()); - } -} diff --git a/flink/flink1.17-shims/pom.xml b/flink/flink1.17-shims/pom.xml deleted file mode 100644 index 76523c9c8b3..00000000000 --- a/flink/flink1.17-shims/pom.xml +++ /dev/null @@ -1,207 +0,0 @@ - - - - - - flink-parent - org.apache.zeppelin - 0.13.0-SNAPSHOT - ../pom.xml - - - 4.0.0 - org.apache.zeppelin - flink1.17-shims - 0.13.0-SNAPSHOT - jar - Zeppelin: Flink1.17 Shims - - - ${flink1.17.version} - 2.12 - - - - - - org.apache.zeppelin - flink-shims - ${project.version} - - - - org.apache.flink - flink-core - ${flink.version} - provided - - - - org.apache.flink - flink-clients - ${flink.version} - provided - - - - org.apache.flink - flink-runtime - ${flink.version} - provided - - - - org.apache.flink - flink-table-api-scala_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-table-api-scala-bridge_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-table-api-java-bridge - ${flink.version} - provided - - - - org.apache.flink - flink-scala_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-streaming-java - ${flink.version} - provided - - - - org.apache.flink - flink-streaming-scala_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-java - ${flink.version} - provided - - - - org.apache.flink - flink-table-planner_${flink.scala.binary.version} - ${flink.version} - provided - - - - org.apache.flink - flink-python - ${flink.version} - provided - - - - org.apache.flink - flink-sql-client - ${flink.version} - provided - - - - - - - - - net.alchim31.maven - scala-maven-plugin - - - eclipse-add-source - - add-source - - - - scala-compile-first - process-resources - - compile - - - - scala-test-compile-first - process-test-resources - - testCompile - - - - - ${flink.scala.version} - - -unchecked - -deprecation - -feature - -nobootcp - - - -Xms1024m - -Xmx1024m - -XX:MaxMetaspaceSize=${MaxMetaspace} - - - -source - ${java.version} - -target - ${java.version} - -Xlint:all,-serial,-path,-options - - - - - - maven-resources-plugin - - - copy-interpreter-setting - none - - true - - - - - - - - diff --git a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/Flink117Shims.java b/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/Flink117Shims.java deleted file mode 100644 index 9bc22cc57df..00000000000 --- a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/Flink117Shims.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.compress.utils.Lists; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.flink.api.common.RuntimeExecutionMode; -import org.apache.flink.api.common.typeutils.TypeSerializer; -import org.apache.flink.api.java.tuple.Tuple2; -import org.apache.flink.client.cli.CliFrontend; -import org.apache.flink.client.cli.CustomCommandLine; -import org.apache.flink.configuration.Configuration; -import org.apache.flink.configuration.ExecutionOptions; -import org.apache.flink.configuration.ReadableConfig; -import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; -import org.apache.flink.streaming.api.environment.StreamExecutionEnvironmentFactory; -import org.apache.flink.table.api.*; -import org.apache.flink.table.api.bridge.java.internal.StreamTableEnvironmentImpl; -import org.apache.flink.table.api.config.TableConfigOptions; -import org.apache.flink.table.catalog.CatalogManager; -import org.apache.flink.table.catalog.FunctionCatalog; -import org.apache.flink.table.catalog.GenericInMemoryCatalog; -import org.apache.flink.table.catalog.ResolvedSchema; -import org.apache.flink.table.client.resource.ClientResourceManager; -import org.apache.flink.table.client.util.ClientClassloaderUtil; -import org.apache.flink.table.client.util.ClientWrapperClassLoader; -import org.apache.flink.table.delegation.Executor; -import org.apache.flink.table.delegation.ExecutorFactory; -import org.apache.flink.table.delegation.Planner; -import org.apache.flink.table.factories.FactoryUtil; -import org.apache.flink.table.factories.PlannerFactoryUtil; -import org.apache.flink.table.functions.AggregateFunction; -import org.apache.flink.table.functions.ScalarFunction; -import org.apache.flink.table.functions.TableAggregateFunction; -import org.apache.flink.table.functions.TableFunction; -import org.apache.flink.table.module.ModuleManager; -import org.apache.flink.table.resource.ResourceManager; -import org.apache.flink.table.sinks.TableSink; -import org.apache.flink.table.typeutils.TimeIndicatorTypeInfo; -import org.apache.flink.types.Row; -import org.apache.flink.types.RowKind; -import org.apache.flink.util.FlinkException; -import org.apache.zeppelin.flink.shims117.CollectStreamTableSink; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.URL; -import java.time.ZoneId; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - - -/** - * Shims for flink 1.17 - */ -public class Flink117Shims extends FlinkShims { - - private static final Logger LOGGER = LoggerFactory.getLogger(Flink117Shims.class); - - private Flink117SqlInterpreter batchSqlInterpreter; - private Flink117SqlInterpreter streamSqlInterpreter; - - public Flink117Shims(FlinkVersion flinkVersion, Properties properties) { - super(flinkVersion, properties); - } - - public void initInnerBatchSqlInterpreter(FlinkSqlContext flinkSqlContext) { - this.batchSqlInterpreter = new Flink117SqlInterpreter(flinkSqlContext, true); - } - - public void initInnerStreamSqlInterpreter(FlinkSqlContext flinkSqlContext) { - this.streamSqlInterpreter = new Flink117SqlInterpreter(flinkSqlContext, false); - } - - @Override - public Object createResourceManager(List jars, Object tableConfig) { - Configuration configuration = ((TableConfig) tableConfig).getConfiguration().clone(); - ClientWrapperClassLoader userClassLoader = - new ClientWrapperClassLoader( - ClientClassloaderUtil.buildUserClassLoader( - jars, - Thread.currentThread().getContextClassLoader(), - new Configuration(configuration)), - configuration); - return new ClientResourceManager(configuration, userClassLoader); - } - - @Override - public Object createFunctionCatalog(Object tableConfig, Object catalogManager, Object moduleManager, List jars) { - ResourceManager resourceManager = (ResourceManager) createResourceManager(jars, (TableConfig) tableConfig); - return new FunctionCatalog((TableConfig) tableConfig, resourceManager, (CatalogManager) catalogManager, (ModuleManager) moduleManager); - } - - @Override - public void disableSysoutLogging(Object batchConfig, Object streamConfig) { - // do nothing - } - - @Override - public Object createScalaBlinkStreamTableEnvironment(Object environmentSettingsObj, - Object senvObj, - Object tableConfigObj, - Object moduleManagerObj, - Object functionCatalogObj, - Object catalogManagerObj, - List jars, - ClassLoader classLoader) { - EnvironmentSettings environmentSettings = (EnvironmentSettings) environmentSettingsObj; - StreamExecutionEnvironment senv = (StreamExecutionEnvironment) senvObj; - TableConfig tableConfig = (TableConfig) tableConfigObj; - ModuleManager moduleManager = (ModuleManager) moduleManagerObj; - FunctionCatalog functionCatalog = (FunctionCatalog) functionCatalogObj; - CatalogManager catalogManager = (CatalogManager) catalogManagerObj; - ImmutablePair pair = createPlannerAndExecutor( - classLoader, environmentSettings, senv, - tableConfig, moduleManager, functionCatalog, catalogManager); - Planner planner = (Planner) pair.left; - Executor executor = (Executor) pair.right; - - ResourceManager resourceManager = (ResourceManager) createResourceManager(jars, tableConfig); - - return new org.apache.flink.table.api.bridge.scala.internal.StreamTableEnvironmentImpl(catalogManager, - moduleManager, resourceManager, - functionCatalog, tableConfig, new org.apache.flink.streaming.api.scala.StreamExecutionEnvironment(senv), - planner, executor, environmentSettings.isStreamingMode()); - } - - @Override - public Object createJavaBlinkStreamTableEnvironment(Object environmentSettingsObj, - Object senvObj, - Object tableConfigObj, - Object moduleManagerObj, - Object functionCatalogObj, - Object catalogManagerObj, - List jars, - ClassLoader classLoader) { - EnvironmentSettings environmentSettings = (EnvironmentSettings) environmentSettingsObj; - StreamExecutionEnvironment senv = (StreamExecutionEnvironment) senvObj; - TableConfig tableConfig = (TableConfig) tableConfigObj; - ModuleManager moduleManager = (ModuleManager) moduleManagerObj; - FunctionCatalog functionCatalog = (FunctionCatalog) functionCatalogObj; - CatalogManager catalogManager = (CatalogManager) catalogManagerObj; - ImmutablePair pair = createPlannerAndExecutor( - classLoader, environmentSettings, senv, - tableConfig, moduleManager, functionCatalog, catalogManager); - Planner planner = (Planner) pair.left; - Executor executor = (Executor) pair.right; - - ResourceManager resourceManager = (ResourceManager) createResourceManager(jars, tableConfig); - - return new StreamTableEnvironmentImpl(catalogManager, moduleManager, resourceManager, - functionCatalog, tableConfig, senv, planner, executor, environmentSettings.isStreamingMode()); - } - - @Override - public Object createStreamExecutionEnvironmentFactory(Object streamExecutionEnvironment) { - return new StreamExecutionEnvironmentFactory() { - @Override - public StreamExecutionEnvironment createExecutionEnvironment(Configuration configuration) { - return (StreamExecutionEnvironment) streamExecutionEnvironment; - } - }; - } - - @Override - public Object createCatalogManager(Object config) { - return CatalogManager.newBuilder() - .classLoader(Thread.currentThread().getContextClassLoader()) - .config((ReadableConfig) config) - .defaultCatalog("default_catalog", - new GenericInMemoryCatalog("default_catalog", "default_database")) - .build(); - } - - @Override - public String getPyFlinkPythonPath(Properties properties) throws IOException { - String mode = properties.getProperty("flink.execution.mode"); - if ("yarn-application".equalsIgnoreCase(mode)) { - // for yarn application mode, FLINK_HOME is container working directory - String flinkHome = new File(".").getAbsolutePath(); - return getPyFlinkPythonPath(new File(flinkHome + "/lib/python")); - } - - String flinkHome = System.getenv("FLINK_HOME"); - if (StringUtils.isNotBlank(flinkHome)) { - return getPyFlinkPythonPath(new File(flinkHome + "/opt/python")); - } else { - throw new IOException("No FLINK_HOME is specified"); - } - } - - private String getPyFlinkPythonPath(File pyFlinkFolder) throws IOException { - LOGGER.info("Getting pyflink lib from {}", pyFlinkFolder); - if (!pyFlinkFolder.exists() || !pyFlinkFolder.isDirectory()) { - throw new IOException(String.format("PyFlink folder %s does not exist or is not a folder", - pyFlinkFolder.getAbsolutePath())); - } - List depFiles = Arrays.asList(pyFlinkFolder.listFiles()); - StringBuilder builder = new StringBuilder(); - for (File file : depFiles) { - LOGGER.info("Adding extracted file {} to PYTHONPATH", file.getAbsolutePath()); - builder.append(file.getAbsolutePath() + ":"); - } - return builder.toString(); - } - - @Override - public Object getCollectStreamTableSink(InetAddress targetAddress, int targetPort, Object serializer) { - return new CollectStreamTableSink(targetAddress, targetPort, (TypeSerializer>) serializer); - } - - @Override - public List collectToList(Object table) throws Exception { - return Lists.newArrayList(((Table) table).execute().collect()); - } - - @Override - public boolean rowEquals(Object row1, Object row2) { - Row r1 = (Row) row1; - Row r2 = (Row) row2; - r1.setKind(RowKind.INSERT); - r2.setKind(RowKind.INSERT); - return r1.equals(r2); - } - - @Override - public Object fromDataSet(Object btenv, Object ds) { - throw new RuntimeException("Conversion from DataSet is not supported in Flink 1.17"); - } - - @Override - public Object toDataSet(Object btenv, Object table) { - throw new RuntimeException("Conversion to DataSet is not supported in Flink 1.17"); - } - - @Override - public void registerTableSink(Object stenv, String tableName, Object collectTableSink) { - ((org.apache.flink.table.api.internal.TableEnvironmentInternal) stenv) - .registerTableSinkInternal(tableName, (TableSink) collectTableSink); - } - - @Override - public void registerScalarFunction(Object btenv, String name, Object scalarFunction) { - ((StreamTableEnvironmentImpl) (btenv)).createTemporarySystemFunction(name, (ScalarFunction) scalarFunction); - } - - @Override - public void registerTableFunction(Object btenv, String name, Object tableFunction) { - ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (TableFunction) tableFunction); - } - - @Override - public void registerAggregateFunction(Object btenv, String name, Object aggregateFunction) { - ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (AggregateFunction) aggregateFunction); - } - - @Override - public void registerTableAggregateFunction(Object btenv, String name, Object tableAggregateFunction) { - ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (TableAggregateFunction) tableAggregateFunction); - } - - /** - * Flink 1.11 bind CatalogManager with parser which make blink and flink could not share the same CatalogManager. - * This is a workaround which always reset CatalogTableSchemaResolver before running any flink code. - * - * @param catalogManager - * @param parserObject - * @param environmentSetting - */ - @Override - public void setCatalogManagerSchemaResolver(Object catalogManager, - Object parserObject, - Object environmentSetting) { - - } - - @Override - public Object updateEffectiveConfig(Object cliFrontend, Object commandLine, Object effectiveConfig) { - CustomCommandLine customCommandLine = ((CliFrontend) cliFrontend).validateAndGetActiveCommandLine((CommandLine) commandLine); - try { - ((Configuration) effectiveConfig).addAll(customCommandLine.toConfiguration((CommandLine) commandLine)); - return effectiveConfig; - } catch (FlinkException e) { - throw new RuntimeException("Fail to call addAll", e); - } - } - - @Override - public void setBatchRuntimeMode(Object tableConfig) { - ((TableConfig) tableConfig).getConfiguration() - .set(ExecutionOptions.RUNTIME_MODE, RuntimeExecutionMode.BATCH); - } - - @Override - public void setOldPlanner(Object tableConfig) { - - } - - @Override - public String[] rowToString(Object row, Object table, Object tableConfig) { - final String zone = ((TableConfig) tableConfig).getConfiguration() - .get(TableConfigOptions.LOCAL_TIME_ZONE); - ZoneId zoneId = TableConfigOptions.LOCAL_TIME_ZONE.defaultValue().equals(zone) - ? ZoneId.systemDefault() - : ZoneId.of(zone); - - ResolvedSchema resolvedSchema = ((Table) table).getResolvedSchema(); - return PrintUtils.rowToString((Row) row, resolvedSchema, zoneId); - } - - @Override - public boolean isTimeIndicatorType(Object type) { - if (type instanceof TimeIndicatorTypeInfo) { - return true; - } else { - return false; - } - } - - private Object lookupExecutor(ClassLoader classLoader, - Object settings, - Object sEnv) { - try { - final ExecutorFactory executorFactory = - FactoryUtil.discoverFactory( - classLoader, ExecutorFactory.class, ExecutorFactory.DEFAULT_IDENTIFIER); - final Method createMethod = - executorFactory - .getClass() - .getMethod("create", StreamExecutionEnvironment.class); - - return createMethod.invoke(executorFactory, sEnv); - } catch (Exception e) { - throw new TableException( - "Could not instantiate the executor. Make sure a planner module is on the classpath", - e); - } - } - - @Override - public ImmutablePair createPlannerAndExecutor( - ClassLoader classLoader, Object environmentSettings, Object sEnv, - Object tableConfig, Object moduleManager, Object functionCatalog, Object catalogManager) { - EnvironmentSettings settings = (EnvironmentSettings) environmentSettings; - Executor executor = (Executor) lookupExecutor(classLoader, environmentSettings, sEnv); - Planner planner = PlannerFactoryUtil.createPlanner(executor, - (TableConfig) tableConfig, - Thread.currentThread().getContextClassLoader(), - (ModuleManager) moduleManager, - (CatalogManager) catalogManager, - (FunctionCatalog) functionCatalog); - return ImmutablePair.of(planner, executor); - } - - @Override - public Object createBlinkPlannerEnvSettingBuilder() { - return EnvironmentSettings.newInstance(); - } - - @Override - public Object createOldPlannerEnvSettingBuilder() { - return EnvironmentSettings.newInstance(); - } - - public InterpreterResult runSqlList(String st, InterpreterContext context, boolean isBatch) { - if (isBatch) { - return batchSqlInterpreter.runSqlList(st, context); - } else { - return streamSqlInterpreter.runSqlList(st, context); - } - } -} diff --git a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java b/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java deleted file mode 100644 index a35ad3a6cd1..00000000000 --- a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - - -import org.apache.flink.table.catalog.ResolvedSchema; -import org.apache.flink.table.data.MapData; -import org.apache.flink.table.data.RowData; -import org.apache.flink.table.data.TimestampData; -import org.apache.flink.table.types.logical.*; -import org.apache.flink.types.Row; -import org.apache.flink.util.StringUtils; - -import java.sql.Time; -import java.sql.Timestamp; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.apache.flink.table.types.logical.utils.LogicalTypeChecks.getPrecision; -import static org.apache.zeppelin.flink.TimestampStringUtils.*; - -/** - * Copied from flink-project with minor modification. - * */ -public class PrintUtils { - - public static final String NULL_COLUMN = "(NULL)"; - private static final String COLUMN_TRUNCATED_FLAG = "..."; - - private PrintUtils() {} - - - public static String[] rowToString( - Row row, ResolvedSchema resolvedSchema, ZoneId sessionTimeZone) { - return rowToString(row, NULL_COLUMN, false, resolvedSchema, sessionTimeZone); - } - - public static String[] rowToString( - Row row, - String nullColumn, - boolean printRowKind, - ResolvedSchema resolvedSchema, - ZoneId sessionTimeZone) { - final int len = printRowKind ? row.getArity() + 1 : row.getArity(); - final List fields = new ArrayList<>(len); - if (printRowKind) { - fields.add(row.getKind().shortString()); - } - for (int i = 0; i < row.getArity(); i++) { - final Object field = row.getField(i); - final LogicalType fieldType = - resolvedSchema.getColumnDataTypes().get(i).getLogicalType(); - if (field == null) { - fields.add(nullColumn); - } else { - fields.add( - StringUtils.arrayAwareToString( - formattedTimestamp(field, fieldType, sessionTimeZone))); - } - } - return fields.toArray(new String[0]); - } - - /** - * Normalizes field that contains TIMESTAMP, TIMESTAMP_LTZ and TIME type data. - * - *

This method also supports nested type ARRAY, ROW, MAP. - */ - private static Object formattedTimestamp( - Object field, LogicalType fieldType, ZoneId sessionTimeZone) { - final LogicalTypeRoot typeRoot = fieldType.getTypeRoot(); - if (field == null) { - return "null"; - } - switch (typeRoot) { - case TIMESTAMP_WITHOUT_TIME_ZONE: - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - return formatTimestampField(field, fieldType, sessionTimeZone); - case TIME_WITHOUT_TIME_ZONE: - return formatTimeField(field); - case ARRAY: - LogicalType elementType = ((ArrayType) fieldType).getElementType(); - if (field instanceof List) { - List array = (List) field; - Object[] formattedArray = new Object[array.size()]; - for (int i = 0; i < array.size(); i++) { - formattedArray[i] = - formattedTimestamp(array.get(i), elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass().isArray()) { - // primitive type - if (field.getClass() == byte[].class) { - byte[] array = (byte[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == short[].class) { - short[] array = (short[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == int[].class) { - int[] array = (int[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == long[].class) { - long[] array = (long[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == float[].class) { - float[] array = (float[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == double[].class) { - double[] array = (double[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == boolean[].class) { - boolean[] array = (boolean[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else if (field.getClass() == char[].class) { - char[] array = (char[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } else { - // non-primitive type - Object[] array = (Object[]) field; - Object[] formattedArray = new Object[array.length]; - for (int i = 0; i < array.length; i++) { - formattedArray[i] = - formattedTimestamp(array[i], elementType, sessionTimeZone); - } - return formattedArray; - } - } else { - return field; - } - case ROW: - if (fieldType instanceof RowType && field instanceof Row) { - Row row = (Row) field; - Row formattedRow = new Row(row.getKind(), row.getArity()); - for (int i = 0; i < ((RowType) fieldType).getFields().size(); i++) { - LogicalType type = ((RowType) fieldType).getFields().get(i).getType(); - formattedRow.setField( - i, formattedTimestamp(row.getField(i), type, sessionTimeZone)); - } - return formattedRow; - - } else if (fieldType instanceof RowType && field instanceof RowData) { - RowData rowData = (RowData) field; - Row formattedRow = new Row(rowData.getRowKind(), rowData.getArity()); - for (int i = 0; i < ((RowType) fieldType).getFields().size(); i++) { - LogicalType type = ((RowType) fieldType).getFields().get(i).getType(); - RowData.FieldGetter fieldGetter = RowData.createFieldGetter(type, i); - formattedRow.setField( - i, - formattedTimestamp( - fieldGetter.getFieldOrNull(rowData), - type, - sessionTimeZone)); - } - return formattedRow; - } else { - return field; - } - case MAP: - LogicalType keyType = ((MapType) fieldType).getKeyType(); - LogicalType valueType = ((MapType) fieldType).getValueType(); - if (fieldType instanceof MapType && field instanceof Map) { - Map map = ((Map) field); - Map formattedMap = new HashMap<>(map.size()); - for (Object key : map.keySet()) { - formattedMap.put( - formattedTimestamp(key, keyType, sessionTimeZone), - formattedTimestamp(map.get(key), valueType, sessionTimeZone)); - } - return formattedMap; - } else if (fieldType instanceof MapType && field instanceof MapData) { - MapData map = ((MapData) field); - Map formattedMap = new HashMap<>(map.size()); - Object[] keyArray = - (Object[]) formattedTimestamp(map.keyArray(), keyType, sessionTimeZone); - Object[] valueArray = - (Object[]) - formattedTimestamp( - map.valueArray(), valueType, sessionTimeZone); - for (int i = 0; i < keyArray.length; i++) { - formattedMap.put(keyArray[i], valueArray[i]); - } - return formattedMap; - } else { - return field; - } - default: - return field; - } - } - - /** - * Formats the print content of TIMESTAMP and TIMESTAMP_LTZ type data, consider the user - * configured time zone. - */ - private static Object formatTimestampField( - Object timestampField, LogicalType fieldType, ZoneId sessionTimeZone) { - switch (fieldType.getTypeRoot()) { - case TIMESTAMP_WITHOUT_TIME_ZONE: - final int precision = getPrecision(fieldType); - if (timestampField instanceof java.sql.Timestamp) { - // conversion between java.sql.Timestamp and TIMESTAMP_WITHOUT_TIME_ZONE - return timestampToString( - ((Timestamp) timestampField).toLocalDateTime(), precision); - } else if (timestampField instanceof java.time.LocalDateTime) { - return timestampToString(((LocalDateTime) timestampField), precision); - } else if (timestampField instanceof TimestampData) { - return timestampToString( - ((TimestampData) timestampField).toLocalDateTime(), precision); - } else { - return timestampField; - } - case TIMESTAMP_WITH_LOCAL_TIME_ZONE: - Instant instant = null; - if (timestampField instanceof java.time.Instant) { - instant = ((Instant) timestampField); - } else if (timestampField instanceof java.sql.Timestamp) { - Timestamp timestamp = ((Timestamp) timestampField); - // conversion between java.sql.Timestamp and TIMESTAMP_WITH_LOCAL_TIME_ZONE - instant = - TimestampData.fromEpochMillis( - timestamp.getTime(), timestamp.getNanos() % 1000_000) - .toInstant(); - } else if (timestampField instanceof TimestampData) { - instant = ((TimestampData) timestampField).toInstant(); - } else if (timestampField instanceof Integer) { - instant = Instant.ofEpochSecond((Integer) timestampField); - } else if (timestampField instanceof Long) { - instant = Instant.ofEpochMilli((Long) timestampField); - } - if (instant != null) { - return timestampToString( - instant.atZone(sessionTimeZone).toLocalDateTime(), - getPrecision(fieldType)); - } else { - return timestampField; - } - default: - return timestampField; - } - } - - /** Formats the print content of TIME type data. */ - private static Object formatTimeField(Object timeField) { - if (timeField.getClass().isAssignableFrom(int.class) || timeField instanceof Integer) { - return unixTimeToString((int) timeField); - } else if (timeField.getClass().isAssignableFrom(long.class) || timeField instanceof Long) { - return unixTimeToString(((Long) timeField).intValue()); - } else if (timeField instanceof Time) { - return unixTimeToString(timeToInternal((Time) timeField)); - } else if (timeField instanceof LocalTime) { - return unixTimeToString(localTimeToUnixDate((LocalTime) timeField)); - } else { - return timeField; - } - } -} diff --git a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java b/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java deleted file mode 100644 index c52104e45af..00000000000 --- a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.flink; - -import java.sql.Time; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.util.TimeZone; - -/** - * Copied from flink-project with minor modification. - * */ -public class TimestampStringUtils { - - private static final TimeZone LOCAL_TZ = TimeZone.getDefault(); - - public TimestampStringUtils() { - } - - public static String timestampToString(LocalDateTime ldt, int precision) { - String fraction; - for(fraction = pad(9, (long)ldt.getNano()); fraction.length() > precision && fraction.endsWith("0"); fraction = fraction.substring(0, fraction.length() - 1)) { - } - - StringBuilder ymdhms = ymdhms(new StringBuilder(), ldt.getYear(), ldt.getMonthValue(), ldt.getDayOfMonth(), ldt.getHour(), ldt.getMinute(), ldt.getSecond()); - if (fraction.length() > 0) { - ymdhms.append(".").append(fraction); - } - - return ymdhms.toString(); - } - - private static String pad(int length, long v) { - StringBuilder s = new StringBuilder(Long.toString(v)); - - while(s.length() < length) { - s.insert(0, "0"); - } - - return s.toString(); - } - - private static StringBuilder hms(StringBuilder b, int h, int m, int s) { - int2(b, h); - b.append(':'); - int2(b, m); - b.append(':'); - int2(b, s); - return b; - } - - private static StringBuilder ymdhms(StringBuilder b, int year, int month, int day, int h, int m, int s) { - ymd(b, year, month, day); - b.append(' '); - hms(b, h, m, s); - return b; - } - - private static StringBuilder ymd(StringBuilder b, int year, int month, int day) { - int4(b, year); - b.append('-'); - int2(b, month); - b.append('-'); - int2(b, day); - return b; - } - - private static void int4(StringBuilder buf, int i) { - buf.append((char)(48 + i / 1000 % 10)); - buf.append((char)(48 + i / 100 % 10)); - buf.append((char)(48 + i / 10 % 10)); - buf.append((char)(48 + i % 10)); - } - - private static void int2(StringBuilder buf, int i) { - buf.append((char)(48 + i / 10 % 10)); - buf.append((char)(48 + i % 10)); - } - - public static String unixTimeToString(int time) { - StringBuilder buf = new StringBuilder(8); - unixTimeToString(buf, time, 0); - return buf.toString(); - } - - private static void unixTimeToString(StringBuilder buf, int time, int precision) { - while(time < 0) { - time = (int)((long)time + 86400000L); - } - - int h = time / 3600000; - int time2 = time % 3600000; - int m = time2 / '\uea60'; - int time3 = time2 % '\uea60'; - int s = time3 / 1000; - int ms = time3 % 1000; - int2(buf, h); - buf.append(':'); - int2(buf, m); - buf.append(':'); - int2(buf, s); - if (precision > 0) { - buf.append('.'); - - while(precision > 0) { - buf.append((char)(48 + ms / 100)); - ms %= 100; - ms *= 10; - if (ms == 0) { - break; - } - - --precision; - } - } - - } - - public static int timeToInternal(Time time) { - long ts = time.getTime() + (long)LOCAL_TZ.getOffset(time.getTime()); - return (int)(ts % 86400000L); - } - - public static int localTimeToUnixDate(LocalTime time) { - return time.getHour() * 3600000 + time.getMinute() * '\uea60' + time.getSecond() * 1000 + time.getNano() / 1000000; - } -} diff --git a/flink/flink1.16-shims/pom.xml b/flink/flink1.20-shims/pom.xml similarity index 98% rename from flink/flink1.16-shims/pom.xml rename to flink/flink1.20-shims/pom.xml index ddac426ab47..b0a91e3e04d 100644 --- a/flink/flink1.16-shims/pom.xml +++ b/flink/flink1.20-shims/pom.xml @@ -26,12 +26,12 @@ 4.0.0 - flink1.16-shims + flink1.20-shims jar - Zeppelin: Flink1.16 Shims + Zeppelin: Flink1.20 Shims - ${flink1.16.version} + ${flink1.20.version} 2.12 diff --git a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/Flink116Shims.java b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/Flink120Shims.java similarity index 92% rename from flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/Flink116Shims.java rename to flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/Flink120Shims.java index 3578ffc8bb0..8a308b8b966 100644 --- a/flink/flink1.16-shims/src/main/java/org/apache/zeppelin/flink/Flink116Shims.java +++ b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/Flink120Shims.java @@ -36,8 +36,10 @@ import org.apache.flink.table.api.bridge.java.internal.StreamTableEnvironmentImpl; import org.apache.flink.table.api.config.TableConfigOptions; import org.apache.flink.table.catalog.CatalogManager; +import org.apache.flink.table.catalog.CatalogStoreHolder; import org.apache.flink.table.catalog.FunctionCatalog; import org.apache.flink.table.catalog.GenericInMemoryCatalog; +import org.apache.flink.table.catalog.GenericInMemoryCatalogStore; import org.apache.flink.table.catalog.ResolvedSchema; import org.apache.flink.table.client.resource.ClientResourceManager; import org.apache.flink.table.client.util.ClientClassloaderUtil; @@ -58,7 +60,7 @@ import org.apache.flink.types.Row; import org.apache.flink.types.RowKind; import org.apache.flink.util.FlinkException; -import org.apache.zeppelin.flink.shims116.CollectStreamTableSink; +import org.apache.zeppelin.flink.shims120.CollectStreamTableSink; import org.apache.zeppelin.interpreter.InterpreterContext; import org.apache.zeppelin.interpreter.InterpreterResult; import org.slf4j.Logger; @@ -76,25 +78,25 @@ /** - * Shims for flink 1.16 + * Shims for Flink 1.19/1.20 (1.x series, last LTS) */ -public class Flink116Shims extends FlinkShims { +public class Flink120Shims extends FlinkShims { - private static final Logger LOGGER = LoggerFactory.getLogger(Flink116Shims.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Flink120Shims.class); - private Flink116SqlInterpreter batchSqlInterpreter; - private Flink116SqlInterpreter streamSqlInterpreter; + private Flink120SqlInterpreter batchSqlInterpreter; + private Flink120SqlInterpreter streamSqlInterpreter; - public Flink116Shims(FlinkVersion flinkVersion, Properties properties) { + public Flink120Shims(FlinkVersion flinkVersion, Properties properties) { super(flinkVersion, properties); } public void initInnerBatchSqlInterpreter(FlinkSqlContext flinkSqlContext) { - this.batchSqlInterpreter = new Flink116SqlInterpreter(flinkSqlContext, true); + this.batchSqlInterpreter = new Flink120SqlInterpreter(flinkSqlContext, true); } public void initInnerStreamSqlInterpreter(FlinkSqlContext flinkSqlContext) { - this.streamSqlInterpreter = new Flink116SqlInterpreter(flinkSqlContext, false); + this.streamSqlInterpreter = new Flink120SqlInterpreter(flinkSqlContext, false); } @Override @@ -189,11 +191,21 @@ public StreamExecutionEnvironment createExecutionEnvironment(Configuration confi @Override public Object createCatalogManager(Object config) { + ReadableConfig readableConfig = (ReadableConfig) config; + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + + CatalogStoreHolder catalogStoreHolder = CatalogStoreHolder.newBuilder() + .catalogStore(new GenericInMemoryCatalogStore()) + .config(readableConfig) + .classloader(classLoader) + .build(); + return CatalogManager.newBuilder() - .classLoader(Thread.currentThread().getContextClassLoader()) - .config((ReadableConfig) config) + .classLoader(classLoader) + .config(readableConfig) .defaultCatalog("default_catalog", new GenericInMemoryCatalog("default_catalog", "default_database")) + .catalogStoreHolder(catalogStoreHolder) .build(); } @@ -248,16 +260,6 @@ public boolean rowEquals(Object row1, Object row2) { return r1.equals(r2); } - @Override - public Object fromDataSet(Object btenv, Object ds) { - throw new RuntimeException("Conversion from DataSet is not supported in Flink 1.15"); - } - - @Override - public Object toDataSet(Object btenv, Object table) { - throw new RuntimeException("Conversion to DataSet is not supported in Flink 1.15"); - } - @Override public void registerTableSink(Object stenv, String tableName, Object collectTableSink) { ((org.apache.flink.table.api.internal.TableEnvironmentInternal) stenv) @@ -284,14 +286,6 @@ public void registerTableAggregateFunction(Object btenv, String name, Object tab ((StreamTableEnvironmentImpl) (btenv)).registerFunction(name, (TableAggregateFunction) tableAggregateFunction); } - /** - * Flink 1.11 bind CatalogManager with parser which make blink and flink could not share the same CatalogManager. - * This is a workaround which always reset CatalogTableSchemaResolver before running any flink code. - * - * @param catalogManager - * @param parserObject - * @param environmentSetting - */ @Override public void setCatalogManagerSchemaResolver(Object catalogManager, Object parserObject, diff --git a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/Flink117SqlInterpreter.java b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/Flink120SqlInterpreter.java similarity index 97% rename from flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/Flink117SqlInterpreter.java rename to flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/Flink120SqlInterpreter.java index b53d02c8e62..c9bdefb7928 100644 --- a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/Flink117SqlInterpreter.java +++ b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/Flink120SqlInterpreter.java @@ -63,9 +63,9 @@ import static org.apache.flink.util.Preconditions.checkState; -public class Flink117SqlInterpreter { +public class Flink120SqlInterpreter { - private static final Logger LOGGER = LoggerFactory.getLogger(Flink117SqlInterpreter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Flink120SqlInterpreter.class); private static final String CMD_DESC_DELIMITER = "\t\t"; /** @@ -142,7 +142,6 @@ public AttributedString build() { "BEGIN STATEMENT SET", "Begins a statement set. Syntax: \"BEGIN STATEMENT SET;\"") .commandDescription("END", "Ends a statement set. Syntax: \"END;\"") - // (TODO) zjffdu, ADD/REMOVE/SHOW JAR .build(); // -------------------------------------------------------------------------------------------- @@ -169,17 +168,12 @@ public AttributedString build() { private ZeppelinContext z; private Parser sqlParser; private SqlSplitter sqlSplitter; - // paragraphId -> list of ModifyOperation, used for statement set in 2 syntax: - // 1. runAsOne= true - // 2. begin statement set; - // ... - // end; private Map> statementOperationsMap = new HashMap<>(); private boolean isBatch; private ReentrantReadWriteLock.WriteLock lock = new ReentrantReadWriteLock().writeLock(); - public Flink117SqlInterpreter(FlinkSqlContext flinkSqlContext, boolean isBatch) { + public Flink120SqlInterpreter(FlinkSqlContext flinkSqlContext, boolean isBatch) { this.flinkSqlContext = flinkSqlContext; this.isBatch = isBatch; if (isBatch) { @@ -277,28 +271,20 @@ public InterpreterResult runSqlList(String st, InterpreterContext context) { private void callOperation(String sql, Operation operation, InterpreterContext context) throws IOException { if (operation instanceof HelpOperation) { - // HELP callHelp(context); } else if (operation instanceof SetOperation) { - // SET callSet((SetOperation) operation, context); } else if (operation instanceof ModifyOperation) { - // INSERT INTO/OVERWRITE callInsert((ModifyOperation) operation, context); } else if (operation instanceof QueryOperation) { - // SELECT callSelect(sql, (QueryOperation) operation, context); } else if (operation instanceof ExplainOperation) { - // EXPLAIN callExplain((ExplainOperation) operation, context); } else if (operation instanceof BeginStatementSetOperation) { - // BEGIN STATEMENT SET callBeginStatementSet(context); } else if (operation instanceof EndStatementSetOperation) { - // END callEndStatementSet(context); } else if (operation instanceof ShowCreateTableOperation) { - // SHOW CREATE TABLE callShowCreateTable((ShowCreateTableOperation) operation, context); } else if (operation instanceof ShowCatalogsOperation) { callShowCatalogs(context); @@ -448,13 +434,11 @@ public void callStreamInnerSelect(String sql, InterpreterContext context) throws public void callSet(SetOperation setOperation, InterpreterContext context) throws IOException { if (setOperation.getKey().isPresent() && setOperation.getValue().isPresent()) { - // set a property String key = setOperation.getKey().get().trim(); String value = setOperation.getValue().get().trim(); this.tbenv.getConfig().getConfiguration().setString(key, value); LOGGER.info("Set table config: {}={}", key, value); } else { - // show all properties final Map properties = this.tbenv.getConfig().getConfiguration().toMap(); List prettyEntries = new ArrayList<>(); for (String key : properties.keySet()) { diff --git a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java similarity index 100% rename from flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java rename to flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/PrintUtils.java diff --git a/flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java similarity index 100% rename from flink/flink1.15-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java rename to flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/TimestampStringUtils.java diff --git a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/shims117/CollectStreamTableSink.java b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/shims120/CollectStreamTableSink.java similarity index 98% rename from flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/shims117/CollectStreamTableSink.java rename to flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/shims120/CollectStreamTableSink.java index ee58e770d44..cc7683c731f 100644 --- a/flink/flink1.17-shims/src/main/java/org/apache/zeppelin/flink/shims117/CollectStreamTableSink.java +++ b/flink/flink1.20-shims/src/main/java/org/apache/zeppelin/flink/shims120/CollectStreamTableSink.java @@ -16,7 +16,7 @@ * limitations under the License. */ -package org.apache.zeppelin.flink.shims117; +package org.apache.zeppelin.flink.shims120; import org.apache.flink.api.common.typeinfo.TypeInformation; import org.apache.flink.api.common.typeinfo.Types; diff --git a/flink/pom.xml b/flink/pom.xml index 833c068a8c6..490ee787baa 100644 --- a/flink/pom.xml +++ b/flink/pom.xml @@ -35,17 +35,14 @@ flink-scala-2.12 flink-shims - flink1.15-shims - flink1.16-shims - flink1.17-shims + flink1.20-shims flink - 1.15.1 - 1.16.0 - 1.17.1 + 1.19.3 + 1.20.4 2.12.7 2.12 diff --git a/testing/env_python_3_with_flink_117.yml b/testing/env_python_3_with_flink_117.yml deleted file mode 100644 index 84ec862e2e5..00000000000 --- a/testing/env_python_3_with_flink_117.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: python_3_with_flink -channels: - - conda-forge - - defaults -dependencies: - - pycodestyle - - scipy - - numpy=1.19.5 - - grpcio - - protobuf - - pandasql - - ipython - - ipython_genutils - - ipykernel - - jupyter_client=5 - - hvplot - - holoviews=1.16 - - plotnine - - seaborn - - intake - - intake-parquet - - intake-xarray - - altair - - vega_datasets - - plotly - - jinja2=3.0.3 - - pip - - pip: - - apache-flink==1.17.1 - diff --git a/testing/env_python_3_with_flink_115.yml b/testing/env_python_3_with_flink_119.yml similarity index 89% rename from testing/env_python_3_with_flink_115.yml rename to testing/env_python_3_with_flink_119.yml index 837a372b1a9..235010b137f 100644 --- a/testing/env_python_3_with_flink_115.yml +++ b/testing/env_python_3_with_flink_119.yml @@ -7,7 +7,7 @@ dependencies: - scipy - numpy=1.19.5 - grpcio - - protobuf + - protobuf<4 - pandasql - ipython - ipython_genutils @@ -26,5 +26,4 @@ dependencies: - jinja2=3.0.3 - pip - pip: - - apache-flink==1.15.1 - + - apache-flink==1.19.3 diff --git a/testing/env_python_3_with_flink_116.yml b/testing/env_python_3_with_flink_120.yml similarity index 89% rename from testing/env_python_3_with_flink_116.yml rename to testing/env_python_3_with_flink_120.yml index 8ff6520e5f4..05066fc6c1f 100644 --- a/testing/env_python_3_with_flink_116.yml +++ b/testing/env_python_3_with_flink_120.yml @@ -7,7 +7,7 @@ dependencies: - scipy - numpy=1.19.5 - grpcio - - protobuf + - protobuf<4 - pandasql - ipython - ipython_genutils @@ -26,5 +26,4 @@ dependencies: - jinja2=3.0.3 - pip - pip: - - apache-flink==1.16.0 - + - apache-flink==1.20.4 diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java index 2dfb87d2e0b..8f469e7a956 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/InterpreterModeActionsIT.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; @@ -44,6 +45,7 @@ import java.time.Duration; +@Disabled("ZEPPELIN-6410: InterpreterModeActionsIT consistently fails due to Selenium element timeouts on CI") public class InterpreterModeActionsIT extends AbstractZeppelinIT { private static final Logger LOGGER = LoggerFactory.getLogger(InterpreterModeActionsIT.class); @@ -261,6 +263,7 @@ void testGloballyAction() throws Exception { } @Test + @Disabled("ZEPPELIN-6410: testPerUserScopedAction consistently fails due to element click/visibility timeout") void testPerUserScopedAction() throws Exception { try { //step 1: (admin) login, set 'Per user in scoped' mode of python interpreter, logout @@ -549,6 +552,7 @@ void testPerUserScopedAction() throws Exception { } @Test + @Disabled("ZEPPELIN-6410: testPerUserIsolatedAction consistently fails due to element visibility timeout") void testPerUserIsolatedAction() throws Exception { try { //step 1: (admin) login, set 'Per user in isolated' mode of python interpreter, logout diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java index 3863d7df372..7027d5591b9 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ParagraphActionsIT.java @@ -822,6 +822,7 @@ void testSingleDynamicFormCheckboxForm() throws Exception { } @Test + @Disabled("ZEPPELIN-6410: testMultipleDynamicFormsSameType consistently fails due to element timeout") void testMultipleDynamicFormsSameType() throws Exception { try { createNewNote(); diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java index 745cfd284bf..0d21e20d689 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinIT.java @@ -297,6 +297,7 @@ void testSparkInterpreterDependencyLoading() throws Exception { } @Test + @Disabled("ZEPPELIN-6410: testAngularRunParagraph consistently fails due to element clickability timeout") void testAngularRunParagraph() throws Exception { try { createNewNote(); diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest.java index 776df28f1d6..19d0c51de17 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest.java @@ -37,6 +37,7 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -171,6 +172,7 @@ public void testYarnMode() throws IOException, InterpreterException, YarnExcepti } @Test + @Disabled("ZEPPELIN-6406: YARN application mode fails with AM container exit code 1 on MiniYARN cluster with Flink 1.19+") public void testYarnApplicationMode() throws IOException, InterpreterException, YarnException { if (flinkVersion.startsWith("1.10")) { LOGGER.info("Skip yarn application mode test for flink 1.10"); diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest113.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest113.java deleted file mode 100644 index 346ac5b58db..00000000000 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest113.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.integration; - -import java.io.IOException; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; - -public class FlinkIntegrationTest113 { - - @Nested - @DisplayName("Scala 2.11") - public class Scala211 extends FlinkIntegrationTest { - - @BeforeEach - public void downloadFlink() throws IOException { - download("1.13.2", "2.11"); - } - } - - @Nested - @DisplayName("Scala 2.12") - public class Scala212 extends FlinkIntegrationTest { - - @BeforeEach - public void downloadFlink() throws IOException { - download("1.13.2", "2.12"); - } - } -} diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest115.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest119.java similarity index 82% rename from zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest115.java rename to zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest119.java index 45da9738cf4..2ba705a8a62 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest115.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest119.java @@ -17,19 +17,21 @@ package org.apache.zeppelin.integration; +import java.io.IOException; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; -public class ZeppelinFlinkClusterTest115 extends ZeppelinFlinkClusterTest { +public class FlinkIntegrationTest119 { @Nested @DisplayName("Scala 2.12") - public class Scala212 extends ZeppelinFlinkClusterTest { + public class Scala212 extends FlinkIntegrationTest { @BeforeEach - public void downloadFlink() { - download("1.15.0", "2.12"); + public void downloadFlink() throws IOException { + download("1.19.3", "2.12"); } } } diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest114.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest120.java similarity index 80% rename from zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest114.java rename to zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest120.java index 1b94e69f638..4514ddf0714 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest114.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/FlinkIntegrationTest120.java @@ -17,22 +17,13 @@ package org.apache.zeppelin.integration; +import java.io.IOException; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; -import java.io.IOException; - -public class FlinkIntegrationTest114 { - - @Nested - @DisplayName("Scala 2.11") - public class Scala211 extends FlinkIntegrationTest { - @BeforeEach - public void downloadFlink() throws IOException { - download("1.14.0", "2.11"); - } - } +public class FlinkIntegrationTest120 { @Nested @DisplayName("Scala 2.12") @@ -40,7 +31,7 @@ public class Scala212 extends FlinkIntegrationTest { @BeforeEach public void downloadFlink() throws IOException { - download("1.14.0", "2.12"); + download("1.20.4", "2.12"); } } } diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java index 4050a7727fe..db8b36d3f20 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java @@ -77,7 +77,7 @@ static void init() throws Exception { zConf.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_CHECK_INTERVAL.getVarName(), "5000"); zConf.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD.getVarName(), "10000"); sparkHome = DownloadUtils.downloadSpark(); - flinkHome = DownloadUtils.downloadFlink("1.17.1", "2.12"); + flinkHome = DownloadUtils.downloadFlink("1.19.3", "2.12"); zepServer.start(); notebook = zepServer.getService(Notebook.class); @@ -340,6 +340,8 @@ void testZSession_Spark_Submit() throws Exception { void testZSession_Flink() throws Exception { Map intpProperties = new HashMap<>(); intpProperties.put("FLINK_HOME", flinkHome); + // Disable Hive delegation token provider which fails without full Hive classpath in Flink 1.19+ + intpProperties.put("security.delegation.token.provider.hive.enabled", "false"); ZSession session = ZSession.builder() .setClientConfig(clientConfig) @@ -377,6 +379,7 @@ void testZSession_Flink() throws Exception { void testZSession_Flink_Submit() throws Exception { Map intpProperties = new HashMap<>(); intpProperties.put("FLINK_HOME", flinkHome); + intpProperties.put("security.delegation.token.provider.hive.enabled", "false"); ZSession session = ZSession.builder() .setClientConfig(clientConfig) diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest113.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest113.java deleted file mode 100644 index 629551ef9f1..00000000000 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest113.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.integration; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; - -public class ZeppelinFlinkClusterTest113 { - - @Nested - @DisplayName("Scala 2.11") - public class Scala211 extends ZeppelinFlinkClusterTest { - - @BeforeEach - public void downloadFlink() { - download("1.13.2", "2.11"); - } - } - - @Nested - @DisplayName("Scala 2.12") - public class Scala212 extends ZeppelinFlinkClusterTest { - - @BeforeEach - public void downloadFlink() { - download("1.13.2", "2.12"); - } - } -} diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest114.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest114.java deleted file mode 100644 index 0af0b652369..00000000000 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinFlinkClusterTest114.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.integration; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; - -public class ZeppelinFlinkClusterTest114 extends ZeppelinFlinkClusterTest { - - @Nested - @DisplayName("Scala 2.11") - public class Scala211 extends ZeppelinFlinkClusterTest { - - @BeforeEach - public void downloadFlink() { - download("1.14.0", "2.11"); - } - } - - @Nested - @DisplayName("Scala 2.12") - public class Scala212 extends ZeppelinFlinkClusterTest { - - @BeforeEach - public void downloadFlink() { - download("1.14.0", "2.12"); - } - } -} diff --git a/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java b/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java index 18db47647f7..f72511f2a0f 100644 --- a/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java +++ b/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java @@ -509,6 +509,11 @@ public static String downloadFlink(String flinkVersion, String scalaVersion) { "https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-client-runtime/3.3.6/hadoop-client-runtime-3.3.6.jar", 3, new File(targetFlinkHomeFolder, "lib" + File.separator + "hadoop-client-runtime-3.3.6.jar")); + // commons-logging is required by Hadoop's FileSystem but not bundled in Flink 1.19+ + download( + "https://repo1.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar", + 3, new File(targetFlinkHomeFolder, + "lib" + File.separator + "commons-logging-1.2.jar")); download("https://repo1.maven.org/maven2/org/apache/flink/flink-table-api-scala_" + scalaVersion + "/" + flinkVersion + "/flink-table-api-scala_" + scalaVersion + "-" + flinkVersion + ".jar", From 618036ba70a6524432cb11c9c3219d1161c56134 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Fri, 29 May 2026 12:40:59 +0900 Subject: [PATCH 042/179] [MINOR] chore(zeppelin-web-angular): remove @antv/g2plot and migrate to chart.js to fix npm audit (#5257) --- .../projects/zeppelin-react/package-lock.json | 398 +----------------- .../projects/zeppelin-react/package.json | 2 +- .../visualizations/TableVisualization.tsx | 147 +++++-- 3 files changed, 126 insertions(+), 421 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index 422ac91ed5c..598ac2b7bb6 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -9,10 +9,10 @@ "version": "0.0.1", "dependencies": { "@ant-design/icons": "5.4.0", - "@antv/g2plot": "2.3.32", "@zeppelin/sdk": "file:../zeppelin-sdk", "ansi-to-react": "6.2.6", "antd": "5.21.0", + "chart.js": "^4.5.1", "file-saver": "2.0.5", "react": "18.3.1", "react-dom": "18.3.1", @@ -146,302 +146,6 @@ "react": ">=16.9.0" } }, - "node_modules/@antv/adjust": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.2.5.tgz", - "integrity": "sha512-MfWZOkD9CqXRES6MBGRNe27Q577a72EIwyMnE29wIlPliFvJfWwsrONddpGU7lilMpVKecS3WAzOoip3RfPTRQ==", - "license": "MIT", - "dependencies": { - "@antv/util": "~2.0.0", - "tslib": "^1.10.0" - } - }, - "node_modules/@antv/adjust/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/@antv/attr": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.3.5.tgz", - "integrity": "sha512-wuj2gUo6C8Q2ASSMrVBuTcb5LcV+Tc0Egiy6bC42D0vxcQ+ta13CLxgMmHz8mjD0FxTPJDXSciyszRSC5TdLsg==", - "license": "MIT", - "dependencies": { - "@antv/color-util": "^2.0.1", - "@antv/scale": "^0.3.0", - "@antv/util": "~2.0.0", - "tslib": "^2.3.1" - } - }, - "node_modules/@antv/color-util": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@antv/color-util/-/color-util-2.0.6.tgz", - "integrity": "sha512-KnPEaAH+XNJMjax9U35W67nzPI+QQ2x27pYlzmSIWrbj4/k8PGrARXfzDTjwoozHJY8qG62Z+Ww6Alhu2FctXQ==", - "license": "ISC", - "dependencies": { - "@antv/util": "^2.0.9", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/component": { - "version": "0.8.35", - "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.8.35.tgz", - "integrity": "sha512-VnRa5X77nBPI952o2xePEEMSNZ6g2mcUDrQY8mVL2kino/8TFhqDq5fTRmDXZyWyIYd4ulJTz5zgeSwAnX/INQ==", - "license": "MIT", - "dependencies": { - "@antv/color-util": "^2.0.3", - "@antv/dom-util": "~2.0.1", - "@antv/g-base": "^0.5.9", - "@antv/matrix-util": "^3.1.0-beta.1", - "@antv/path-util": "~2.0.7", - "@antv/scale": "~0.3.1", - "@antv/util": "~2.0.0", - "fecha": "~4.2.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/component/node_modules/@antv/path-util": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", - "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", - "license": "ISC", - "dependencies": { - "@antv/matrix-util": "^3.0.4", - "@antv/util": "^2.0.9", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/component/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", - "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", - "license": "ISC", - "dependencies": { - "@antv/util": "^2.0.9", - "gl-matrix": "^3.3.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/coord": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.3.1.tgz", - "integrity": "sha512-rFE94C8Xzbx4xmZnHh2AnlB3Qm1n5x0VT3OROy257IH6Rm4cuzv1+tZaUBATviwZd99S+rOY9telw/+6C9GbRw==", - "license": "MIT", - "dependencies": { - "@antv/matrix-util": "^3.1.0-beta.2", - "@antv/util": "~2.0.12", - "tslib": "^2.1.0" - } - }, - "node_modules/@antv/dom-util": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.4.tgz", - "integrity": "sha512-2shXUl504fKwt82T3GkuT4Uoc6p9qjCKnJ8gXGLSW4T1W37dqf9AV28aCfoVPHp2BUXpSsB+PAJX2rG/jLHsLQ==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/event-emitter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@antv/event-emitter/-/event-emitter-0.1.3.tgz", - "integrity": "sha512-4ddpsiHN9Pd4UIlWuKVK1C4IiZIdbwQvy9i7DUSI3xNJ89FPUFt8lxDYj8GzzfdllV0NkJTRxnG+FvLk0llidg==", - "license": "MIT" - }, - "node_modules/@antv/g-base": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/@antv/g-base/-/g-base-0.5.16.tgz", - "integrity": "sha512-jP06wggTubDPHXoKwFg3/f1lyxBX9ywwN3E/HG74Nd7DXqOXQis8tsIWW+O6dS/h9vyuXLd1/wDWkMMm3ZzXdg==", - "license": "ISC", - "dependencies": { - "@antv/event-emitter": "^0.1.1", - "@antv/g-math": "^0.1.9", - "@antv/matrix-util": "^3.1.0-beta.1", - "@antv/path-util": "~2.0.5", - "@antv/util": "~2.0.13", - "@types/d3-timer": "^2.0.0", - "d3-ease": "^1.0.5", - "d3-interpolate": "^3.0.1", - "d3-timer": "^1.0.9", - "detect-browser": "^5.1.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g-base/node_modules/@antv/path-util": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", - "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", - "license": "ISC", - "dependencies": { - "@antv/matrix-util": "^3.0.4", - "@antv/util": "^2.0.9", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g-base/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", - "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", - "license": "ISC", - "dependencies": { - "@antv/util": "^2.0.9", - "gl-matrix": "^3.3.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g-canvas": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-0.5.17.tgz", - "integrity": "sha512-sXYJMWTOlb/Ycb6sTKu00LcJqInXJY4t99+kSM40u2OfqrXYmaXDjHR7D2V0roMkbK/QWiWS9UnEidCR1VtMOA==", - "license": "ISC", - "dependencies": { - "@antv/g-base": "^0.5.12", - "@antv/g-math": "^0.1.9", - "@antv/matrix-util": "^3.1.0-beta.1", - "@antv/path-util": "~2.0.5", - "@antv/util": "~2.0.0", - "gl-matrix": "^3.0.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g-canvas/node_modules/@antv/path-util": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", - "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", - "license": "ISC", - "dependencies": { - "@antv/matrix-util": "^3.0.4", - "@antv/util": "^2.0.9", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g-canvas/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", - "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", - "license": "ISC", - "dependencies": { - "@antv/util": "^2.0.9", - "gl-matrix": "^3.3.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g-math": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-0.1.9.tgz", - "integrity": "sha512-KHMSfPfZ5XHM1PZnG42Q2gxXfOitYveNTA7L61lR6mhZ8Y/aExsYmHqaKBsSarU0z+6WLrl9C07PQJZaw0uljQ==", - "license": "ISC", - "dependencies": { - "@antv/util": "~2.0.0", - "gl-matrix": "^3.0.0" - } - }, - "node_modules/@antv/g-svg": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-0.5.7.tgz", - "integrity": "sha512-jUbWoPgr4YNsOat2Y/rGAouNQYGpw4R0cvlN0YafwOyacFFYy2zC8RslNd6KkPhhR3XHNSqJOuCYZj/YmLUwYw==", - "license": "ISC", - "dependencies": { - "@antv/g-base": "^0.5.12", - "@antv/g-math": "^0.1.9", - "@antv/util": "~2.0.0", - "detect-browser": "^5.0.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g2": { - "version": "4.2.12", - "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-4.2.12.tgz", - "integrity": "sha512-kTg6ftJol+0hYRM2eMwJKq3JThdq4UAKgCoQalUPjwyF6SSKkWz2QdrIAxfLE7LSTwcIE+L8So1jMaOVVbEi6w==", - "license": "MIT", - "dependencies": { - "@antv/adjust": "^0.2.1", - "@antv/attr": "^0.3.1", - "@antv/color-util": "^2.0.2", - "@antv/component": "^0.8.27", - "@antv/coord": "^0.3.0", - "@antv/dom-util": "^2.0.2", - "@antv/event-emitter": "~0.1.0", - "@antv/g-base": "~0.5.6", - "@antv/g-canvas": "~0.5.10", - "@antv/g-svg": "~0.5.6", - "@antv/matrix-util": "^3.1.0-beta.3", - "@antv/path-util": "^2.0.15", - "@antv/scale": "^0.3.14", - "@antv/util": "~2.0.5", - "tslib": "^2.0.0" - } - }, - "node_modules/@antv/g2/node_modules/@antv/path-util": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.15.tgz", - "integrity": "sha512-R2VLZ5C8PLPtr3VciNyxtjKqJ0XlANzpFb5sE9GE61UQqSRuSVSzIakMxjEPrpqbgc+s+y8i+fmc89Snu7qbNw==", - "license": "ISC", - "dependencies": { - "@antv/matrix-util": "^3.0.4", - "@antv/util": "^2.0.9", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g2/node_modules/@antv/path-util/node_modules/@antv/matrix-util": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.0.4.tgz", - "integrity": "sha512-BAPyu6dUliHcQ7fm9hZSGKqkwcjEDVLVAstlHULLvcMZvANHeLXgHEgV7JqcAV/GIhIz8aZChIlzM1ZboiXpYQ==", - "license": "ISC", - "dependencies": { - "@antv/util": "^2.0.9", - "gl-matrix": "^3.3.0", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/g2plot": { - "version": "2.3.32", - "resolved": "https://registry.npmjs.org/@antv/g2plot/-/g2plot-2.3.32.tgz", - "integrity": "sha512-ksBCEAjd2pki3H3Ce0c26sOD5Z8v6v7hbFwux1se5H5YPpzf+Vq8FgWO8Tokur07wiOqnAJzuEDflxos2KxApw==", - "license": "MIT", - "dependencies": { - "@antv/event-emitter": "^0.1.2", - "@antv/g2": "^4.1.23", - "d3-hierarchy": "^2.0.0", - "d3-regression": "^1.3.5", - "pdfast": "^0.2.0", - "size-sensor": "^1.0.1", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/matrix-util": { - "version": "3.1.0-beta.3", - "resolved": "https://registry.npmjs.org/@antv/matrix-util/-/matrix-util-3.1.0-beta.3.tgz", - "integrity": "sha512-W2R6Za3A6CmG51Y/4jZUM/tFgYSq7vTqJL1VD9dKrvwxS4sE0ZcXINtkp55CdyBwJ6Cwm8pfoRpnD4FnHahN0A==", - "license": "ISC", - "dependencies": { - "@antv/util": "^2.0.9", - "gl-matrix": "^3.4.3", - "tslib": "^2.0.3" - } - }, - "node_modules/@antv/scale": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.18.tgz", - "integrity": "sha512-GHwE6Lo7S/Q5fgaLPaCsW+CH+3zl4aXpnN1skOiEY0Ue9/u+s2EySv6aDXYkAqs//i0uilMDD/0/4n8caX9U9w==", - "license": "MIT", - "dependencies": { - "@antv/util": "~2.0.3", - "fecha": "~4.2.0", - "tslib": "^2.0.0" - } - }, - "node_modules/@antv/util": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.17.tgz", - "integrity": "sha512-o6I9hi5CIUvLGDhth0RxNSFDRwXeywmt6ExR4+RmVAzIi48ps6HUy+svxOCayvrPBN37uE6TAc2KDofRo0nK9Q==", - "license": "ISC", - "dependencies": { - "csstype": "^3.0.8", - "tslib": "^2.0.3" - } - }, "node_modules/@babel/runtime": { "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", @@ -1123,6 +827,12 @@ "tslib": "2" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -1530,12 +1240,6 @@ "@types/node": "*" } }, - "node_modules/@types/d3-timer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-2.0.3.tgz", - "integrity": "sha512-jhAJzaanK5LqyLQ50jJNIrB8fjL9gwWZTgYjevPvkDLMU+kTAZkYsobI59nYoeSrH1PucuyJEi247Pb90t6XUg==", - "license": "MIT" - }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -3121,6 +2825,18 @@ "node": ">=0.8" } }, + "node_modules/chart.js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", + "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -3441,51 +3157,6 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-hierarchy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-2.0.0.tgz", - "integrity": "sha512-SwIdqM3HxQX2214EG9GTjgmCc/mbSx4mQBn+DuEETubhOw6/U3fmnji4uCVrmzOydMHSO1nZle5gh6HB/wdOzw==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-regression": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/d3-regression/-/d3-regression-1.3.10.tgz", - "integrity": "sha512-PF8GWEL70cHHWpx2jUQXc68r1pyPHIA+St16muk/XRokETzlegj5LriNKg7o4LR0TySug4nHYPJNNRz/W+/Niw==", - "license": "BSD-3-Clause" - }, - "node_modules/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", - "license": "BSD-3-Clause" - }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -3663,12 +3334,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", - "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", - "license": "MIT" - }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -4721,12 +4386,6 @@ "node": ">=0.8.0" } }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT" - }, "node_modules/fflate": { "version": "0.3.11", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz", @@ -5026,12 +4685,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gl-matrix": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz", - "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==", - "license": "MIT" - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -6978,12 +6631,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pdfast": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/pdfast/-/pdfast-0.2.0.tgz", - "integrity": "sha512-cq6TTu6qKSFUHwEahi68k/kqN2mfepjkGrG9Un70cgdRRKLKY6Rf8P8uvP2NvZktaQZNF3YE7agEkLj0vGK9bA==", - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -8790,12 +8437,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/size-sensor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.2.tgz", - "integrity": "sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==", - "license": "ISC" - }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -9434,6 +9075,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, "license": "0BSD" }, "node_modules/tsyringe": { diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json index 537ea10cd37..7621820adaa 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -13,10 +13,10 @@ }, "dependencies": { "@ant-design/icons": "5.4.0", - "@antv/g2plot": "2.3.32", "@zeppelin/sdk": "file:../zeppelin-sdk", "ansi-to-react": "6.2.6", "antd": "5.21.0", + "chart.js": "^4.5.1", "file-saver": "2.0.5", "react": "18.3.1", "react-dom": "18.3.1", diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx index 4b34591c23a..bec6bc8673e 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/visualizations/TableVisualization.tsx @@ -12,10 +12,10 @@ import { useState, useEffect, useMemo, useRef } from 'react'; import { Table } from 'antd'; -import type { Column, Line, Pie, Scatter } from '@antv/g2plot'; import { VisualizationControls } from './VisualizationControls'; import { parseTableData, exportFile } from '@/utils'; import type { ParagraphConfigResult, ParagraphIResultsMsgItem, VisualizationMode } from '@zeppelin/sdk'; +import type { Chart, ChartConfiguration } from 'chart.js'; interface TableVisualizationProps { result: ParagraphIResultsMsgItem; @@ -66,7 +66,8 @@ export const TableVisualization = ({ result, config }: TableVisualizationProps) }; useEffect(() => { - if (!chartRef.current || !tableData || tableData.rows.length === 0 || currentMode === 'table') return; + const container = chartRef.current; + if (!container || !tableData || tableData.rows.length === 0 || currentMode === 'table') return; const data = tableData.rows.map((row, idx) => ({ category: row[0] || `Row ${idx + 1}`, @@ -75,64 +76,123 @@ export const TableVisualization = ({ result, config }: TableVisualizationProps) y: parseFloat(row[1] || '0') || 0 })); - let chart: Column | Line | Pie | Scatter | null = null; + container.innerHTML = ''; + + let chart: Chart | null = null; let cancelled = false; - import('@antv/g2plot').then(g2plot => { - if (cancelled || !chartRef.current) return; + import('chart.js/auto').then(module => { + if (cancelled || !container) return; + + const ChartConstructor = module.Chart || module.default; + + const canvas = document.createElement('canvas'); + canvas.style.width = '100%'; + canvas.style.height = '100%'; + container.appendChild(canvas); + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + let chartConfig: ChartConfiguration | null = null; switch (currentMode) { case 'multiBarChart': - chart = new g2plot.Column(chartRef.current, { - data, - xField: 'category', - yField: 'value', - color: '#1890ff', - columnWidthRatio: 0.8 - }); + chartConfig = { + type: 'bar', + data: { + labels: data.map(d => d.category), + datasets: [{ + label: 'Value', + data: data.map(d => d.value), + backgroundColor: '#1890ff' + }] + }, + options: { + responsive: true, + maintainAspectRatio: false + } + }; break; case 'lineChart': - chart = new g2plot.Line(chartRef.current, { - data, - xField: 'category', - yField: 'value', - color: '#1890ff' - }); + chartConfig = { + type: 'line', + data: { + labels: data.map(d => d.category), + datasets: [{ + label: 'Value', + data: data.map(d => d.value), + borderColor: '#1890ff', + backgroundColor: 'rgba(24, 144, 255, 0.1)', + tension: 0.1 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false + } + }; break; case 'pieChart': - chart = new g2plot.Pie(chartRef.current, { - data, - angleField: 'value', - colorField: 'category' - }); + chartConfig = { + type: 'pie', + data: { + labels: data.map(d => d.category), + datasets: [{ + data: data.map(d => d.value), + backgroundColor: [ + '#1890ff', '#2fc25b', '#facc14', '#223273', '#8543e0', '#13c2c2', '#3436c7', '#f04864' + ] + }] + }, + options: { + responsive: true, + maintainAspectRatio: false + } + }; break; case 'scatterChart': - chart = new g2plot.Scatter(chartRef.current, { - data, - xField: 'x', - yField: 'y', - color: '#1890ff' - }); + chartConfig = { + type: 'scatter', + data: { + datasets: [{ + label: 'Value', + data: data.map(d => ({ x: d.x, y: d.y })), + backgroundColor: '#1890ff' + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { type: 'linear', position: 'bottom' } + } + } + }; break; case 'stackedAreaChart': - chart = new g2plot.Line(chartRef.current, { - data, - xField: 'category', - yField: 'value', - color: '#1890ff', - point: { - size: 3, - shape: 'circle' + chartConfig = { + type: 'line', + data: { + labels: data.map(d => d.category), + datasets: [{ + label: 'Value', + data: data.map(d => d.value), + borderColor: '#1890ff', + backgroundColor: 'rgba(24, 144, 255, 0.2)', + fill: true, + tension: 0.1 + }] }, - lineStyle: { - lineWidth: 2 + options: { + responsive: true, + maintainAspectRatio: false } - }); + }; break; } - if (chart) { - chart.render(); + if (chartConfig) { + chart = new ChartConstructor(ctx, chartConfig); } }); @@ -141,6 +201,9 @@ export const TableVisualization = ({ result, config }: TableVisualizationProps) if (chart) { chart.destroy(); } + if (container) { + container.innerHTML = ''; + } }; }, [currentMode, tableData]); From 3e470121a007616069b6a3c15ea338e450c6f54f Mon Sep 17 00:00:00 2001 From: Kalyan Date: Mon, 1 Jun 2026 02:03:39 -0700 Subject: [PATCH 043/179] [ZEPPELIN-6411] Semantic search for Zeppelin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Added `EmbeddingSearch` — a new `SearchService` implementation that enables natural language search across Zeppelin notebooks using ONNX-based sentence embeddings (all-MiniLM-L6-v2). Disabled by default, enabled with `zeppelin.search.semantic.enable = true`. **The problem**: Zeppelin's built-in search uses Lucene's keyword matching, which works well for exact terms but falls short for the way analysts actually search. A user looking for "yesterday's spending" gets zero results — even though their notebooks contain SELECT sum(cost) WHERE date = current_date - interval '1' day. The words don't match, so Lucene can't find it. This PR adds EmbeddingSearch, an alternative SearchService that uses sentence embeddings (all-MiniLM-L6-v2 via ONNX Runtime) to match by meaning instead of keywords. It runs entirely in-process with no external services required. Beyond semantic matching, EmbeddingSearch addresses other gaps in notebook search: - Indexes paragraph output — table results and text output become searchable, not just the code - Extracts SQL table names — FROM/JOIN references are extracted and used to boost related paragraphs in a two-phase ranking - Strips interpreter prefixes — %spark.sql, %python etc. are removed so they don't pollute search results - Live indexing — new or updated paragraphs are searchable immediately, no restart needed ### What type of PR is it? Feature ### Todos - [x] EmbeddingSearch core implementation (ONNX inference, mean pooling, cosine similarity) - [x] Table name extraction from SQL (FROM/JOIN regex) with two-phase search boosting - [x] Paragraph output indexing (TABLE, TEXT results) - [x] Versioned binary persistence (v3 format) - [x] Live indexing (new paragraphs searchable immediately) - [x] Angular UI: render search results with separate code/output/tables blocks - [x] Classic UI: same improvements - [x] 11 unit tests including semantic validation - [x] Documentation ### What is the Jira issue? - https://issues.apache.org/jira/browse/ZEPPELIN-6411 ### How should this be tested? **Automated tests:** ```bash # Embedding search tests (requires ~86MB model download, one-time) ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-zengine -Dtest=EmbeddingSearchTest # Verify no regressions to existing Lucene search mvn test -pl zeppelin-zengine -Dtest=LuceneSearchTest Manual testing: 1. Set zeppelin.search.semantic.enable = true in zeppelin-site.xml 2. Restart Zeppelin 3. Search for natural language queries like: - "yesterday's spending" (Lucene: 0 results → Semantic: finds spend queries) - "how much do drivers earn" (finds taxi tip analysis) - "late deliveries" (finds shipping performance queries) - "airport rides" (both work — keyword match exists) ``` ### Screenshots (if appropriate) Semantic Search with New UI image Semantic Search with Classic UI image ### Questions: - Does the license files need to update? - Yes — NOTICE updated with ONNX Runtime (MIT) and DJL Tokenizers (Apache 2.0) attribution. - Is there breaking changes for older versions? - No. Disabled by default. Existing LuceneSearch behavior is unchanged. Closes #5218 from kkalyan/ZEPPELIN-6411-semantic-search. Signed-off-by: Jongyoul Lee --- LICENSE | 18 + NOTICE | 12 + bin/install-search-model.sh | 78 ++ docs/embedding-search.md | 224 +++++ zeppelin-server/pom.xml | 22 + .../zeppelin/conf/ZeppelinConfiguration.java | 5 + .../interpreter/InterpreterFactory.java | 4 + .../zeppelin/search/EmbeddingSearch.java | 952 ++++++++++++++++++ .../apache/zeppelin/search/LuceneSearch.java | 13 +- .../zeppelin/server/ZeppelinServer.java | 7 +- .../zeppelin/search/EmbeddingSearchTest.java | 364 +++++++ .../src/app/interfaces/notebook.ts | 3 + .../result-item/result-item.component.html | 22 +- .../result-item/result-item.component.less | 131 ++- .../result-item/result-item.component.ts | 213 ++-- .../workspace/notebook/notebook.component.ts | 12 +- .../app/share/header/header.component.html | 12 +- .../src/app/share/header/header.component.ts | 18 + .../src/app/search/result-list.controller.js | 172 ++-- zeppelin-web/src/app/search/result-list.html | 28 +- zeppelin-web/src/app/search/search.css | 61 ++ 21 files changed, 2080 insertions(+), 291 deletions(-) create mode 100755 bin/install-search-model.sh create mode 100644 docs/embedding-search.md create mode 100644 zeppelin-server/src/main/java/org/apache/zeppelin/search/EmbeddingSearch.java create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java diff --git a/LICENSE b/LICENSE index 3c3f246917d..c285c1b196a 100644 --- a/LICENSE +++ b/LICENSE @@ -277,3 +277,21 @@ Eclipse Public License - v 1.0 The following components are provided under the Eclipse Public License, version 1.0. See file headers and project links for details. (Eclipse Public License) pty4j - http://www.eclipse.org/legal/epl-v10.html + +======================================================================== +MIT License +======================================================================== +The following components are provided under the MIT License. See file headers and project links for details. + + (MIT License) ONNX Runtime (https://github.com/microsoft/onnxruntime) + Licensed under the MIT License. + https://github.com/microsoft/onnxruntime/blob/main/LICENSE + +======================================================================== +Apache License 2.0 (bundled dependencies) +======================================================================== +The following components are provided under the Apache License 2.0. See file headers and project links for details. + + (Apache License 2.0) DJL - Deep Java Library Tokenizers (https://github.com/deepjavalibrary/djl) + Licensed under the Apache License, Version 2.0. + https://github.com/deepjavalibrary/djl/blob/master/LICENSE diff --git a/NOTICE b/NOTICE index bd7844b811c..e1da12ea081 100644 --- a/NOTICE +++ b/NOTICE @@ -12,3 +12,15 @@ Portions of this software were developed at NFLabs, Inc. (http://www.nflabs.com) * Pseudo terminal(PTY) implementation in Java * (Eclipse Public License) pty4j - http://www.eclipse.org/legal/epl-v10.html + +2. ONNX Runtime + + * Cross-platform ML inferencing and training accelerator + * (MIT License) onnxruntime - https://github.com/microsoft/onnxruntime + * Copyright (c) Microsoft Corporation + +3. Deep Java Library (DJL) HuggingFace Tokenizers + + * Java binding for HuggingFace tokenizers + * (Apache License 2.0) djl-tokenizers - https://github.com/deepjavalibrary/djl + * Copyright (c) Amazon.com, Inc. diff --git a/bin/install-search-model.sh b/bin/install-search-model.sh new file mode 100755 index 00000000000..18ed47e11fb --- /dev/null +++ b/bin/install-search-model.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Downloads the sentence-transformer model required for semantic search. +# Run this once before starting Zeppelin with zeppelin.search.semantic.enable=true. +# +# Usage: bin/install-search-model.sh [INDEX_PATH] +# INDEX_PATH defaults to /tmp/zeppelin-index (matches zeppelin.search.index.path) + +set -euo pipefail + +MODEL_NAME="all-MiniLM-L6-v2" +MODEL_REVISION="c9745ed1d9f207416be6d2e6f8de32d1f16199bf" +BASE_URL="https://huggingface.co/sentence-transformers/${MODEL_NAME}/resolve/${MODEL_REVISION}" + +# Expected SHA256 checksums for integrity verification +MODEL_SHA256="6fd5d72fe4589f189f8ebc006442dbb529bb7ce38f8082112682524616046452" +TOKENIZER_SHA256="be50c3628f2bf5bb5e3a7f17b1f74611b2561a3a27eeab05e5aa30f411572037" + +INDEX_PATH="${1:-/tmp/zeppelin-index}" +MODEL_DIR="${INDEX_PATH}/models/${MODEL_NAME}" + +mkdir -p "${MODEL_DIR}" + +verify_sha256() { + local file="$1" expected="$2" + local actual + if command -v sha256sum >/dev/null 2>&1; then + actual=$(sha256sum "${file}" | cut -d' ' -f1) + elif command -v shasum >/dev/null 2>&1; then + actual=$(shasum -a 256 "${file}" | cut -d' ' -f1) + else + echo "WARNING: Neither sha256sum nor shasum found, skipping integrity check for ${file}" + return 0 + fi + if [ "${actual}" != "${expected}" ]; then + echo "ERROR: SHA256 mismatch for ${file}" + echo " Expected: ${expected}" + echo " Actual: ${actual}" + rm -f "${file}" + return 1 + fi + echo "SHA256 verified: ${file}" +} + +download() { + local url="$1" dest="$2" expected_sha="$3" + if [ -f "${dest}" ]; then + if verify_sha256 "${dest}" "${expected_sha}"; then + echo "Already exists and verified: ${dest}" + return + fi + echo "Existing file failed verification, re-downloading..." + fi + echo "Downloading ${url} ..." + curl -fSL --connect-timeout 30 --max-time 300 -o "${dest}.tmp" "${url}" + mv "${dest}.tmp" "${dest}" + verify_sha256 "${dest}" "${expected_sha}" + echo "Saved: ${dest}" +} + +download "${BASE_URL}/onnx/model.onnx" "${MODEL_DIR}/model.onnx" "${MODEL_SHA256}" +download "${BASE_URL}/tokenizer.json" "${MODEL_DIR}/tokenizer.json" "${TOKENIZER_SHA256}" + +echo "Model installed to ${MODEL_DIR}" diff --git a/docs/embedding-search.md b/docs/embedding-search.md new file mode 100644 index 00000000000..5dac212ed22 --- /dev/null +++ b/docs/embedding-search.md @@ -0,0 +1,224 @@ + + +# ZEPPELIN-6411: Semantic Search for Notebooks using Sentence Embeddings + +## Summary + +Add `EmbeddingSearch` — a new `SearchService` implementation that enables natural language +search across Zeppelin notebooks using ONNX-based sentence embeddings. This is a drop-in +replacement for `LuceneSearch` that understands meaning, not just keywords. + +**Example**: Searching "yesterday's spending" finds paragraphs containing +`SELECT sum(cost) FROM analytics.daily_sales WHERE date = current_date - interval '1' day` +— something keyword search cannot do (returns 0 results with LuceneSearch). + +## Motivation + +Zeppelin's current search (`LuceneSearch`) uses keyword-based full-text search with +Lucene's `StandardAnalyzer`. This has several limitations for notebook search: + +1. **No semantic understanding** — "yesterday's spend" won't find `current_date - 1` +2. **Poor SQL tokenization** — `StandardAnalyzer` breaks on underscores and dots in + table names like `analytics_db.daily_sales` +3. **No output indexing** — query results (table data, text output) are not searchable +4. **Exact match only** — users must guess the exact terms used in notebooks + +For teams with hundreds or thousands of notebooks (common in data/analytics teams), +finding the right query becomes a significant productivity bottleneck. + +## Architecture + +``` + SearchService (abstract) + ├── LuceneSearch (existing, keyword-based) + ├── EmbeddingSearch (new, semantic) + └── NoSearchService (existing, no-op) + +┌─────────────────────────────────────────────────────────────┐ +│ EmbeddingSearch │ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │ +│ │ HuggingFace │ │ ONNX Runtime │ │ In-Memory Index │ │ +│ │ Tokenizer │→ │ Inference │→ │ float[][] + meta │ │ +│ │ (DJL) │ │ (CPU) │ │ ConcurrentHashMap│ │ +│ └──────────────┘ └──────────────┘ └────────┬─────────┘ │ +│ │ │ +│ Two-phase query: │ │ +│ 1. Embed query → cosine sim → find tables │ │ +│ 2. Re-rank with table boost → top-20 │ │ +│ ▼ │ +│ Index: text + title + output + tables embedding_index.bin│ +│ (persisted to disk, versioned) │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Model + +- **all-MiniLM-L6-v2**: 384-dimensional sentence embeddings +- 86MB ONNX model (quantized version available at 22MB) +- Downloaded on first use to `zeppelin.search.index.path/models/` +- Runs on CPU via ONNX Runtime (~5ms per paragraph) + +### Index + +- In-memory `ConcurrentHashMap` with `ReadWriteLock` +- Each entry stores: embedding (384 floats), notebook name, paragraph text, + title, extracted SQL table names, and paragraph output +- 10K paragraphs ≈ 15MB RAM, 50K paragraphs ≈ 75MB RAM +- Persisted as versioned binary file (`embedding_index.bin`, currently v3) +- Brute-force cosine similarity: < 50ms for 50K paragraphs + +### What gets indexed (vs. LuceneSearch) + +| Content | LuceneSearch | EmbeddingSearch | +|---------|:---:|:---:| +| Paragraph text | ✓ | ✓ | +| Paragraph title | ✓ | ✓ | +| Notebook name | ✓ | ✓ (in embedding context) | +| Paragraph output (TABLE, TEXT) | ✗ | ✓ | +| SQL table names (FROM/JOIN) | ✗ | ✓ (extracted + boosted) | +| Interpreter prefix stripped | ✗ | ✓ | + +### Two-Phase Search + +1. **Phase 1 — Table Discovery**: Run cosine similarity, collect SQL table names + from top-20 results weighted by rank +2. **Phase 2 — Table Boost**: Re-score results, boosting paragraphs that reference + the discovered tables (+0.05 per matching table) + +This helps queries like "click funnel analysis" surface all paragraphs that query +the same tables, even if their SQL text is very different. + +## Configuration + +Disabled by default. Enable with a single property: + +```xml + + + zeppelin.search.semantic.enable + true + +``` + +Requires `zeppelin.search.enable = true` (already the default). + +### Configuration matrix + +| `search.enable` | `search.semantic.enable` | Result | +|:---:|:---:|---| +| true | false (default) | LuceneSearch (existing behavior) | +| true | true | EmbeddingSearch (semantic) | +| false | any | NoSearchService | + +## Changes + +### New files +- `zeppelin-zengine/.../search/EmbeddingSearch.java` — Core implementation (~700 lines) +- `zeppelin-zengine/.../search/EmbeddingSearchTest.java` — 11 tests including semantic validation +- `docs/embedding-search.md` — This document + +### Modified files — Backend +- `zeppelin-zengine/pom.xml` — Add `onnxruntime` and `djl-tokenizers` dependencies +- `zeppelin-zengine/.../conf/ZeppelinConfiguration.java` — Add `ZEPPELIN_SEARCH_SEMANTIC_ENABLE` +- `zeppelin-server/.../server/ZeppelinServer.java` — Wire `EmbeddingSearch` based on config +- `NOTICE` — Attribution for ONNX Runtime and DJL + +### Modified files — Frontend +- `zeppelin-web-angular/.../result-item/` — Render search results with separate + code block, output block, and table name display (replaces Monaco editor) +- `zeppelin-web/src/app/search/` — Same improvements for Classic UI + +### Dependencies added +- `com.microsoft.onnxruntime:onnxruntime:1.18.0` (~50MB, Apache 2.0 compatible) +- `ai.djl.huggingface:tokenizers:0.28.0` (~2MB, Apache 2.0, JNA excluded to + avoid version conflict with Zeppelin's existing JNA 4.1.0) + +## Search Result Response Contract + +Both `LuceneSearch` and `EmbeddingSearch` return `List>` with +these keys: + +| Key | LuceneSearch | EmbeddingSearch | +|-----|-------------|-----------------| +| `id` | `noteId` or `noteId/paragraph/paragraphId` | Same | +| `name` | Notebook title | Notebook title | +| `snippet` | Highlighted paragraph text (`` tags) | Paragraph text (no highlighting) | +| `text` | Full paragraph text | Full paragraph text | +| `header` | Highlighted paragraph title (`` tags) | Paragraph title (plain) | +| `title` | Same as `header` | Paragraph title (plain) | +| `tables` | `""` (empty) | Space-separated SQL table names | +| `output` | `""` (empty) | Paragraph output (truncated to 300 chars) | + +The `title`, `tables`, and `output` fields are dedicated structured fields. The +`header` field preserves backward compatibility — for `LuceneSearch` it contains +the highlighted paragraph title, for `EmbeddingSearch` it contains the plain title. + +### Frontend Display + +Both Angular and Classic UIs render search results with: +- **Code block**: SQL/Python code with syntax-appropriate styling +- **Output block**: Paragraph execution results (from `output` field) +- **Table names**: Extracted SQL table names (from `tables` field) +- **Language badge**: `sql`, `python`, `md`, etc. + +## Design Decisions + +### Why ONNX Runtime instead of a Java ML library? + +ONNX Runtime is the standard inference engine for transformer models. It supports +the exact same model files used by Python (HuggingFace, ChromaDB, etc.), ensuring +embedding compatibility. + +### Why brute-force instead of HNSW/ANN? + +For Zeppelin's scale (typically < 50K paragraphs), brute-force cosine similarity +on normalized vectors is fast enough (< 50ms), exact (no approximation error), +and adds zero complexity. + +### Why download model on first use instead of bundling? + +The ONNX model is 86MB. Bundling it would bloat the Zeppelin distribution. +Downloading on first use keeps the distribution lean and allows users to swap models. + +### Why not use Lucene's vector search (since 9.0)? + +Zeppelin uses Lucene 8.7.0. Upgrading to 9.x is a separate, larger effort. + +## Testing + +```bash +# Run embedding search tests (requires model download, ~86MB first time) +ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-zengine \ + -Dtest=EmbeddingSearchTest + +# Run existing Lucene tests (should still pass, no changes) +mvn test -pl zeppelin-zengine -Dtest=LuceneSearchTest +``` + +### Key tests + +- `semanticSearchFindsRelatedConcepts` — validates that "yesterday's spending" + ranks a SQL spend query above an unrelated user count query +- `newParagraphIsLiveIndexed` — validates that newly added paragraphs are + immediately searchable without restart + +## Future Work + +- [ ] Quantized model support (22MB INT8 vs 86MB FP32) +- [ ] Hybrid search: combine embedding similarity with keyword matching +- [ ] Configurable model URL for air-gapped environments +- [ ] Batch embedding during initial index rebuild +- [ ] Similarity score display in search results diff --git a/zeppelin-server/pom.xml b/zeppelin-server/pom.xml index 6c6b9a0b266..8dbdb575673 100644 --- a/zeppelin-server/pom.xml +++ b/zeppelin-server/pom.xml @@ -42,6 +42,8 @@ 2.0.0-M15 32.0.0-jre 8.7.0 + 1.18.0 + 0.28.0 2.10.0 4.5.4.201711221230-r 1.6 @@ -176,6 +178,26 @@ ${lucene.version} + + + com.microsoft.onnxruntime + onnxruntime + ${onnxruntime.version} + + + + + ai.djl.huggingface + tokenizers + ${djl.version} + + + net.java.dev.jna + jna + + + + com.github.eirslett frontend-plugin-core diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index 958e4a5eddd..252fd51a9bd 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -840,6 +840,10 @@ public String getZeppelinSearchIndexPath() { return getAbsoluteDir(ConfVars.ZEPPELIN_SEARCH_INDEX_PATH); } + public boolean isZeppelinSearchSemanticEnable() { + return getBoolean(ConfVars.ZEPPELIN_SEARCH_SEMANTIC_ENABLE); + } + public boolean isOnlyYarnCluster() { return getBoolean(ConfVars.ZEPPELIN_SPARK_ONLY_YARN_CLUSTER); } @@ -1131,6 +1135,7 @@ public enum ConfVars { ZEPPELIN_SEARCH_INDEX_REBUILD("zeppelin.search.index.rebuild", false), ZEPPELIN_SEARCH_USE_DISK("zeppelin.search.use.disk", true), ZEPPELIN_SEARCH_INDEX_PATH("zeppelin.search.index.path", "/tmp/zeppelin-index"), + ZEPPELIN_SEARCH_SEMANTIC_ENABLE("zeppelin.search.semantic.enable", false), ZEPPELIN_JOBMANAGER_ENABLE("zeppelin.jobmanager.enable", false), ZEPPELIN_SPARK_ONLY_YARN_CLUSTER("zeppelin.spark.only_yarn_cluster", false), ZEPPELIN_SESSION_CHECK_INTERVAL("zeppelin.session.check_interval", 60 * 10 * 1000), diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java index 95dbce1e811..bb614c29f8c 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java @@ -44,6 +44,10 @@ public Interpreter getInterpreter(String replName, // Get the default interpreter of the defaultInterpreterSetting InterpreterSetting defaultSetting = interpreterSettingManager.getByName(executionContext.getDefaultInterpreterGroup()); + if (defaultSetting == null) { + throw new InterpreterNotFoundException("No interpreter found for group: " + + executionContext.getDefaultInterpreterGroup()); + } return defaultSetting.getDefaultInterpreter(executionContext); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/search/EmbeddingSearch.java b/zeppelin-server/src/main/java/org/apache/zeppelin/search/EmbeddingSearch.java new file mode 100644 index 00000000000..2d60d3fc286 --- /dev/null +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/search/EmbeddingSearch.java @@ -0,0 +1,952 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zeppelin.search; + +import ai.djl.huggingface.tokenizers.Encoding; +import ai.djl.huggingface.tokenizers.HuggingFaceTokenizer; +import com.google.common.collect.ImmutableMap; +import ai.onnxruntime.OnnxTensor; +import ai.onnxruntime.OrtEnvironment; +import ai.onnxruntime.OrtException; +import ai.onnxruntime.OrtSession; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.LongBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermissions; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.PreDestroy; +import jakarta.inject.Inject; + +import org.apache.commons.lang3.StringUtils; +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.interpreter.InterpreterResult; +import org.apache.zeppelin.interpreter.InterpreterResultMessage; +import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.notebook.Notebook; +import org.apache.zeppelin.notebook.Paragraph; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Semantic search for Zeppelin notebooks using ONNX-based sentence embeddings. + * + *

Uses the all-MiniLM-L6-v2 model to generate 384-dimensional embeddings for each + * paragraph's text, title, and output. Queries are embedded with the same model and + * matched via cosine similarity, enabling natural language search like + * "yesterday's spend query" to find {@code WHERE date = current_date - 1}. + * + *

The embedding index is held in memory (float[][] + metadata) and persisted to a + * single binary file on disk. For typical Zeppelin deployments (< 50K paragraphs), + * brute-force cosine similarity completes in under 50ms. + * + *

Model files are downloaded on first use to {@code zeppelin.search.index.path} + * and cached for subsequent starts. + */ +public class EmbeddingSearch extends SearchService { + private static final Logger LOGGER = LoggerFactory.getLogger(EmbeddingSearch.class); + + private static final String MODEL_NAME = "all-MiniLM-L6-v2"; + private static final int EMBEDDING_DIM = 384; + private static final int MAX_SEQ_LENGTH = 256; + /** Maximum number of candidates returned from {@link #query(String)}. */ + private static final int MAX_RESULTS = 20; + /** + * Cosine similarity floor for a candidate to be considered a match. + * Tuned empirically against all-MiniLM-L6-v2: values below this are effectively noise + * for short-query / long-paragraph comparisons. See embedding-search.md for details. + */ + private static final float MIN_SIMILARITY = 0.25f; + private static final int MAX_TEXT_LENGTH = 1500; + + static final String ID_FIELD = "id"; + private static final String PARAGRAPH = "paragraph"; + /** Regex to extract qualified table names from SQL (e.g. schema.table). */ + private static final Pattern TABLE_RE = + Pattern.compile("(?:FROM|JOIN)\\s+([a-zA-Z_]\\w*\\.[a-zA-Z_]\\w*)", Pattern.CASE_INSENSITIVE); + /** + * Additive score boost applied to a candidate for each relevant table it references. + * Chosen small enough that it only breaks ties among already-similar candidates + * and cannot promote semantically unrelated results past {@link #MIN_SIMILARITY}. + */ + private static final float TABLE_BOOST = 0.05f; + /** + * Additive score boost when the query string appears literally in the indexed text. + * Ensures exact keyword matches surface even when the embedding similarity is low + * (e.g. searching "TETRIS" in SQL containing TETRIS_VIDEO_SINGLE_MEDIA). + */ + private static final float KEYWORD_BOOST = 0.30f; + /** + * Fraction of the top table's weight used as the cutoff for "relevant" tables in Phase 1 + * of {@link #query(String)}. Tables below this share are dropped from the boost set + * to avoid amplifying incidental mentions. + */ + private static final float TABLE_WEIGHT_THRESHOLD_RATIO = 0.2f; + private static final long FLUSH_INTERVAL_SECONDS = 5; + /** + * Hard upper bound on deserialized entry count to protect against a corrupted/tampered + * index file causing unbounded allocation on startup. 10M paragraphs is well beyond any + * plausible deployment (~18 GB of vectors alone at 384 floats/entry). + */ + private static final int MAX_INDEX_ENTRIES = 10_000_000; + private static final String INDEX_FILE_NAME = "embedding_index.bin"; + /** Binary format version written by {@link #saveIndex()} and required by {@link #loadIndex()}. */ + private static final int INDEX_VERSION = 3; + private static final String EXPECTED_MODEL_SHA256 = + "6fd5d72fe4589f189f8ebc006442dbb529bb7ce38f8082112682524616046452"; + + private final Notebook notebook; + private final Path indexPath; + + // ONNX inference + private OrtEnvironment ortEnv; + private OrtSession ortSession; + private HuggingFaceTokenizer tokenizer; + + // In-memory vector index: docId -> (embedding, metadata) + private final ConcurrentHashMap index = new ConcurrentHashMap<>(); + private final ReadWriteLock indexLock = new ReentrantReadWriteLock(); + private final AtomicBoolean indexDirty = new AtomicBoolean(false); + private final ScheduledExecutorService flushScheduler = + Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "EmbeddingSearch-flush"); + t.setDaemon(true); + return t; + }); + + /** A single indexed document (paragraph or note name). */ + // TODO(ZEPPELIN-6413): Reduce in-memory duplication by keeping only {embedding, docId} here + // and rehydrating text/title/output from Notebook.processNote() at query time. Needs a perf + // comparison against the current in-memory path and a consistency story on LRU eviction. + private static class IndexEntry { + final float[] embedding; + final String noteName; + final String text; + final String title; + final String tables; + final String output; + + IndexEntry(float[] embedding, String noteName, String text, String title, + String tables, String output) { + this.embedding = embedding; + this.noteName = noteName; + this.text = text; + this.title = title; + this.tables = tables; + this.output = output; + } + } + + @Inject + public EmbeddingSearch(ZeppelinConfiguration zConf, Notebook notebook) throws IOException { + super("EmbeddingSearch"); + this.notebook = notebook; + this.indexPath = Paths.get(zConf.getZeppelinSearchIndexPath()); + Files.createDirectories(indexPath); + restrictPermissions(indexPath); + + try { + initModel(); + } catch (Exception e) { + throw new IOException("Failed to initialize embedding model", e); + } + + boolean indexLoaded = loadIndex(); + if (shouldBootstrapIndex(zConf, indexLoaded)) { + notebook.addInitConsumer(this::addNoteIndex); + } + flushScheduler.scheduleWithFixedDelay(this::flushIfDirty, + FLUSH_INTERVAL_SECONDS, FLUSH_INTERVAL_SECONDS, TimeUnit.SECONDS); + this.notebook.addNotebookEventListener(this); + } + + /** Package-private constructor for testing without DI. */ + EmbeddingSearch(ZeppelinConfiguration zConf, Notebook notebook, boolean skipModel) + throws IOException { + super("EmbeddingSearch"); + this.notebook = notebook; + this.indexPath = Paths.get(zConf.getZeppelinSearchIndexPath()); + Files.createDirectories(indexPath); + restrictPermissions(indexPath); + if (!skipModel) { + try { + initModel(); + } catch (Exception e) { + throw new IOException("Failed to initialize embedding model", e); + } + } + boolean indexLoaded = loadIndex(); + if (shouldBootstrapIndex(zConf, indexLoaded)) { + notebook.addInitConsumer(this::addNoteIndex); + } + flushScheduler.scheduleWithFixedDelay(this::flushIfDirty, + FLUSH_INTERVAL_SECONDS, FLUSH_INTERVAL_SECONDS, TimeUnit.SECONDS); + this.notebook.addNotebookEventListener(this); + } + + private static void restrictPermissions(Path dir) { + try { + if (Files.getFileStore(dir).supportsFileAttributeView("posix")) { + Files.setPosixFilePermissions(dir, + PosixFilePermissions.fromString("rwx------")); + } + } catch (IOException e) { + LOGGER.warn("Could not restrict permissions on {}", dir, e); + } + if (dir.toAbsolutePath().startsWith("/tmp")) { + LOGGER.warn("zeppelin.search.index.path is under /tmp ({}); " + + "paragraph text and output will be readable by other local users. " + + "Consider setting it to a private directory.", dir); + } + } + + // ---- Model initialization ---- + + private void initModel() throws OrtException, IOException { + Path modelDir = indexPath.resolve("models").resolve(MODEL_NAME); + Files.createDirectories(modelDir); + + Path modelFile = modelDir.resolve("model.onnx"); + Path tokenizerFile = modelDir.resolve("tokenizer.json"); + + if (!Files.exists(modelFile) || !Files.exists(tokenizerFile)) { + throw new IOException( + "Embedding model not found at " + modelDir + ". " + + "Run bin/install-search-model.sh before enabling semantic search."); + } + + verifyModelSha256(modelFile); + + ortEnv = OrtEnvironment.getEnvironment(); + OrtSession.SessionOptions opts = new OrtSession.SessionOptions(); + opts.setIntraOpNumThreads(Runtime.getRuntime().availableProcessors()); + ortSession = ortEnv.createSession(modelFile.toString(), opts); + tokenizer = HuggingFaceTokenizer.newInstance(tokenizerFile); + LOGGER.info("Embedding model loaded: {}, dim={}", MODEL_NAME, EMBEDDING_DIM); + } + + private static void verifyModelSha256(Path modelFile) throws IOException { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] fileBytes = Files.readAllBytes(modelFile); + byte[] hash = digest.digest(fileBytes); + StringBuilder sb = new StringBuilder(); + for (byte b : hash) { + sb.append(String.format("%02x", b)); + } + String actual = sb.toString(); + if (!EXPECTED_MODEL_SHA256.equals(actual)) { + throw new IOException("model.onnx SHA256 mismatch — expected " + + EXPECTED_MODEL_SHA256 + " but got " + actual + + ". Re-run bin/install-search-model.sh"); + } + LOGGER.info("Model SHA256 verified: {}", modelFile); + } catch (NoSuchAlgorithmException e) { + LOGGER.warn("SHA-256 not available, skipping model integrity check", e); + } + } + + // ---- Embedding computation ---- + + /** + * Compute a normalized embedding for the given text. + * Uses mean pooling over token embeddings with attention mask. + */ + float[] embed(String text) { + if (ortSession == null || tokenizer == null) { + return new float[EMBEDDING_DIM]; + } + try { + Encoding encoding = tokenizer.encode(text, true, true); + long[] inputIds = encoding.getIds(); + long[] attentionMask = encoding.getAttentionMask(); + + // Truncate to max sequence length + int seqLen = Math.min(inputIds.length, MAX_SEQ_LENGTH); + long[] ids = new long[seqLen]; + long[] mask = new long[seqLen]; + long[] tokenTypeIds = new long[seqLen]; + System.arraycopy(inputIds, 0, ids, 0, seqLen); + System.arraycopy(attentionMask, 0, mask, 0, seqLen); + + long[] shape = {1, seqLen}; + OnnxTensor idsTensor = null; + OnnxTensor maskTensor = null; + OnnxTensor typeTensor = null; + try { + idsTensor = OnnxTensor.createTensor(ortEnv, LongBuffer.wrap(ids), shape); + maskTensor = OnnxTensor.createTensor(ortEnv, LongBuffer.wrap(mask), shape); + typeTensor = OnnxTensor.createTensor(ortEnv, LongBuffer.wrap(tokenTypeIds), shape); + + Map inputs = new HashMap<>(); + inputs.put("input_ids", idsTensor); + inputs.put("attention_mask", maskTensor); + inputs.put("token_type_ids", typeTensor); + + try (OrtSession.Result result = ortSession.run(inputs)) { + // Output shape: [1, seqLen, 384] — mean pool over sequence dim + float[][][] output = (float[][][]) result.get(0).getValue(); + float[] pooled = meanPool(output[0], mask, seqLen); + normalize(pooled); + return pooled; + } + } finally { + if (idsTensor != null) { + idsTensor.close(); + } + if (maskTensor != null) { + maskTensor.close(); + } + if (typeTensor != null) { + typeTensor.close(); + } + } + } catch (OrtException e) { + LOGGER.error("Embedding failed for text length {}", text.length(), e); + return new float[EMBEDDING_DIM]; + } + } + + /** Mean pooling: average token embeddings weighted by attention mask. */ + private static float[] meanPool(float[][] tokenEmbeddings, long[] mask, int seqLen) { + float[] result = new float[EMBEDDING_DIM]; + float maskSum = 0; + for (int i = 0; i < seqLen; i++) { + if (mask[i] == 1) { + maskSum++; + for (int j = 0; j < EMBEDDING_DIM; j++) { + result[j] += tokenEmbeddings[i][j]; + } + } + } + if (maskSum > 0) { + for (int j = 0; j < EMBEDDING_DIM; j++) { + result[j] /= maskSum; + } + } + return result; + } + + /** L2-normalize in place. */ + private static void normalize(float[] vec) { + float norm = 0; + for (float v : vec) { + norm += v * v; + } + norm = (float) Math.sqrt(norm); + if (norm > 0) { + for (int i = 0; i < vec.length; i++) { + vec[i] /= norm; + } + } + } + + /** Cosine similarity between two normalized vectors (= dot product). */ + private static float cosineSimilarity(float[] a, float[] b) { + float dot = 0; + for (int i = 0; i < a.length; i++) { + dot += a[i] * b[i]; + } + return dot; + } + + /** + * Wrap occurrences of each query word in {@code } tags (case-insensitive) + * to match Lucene's highlighting convention. + */ + static String highlightTerms(String text, String queryStr) { + if (StringUtils.isBlank(text) || StringUtils.isBlank(queryStr)) { + return text; + } + String[] words = queryStr.split("\\s+"); + for (String word : words) { + if (word.isEmpty()) { + continue; + } + String escaped = Pattern.quote(word); + text = text.replaceAll("(?i)(" + escaped + ")", "$1"); + } + return text; + } + + // ---- Text extraction ---- + + /** + * Strip interpreter prefix like {@code %spark.sql}, {@code %athena} from paragraph text. + * Handles both {@code %name\ncode} and {@code %name code} formats. + */ + static String stripInterpreterPrefix(String text) { + if (text == null || !text.startsWith("%")) { + return text; + } + // Find end of interpreter directive: first newline or first space after %word + int newlineIdx = text.indexOf('\n'); + if (newlineIdx >= 0) { + return text.substring(newlineIdx + 1); + } + // Single-line: "%interpreter some code" — strip up to first space + int spaceIdx = text.indexOf(' '); + if (spaceIdx >= 0) { + return text.substring(spaceIdx + 1); + } + // Just "%interpreter" with no content + return ""; + } + + /** + * Extract qualified table names (schema.table) from SQL text. + */ + static String extractTables(String text) { + if (text == null) { + return ""; + } + Set tables = new HashSet<>(); + Matcher m = TABLE_RE.matcher(text); + while (m.find()) { + tables.add(m.group(1).toLowerCase()); + } + return String.join(" ", tables); + } + + /** + * Extract searchable output text from paragraph results (TABLE headers, TEXT). + */ + static String extractOutput(Paragraph p) { + InterpreterResult result = p.getReturn(); + if (result == null) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (InterpreterResultMessage msg : result.message()) { + if (msg.getType() == InterpreterResult.Type.TEXT + || msg.getType() == InterpreterResult.Type.TABLE) { + String data = msg.getData(); + if (StringUtils.isNotBlank(data)) { + sb.append(data, 0, Math.min(data.length(), 500)); + sb.append("\n"); + } + } + } + return sb.toString().trim(); + } + + /** + * Build a rich text representation of a paragraph for embedding. + * Includes code/text, title, table names, and output (table headers, text results). + */ + private String buildParagraphText(String noteName, Paragraph p) { + StringBuilder sb = new StringBuilder(); + if (StringUtils.isNotBlank(noteName)) { + sb.append("Notebook: ").append(noteName).append("\n"); + } + if (StringUtils.isNotBlank(p.getTitle())) { + sb.append(p.getTitle()).append("\n"); + } + if (StringUtils.isNotBlank(p.getText())) { + String text = p.getText(); + // Strip interpreter prefix (e.g. "%spark.sql", "%athena\n") + text = stripInterpreterPrefix(text); + // Include extracted table names for better semantic matching + String tables = extractTables(text); + if (StringUtils.isNotBlank(tables)) { + sb.append("Tables: ").append(tables).append("\n"); + } + sb.append(text, 0, Math.min(text.length(), MAX_TEXT_LENGTH)); + } + // Include output for richer semantic matching + InterpreterResult result = p.getReturn(); + if (result != null) { + for (InterpreterResultMessage msg : result.message()) { + if (msg.getType() == InterpreterResult.Type.TEXT + || msg.getType() == InterpreterResult.Type.TABLE) { + String data = msg.getData(); + if (StringUtils.isNotBlank(data)) { + sb.append("\n").append(data, 0, Math.min(data.length(), 500)); + } + } + } + } + return sb.toString(); + } + + // ---- SearchService implementation ---- + + @Override + // TODO(ZEPPELIN-6414): Accept user/roles (or a readability Predicate) and apply the auth + // filter before Phase-1 table collection and before the top-K cutoff. Currently the REST + // layer filters after truncation, which can hide results the caller is authorized for and + // lets inaccessible notes contaminate the table-boost ranking. Requires a SearchService + // interface change that also affects LuceneSearch. + public List> query(String queryStr) { + if (StringUtils.isBlank(queryStr) || index.isEmpty()) { + return Collections.emptyList(); + } + + float[] queryEmbedding = embed(queryStr); + String queryLower = queryStr.toLowerCase(Locale.ROOT); + + // Phase 1: find top-N results and discover relevant tables + List> scored = new ArrayList<>(); + indexLock.readLock().lock(); + try { + for (Map.Entry entry : index.entrySet()) { + float sim = cosineSimilarity(queryEmbedding, entry.getValue().embedding); + IndexEntry ie = entry.getValue(); + if (ie.text != null && ie.text.toLowerCase(Locale.ROOT).contains(queryLower)) { + sim += KEYWORD_BOOST; + } + scored.add(Map.entry(entry.getKey(), sim)); + } + } finally { + indexLock.readLock().unlock(); + } + scored.sort((a, b) -> Float.compare(b.getValue(), a.getValue())); + + // Collect tables from the top candidates, weighted by rank + Map tableWeights = new HashMap<>(); + for (int i = 0; i < Math.min(scored.size(), MAX_RESULTS); i++) { + IndexEntry entry = index.get(scored.get(i).getKey()); + if (entry != null && StringUtils.isNotBlank(entry.tables)) { + float weight = 1.0f / (i + 1); + for (String t : entry.tables.split(" ")) { + tableWeights.merge(t, weight, Float::sum); + } + } + } + // Keep tables with weight >= TABLE_WEIGHT_THRESHOLD_RATIO of top table's weight + Set relevantTables = new HashSet<>(); + if (!tableWeights.isEmpty()) { + float maxWeight = Collections.max(tableWeights.values()); + float threshold = maxWeight * TABLE_WEIGHT_THRESHOLD_RATIO; + tableWeights.forEach((t, w) -> { + if (w >= threshold) { + relevantTables.add(t); + } + }); + } + + // Phase 2: re-score with table boost, collect candidates with boosted scores + List, Float>> candidates = new ArrayList<>(); + for (int i = 0; i < scored.size() && candidates.size() < MAX_RESULTS; i++) { + float sim = scored.get(i).getValue(); + if (sim < MIN_SIMILARITY) { + break; + } + String docId = scored.get(i).getKey(); + IndexEntry entry = index.get(docId); + if (entry == null || StringUtils.isBlank(entry.text)) { + continue; + } + if (!relevantTables.isEmpty() && StringUtils.isNotBlank(entry.tables)) { + for (String t : entry.tables.split(" ")) { + if (relevantTables.contains(t)) { + sim += TABLE_BOOST; + } + } + } + String title = entry.title != null ? entry.title : ""; + String tables = entry.tables != null ? entry.tables : ""; + String output = ""; + if (StringUtils.isNotBlank(entry.output)) { + output = entry.output; + if (output.length() > 300) { + output = output.substring(0, 300); + } + } + String snippet = highlightTerms(entry.text, queryStr); + String highlightedTitle = highlightTerms(title, queryStr); + candidates.add(Map.entry(ImmutableMap.builder() + .put("id", docId) + .put("name", entry.noteName != null ? entry.noteName : "") + .put("snippet", snippet) + .put("text", entry.text) + .put("header", highlightedTitle) + .put("title", highlightedTitle) + .put("tables", tables) + .put("output", output) + .build(), sim)); + } + // Re-sort by boosted score + candidates.sort((a, b) -> Float.compare(b.getValue(), a.getValue())); + List> results = new ArrayList<>(); + for (Map.Entry, Float> c : candidates) { + results.add(c.getKey()); + } + return results; + } + + @Override + public void addNoteIndex(String noteId) { + try { + notebook.processNote(noteId, note -> { + if (note != null) { + indexNote(note); + } + return null; + }); + markDirty(); + } catch (IOException e) { + LOGGER.error("Failed to add note {} to index", noteId, e); + } + } + + @Override + public void addParagraphIndex(String noteId, String paragraphId) { + try { + notebook.processNote(noteId, note -> { + if (note != null) { + Paragraph p = note.getParagraph(paragraphId); + if (p != null) { + indexParagraph(note.getId(), note.getName(), p); + } + } + return null; + }); + markDirty(); + } catch (IOException e) { + LOGGER.error("Failed to add paragraph {} of note {}", paragraphId, noteId, e); + } + } + + @Override + public void updateNoteIndex(String noteId) { + // Mirror LuceneSearch.updateNoteIndex: this event path is invoked for note-metadata + // changes (rename, cron config, etc.) — paragraph edits come through the + // add/updateParagraphIndex path. Re-embedding every paragraph here was pure waste for + // cron changes and heavy even for renames. Just refresh the noteName field on existing + // entries; the embedding slightly drifts (note name contributes to buildParagraphText) + // but self-heals on the next paragraph touch. + if (noteId == null) { + return; + } + try { + notebook.processNote(noteId, note -> { + if (note == null) { + return null; + } + String newName = note.getName(); + if (newName == null) { + return null; + } + indexLock.writeLock().lock(); + try { + boolean mutated = false; + String notePrefix = noteId + "/"; + for (Map.Entry e : index.entrySet()) { + String docId = e.getKey(); + if (!docId.equals(noteId) && !docId.startsWith(notePrefix)) { + continue; + } + IndexEntry old = e.getValue(); + if (newName.equals(old.noteName)) { + continue; + } + e.setValue(new IndexEntry(old.embedding, newName, old.text, old.title, + old.tables, old.output)); + mutated = true; + } + if (mutated) { + markDirty(); + } + } finally { + indexLock.writeLock().unlock(); + } + return null; + }); + } catch (IOException e) { + LOGGER.error("Failed to update note index {}", noteId, e); + } + } + + @Override + public void updateParagraphIndex(String noteId, String paragraphId) { + try { + notebook.processNote(noteId, note -> { + if (note != null) { + Paragraph p = note.getParagraph(paragraphId); + if (p != null) { + indexParagraph(noteId, note.getName(), p); + } + } + return null; + }); + markDirty(); + } catch (IOException e) { + LOGGER.error("Failed to update paragraph {} of note {}", paragraphId, noteId, e); + } + } + + @Override + public void deleteNoteIndex(String noteId) { + if (noteId == null) { + return; + } + indexLock.writeLock().lock(); + try { + index.entrySet().removeIf(e -> + e.getKey().equals(noteId) || e.getKey().startsWith(noteId + "/")); + } finally { + indexLock.writeLock().unlock(); + } + markDirty(); + } + + @Override + public void deleteParagraphIndex(String noteId, String paragraphId) { + if (noteId == null) { + return; + } + String docId = paragraphId != null + ? String.join("/", noteId, PARAGRAPH, paragraphId) + : noteId; + index.remove(docId); + markDirty(); + } + + @Override + @PreDestroy + public void close() { + super.close(); + flushScheduler.shutdown(); + flushIfDirty(); + try { + if (ortSession != null) { + ortSession.close(); + } + if (tokenizer != null) { + tokenizer.close(); + } + } catch (OrtException e) { + LOGGER.error("Failed to close ONNX session", e); + } + } + + private void markDirty() { + indexDirty.set(true); + } + + /** + * Decide whether to register the initial-indexing consumer. + * + * @param zConf Zeppelin configuration (for {@code isIndexRebuild}) + * @param loaded whether {@link #loadIndex()} completed successfully + * @return {@code true} if the index needs to be (re)built from notebooks. Triggers when + * config requests rebuild, the index file is missing, or it was present but + * failed to load (corrupt/partial). A failed load also deletes the bad file so + * the rebuilt index is written fresh. + */ + private boolean shouldBootstrapIndex(ZeppelinConfiguration zConf, boolean loaded) { + Path indexFile = indexPath.resolve(INDEX_FILE_NAME); + boolean fileMissing = !Files.exists(indexFile); + boolean corrupt = !loaded; + if (corrupt && !fileMissing) { + try { + Files.deleteIfExists(indexFile); + LOGGER.warn("Deleted corrupt embedding index file {}; will rebuild", indexFile); + } catch (IOException e) { + LOGGER.warn("Failed to delete corrupt embedding index file {}; will rebuild anyway", + indexFile, e); + } + } + return zConf.isIndexRebuild() || fileMissing || corrupt; + } + + private void flushIfDirty() { + if (indexDirty.compareAndSet(true, false)) { + try { + saveIndex(); + } catch (IOException e) { + // Re-set dirty so the next scheduled tick retries the flush + // instead of silently dropping the failed write until the next mutation. + indexDirty.set(true); + LOGGER.error("Failed to flush embedding index to disk; will retry on next tick", e); + } + } + } + + // ---- Internal indexing ---- + + private void indexNote(Note note) { + String noteName = note.getName(); + // Index each paragraph (note name is included in paragraph embedding text) + for (Paragraph p : note.getParagraphs()) { + indexParagraph(note.getId(), noteName, p); + } + } + + private void indexParagraph(String noteId, String noteName, Paragraph p) { + String text = buildParagraphText(noteName, p); + if (StringUtils.isBlank(text)) { + return; + } + float[] emb = embed(text); + String docId = String.join("/", noteId, PARAGRAPH, p.getId()); + String title = p.getTitle() != null ? p.getTitle() : ""; + String pText = p.getText() != null ? stripInterpreterPrefix(p.getText()) : ""; + String tables = extractTables(pText); + String output = extractOutput(p); + + indexLock.writeLock().lock(); + try { + index.put(docId, new IndexEntry(emb, noteName, pText, title, tables, output)); + } finally { + indexLock.writeLock().unlock(); + } + } + + static String formatId(String noteId, Paragraph p) { + if (p != null) { + return String.join("/", noteId, PARAGRAPH, p.getId()); + } + return noteId; + } + + // ---- Persistence ---- + + /** + * Save index to a binary file. + * Format: [int:version=INDEX_VERSION][int:count] then for each entry: + * [utf:docId] [utf:noteName] [utf:text] [utf:title] [utf:tables] [utf:output] [float[384]:embedding] + */ + // TODO(ZEPPELIN-6412): Shard persistence by note (e.g. index/notes/.bin) so a single + // paragraph edit only rewrites that note's file instead of the full index. Needs a per-note + // lock strategy, a manifest for load, and a compaction path for deletes; may also revisit + // append-only log + periodic compaction as the persistence model. + private void saveIndex() throws IOException { + Path file = indexPath.resolve(INDEX_FILE_NAME); + Path tmpFile = indexPath.resolve(INDEX_FILE_NAME + ".tmp"); + + // Serialize to buffer under lock + byte[] data; + indexLock.readLock().lock(); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream out = new DataOutputStream(baos)) { + out.writeInt(INDEX_VERSION); + out.writeInt(index.size()); + for (Map.Entry e : index.entrySet()) { + out.writeUTF(e.getKey()); + out.writeUTF(e.getValue().noteName != null ? e.getValue().noteName : ""); + String text = e.getValue().text != null ? e.getValue().text : ""; + if (text.length() > 2000) { + text = text.substring(0, 2000); + } + out.writeUTF(text); + out.writeUTF(e.getValue().title != null ? e.getValue().title : ""); + out.writeUTF(e.getValue().tables != null ? e.getValue().tables : ""); + String output = e.getValue().output != null ? e.getValue().output : ""; + if (output.length() > 1000) { + output = output.substring(0, 1000); + } + out.writeUTF(output); + for (float v : e.getValue().embedding) { + out.writeFloat(v); + } + } + } + data = baos.toByteArray(); + } finally { + indexLock.readLock().unlock(); + } + + // Write to disk outside lock + Files.write(tmpFile, data); + Files.move(tmpFile, file, java.nio.file.StandardCopyOption.REPLACE_EXISTING, + java.nio.file.StandardCopyOption.ATOMIC_MOVE); + // Restrict file permissions + try { + if (Files.getFileStore(file).supportsFileAttributeView("posix")) { + Files.setPosixFilePermissions(file, + PosixFilePermissions.fromString("rw-------")); + } + } catch (IOException e) { + LOGGER.warn("Could not restrict permissions on {}", file, e); + } + } + + /** + * Load the index from disk. + * + * @return {@code true} if the index loaded successfully (or file was absent); + * {@code false} if the file was present but failed to load or was corrupt, + * signalling the caller to trigger a bootstrap rebuild. + */ + private boolean loadIndex() { + Path file = indexPath.resolve(INDEX_FILE_NAME); + if (!Files.exists(file)) { + return true; + } + try (DataInputStream in = new DataInputStream(Files.newInputStream(file))) { + int version = in.readInt(); + if (version != INDEX_VERSION) { + LOGGER.warn("Index file version {} does not match expected {}; treating as corrupt " + + "and rebuilding", version, INDEX_VERSION); + return false; + } + int count = in.readInt(); + LOGGER.info("Loading {} embedding index entries (v{}) from {}", count, version, file); + if (count < 0 || count > MAX_INDEX_ENTRIES) { + LOGGER.error("Index entry count {} exceeds sanity bound ({}), treating as corrupt", + count, MAX_INDEX_ENTRIES); + return false; + } + for (int i = 0; i < count; i++) { + String docId = in.readUTF(); + String noteName = in.readUTF(); + String text = in.readUTF(); + String title = in.readUTF(); + String tables = in.readUTF(); + String output = in.readUTF(); + float[] emb = new float[EMBEDDING_DIM]; + for (int j = 0; j < EMBEDDING_DIM; j++) { + emb[j] = in.readFloat(); + } + index.put(docId, new IndexEntry(emb, noteName, text, title, tables, output)); + } + LOGGER.info("Loaded {} entries into embedding index", index.size()); + return true; + } catch (IOException e) { + LOGGER.warn("Failed to load embedding index from {}; will rebuild on init", file, e); + // Clear any partially-loaded state so we start from a clean slate on rebuild. + index.clear(); + return false; + } + } +} diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/search/LuceneSearch.java b/zeppelin-server/src/main/java/org/apache/zeppelin/search/LuceneSearch.java index 3f28f8eb65a..904069fb332 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/search/LuceneSearch.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/search/LuceneSearch.java @@ -190,9 +190,16 @@ private List> doSearch( header = ""; } matchingParagraphs.add( - ImmutableMap.of( - "id", path, // /paragraph/ - "name", title, "snippet", fragment, "text", text, "header", header)); + ImmutableMap.builder() + .put("id", path) + .put("name", title) + .put("snippet", fragment) + .put("text", text) + .put("header", header) + .put("title", header) + .put("tables", "") + .put("output", "") + .build()); } else { LOGGER.info("{}. No {} for this document", i + 1, ID_FIELD); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java index eca789e38b4..b3f78816aec 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java @@ -87,6 +87,7 @@ import org.apache.zeppelin.notebook.scheduler.QuartzSchedulerService; import org.apache.zeppelin.notebook.scheduler.SchedulerService; import org.apache.zeppelin.plugin.PluginManager; +import org.apache.zeppelin.search.EmbeddingSearch; import org.apache.zeppelin.search.LuceneSearch; import org.apache.zeppelin.search.NoSearchService; import org.apache.zeppelin.search.SearchService; @@ -210,7 +211,11 @@ protected void configure() { bind(NoSchedulerService.class).to(SchedulerService.class).in(Singleton.class); } if (zConf.getBoolean(ConfVars.ZEPPELIN_SEARCH_ENABLE)) { - bind(LuceneSearch.class).to(SearchService.class).in(Singleton.class); + if (zConf.isZeppelinSearchSemanticEnable()) { + bind(EmbeddingSearch.class).to(SearchService.class).in(Singleton.class); + } else { + bind(LuceneSearch.class).to(SearchService.class).in(Singleton.class); + } } else { bind(NoSearchService.class).to(SearchService.class).in(Singleton.class); } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java new file mode 100644 index 00000000000..2eb9d4be7b9 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java @@ -0,0 +1,364 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zeppelin.search; + +import static org.apache.zeppelin.search.EmbeddingSearch.formatId; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.interpreter.InterpreterFactory; +import org.apache.zeppelin.interpreter.InterpreterSetting; +import org.apache.zeppelin.interpreter.InterpreterSettingManager; +import org.apache.zeppelin.notebook.AuthorizationService; +import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.notebook.NoteManager; +import org.apache.zeppelin.notebook.Notebook; +import org.apache.zeppelin.notebook.Paragraph; +import org.apache.zeppelin.notebook.repo.InMemoryNotebookRepo; +import org.apache.zeppelin.notebook.repo.NotebookRepo; +import org.apache.zeppelin.user.AuthenticationInfo; +import org.apache.zeppelin.user.Credentials; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; + +/** + * Tests for {@link EmbeddingSearch}. + * + *

These tests require the ONNX model to be downloaded, so they are gated behind + * the {@code ZEPPELIN_EMBEDDING_TEST} environment variable. To run: + *

+ *   ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-zengine \
+ *     -Dtest=EmbeddingSearchTest
+ * 
+ * + *

The model (~86MB) is downloaded once to a temp directory and cached for the + * duration of the test run. + */ +@EnabledIfEnvironmentVariable(named = "ZEPPELIN_EMBEDDING_TEST", matches = "true") +class EmbeddingSearchTest { + + /** Shared model directory — avoids re-downloading 86MB model per test method. */ + private static File sharedModelDir; + + private Notebook notebook; + private InterpreterSettingManager interpreterSettingManager; + private NoteManager noteManager; + private EmbeddingSearch searchService; + private File indexDir; + + @BeforeEach + public void startUp() throws IOException { + if (sharedModelDir == null) { + // Look for model in the default install location first + File defaultModelDir = new File("/tmp/zeppelin-index/models"); + if (defaultModelDir.exists() + && new File(defaultModelDir, "all-MiniLM-L6-v2/model.onnx").exists()) { + sharedModelDir = defaultModelDir; + } else { + sharedModelDir = Files.createTempDirectory("EmbeddingSearchTest-models").toFile(); + } + } + indexDir = Files.createTempDirectory(this.getClass().getSimpleName()).toFile(); + // Symlink models dir so model is cached across tests + File modelsLink = new File(indexDir, "models"); + Files.createSymbolicLink(modelsLink.toPath(), sharedModelDir.toPath()); + ZeppelinConfiguration zConf = ZeppelinConfiguration.load(); + zConf.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_SEARCH_INDEX_PATH.getVarName(), + indexDir.getAbsolutePath()); + + noteManager = new NoteManager(new InMemoryNotebookRepo(), zConf); + interpreterSettingManager = mock(InterpreterSettingManager.class); + InterpreterSetting defaultInterpreterSetting = mock(InterpreterSetting.class); + when(defaultInterpreterSetting.getName()).thenReturn("test"); + when(interpreterSettingManager.getDefaultInterpreterSetting()) + .thenReturn(defaultInterpreterSetting); + notebook = new Notebook(zConf, mock(AuthorizationService.class), + mock(NotebookRepo.class), noteManager, + mock(InterpreterFactory.class), interpreterSettingManager, + mock(Credentials.class), null); + searchService = new EmbeddingSearch(zConf, notebook); + } + + @AfterEach + public void shutDown() throws IOException { + searchService.close(); + FileUtils.deleteDirectory(indexDir); + } + + private void drainSearchEvents() throws InterruptedException { + while (!searchService.isEventQueueEmpty()) { + Thread.sleep(500); + } + Thread.sleep(500); + } + + @Test + void canIndexAndQuery() throws IOException, InterruptedException { + // given + newNoteWithParagraph("Notebook1", "test"); + String note2Id = newNoteWithParagraphs("Notebook2", "not test", "not test at all"); + drainSearchEvents(); + + // when — semantic search for a meaningful phrase + List> results = searchService.query("testing something"); + + // then + assertFalse(results.isEmpty()); + boolean foundTest = results.stream() + .anyMatch(r -> r.get("text").contains("test")); + assertTrue(foundTest, "Should find paragraph containing 'test'"); + } + + @Test + void canIndexAndQueryByNotebookName() throws IOException, InterruptedException { + // given + newNoteWithParagraph("Notebook1", "test"); + newNoteWithParagraphs("Notebook2", "not test", "not test at all"); + drainSearchEvents(); + + // when + List> results = searchService.query("Notebook1"); + + // then + assertFalse(results.isEmpty()); + assertTrue(results.get(0).get("name").contains("Notebook1")); + } + + @Test + void canIndexAndQueryByParagraphTitle() throws IOException, InterruptedException { + // given + newNoteWithParagraph("Notebook1", "test", "testingTitleSearch"); + newNoteWithParagraph("Notebook2", "not test", "notTestingTitleSearch"); + drainSearchEvents(); + + // when + List> results = searchService.query("testingTitleSearch"); + + // then + assertFalse(results.isEmpty()); + boolean foundTitle = results.stream() + .anyMatch(r -> r.get("header").contains("testingTitleSearch")); + assertTrue(foundTitle); + } + + @Test + void semanticSearchFindsRelatedConcepts() throws IOException, InterruptedException { + // given — this is the key test that differentiates from Lucene + newNoteWithParagraph("SpendAnalysis", + "SELECT sum(cost) FROM analytics.daily_sales WHERE date = current_date - interval '1' day"); + newNoteWithParagraph("UserCounts", + "SELECT count(distinct user_id) FROM sessions WHERE region = 'us'"); + drainSearchEvents(); + + // when — natural language query, no exact keyword match + List> results = searchService.query("yesterday's spending"); + + // then — should rank the spend query higher than the user count query + assertFalse(results.isEmpty()); + assertEquals("SpendAnalysis", results.get(0).get("name"), + "Semantic search should rank spend-related paragraph first"); + } + + @Test + void indexKeyContract() throws IOException, InterruptedException { + // given + String note1Id = newNoteWithParagraph("Notebook1", "test"); + drainSearchEvents(); + + // when + List> results = searchService.query("test"); + assertFalse(results.isEmpty()); + + // then — find the paragraph result (not the note-name result) + String id = results.stream() + .filter(r -> r.get("id").contains("paragraph")) + .findFirst() + .map(r -> r.get("id")) + .orElse(""); + + notebook.processNote(note1Id, note1 -> { + String expected = formatId(note1.getId(), note1.getLastParagraph()); + assertEquals(expected, id, "Key should be /paragraph/"); + return null; + }); + } + + @Test + void canNotSearchBeforeIndexing() { + // given NO indexing was done + // when + List> result = searchService.query("anything"); + // then + assertTrue(result.isEmpty()); + } + + @Test + void canIndexAndReIndex() throws IOException, InterruptedException { + // given + newNoteWithParagraph("Notebook1", "test"); + String note2Id = newNoteWithParagraphs("Notebook2", "not test", "not test at all"); + drainSearchEvents(); + + // when + notebook.processNote(note2Id, note2 -> { + Paragraph p2 = note2.getLastParagraph(); + p2.setText("updated paragraph with unique content about reindexing"); + searchService.updateParagraphIndex(note2Id, p2.getId()); + return null; + }); + + // then — updated content should now be findable + List> results = searchService.query("reindexing updated content"); + assertFalse(results.isEmpty()); + } + + @Test + void canDeleteNull() { + // should not throw + searchService.deleteNoteIndex(null); + } + + @Test + void canDeleteFromIndex() throws IOException, InterruptedException { + // given + newNoteWithParagraph("Notebook1", "test"); + String note2Id = newNoteWithParagraphs("Notebook2", "not test", "not test at all"); + drainSearchEvents(); + + assertFalse(searchService.query("Notebook2").isEmpty()); + + // when + searchService.deleteNoteIndex(note2Id); + + // then — no results should reference the deleted note's ID + boolean foundNote2After = searchService.query("not test at all").stream() + .anyMatch(r -> r.get("id").startsWith(note2Id)); + assertFalse(foundNote2After, "Note2 should be removed from index after deletion"); + assertFalse(searchService.query("Notebook1").isEmpty()); + } + + @Test + void indexParagraphUpdatedOnNoteSave() throws IOException, InterruptedException { + // given + String note1Id = newNoteWithParagraph("Notebook1", "test"); + newNoteWithParagraphs("Notebook2", "not test", "not test at all"); + drainSearchEvents(); + + // when + notebook.processNote(note1Id, note1 -> { + Paragraph p1 = note1.getLastParagraph(); + p1.setText("no no no"); + notebook.saveNote(note1, AuthenticationInfo.ANONYMOUS); + p1.getNote().fireParagraphUpdateEvent(p1); + return null; + }); + drainSearchEvents(); + + // then — "Notebook1" note name should still be findable + assertFalse(searchService.query("Notebook1").isEmpty()); + } + + @Test + void newParagraphIsLiveIndexed() throws IOException, InterruptedException { + // given — one notebook exists + String noteId = newNoteWithParagraph("Analytics", "SELECT 1"); + drainSearchEvents(); + + // when — add a new paragraph with unique content + notebook.processNote(noteId, note -> { + Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); + p.setText("SELECT customer_id, SUM(amount) as lifetime_value FROM orders GROUP BY 1"); + notebook.saveNote(note, AuthenticationInfo.ANONYMOUS); + note.fireParagraphUpdateEvent(p); + return null; + }); + drainSearchEvents(); + + // then — the new paragraph should be findable by semantic query + List> results = searchService.query("lifetime value"); + assertFalse(results.isEmpty(), "Newly added paragraph should be searchable"); + boolean found = results.stream() + .anyMatch(r -> r.get("text").contains("lifetime_value")); + assertTrue(found, "Should find the paragraph with lifetime_value"); + } + + // ---- Helper methods (same as LuceneSearchTest) ---- + + private String newNoteWithParagraph(String noteName, String parText) throws IOException { + String noteId = newNote(noteName); + notebook.processNote(noteId, note -> { + addParagraphWithText(note, parText); + return null; + }); + // Re-index after paragraphs are added (createNote event may fire before paragraphs exist) + searchService.updateNoteIndex(noteId); + return noteId; + } + + private String newNoteWithParagraph(String noteName, String parText, String title) + throws IOException { + String noteId = newNote(noteName); + notebook.processNote(noteId, note -> { + addParagraphWithTextAndTitle(note, parText, title); + return null; + }); + searchService.updateNoteIndex(noteId); + return noteId; + } + + private String newNoteWithParagraphs(String noteName, String... parTexts) throws IOException { + String noteId = newNote(noteName); + notebook.processNote(noteId, note -> { + for (String parText : parTexts) { + addParagraphWithText(note, parText); + } + return null; + }); + searchService.updateNoteIndex(noteId); + return noteId; + } + + private Paragraph addParagraphWithText(Note note, String text) { + Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); + p.setText(text); + return p; + } + + private Paragraph addParagraphWithTextAndTitle(Note note, String text, String title) { + Paragraph p = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); + p.setText(text); + p.setTitle(title); + return p; + } + + private String newNote(String name) throws IOException { + return notebook.createNote(name, AuthenticationInfo.ANONYMOUS); + } +} diff --git a/zeppelin-web-angular/src/app/interfaces/notebook.ts b/zeppelin-web-angular/src/app/interfaces/notebook.ts index c6c591524b0..08db8f3acff 100644 --- a/zeppelin-web-angular/src/app/interfaces/notebook.ts +++ b/zeppelin-web-angular/src/app/interfaces/notebook.ts @@ -16,6 +16,9 @@ export interface NotebookSearchResultItem { snippet: string; text: string; header: string; + title?: string; + tables?: string; + output?: string; } export interface NotebookCapabilities { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html index 19e3ccb6ba7..5e393de9129 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html @@ -10,13 +10,17 @@ ~ limitations under the License. --> - - - {{ displayName }} - - + +

+ {{ displayName }} + {{ interpreter }} +
+
+
+

+  
+
+
{{ outputText }}
+
+
Tables: {{ tablesText }}
diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less index cb24d4e47b3..96caf1916d6 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.less @@ -10,10 +10,131 @@ * limitations under the License. */ -::ng-deep { - .monaco-editor { - .mark { - background: #fdf733; - } +@import 'theme-mixin'; + +:host { + display: block; + margin-bottom: 12px; +} + +.result-card { + cursor: pointer; + user-select: text; +} + +.result-header { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; +} + +.badge { + font-size: 11px; + padding: 1px 8px; + border-radius: 10px; +} + +.code-block { + border-radius: 6px; + padding: 10px 12px; + margin-bottom: 8px; + overflow-x: auto; + + pre { + margin: 0; + font-size: 12px; + line-height: 1.5; + white-space: pre-wrap; + word-break: break-word; + max-height: 200px; + overflow-y: auto; } } + +.output-block { + border-radius: 0 4px 4px 0; + padding: 8px 12px; + margin-bottom: 8px; + overflow-x: auto; + + pre { + margin: 0; + font-size: 11px; + line-height: 1.4; + white-space: pre-wrap; + word-break: break-word; + max-height: 120px; + overflow-y: auto; + } +} + +.title-block { + font-size: 12px; + padding: 4px 0; + margin-bottom: 4px; +} + +.tables-block { + font-size: 12px; + padding: 4px 0; +} + +mark { + padding: 0 1px; + border-radius: 2px; +} + +.themeMixin({ + .badge { + background: @background-color-base; + color: @text-color-secondary; + } + + .badge.sql { + background: @green-1; + color: @green-7; + } + + .badge.python, .badge.pyspark { + background: @gold-1; + color: @gold-7; + } + + .badge.md { + background: @blue-1; + color: @blue-6; + } + + .code-block { + background: @background-color-light; + border: 1px solid @border-color-split; + + pre { + font-family: @code-family; + color: @text-color; + } + } + + .output-block { + background: @background-color-light; + border-left: 3px solid @border-color-base; + + pre { + font-family: @code-family; + color: @text-color-secondary; + } + } + + .title-block { + color: @text-color-secondary; + } + + .tables-block { + color: @green-7; + } + + mark { + background-color: @gold-1; + } +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts index 046a83c7c74..1c8e10545ed 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts @@ -10,23 +10,9 @@ * limitations under the License. */ -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - Input, - NgZone, - OnChanges, - OnDestroy, - SimpleChanges -} from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { NotebookSearchResultItem } from '@zeppelin/interfaces'; -import { JoinedEditorOptions } from '@zeppelin/share'; -import { getKeywordPositions, KeywordPosition } from '@zeppelin/utility'; -import { editor, Range } from 'monaco-editor'; -import IEditor = editor.IEditor; -import IStandaloneCodeEditor = editor.IStandaloneCodeEditor; @Component({ selector: 'zeppelin-notebook-search-result-item', @@ -34,40 +20,39 @@ import IStandaloneCodeEditor = editor.IStandaloneCodeEditor; styleUrls: ['./result-item.component.less'], changeDetection: ChangeDetectionStrategy.OnPush }) -export class NotebookSearchResultItemComponent implements OnChanges, OnDestroy { +export class NotebookSearchResultItemComponent implements OnChanges { @Input() result!: NotebookSearchResultItem; queryParams = {}; displayName = ''; routerLink: string[] = []; - mergedStr?: string; - keywords: string[] = []; - highlightPositions: KeywordPosition[] = []; - editor?: IStandaloneCodeEditor; - height = 0; - decorations: string[] = []; - editorOption = { - readOnly: true, - fontSize: 12, - renderLineHighlight: 'none', - minimap: { enabled: false }, - lineNumbers: 'off', - glyphMargin: false, - scrollBeyondLastLine: false, - contextmenu: false, - scrollbar: { - handleMouseWheel: false, - alwaysConsumeMouseWheel: false - } - } as JoinedEditorOptions; + codeText = ''; + codeHtml = ''; + outputText = ''; + tablesText = ''; + titleHtml = ''; + interpreter = ''; constructor( - private ngZone: NgZone, - private cdr: ChangeDetectorRef, - private router: ActivatedRoute + private route: ActivatedRoute, + private router: Router ) {} - setDisplayNameAndRouterLink(): void { - const term = this.router.snapshot.params.queryStr; + ngOnChanges(changes: SimpleChanges): void { + if (changes.result) { + this.parseResult(); + } + } + + navigateToResult(): void { + const selection = window.getSelection(); + if (selection && selection.toString().length > 0) { + return; + } + this.router.navigate(this.routerLink, { queryParams: this.queryParams }); + } + + private parseResult(): void { + const term = this.route.snapshot.params.queryStr; const listOfId = this.result.id.split('/'); const [noteId, hasParagraph, paragraph] = listOfId; if (!hasParagraph) { @@ -75,110 +60,68 @@ export class NotebookSearchResultItemComponent implements OnChanges, OnDestroy { this.queryParams = {}; } else { this.routerLink = ['/', 'notebook', noteId]; - this.queryParams = { - paragraph, - term - }; + this.queryParams = { paragraph, term }; } this.displayName = this.result.name ? this.result.name : `Note ${noteId}`; - } - setHighlightKeyword(): void { - let mergedStr = this.result.header ? `${this.result.header}\n\n${this.result.snippet}` : this.result.snippet; + const snippet = this.result.snippet || ''; + // HTML-escape first so raw '<' in code (e.g. WHERE id < 100) is not parsed + // as a DOM tag, then promote only the Lucene markers to . + this.codeHtml = this.highlightToMark(snippet); + this.codeText = snippet.replace(/<\/?B>/gi, ''); + this.interpreter = this.detectInterpreter(this.codeText); - const regexp = /(.+?)<\/B>/g; - const matches = []; - let match = regexp.exec(mergedStr); + const title = this.result.title || ''; + this.titleHtml = this.highlightToMark(title); - while (match !== null) { - if (match[1]) { - matches.push(match[1].toLocaleLowerCase()); - } - match = regexp.exec(mergedStr); - } - - mergedStr = mergedStr.replace(regexp, '$1'); - this.mergedStr = mergedStr; - const keywords = [...new Set(matches)]; - this.highlightPositions = getKeywordPositions(keywords, mergedStr); + const tables = this.result.tables || ''; + this.tablesText = tables + .trim() + .split(/\s+/) + .filter(t => t) + .join(', '); + this.outputText = this.result.output || ''; } - applyHighlight() { - if (this.editor) { - this.decorations = this.editor.deltaDecorations( - this.decorations, - this.highlightPositions.map(highlight => { - const line = highlight.line + 1; - const character = highlight.character + 1; - return { - range: new Range(line, character, line, character + highlight.length), - options: { - className: 'mark', - stickiness: 1 - } - }; - }) - ); - this.cdr.markForCheck(); - } + private highlightToMark(text: string): string { + // Escape HTML so raw '<' in source (e.g. WHERE id < 100) is not parsed as + // a DOM tag, then convert the Lucene /<\/B> markers back to . + return text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/<B>/gi, '') + .replace(/<\/B>/gi, ''); } - setLanguage() { - const model = this.editor?.getModel(); - if (!model) { - throw new Error('Editor model is not defined.'); + private detectInterpreter(text: string): string { + if (!text) { + return ''; } - const editorModes = { - scala: /^%(\w*\.)?(spark|flink)/, - python: /^%(\w*\.)?(pyspark|python)/, - html: /^%(\w*\.)?(angular|ng)/, - r: /^%(\w*\.)?(r|sparkr|knitr)/, - sql: /^%(\w*\.)?\wql/, - yaml: /^%(\w*\.)?\wconf/, - markdown: /^%md/, - shell: /^%sh/ - }; - let mode = 'text'; - for (const [modeOption, regex] of Object.entries(editorModes)) { - if (regex.test(this.result.snippet)) { - mode = modeOption; - break; - } + // Check interpreter prefix first — this is reliable + if (/^%(\w*\.)?sql/i.test(text)) { + return 'sql'; } - editor.setModelLanguage(model, mode); - } - - autoAdjustEditorHeight() { - this.ngZone.run(() => { - setTimeout(() => { - const model = this.editor?.getModel(); - if (model) { - this.height = this.editor!.getOption(monaco.editor.EditorOption.lineHeight) * (model.getLineCount() + 2); - this.editor!.layout(); - this.cdr.markForCheck(); - } - }); - }); - } - - initializedEditor(editorInstance: IEditor) { - this.editor = editorInstance as IStandaloneCodeEditor; - this.editor.setValue(this.mergedStr ?? ''); - this.setLanguage(); - this.autoAdjustEditorHeight(); - this.applyHighlight(); - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes.result) { - this.setDisplayNameAndRouterLink(); - this.setHighlightKeyword(); - this.autoAdjustEditorHeight(); - this.applyHighlight(); + if (/^%(\w*\.)?py/i.test(text)) { + return 'python'; } - } - - ngOnDestroy(): void { - this.editor?.dispose(); + if (/^%md/i.test(text)) { + return 'md'; + } + if (/^%sh/i.test(text)) { + return 'sh'; + } + // Fall back to conservative heuristics only if no prefix present. + // Require SELECT ... FROM pattern to avoid false positives from Python + // "from ... import" or markdown containing words like "create". + if (!text.startsWith('%')) { + if (/\bSELECT\b/i.test(text) && /\bFROM\b/i.test(text)) { + return 'sql'; + } + if (/^(import |from \w+ import |def |class )/m.test(text)) { + return 'python'; + } + } + return ''; } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index ff73912d182..6656945188a 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -23,7 +23,7 @@ import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { isNil } from 'lodash'; import { Subject } from 'rxjs'; -import { distinctUntilKeyChanged, map, startWith, takeUntil } from 'rxjs/operators'; +import { distinctUntilKeyChanged, startWith, takeUntil } from 'rxjs/operators'; import { NzResizeEvent } from 'ng-zorro-antd/resizable'; @@ -422,14 +422,12 @@ export class NotebookComponent extends MessageListenersManager implements OnInit ngOnInit() { this.activatedRoute.queryParamMap - .pipe( - startWith(this.activatedRoute.snapshot.queryParamMap), - takeUntil(this.destroy$), - map(data => data.get('paragraph')) - ) - .subscribe(id => { + .pipe(startWith(this.activatedRoute.snapshot.queryParamMap), takeUntil(this.destroy$)) + .subscribe(params => { + const id = params.get('paragraph'); this.onParagraphSelect(id); this.onParagraphScrolled(id); + this.onParagraphSearch(params.get('term') || ''); }); this.activatedRoute.params.pipe(takeUntil(this.destroy$), distinctUntilKeyChanged('noteId')).subscribe(() => { this.noteVarShareService.clear(); diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html index d77aa12df72..c9d3246ee8d 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.html +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -78,8 +78,18 @@
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts b/zeppelin-web-angular/src/app/share/header/header.component.ts index 5dbb14f9b33..2692cb648d8 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.ts +++ b/zeppelin-web-angular/src/app/share/header/header.component.ts @@ -34,6 +34,9 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, noteListVisible = false; queryStr: string | null = null; classicUiHref: string; + searchHistory: string[] = []; + private static readonly HISTORY_KEY = 'zeppelin.search.history'; + private static readonly MAX_HISTORY = 20; about() { this.nzModalService.create({ @@ -54,10 +57,20 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, } this.queryStr = this.queryStr.trim(); if (this.queryStr) { + this.addToHistory(this.queryStr); this.router.navigate(['/search', this.queryStr]); } } + private addToHistory(term: string): void { + this.searchHistory = this.searchHistory.filter(h => h !== term); + this.searchHistory.unshift(term); + if (this.searchHistory.length > HeaderComponent.MAX_HISTORY) { + this.searchHistory = this.searchHistory.slice(0, HeaderComponent.MAX_HISTORY); + } + localStorage.setItem(HeaderComponent.HISTORY_KEY, JSON.stringify(this.searchHistory)); + } + @MessageListener(OP.CONFIGURATIONS_INFO) getConfiguration(data: MessageReceiveDataTypeMap[OP.CONFIGURATIONS_INFO]) { this.ticketService.setConfiguration(data); @@ -76,6 +89,11 @@ export class HeaderComponent extends MessageListenersManager implements OnInit, } ngOnInit() { + try { + this.searchHistory = JSON.parse(localStorage.getItem(HeaderComponent.HISTORY_KEY) || '[]'); + } catch { + this.searchHistory = []; + } this.messageService.listConfigurations(); this.messageService.connectedStatus$.pipe(takeUntil(this.destroy$)).subscribe(status => { this.connectStatus = status ? 'success' : 'error'; diff --git a/zeppelin-web/src/app/search/result-list.controller.js b/zeppelin-web/src/app/search/result-list.controller.js index 65c10b1f7bf..ea830936e0a 100644 --- a/zeppelin-web/src/app/search/result-list.controller.js +++ b/zeppelin-web/src/app/search/result-list.controller.js @@ -21,24 +21,73 @@ function SearchResultCtrl($scope, $routeParams, searchService) { $scope.searchTerm = $routeParams.searchTerm; let results = searchService.search({'q': $routeParams.searchTerm}).query(); + function detectLang(text) { + if (!text) { + return ''; + } + // Check interpreter prefix first — this is reliable + if (/^%(\w*\.)?sql/i.test(text)) { + return 'sql'; + } + if (/^%(\w*\.)?py/i.test(text)) { + return 'python'; + } + if (/^%md/i.test(text)) { + return 'md'; + } + if (/^%sh/i.test(text)) { + return 'sh'; + } + // Fall back to conservative heuristics only if no prefix present. + // Require SELECT ... FROM pattern to avoid false positives from Python + // "from ... import" or markdown containing words like "create". + if (!text.startsWith('%')) { + if (/\bSELECT\b/i.test(text) && /\bFROM\b/i.test(text)) { + return 'sql'; + } + if (/^(import |from \w+ import |def |class )/m.test(text)) { + return 'python'; + } + } + return ''; + } + + // HTML-escape raw text so '<' in source (e.g. WHERE id < 100) is not parsed + // as a DOM tag, then promote only the Lucene /<\/B> markers to . + function highlightToMark(text) { + return text + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/<B>/gi, '') + .replace(/<\/B>/gi, ''); + } + results.$promise.then(function(result) { $scope.notes = result.body.map(function(note) { - // redirect to notebook when search result is a notebook itself, - // not a paragraph if (!/\/paragraph\//.test(note.id)) { return note; } - note.id = note.id.replace('paragraph/', '?paragraph=') + '&term=' + $routeParams.searchTerm; + let code = (note.snippet || '').replace(//g, '').replace(/<\/B>/g, ''); + + let tables = (note.tables || '').trim().split(/\s+/).filter(function(t) { + return t; + }).join(', '); + + note.codeText = code; + note.codeHtml = highlightToMark(note.snippet || ''); + note.titleHtml = highlightToMark(note.title || ''); + note.outputText = note.output || ''; + note.tablesText = tables; + note.langBadge = detectLang(code); + return note; }); - if ($scope.notes.length === 0) { - $scope.isResult = false; - } else { - $scope.isResult = true; - } + + $scope.isResult = $scope.notes.length > 0; $scope.$on('$routeChangeStart', function(event, next, current) { if (next.originalPath !== '/search/:searchTerm') { @@ -46,111 +95,4 @@ function SearchResultCtrl($scope, $routeParams, searchService) { } }); }); - - $scope.page = 0; - $scope.allResults = false; - - $scope.highlightSearchResults = function(note) { - return function(_editor) { - function getEditorMode(text) { - let editorModes = { - 'ace/mode/scala': /^%(\w*\.)?spark/, - 'ace/mode/python': /^%(\w*\.)?(pyspark|python)/, - 'ace/mode/r': /^%(\w*\.)?(r|sparkr|knitr)/, - 'ace/mode/sql': /^%(\w*\.)?\wql/, - 'ace/mode/markdown': /^%md/, - 'ace/mode/sh': /^%sh/, - }; - - return Object.keys(editorModes).reduce(function(res, mode) { - return editorModes[mode].test(text) ? mode : res; - }, 'ace/mode/scala'); - } - - let Range = ace.require('ace/range').Range; - - _editor.setOption('highlightActiveLine', false); - _editor.$blockScrolling = Infinity; - _editor.setReadOnly(true); - _editor.renderer.setShowGutter(false); - _editor.setTheme('ace/theme/chrome'); - _editor.getSession().setMode(getEditorMode(note.text)); - - function getIndeces(term) { - return function(str) { - let indeces = []; - let i = -1; - while ((i = str.indexOf(term, i + 1)) >= 0) { - indeces.push(i); - } - return indeces; - }; - } - - let result = ''; - if (note.header !== '') { - result = note.header + '\n\n' + note.snippet; - } else { - result = note.snippet; - } - - let lines = result - .split('\n') - .map(function(line, row) { - let match = line.match(/(.+?)<\/B>/); - - // return early if nothing to highlight - if (!match) { - return line; - } - - let term = match[1]; - let __line = line - .replace(//g, '') - .replace(/<\/B>/g, ''); - - let indeces = getIndeces(term)(__line); - - indeces.forEach(function(start) { - let end = start + term.length; - if (note.header !== '' && row === 0) { - _editor - .getSession() - .addMarker( - new Range(row, 0, row, line.length), - 'search-results-highlight-header', - 'background' - ); - _editor - .getSession() - .addMarker( - new Range(row, start, row, end), - 'search-results-highlight', - 'line' - ); - } else { - _editor - .getSession() - .addMarker( - new Range(row, start, row, end), - 'search-results-highlight', - 'line' - ); - } - }); - return __line; - }); - - // resize editor based on content length - _editor.setOption( - 'maxLines', - lines.reduce(function(len, line) { - return len + line.length; - }, 0) - ); - - _editor.getSession().setValue(lines.join('\n')); - note.searchResult = lines; - }; - }; } diff --git a/zeppelin-web/src/app/search/result-list.html b/zeppelin-web/src/app/search/result-list.html index 804fc16724a..7f617a08f39 100644 --- a/zeppelin-web/src/app/search/result-list.html +++ b/zeppelin-web/src/app/search/result-list.html @@ -13,34 +13,32 @@ -->
-
-
- We couldn’t find any notebook matching '{{searchTerm}}' + We couldn't find any notebook matching '{{searchTerm}}'
diff --git a/zeppelin-web/src/app/search/search.css b/zeppelin-web/src/app/search/search.css index 90a7a3f41d6..9b5ceb1cf54 100644 --- a/zeppelin-web/src/app/search/search.css +++ b/zeppelin-web/src/app/search/search.css @@ -49,3 +49,64 @@ text-align: center; background-color: #f4f6f8; } + +.search-result-container { + margin: 0 auto; + float: none; +} + +.search-result-list { + list-style: none; + padding: 0; +} + +.search-result-heading { + margin: 0; + display: flex; + align-items: center; + gap: 8px; +} + +.search-result-heading .icon-doc { + font-size: 10px; +} + +.search-result-body { + padding: 0; +} + +.search-result-title { + padding: 4px 12px; + font-size: 12px; + color: #777; +} + +.search-result-code { + margin: 0; + border: none; + border-radius: 0; + background: #f8f9fa; + border-bottom: 1px solid #eee; + max-height: 200px; + overflow: auto; + font-size: 12px; +} + +.search-result-output { + margin: 0; + border: none; + border-radius: 0; + background: #fafbfc; + border-left: 3px solid #ddd; + color: #666; + max-height: 120px; + overflow: auto; + font-size: 11px; + padding: 8px 12px; +} + +.search-result-tables { + padding: 6px 12px; + font-size: 12px; + color: #3c763d; +} From 1893e11282400e1d0e5be1f89ef2a93a025026f2 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Wed, 3 Jun 2026 01:00:13 +0900 Subject: [PATCH 044/179] [ZEPPELIN-6424] Upgrade zeppelin-web-angular from Angular 13 to Angular 21 ### What is this PR for? `zeppelin-web-angular` was on Angular 13 (end-of-life). This upgrades it to Angular 21 (latest), one major version at a time so each step stays small and reviewable. The production build, lint, and dev-server are green at every bump. Included: - Angular 13 to 21 (framework, CLI, CDK), bumped lock-step one major at a time - ng-zorro-antd to 21, adapting to its breaking changes (moved/removed entry points, checkbox / input-number / modal API changes, native CSS animations) - Pinned Node 18 to 22 (npm 8 to 10) for the frontend-maven-plugin and `engines` - ESLint 8 (eslintrc) to ESLint 9 (flat config) - Adopt required modern Angular APIs: built-in control flow (`if/for/switch`), `provideHttpClient`, explicit zone change detection, `standalone: false` on NgModule declarations, RxJS 7 typing No intended functional or UI changes. This is a framework and tooling upgrade only. Commits are grouped per major version (and per concern within a version) so the PR can be reviewed commit by commit. ### What type of PR is it? Improvement ### Todos * [ ] Reviewer: manual smoke test of notebook / interpreter / job-manager / credential / theme toggle ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6424 ### How should this be tested? * `cd zeppelin-web-angular && npm ci` * Production build: `npm run build:angular` (passes) * Lint: `npm run lint` (passes) * Dev server: `npm start`, then click through the main screens to confirm they still work: open and run notebook paragraphs (all result types), the interpreter page, job manager, credentials, header dropdowns, and the dark/light theme toggle. ### Screenshots (if appropriate) N/A (no intended UI changes). ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5260 from tbonelee/upgrade/angular-21. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/.eslintrc.json | 139 - zeppelin-web-angular/.nvmrc | 2 +- zeppelin-web-angular/angular.json | 20 +- .../e2e/models/header-page.ts | 21 + .../workspace/user-menu-navigation.spec.ts | 64 + zeppelin-web-angular/eslint.config.js | 150 + zeppelin-web-angular/package-lock.json | 43540 ++++++---------- zeppelin-web-angular/package.json | 65 +- zeppelin-web-angular/pom.xml | 4 +- .../projects/zeppelin-sdk/.eslintrc.json | 35 - .../projects/zeppelin-sdk/src/message.ts | 2 +- .../projects/zeppelin-sdk/tsconfig.json | 3 +- .../zeppelin-visualization/.eslintrc.json | 35 - .../src/g2-visualization-component-base.ts | 5 +- .../src/visualization-component-portal.ts | 16 +- .../zeppelin-visualization/tsconfig.json | 3 +- .../src/app/app-runtime-compiler.providers.ts | 1 - .../src/app/app.component.html | 28 +- zeppelin-web-angular/src/app/app.component.ts | 3 +- zeppelin-web-angular/src/app/app.module.ts | 20 +- .../core/copy-text/copy-text-to-clipboard.ts | 2 +- .../destroy-hook/destroy-hook.component.ts | 7 +- .../core/message-listener/message-listener.ts | 5 +- .../ng-zorro-antd-module.ts | 12 +- .../src/app/key-binding/key-binder.ts | 4 +- ...tebook-paragraph-keyboard-event-handler.ts | 2 + .../src/app/pages/login/login.component.ts | 3 +- .../src/app/pages/login/login.guard.ts | 4 +- .../configuration.component.html | 30 +- .../configuration/configuration.component.ts | 3 +- .../credential/credential.component.html | 185 +- .../credential/credential.component.less | 9 + .../credential/credential.component.ts | 29 +- .../workspace/credential/credential.module.ts | 8 +- .../pages/workspace/home/home.component.ts | 3 +- .../app/pages/workspace/home/home.module.ts | 4 +- .../create-repository-modal.component.ts | 9 +- .../interpreter/interpreter.component.html | 79 +- .../interpreter/interpreter.component.less | 11 +- .../interpreter/interpreter.component.ts | 6 +- .../interpreter/interpreter.module.ts | 8 +- .../interpreter/item/item.component.html | 556 +- .../interpreter/item/item.component.ts | 23 +- .../job-manager/job-manager.component.html | 77 +- .../job-manager/job-manager.component.ts | 9 +- .../job-manager/job-manager.module.ts | 8 +- .../job-status/job-status.component.ts | 3 +- .../job-manager/job/job.component.html | 64 +- .../job-manager/job/job.component.ts | 3 +- .../notebook-repos/item/item.component.html | 93 +- .../notebook-repos/item/item.component.ts | 13 +- .../notebook-repos.component.html | 28 +- .../notebook-repos.component.ts | 3 +- .../notebook-search.component.html | 39 +- .../notebook-search.component.ts | 5 +- .../result-item/result-item.component.ts | 3 +- .../action-bar/action-bar.component.html | 505 +- .../action-bar/action-bar.component.less | 4 +- .../action-bar/action-bar.component.ts | 5 +- .../add-paragraph/add-paragraph.component.ts | 3 +- .../interpreter-binding.component.html | 72 +- .../interpreter-binding.component.ts | 3 +- .../note-form-block.component.ts | 3 +- .../notebook/notebook.component.html | 205 +- .../workspace/notebook/notebook.component.ts | 5 +- .../workspace/notebook/notebook.module.ts | 10 +- .../code-editor/code-editor.component.ts | 3 +- .../paragraph/control/control.component.html | 150 +- .../paragraph/control/control.component.ts | 3 +- .../paragraph/footer/footer.component.html | 28 +- .../paragraph/footer/footer.component.ts | 3 +- .../paragraph/paragraph.component.html | 254 +- .../notebook/paragraph/paragraph.component.ts | 5 +- .../paragraph/progress/progress.component.ts | 3 +- .../permissions/permissions.component.html | 76 +- .../permissions/permissions.component.ts | 3 +- .../revisions-comparator.component.html | 179 +- .../revisions-comparator.component.ts | 3 +- .../elastic-input.component.html | 45 +- .../elastic-input/elastic-input.component.ts | 3 +- .../notebook/sidebar/sidebar.component.html | 42 +- .../notebook/sidebar/sidebar.component.ts | 3 +- .../paragraph/paragraph.component.html | 70 +- .../paragraph/paragraph.component.ts | 3 +- .../dynamic-forms.component.html | 120 +- .../dynamic-forms/dynamic-forms.component.ts | 39 +- .../share/result/result.component.html | 207 +- .../share/result/result.component.ts | 5 +- .../app/pages/workspace/share/share.module.ts | 8 +- .../pages/workspace/workspace.component.html | 24 +- .../pages/workspace/workspace.component.ts | 5 +- .../app/pages/workspace/workspace.guard.ts | 4 +- .../app/pages/workspace/workspace.module.ts | 14 +- .../services/classic-visualization.service.ts | 5 +- .../src/app/services/configuration.service.ts | 4 +- .../src/app/services/shortcut.service.ts | 5 +- .../about-zeppelin.component.ts | 3 +- .../code-editor/code-editor.component.html | 36 +- .../code-editor/code-editor.component.ts | 3 +- .../share/code-editor/code-editor.service.ts | 3 +- .../external-links/external-link.directive.ts | 3 +- .../folder-rename.component.html | 32 +- .../folder-rename/folder-rename.component.ts | 19 +- .../app/share/header/header.component.html | 100 +- .../app/share/header/header.component.less | 27 + .../src/app/share/header/header.component.ts | 5 +- .../app/share/math-jax/math-jax.directive.ts | 3 +- .../share/node-list/node-list.component.html | 245 +- .../share/node-list/node-list.component.ts | 3 +- .../share/node-list/note-action.service.ts | 6 +- .../note-create/note-create.component.html | 64 +- .../note-create/note-create.component.ts | 16 +- .../note-import/note-import.component.html | 28 +- .../note-import/note-import.component.ts | 5 +- .../note-rename/note-rename.component.ts | 19 +- .../share/note-toc/note-toc.component.html | 42 +- .../app/share/note-toc/note-toc.component.ts | 3 +- .../page-header/page-header.component.html | 24 +- .../page-header/page-header.component.ts | 3 +- .../app/share/pipes/humanize-bytes.pipe.ts | 3 +- .../resize-handle/resize-handle.component.ts | 3 +- .../run-scripts/run-scripts.directive.ts | 3 +- .../src/app/share/share.module.ts | 8 +- .../app/share/shortcut/shortcut.component.ts | 3 +- .../src/app/share/spin/spin.component.ts | 3 +- .../theme-toggle/theme-toggle.component.ts | 5 +- .../src/app/spell/spell-result.ts | 2 +- .../area-chart-visualization.component.ts | 3 +- .../bar-chart-visualization.component.ts | 3 +- .../pivot-setting.component.html | 93 +- .../pivot-setting/pivot-setting.component.ts | 3 +- .../scatter-setting.component.html | 92 +- .../scatter-setting.component.ts | 3 +- .../x-axis-setting.component.html | 48 +- .../x-axis-setting.component.ts | 3 +- .../line-chart-visualization.component.html | 47 +- .../line-chart-visualization.component.ts | 3 +- .../pie-chart-visualization.component.ts | 3 +- .../scatter-chart-visualization.component.ts | 3 +- .../table/table-visualization.component.html | 192 +- .../table/table-visualization.component.ts | 3 +- .../columnselector_settings.html | 14 +- .../pivot_settings.html | 50 +- zeppelin-web-angular/src/main.ts | 4 +- .../src/styles/theme/dark-theme-overrides.css | 5 - .../src/styles/theme/dark/theme-dark.less | 38 +- .../src/styles/theme/light/theme-light.less | 38 +- zeppelin-web-angular/tsconfig.base.json | 4 +- zeppelin-web-angular/webpack.config.js | 69 +- 149 files changed, 19690 insertions(+), 29390 deletions(-) delete mode 100644 zeppelin-web-angular/.eslintrc.json create mode 100644 zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts create mode 100644 zeppelin-web-angular/eslint.config.js delete mode 100644 zeppelin-web-angular/projects/zeppelin-sdk/.eslintrc.json delete mode 100644 zeppelin-web-angular/projects/zeppelin-visualization/.eslintrc.json diff --git a/zeppelin-web-angular/.eslintrc.json b/zeppelin-web-angular/.eslintrc.json deleted file mode 100644 index 50793bb947c..00000000000 --- a/zeppelin-web-angular/.eslintrc.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "extends": ["prettier"], - "root": true, - "ignorePatterns": ["node_modules/**/*", "projects/**/*"], - "overrides": [ - { - "files": ["*.ts"], - "parserOptions": { - "project": true, - "createDefaultProgram": true - }, - "extends": [ - "plugin:@angular-eslint/ng-cli-compat", - "plugin:@angular-eslint/ng-cli-compat--formatting-add-on", - "plugin:@angular-eslint/template/process-inline-templates" - ], - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "type": ["element", "attribute"], - "prefix": ["zeppelin"], - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": ["zeppelin"], - "style": "kebab-case" - } - ], - "@angular-eslint/no-forward-ref": "off", - "@angular-eslint/prefer-output-readonly": "error", - "@typescript-eslint/adjacent-overload-signatures": "off", - "@typescript-eslint/array-type": "off", - "@typescript-eslint/ban-tslint-comment": "off", - "@typescript-eslint/class-literal-property-style": "off", - "@typescript-eslint/consistent-generic-constructors": "off", - "@typescript-eslint/consistent-indexed-object-style": "off", - "@typescript-eslint/consistent-type-assertions": "off", - "@typescript-eslint/consistent-type-definitions": "off", - "@typescript-eslint/no-confusing-non-null-assertion": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/prefer-for-of": "off", - "@typescript-eslint/prefer-function-type": "off", - "@typescript-eslint/member-delimiter-style": "off", - "@typescript-eslint/semi": "off", - "@typescript-eslint/type-annotation-spacing": "off", - "@typescript-eslint/ban-types": [ - "error", - { - "types": { - "Object": { - "message": "Use {} instead." - }, - "String": { - "message": "Use string instead." - }, - "Number": { - "message": "Use number instead." - }, - "Boolean": { - "message": "Use boolean instead." - }, - "Function": { - "message": "Use specific callable interface instead." - } - } - } - ], - "@typescript-eslint/member-ordering": "warn", - "@typescript-eslint/explicit-member-accessibility": [ - "off", - { - "accessibility": "explicit" - } - ], - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-floating-promises": "off", - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-this-alias": "error", - "@typescript-eslint/no-unused-vars": [ - "error", - { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_" - } - ], - "@typescript-eslint/quotes": "off", - "eol-last": "off", - "import/no-cycle": "error", - "import/no-deprecated": "off", - "import/no-unassigned-import": "error", - "import/order": "error", - "jsdoc/newline-after-description": "off", - "max-len": "off", - "new-parens": "off", - "no-bitwise": "off", - "no-duplicate-imports": "error", - "no-invalid-this": "error", - "no-irregular-whitespace": "error", - "no-magic-numbers": "off", - "no-param-reassign": "error", - "no-redeclare": "error", - "no-sparse-arrays": "error", - "no-template-curly-in-string": "error", - "no-trailing-spaces": "off", - "no-underscore-dangle": "off", - "prefer-arrow/prefer-arrow-functions": "warn", - "prefer-object-spread": "error", - "prefer-template": "error", - "quote-props": "off", - "space-before-function-paren": "off", - "yoda": "error" - } - }, - { - "files": ["*.js"], - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "env": { - "node": true, - "es6": true - } - }, - { - "files": ["*.html"], - "extends": ["plugin:@angular-eslint/template/recommended"], - "rules": {} - } - ] -} diff --git a/zeppelin-web-angular/.nvmrc b/zeppelin-web-angular/.nvmrc index 4851dc7197a..5ed27e77578 100644 --- a/zeppelin-web-angular/.nvmrc +++ b/zeppelin-web-angular/.nvmrc @@ -8,4 +8,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -18.20.8 +22.21.1 diff --git a/zeppelin-web-angular/angular.json b/zeppelin-web-angular/angular.json index dbd234a7ff7..089cc07ce6b 100644 --- a/zeppelin-web-angular/angular.json +++ b/zeppelin-web-angular/angular.json @@ -126,7 +126,7 @@ "serve": { "builder": "@angular-builders/custom-webpack:dev-server", "options": { - "browserTarget": "zeppelin:build", + "buildTarget": "zeppelin:build", "port": 4200, "host": "localhost", "liveReload": true, @@ -134,10 +134,10 @@ }, "configurations": { "production": { - "browserTarget": "zeppelin:build:production" + "buildTarget": "zeppelin:build:production" }, "development": { - "browserTarget": "zeppelin:build:development" + "buildTarget": "zeppelin:build:development" } }, "defaultConfiguration": "development" @@ -145,7 +145,7 @@ "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "zeppelin:build" + "buildTarget": "zeppelin:build" } }, "lint": { @@ -199,8 +199,16 @@ } } }, - "defaultProject": "zeppelin", "cli": { - "defaultCollection": "@angular-eslint/schematics" + "schematicCollections": ["@angular-eslint/schematics"], + "analytics": false + }, + "schematics": { + "@angular-eslint/schematics:application": { + "setParserOptionsProject": true + }, + "@angular-eslint/schematics:library": { + "setParserOptionsProject": true + } } } diff --git a/zeppelin-web-angular/e2e/models/header-page.ts b/zeppelin-web-angular/e2e/models/header-page.ts index 2f5c1c496fc..0a17045eecb 100644 --- a/zeppelin-web-angular/e2e/models/header-page.ts +++ b/zeppelin-web-angular/e2e/models/header-page.ts @@ -101,6 +101,27 @@ export class HeaderPage extends BasePage { await this.userMenuItems.configuration.click(); } + /** The
  • row for a user-menu entry, scoped to this dropdown's overlay. */ + getUserMenuItemRow(label: string): Locator { + return this.page.locator('.zeppelin-user-menu .ant-dropdown-menu-item').filter({ hasText: label }); + } + + /** + * Click the empty padding area near the right edge of a user-menu row, away from the + * link text. This is the dead zone that only navigates when the inner fills the + * whole row; clicking here regresses to "dropdown closes, no navigation" if the + * full-row click fix is missing. + */ + async clickUserMenuItemEdge(label: string): Promise { + const row = this.getUserMenuItemRow(label); + await row.waitFor({ state: 'visible', timeout: 10000 }); + const box = await row.boundingBox(); + if (!box) { + throw new Error(`User menu item "${label}" has no bounding box`); + } + await row.click({ position: { x: box.width - 8, y: box.height / 2 } }); + } + async getUsernameText(): Promise { return (await this.userBadge.textContent()) || ''; } diff --git a/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts new file mode 100644 index 00000000000..55adf20cf30 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts @@ -0,0 +1,64 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, test } from '@playwright/test'; +import { HeaderPage } from '../../models/header-page'; +import { performLoginIfRequired, waitForZeppelinReady } from '../../utils'; + +/** + * Regression guard for the header user-menu navigation. + * + * ng-zorro renders dropdown nz-menu-item content inside , + * but the upstream rule that stretches the inner across the whole item targets a + * different class (.ant-dropdown-menu-title-content). The class mismatch left the + * covering only its text, so clicking the row padding closed the dropdown without + * navigating. This was exposed by the Angular/ng-zorro 13 -> 17 upgrade and fixed by a + * scoped full-row click rule (nzOverlayClassName="zeppelin-user-menu" + ::ng-deep ::after). + * + * Each test deliberately clicks the EMPTY PADDING of the row (not the link text) so a + * future ng-zorro/Angular upgrade that reintroduces the dead zone fails here. + */ +const MENU_ITEMS = [ + { label: 'Interpreter', route: '/interpreter' }, + { label: 'Notebook Repos', route: '/notebook-repos' }, + { label: 'Credential', route: '/credential' }, + { label: 'Configuration', route: '/configuration' } +]; + +test.describe('Header user menu - full-row navigation', () => { + let header: HeaderPage; + + test.beforeEach(async ({ page }) => { + header = new HeaderPage(page); + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + }); + + for (const item of MENU_ITEMS) { + test(`navigates to ${item.label} when the row padding (not the text) is clicked`, async ({ page }) => { + await test.step('Given the user dropdown is open', async () => { + await header.clickUserDropdown(); + await header.getUserMenuItemRow(item.label).waitFor({ state: 'visible', timeout: 10000 }); + }); + + await test.step(`When I click the empty padding of the "${item.label}" row`, async () => { + await header.clickUserMenuItemEdge(item.label); + }); + + await test.step(`Then the app navigates to ${item.route}`, async () => { + await page.waitForURL(url => url.hash.includes(item.route), { timeout: 10000 }); + expect(page.url()).toContain(item.route); + }); + }); + } +}); diff --git a/zeppelin-web-angular/eslint.config.js b/zeppelin-web-angular/eslint.config.js new file mode 100644 index 00000000000..86f78bb57c1 --- /dev/null +++ b/zeppelin-web-angular/eslint.config.js @@ -0,0 +1,150 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ESLint 9 flat config (migrated from .eslintrc.json during the Angular 20 +// line). angular-eslint / typescript-eslint meta-packages provide the flat +// presets; the rule set below is a 1:1 port of the previous eslintrc rules. +const angular = require('angular-eslint'); +const tseslint = require('typescript-eslint'); +const importPlugin = require('eslint-plugin-import'); +const jsdoc = require('eslint-plugin-jsdoc'); +const preferArrow = require('eslint-plugin-prefer-arrow'); +const prettier = require('eslint-config-prettier'); + +module.exports = tseslint.config( + { + // Build output, vendored binaries and the React sub-app are never linted. + ignores: ['dist/**', 'target/**', '.angular/**', 'coverage/**', 'node/**', 'projects/zeppelin-react/**'] + }, + { + files: ['**/*.ts'], + // == legacy `plugin:@angular-eslint/recommended` (sets the TS parser and + // the @angular-eslint plugin). The @typescript-eslint plugin is registered + // separately below because tsRecommended does not bring it in. + extends: [...angular.configs.tsRecommended], + // == legacy `plugin:@angular-eslint/template/process-inline-templates` + processor: angular.processInlineTemplates, + languageOptions: { + parserOptions: { + project: true, + tsconfigRootDir: __dirname + } + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + import: importPlugin, + jsdoc, + 'prefer-arrow': preferArrow + }, + rules: { + '@angular-eslint/component-selector': [ + 'error', + { type: ['element', 'attribute'], prefix: ['zeppelin'], style: 'kebab-case' } + ], + '@angular-eslint/directive-selector': ['error', { type: 'attribute', prefix: ['zeppelin'], style: 'kebab-case' }], + '@angular-eslint/no-forward-ref': 'off', + + // OFF since the Angular 16 upgrade. Switching from the removed + // ng-cli-compat preset to @angular-eslint `recommended` turned this rule + // on, but the app keeps intentionally-empty lifecycle hooks as override + // placeholders; flagging them adds noise with no benefit. + '@angular-eslint/no-empty-lifecycle-method': 'off', + + // OFF since the Angular 19 upgrade. v19 flipped the `standalone` default + // to true, so `ng update` stamped `standalone: false` onto every + // NgModule-declared component/directive/pipe. This app is deliberately + // NgModule-based; prefer-standalone (added to the angular-eslint 19 + // recommended set) errors on exactly those declarations. Turning it on + // would force a full standalone migration -- a separate effort. + '@angular-eslint/prefer-standalone': 'off', + + // OFF since the Angular 20 upgrade. prefer-inject (added to the + // angular-eslint 20 recommended set) errors on every constructor-parameter + // injection (200+ across the app). Moving to the inject() function is a + // large, separate refactor, so the rule stays off for now. + '@angular-eslint/prefer-inject': 'off', + + '@angular-eslint/prefer-output-readonly': 'error', + '@typescript-eslint/adjacent-overload-signatures': 'off', + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/ban-tslint-comment': 'off', + '@typescript-eslint/class-literal-property-style': 'off', + '@typescript-eslint/consistent-generic-constructors': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/consistent-type-assertions': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-confusing-non-null-assertion': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-inferrable-types': 'off', + '@typescript-eslint/prefer-for-of': 'off', + '@typescript-eslint/prefer-function-type': 'off', + + // Replaced the removed `ban-types` rule during the Angular 19 upgrade + // (@typescript-eslint 8 split it into these). They keep the original + // intent -- ban the Object/String/Number/Boolean wrapper types and the + // unsafe `Function` type -- while still allowing `{}`, which ban-types + // had recommended as the alternative. + '@typescript-eslint/no-wrapper-object-types': 'error', + '@typescript-eslint/no-unsafe-function-type': 'error', + + '@typescript-eslint/member-ordering': 'warn', + '@typescript-eslint/explicit-member-accessibility': ['off', { accessibility: 'explicit' }], + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-for-in-array': 'error', + '@typescript-eslint/naming-convention': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-this-alias': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], + 'eol-last': 'off', + 'import/no-cycle': 'error', + 'import/no-deprecated': 'off', + 'import/no-unassigned-import': 'error', + 'import/order': 'error', + 'max-len': 'off', + 'new-parens': 'off', + 'no-bitwise': 'off', + 'no-duplicate-imports': 'error', + 'no-invalid-this': 'error', + 'no-irregular-whitespace': 'error', + 'no-magic-numbers': 'off', + 'no-param-reassign': 'error', + 'no-redeclare': 'error', + 'no-sparse-arrays': 'error', + 'no-template-curly-in-string': 'error', + 'no-trailing-spaces': 'off', + 'no-underscore-dangle': 'off', + 'prefer-arrow/prefer-arrow-functions': 'warn', + 'prefer-object-spread': 'error', + 'prefer-template': 'error', + 'quote-props': 'off', + 'space-before-function-paren': 'off', + yoda: 'error' + } + }, + { + // Library projects publish under the `lib` selector prefix, not `zeppelin`. + files: ['projects/zeppelin-sdk/**/*.ts', 'projects/zeppelin-visualization/**/*.ts'], + rules: { + '@angular-eslint/component-selector': ['error', { type: 'element', prefix: 'lib', style: 'kebab-case' }], + '@angular-eslint/directive-selector': ['error', { type: 'attribute', prefix: 'lib', style: 'camelCase' }] + } + }, + { + files: ['**/*.html'], + // == legacy `plugin:@angular-eslint/template/recommended` + extends: [...angular.configs.templateRecommended] + }, + // == legacy root `extends: ["prettier"]`; disables formatting rules that + // would conflict with Prettier. Last so it wins. + prettier +); diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index eee6621e538..d65d6296754 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -1,7 +1,7 @@ { "name": "zeppelin", "version": "0.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,17 +9,17 @@ "version": "0.0.0", "hasInstallScript": true, "dependencies": { - "@angular/animations": "~13.4.0", - "@angular/cdk": "~13.3.9", - "@angular/common": "~13.4.0", - "@angular/compiler": "~13.4.0", - "@angular/core": "~13.4.0", - "@angular/forms": "~13.4.0", - "@angular/platform-browser": "~13.4.0", - "@angular/platform-browser-dynamic": "~13.4.0", - "@angular/router": "~13.4.0", + "@angular/cdk": "^21.2.13", + "@angular/common": "^21.2.15", + "@angular/compiler": "^21.2.15", + "@angular/core": "^21.2.15", + "@angular/forms": "^21.2.15", + "@angular/platform-browser": "^21.2.15", + "@angular/platform-browser-dynamic": "^21.2.15", + "@angular/router": "^21.2.15", "@antv/data-set": "^0.10.2", "@antv/g2": "^3.5.4", + "@ctrl/tinycolor": "^3.6.1", "angular": "^1.8.2", "ansi_up": "^6.0.6", "core-js": "^2.5.4", @@ -32,28 +32,25 @@ "jquery-ui": "1.14.0", "lodash": "^4.17.21", "mathjax": "2.7.5", - "monaco-editor": "0.30.1", - "ng-zorro-antd": "^13.4.0", + "monaco-editor": "0.31.1", + "ng-zorro-antd": "^21.3.0", "nvd3": "1.8.6", "parse5": "^5.1.1", - "rxjs": "~6.5.3", + "rxjs": "~7.8.2", "systemjs": "^5.0.0", "tslib": "^2.0.0", "xlsx": "^0.14.3", - "zone.js": "~0.11.4" + "zone.js": "~0.15.1" }, "devDependencies": { - "@angular-architects/module-federation": "13.0.1", - "@angular-builders/custom-webpack": "13.1.0", - "@angular-devkit/build-angular": "^13.3.11", - "@angular-eslint/builder": "13.5.0", - "@angular-eslint/eslint-plugin": "13.5.0", - "@angular-eslint/eslint-plugin-template": "13.5.0", - "@angular-eslint/schematics": "13.5.0", - "@angular-eslint/template-parser": "13.5.0", - "@angular/cli": "~13.3.11", - "@angular/compiler-cli": "~13.4.0", - "@angular/language-service": "~13.4.0", + "@angular-architects/module-federation": "^21.2.2", + "@angular-builders/custom-webpack": "^21.0.3", + "@angular-devkit/build-angular": "^21.2.13", + "@angular-eslint/builder": "21.4.0", + "@angular-eslint/schematics": "21.4.0", + "@angular/cli": "^21.2.13", + "@angular/compiler-cli": "^21.2.15", + "@angular/language-service": "^21.2.15", "@playwright/test": "1.55.1", "@types/angular": "^1.8.0", "@types/diff-match-patch": "^1.0.36", @@ -64,12 +61,11 @@ "@types/node": "~12.19.16", "@types/parse5": "^5.0.2", "@types/webpack-env": "^1.18.8", - "@typescript-eslint/eslint-plugin": "5.62.0", - "@typescript-eslint/parser": "5.62.0", + "angular-eslint": "21.4.0", "concurrently": "9.2.1", "cross-env": "^10.1.0", "dotenv": "^17.2.3", - "eslint": "^8.57.1", + "eslint": "^9.28.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsdoc": "^50.8.0", @@ -77,101 +73,289 @@ "https-proxy-agent": "^2.2.1", "husky": "9.1.7", "lint-staged": "^15.5.2", - "monaco-editor-webpack-plugin": "6.0.0", - "ng-packagr": "^13.3.1", - "ngx-build-plus": "^13.0.1", + "monaco-editor-webpack-plugin": "7.0.1", + "ng-packagr": "^21.2.3", + "ngx-build-plus": "^20.0.0", "prettier": "^3.6.2", "scandirectory": "8.1.1", + "style-loader": "^4.0.0", "ts-node": "~7.0.0", - "typescript": "4.6.4" + "typescript": "~5.9.3", + "typescript-eslint": "^8.33.1" }, "engines": { - "node": ">=18.0.0 <19.0.0" + "node": ">=22.12.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "node_modules/@algolia/abtesting": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.1.tgz", + "integrity": "sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { - "node": ">=6.0.0" + "node": ">= 14.0.0" } }, - "node_modules/@angular-architects/module-federation": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@angular-architects/module-federation/-/module-federation-13.0.1.tgz", - "integrity": "sha512-NFf/UOsP/MjyzaqgDynVYvtoaBKogXTQNAVYGNra/dKwrr2O9gJ7njrjzUih5M2KuG6oJaOvl0D/Dop4PES1FQ==", + "node_modules/@algolia/client-abtesting": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.48.1.tgz", + "integrity": "sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-architects/module-federation-runtime": "^13.0.1", - "callsite": "^1.0.0", - "ngx-build-plus": "^13.0.0", - "node-fetch": "^2.6.1", - "rxjs": "~6.6.3", - "semver": "^7.3.5", - "word-wrap": "^1.2.3" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@angular-architects/module-federation-runtime": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@angular-architects/module-federation-runtime/-/module-federation-runtime-13.0.1.tgz", - "integrity": "sha512-lvXmdCN+/JJMDm3h+FlNPc+lwFgNC3/J7Dr5h6ZHXT6sGgelcUQPpGxO1QUiE87XmUG8/Gdo57CebS0TKCklyQ==", + "node_modules/@algolia/client-analytics": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.48.1.tgz", + "integrity": "sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg==", "dev": true, "license": "MIT", "dependencies": { - "tslib": "^2.0.0" + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, - "peerDependencies": { - "@angular/common": ">=12.0.0", - "@angular/core": ">=12.0.0" + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.48.1.tgz", + "integrity": "sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.48.1.tgz", + "integrity": "sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.48.1.tgz", + "integrity": "sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.48.1.tgz", + "integrity": "sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.48.1.tgz", + "integrity": "sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.48.1.tgz", + "integrity": "sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.48.1.tgz", + "integrity": "sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.48.1.tgz", + "integrity": "sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.48.1.tgz", + "integrity": "sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.48.1.tgz", + "integrity": "sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.48.1.tgz", + "integrity": "sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@angular-architects/module-federation/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "tslib": "^1.9.0" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "npm": ">=2.0.0" + "node": ">=6.0.0" } }, - "node_modules/@angular-architects/module-federation/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "node_modules/@angular-architects/module-federation": { + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@angular-architects/module-federation/-/module-federation-21.2.2.tgz", + "integrity": "sha512-aM6Oys+RGlUZ+GuVz1gx9LlJNMnb+niEtEsCQ3NmgoIMOZDBlfYnm+jbDO0F1TJWrTOBbAvfbKvJbLHfG25r8Q==", "dev": true, - "license": "0BSD" + "license": "MIT", + "dependencies": { + "@angular-architects/module-federation-runtime": "~21.2.2", + "callsite": "^1.0.0", + "node-fetch": "^3.3.2", + "semver": "~7.7.1", + "word-wrap": "^1.2.5" + } }, - "node_modules/@angular-builders/custom-webpack": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-13.1.0.tgz", - "integrity": "sha512-qhtnAv1i7agk14zeKZZfXjrckYt37OZ+3tsTBLhf3ZFbwREK8L1SNi8xhZ1j1JLGsf2Dp0GEcZrSYeFDweo0WA==", + "node_modules/@angular-architects/module-federation-runtime": { + "version": "21.2.2", + "resolved": "https://registry.npmjs.org/@angular-architects/module-federation-runtime/-/module-federation-runtime-21.2.2.tgz", + "integrity": "sha512-Akl6fLcD2dYXqxW4pLVgytq7NKQ998g4OUjEgcLQnhqyvlu+qdPRUfSDPlTGUiIY01/J2M9ZXcIWmUJJ5tOT5Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": ">=0.1300.0 < 0.1400.0", - "@angular-devkit/build-angular": "^13.0.0", - "@angular-devkit/core": "^13.0.0", - "lodash": "^4.17.15", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^21.2.0", + "@angular/core": "^21.2.0", + "@module-federation/enhanced": "^2.2.2", + "@module-federation/runtime-core": "^2.2.2" + } + }, + "node_modules/@angular-builders/common": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@angular-builders/common/-/common-5.0.3.tgz", + "integrity": "sha512-Dro3574mu4/xqmjdA3159+TXDhgTbIJpEY/iBETSKUvHJiCgHel+R3eT105RpHN5o7NaD2rau5Zk2wuZqOk35Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "^21.0.0", "ts-node": "^10.0.0", - "tsconfig-paths": "^3.9.0", - "webpack-merge": "^5.7.3" + "tsconfig-paths": "^4.2.0" }, "engines": { - "node": ">=12.20.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@angular-builders/custom-webpack/node_modules/diff": { + "node_modules/@angular-builders/common/node_modules/diff": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", @@ -181,7 +365,7 @@ "node": ">=0.3.1" } }, - "node_modules/@angular-builders/custom-webpack/node_modules/ts-node": { + "node_modules/@angular-builders/common/node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", @@ -225,7 +409,7 @@ } } }, - "node_modules/@angular-builders/custom-webpack/node_modules/yn": { + "node_modules/@angular-builders/common/node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", @@ -235,2388 +419,2686 @@ "node": ">=6" } }, - "node_modules/@angular-devkit/architect": { - "version": "0.1303.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.11.tgz", - "integrity": "sha512-JwrWomNqNGjAeKlqV2pimUFlCgFxQy+Vioz9+QAPIrUkvvjbkQ1dZKOe8Ul8eosb1N3Ln282U6qzOpHKfJ4TOg==", + "node_modules/@angular-builders/custom-webpack": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-21.0.3.tgz", + "integrity": "sha512-Aq3PZoQxY4jmfDb1sT5E6ZFAdiv35PziFmgYoW5DGX8xbYsV7EoKWZN2ZIjEI3Zr/WUZWGlxmxa11XK9WOtidg==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "rxjs": "6.6.7" + "@angular-builders/common": "5.0.3", + "@angular-devkit/architect": ">=0.2100.0 < 0.2200.0", + "@angular-devkit/build-angular": "^21.0.0", + "@angular-devkit/core": "^21.0.0", + "@angular/build": "^21.0.0", + "lodash": "^4.17.15", + "webpack-merge": "^6.0.0" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^21.0.0" } }, - "node_modules/@angular-devkit/architect/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@angular-builders/custom-webpack/node_modules/@angular/build": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.13.tgz", + "integrity": "sha512-Y9TDAaTQ+E5LScCKA/hPZmns/7Mpu6J2BiPj2cETA1xNjvgRpeb5Mh32KuhZb20NSFLvjpdnLuBTTtbym7hevw==", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/architect/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.3.11.tgz", - "integrity": "sha512-H4tpdmRu+6HSjsL+swV/8qj8v0YSDq6lpb31EYajlBB6fDj+YJQvHgaWvexSWl6eIqgDKXcujhNUjNi1enjwHw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1303.11", - "@angular-devkit/build-webpack": "0.1303.11", - "@angular-devkit/core": "13.3.11", - "@babel/core": "7.16.12", - "@babel/generator": "7.16.8", - "@babel/helper-annotate-as-pure": "7.16.7", - "@babel/plugin-proposal-async-generator-functions": "7.16.8", - "@babel/plugin-transform-async-to-generator": "7.16.8", - "@babel/plugin-transform-runtime": "7.16.10", - "@babel/preset-env": "7.16.11", - "@babel/runtime": "7.16.7", - "@babel/template": "7.16.7", - "@discoveryjs/json-ext": "0.5.6", - "@ngtools/webpack": "13.3.11", - "ansi-colors": "4.1.1", - "babel-loader": "8.2.5", - "babel-plugin-istanbul": "6.1.1", - "browserslist": "^4.9.1", - "cacache": "15.3.0", - "circular-dependency-plugin": "5.2.2", - "copy-webpack-plugin": "10.2.1", - "core-js": "3.20.3", - "critters": "0.0.16", - "css-loader": "6.5.1", - "esbuild-wasm": "0.14.22", - "glob": "7.2.0", - "https-proxy-agent": "5.0.0", - "inquirer": "8.2.0", - "jsonc-parser": "3.0.0", - "karma-source-map-support": "1.4.0", - "less": "4.1.2", - "less-loader": "10.2.0", - "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.1", - "mini-css-extract-plugin": "2.5.3", - "minimatch": "3.0.5", - "open": "8.4.0", - "ora": "5.4.1", - "parse5-html-rewriting-stream": "6.0.1", - "piscina": "3.2.0", - "postcss": "8.4.5", - "postcss-import": "14.0.2", - "postcss-loader": "6.2.1", - "postcss-preset-env": "7.2.3", - "regenerator-runtime": "0.13.9", - "resolve-url-loader": "5.0.0", - "rxjs": "6.6.7", - "sass": "1.49.9", - "sass-loader": "12.4.0", - "semver": "7.3.5", - "source-map-loader": "3.0.1", + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2102.13", + "@babel/core": "7.29.0", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@inquirer/confirm": "5.1.21", + "@vitejs/plugin-basic-ssl": "2.1.4", + "beasties": "0.4.1", + "browserslist": "^4.26.0", + "esbuild": "0.27.3", + "https-proxy-agent": "7.0.6", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "magic-string": "0.30.21", + "mrmime": "2.0.1", + "parse5-html-rewriting-stream": "8.0.0", + "picomatch": "4.0.4", + "piscina": "5.1.4", + "rolldown": "1.0.0-rc.4", + "sass": "1.97.3", + "semver": "7.7.4", "source-map-support": "0.5.21", - "stylus": "0.56.0", - "stylus-loader": "6.2.0", - "terser": "5.14.2", - "text-table": "0.2.0", - "tree-kill": "1.2.2", - "tslib": "2.3.1", - "webpack": "5.76.1", - "webpack-dev-middleware": "5.3.0", - "webpack-dev-server": "4.7.3", - "webpack-merge": "5.8.0", - "webpack-subresource-integrity": "5.1.0" + "tinyglobby": "0.2.15", + "undici": "7.24.4", + "vite": "7.3.2", + "watchpack": "2.5.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.14.22" + "lmdb": "3.5.1" }, "peerDependencies": { - "@angular/compiler-cli": "^13.0.0 || ^13.3.0-rc.0", - "@angular/localize": "^13.0.0 || ^13.3.0-rc.0", - "@angular/service-worker": "^13.0.0 || ^13.3.0-rc.0", - "karma": "^6.3.0", - "ng-packagr": "^13.0.0", - "protractor": "^7.0.0", - "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.4.3 <4.7" + "@angular/compiler": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.2.13", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^21.0.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.9 <6.0", + "vitest": "^4.0.8" }, "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, "@angular/localize": { "optional": true }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, "@angular/service-worker": { "optional": true }, + "@angular/ssr": { + "optional": true + }, "karma": { "optional": true }, + "less": { + "optional": true + }, "ng-packagr": { "optional": true }, - "protractor": { + "postcss": { "optional": true }, "tailwindcss": { "optional": true + }, + "vitest": { + "optional": true } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "node_modules/@angular-builders/custom-webpack/node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "node_modules/@angular-builders/custom-webpack/node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "node_modules/@angular-builders/custom-webpack/node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "node_modules/@angular-builders/custom-webpack/node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "undici-types": ">=7.24.0 <7.24.7" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "node_modules/@angular-builders/custom-webpack/node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", + "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "node_modules/@angular-builders/custom-webpack/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "license": "MIT", + "engines": { + "node": ">= 14" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "node_modules/@angular-builders/custom-webpack/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "node_modules/@angular-builders/custom-webpack/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "node_modules/@angular-builders/custom-webpack/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@angular-devkit/build-angular/node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "node_modules/@angular-builders/custom-webpack/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/@angular-devkit/build-angular/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/@angular-builders/custom-webpack/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "4" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 6.0.0" + "node": ">=8" } }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "node_modules/@angular-builders/custom-webpack/node_modules/undici": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", + "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/core-js": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, "engines": { - "node": ">= 6" + "node": ">=20.18.1" } }, - "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@angular-builders/custom-webpack/node_modules/vite": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^1.9.0" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">= 10.13.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@angular-devkit/build-angular/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/@angular-devkit/build-angular/node_modules/webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": ">=10.13.0" + "optionalDependencies": { + "fsevents": "~2.3.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "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": { - "webpack-cli": { + "@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 } } }, - "node_modules/@angular-devkit/build-webpack": { - "version": "0.1303.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1303.11.tgz", - "integrity": "sha512-599pWAQLq7i/fmEZLb7PaNU6nmPC3EZbJk1nU/UBcpx7FWs9e0o2XQE2PCAs0buqtQxVjSgY6kMO8ex5dUmgUQ==", + "node_modules/@angular-builders/custom-webpack/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1303.11", - "rxjs": "6.6.7" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "webpack": "^5.30.0", - "webpack-dev-server": "^4.0.0" + "node": ">=8" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "node_modules/@angular-devkit/architect": { + "version": "0.2102.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.13.tgz", + "integrity": "sha512-fheyi0gPx6b7tT+WQ+ePlzdGqKjPLUK72wg5Z9pkVtQ5+VN/8yB9mlRlmoivngd2FeNG9wMeNynWZGYycnOWVw==", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^1.9.0" + "@angular-devkit/core": "21.2.13", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" }, "engines": { - "npm": ">=2.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-devkit/core": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.11.tgz", - "integrity": "sha512-rfqoLMRYhlz0wzKlHx7FfyIyQq8dKTsmbCoIVU1cEIH0gyTMVY7PbVzwRRcO6xp5waY+0hA+0Brriujpuhkm4w==", + "node_modules/@angular-devkit/build-angular": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-21.2.13.tgz", + "integrity": "sha512-H+wLj9n4khPIUYlIPCVfOGZzTsTVn/lzkY46DTMHd7gQF35vG+/xWvWCu3Shpf/0c631U7Jc2Mg7G+GBDgxe/g==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "8.9.0", - "ajv-formats": "2.1.1", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.7", - "source-map": "0.7.3" + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2102.13", + "@angular-devkit/build-webpack": "0.2102.13", + "@angular-devkit/core": "21.2.13", + "@angular/build": "21.2.13", + "@babel/core": "7.29.0", + "@babel/generator": "7.29.1", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@babel/plugin-transform-async-generator-functions": "7.29.0", + "@babel/plugin-transform-async-to-generator": "7.28.6", + "@babel/plugin-transform-runtime": "7.29.0", + "@babel/preset-env": "7.29.2", + "@babel/runtime": "7.29.2", + "@discoveryjs/json-ext": "0.6.3", + "@ngtools/webpack": "21.2.13", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.27", + "babel-loader": "10.0.0", + "browserslist": "^4.26.0", + "copy-webpack-plugin": "14.0.0", + "css-loader": "7.1.3", + "esbuild-wasm": "0.27.3", + "http-proxy-middleware": "3.0.5", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "karma-source-map-support": "1.4.0", + "less": "4.4.2", + "less-loader": "12.3.1", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.3.1", + "mini-css-extract-plugin": "2.10.0", + "open": "11.0.0", + "ora": "9.3.0", + "picomatch": "4.0.4", + "piscina": "5.1.4", + "postcss": "8.5.12", + "postcss-loader": "8.2.0", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.2", + "sass": "1.97.3", + "sass-loader": "16.0.7", + "semver": "7.7.4", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.46.0", + "tinyglobby": "0.2.15", + "tree-kill": "1.2.2", + "tslib": "2.8.1", + "webpack": "5.105.2", + "webpack-dev-middleware": "7.4.5", + "webpack-dev-server": "5.2.3", + "webpack-merge": "6.0.1", + "webpack-subresource-integrity": "5.1.0" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, + "optionalDependencies": { + "esbuild": "0.27.3" + }, "peerDependencies": { - "chokidar": "^3.5.2" + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.2.13", + "@web/test-runner": "^0.20.0", + "browser-sync": "^3.0.2", + "jest": "^30.2.0", + "jest-environment-jsdom": "^30.2.0", + "karma": "^6.3.0", + "ng-packagr": "^21.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "typescript": ">=5.9 <6.0" }, "peerDependenciesMeta": { - "chokidar": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { "optional": true } } }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/core/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-devkit/schematics": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.11.tgz", - "integrity": "sha512-ben+EGXpCrClnIVAAnEQmhQdKmnnqFhMp5BqMxgOslSYBAmCutLA6rBu5vsc8kZcGian1wt+lueF7G1Uk5cGBg==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.13.tgz", + "integrity": "sha512-Y9TDAaTQ+E5LScCKA/hPZmns/7Mpu6J2BiPj2cETA1xNjvgRpeb5Mh32KuhZb20NSFLvjpdnLuBTTtbym7hevw==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "jsonc-parser": "3.0.0", - "magic-string": "0.25.7", - "ora": "5.4.1", - "rxjs": "6.6.7" + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2102.13", + "@babel/core": "7.29.0", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@inquirer/confirm": "5.1.21", + "@vitejs/plugin-basic-ssl": "2.1.4", + "beasties": "0.4.1", + "browserslist": "^4.26.0", + "esbuild": "0.27.3", + "https-proxy-agent": "7.0.6", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "magic-string": "0.30.21", + "mrmime": "2.0.1", + "parse5-html-rewriting-stream": "8.0.0", + "picomatch": "4.0.4", + "piscina": "5.1.4", + "rolldown": "1.0.0-rc.4", + "sass": "1.97.3", + "semver": "7.7.4", + "source-map-support": "0.5.21", + "tinyglobby": "0.2.15", + "undici": "7.24.4", + "vite": "7.3.2", + "watchpack": "2.5.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/@angular-eslint/builder": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-13.5.0.tgz", - "integrity": "sha512-IYY/HYS4fSddJLs2pAkMkKhHL07driUILPxGnGLblfWuoJBhRspyrVL3uZc3Q4iJXc1RJfaOno9oRw11FGyL6Q==", - "dev": true, - "dependencies": { - "@nrwl/devkit": "13.1.3" + "optionalDependencies": { + "lmdb": "3.5.1" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-13.5.0.tgz", - "integrity": "sha512-7M/5ilxqPD3ydgqqdLsYs3kBwZgNg2Y6C01B5SEHZNLqLT9kAJa7I4y6GlxCZqejCIh554kdXGeV3abIxFccSg==", - "dev": true - }, - "node_modules/@angular-eslint/eslint-plugin": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-13.5.0.tgz", - "integrity": "sha512-k9o9WIqUkdO8tdYFCJ54PUWsNd9HHflih/GmA13EWciBYx8QxciwBh0u4NSAnbtOwp4Y7juGZ/Dta5ZrT/2VBA==", - "dev": true, - "dependencies": { - "@angular-eslint/utils": "13.5.0", - "@typescript-eslint/experimental-utils": "5.27.1" + "@angular/compiler": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.2.13", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^21.0.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.9 <6.0", + "vitest": "^4.0.8" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "*" + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "karma": { + "optional": true + }, + "less": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + }, + "vitest": { + "optional": true + } } }, - "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-13.5.0.tgz", - "integrity": "sha512-ZVSXayn8MqYOhYomH2Cjc0azhuUQbY9fp9dKjJZOD64KhP8BYHw8+Ogc9E/FU5oZQ9fKw6A+23NAYKmLNqSAgA==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", + "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "13.5.0", - "@typescript-eslint/experimental-utils": "5.27.1", - "aria-query": "^4.2.2", - "axobject-query": "^2.2.0" + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "*" + "vite": "^6.0.0 || ^7.0.0" } }, - "node_modules/@angular-eslint/schematics": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-13.5.0.tgz", - "integrity": "sha512-0LvdalNpYb0oWwptwkeK2PVokfQ9itMIp8/aMjbOLH1RQ3eHFZgBtVvVm3G5EpPKzbL0llaeTifZvH2z70qVYQ==", + "node_modules/@angular-devkit/build-angular/node_modules/@angular/build/node_modules/vite": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-eslint/eslint-plugin": "13.5.0", - "@angular-eslint/eslint-plugin-template": "13.5.0", - "ignore": "5.2.0", - "strip-json-comments": "3.1.1", - "tmp": "0.2.1" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, - "peerDependencies": { - "@angular/cli": ">= 13.0.0 < 14.0.0" - } - }, - "node_modules/@angular-eslint/template-parser": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-13.5.0.tgz", - "integrity": "sha512-k+24+kBjaOuthfp9RBQB0zH6UqeizZuFQFEuZEQbvirPbdQ2SqNBw7IcmW2Qw1v7fjFe6/6gqK7wm2g7o9ZZvA==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "13.5.0", - "eslint-scope": "^5.1.0" + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "*" - } - }, - "node_modules/@angular-eslint/utils": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-13.5.0.tgz", - "integrity": "sha512-wX3W6STSDJDJ7ZyEsUdBp4HUPwmillMmKcdnFsy+qxbpJFzFOxOFpK1zet4ELsq1XpB89i9vRvC3vYbpHn3CSw==", - "dev": true, - "dependencies": { - "@angular-eslint/bundled-angular-compiler": "13.5.0", - "@typescript-eslint/experimental-utils": "5.27.1" + "@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" }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0", - "typescript": "*" + "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 + } } }, - "node_modules/@angular/animations": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.4.0.tgz", - "integrity": "sha512-PkEmDd5zpbz/7fudxyb6qL9sBMTPlzpSIh85AapGhjgRSUSRSGuJLj49R35fQ/44c4K5bHMPEsGZjMR0oDsGdg==", + "node_modules/@angular-devkit/build-angular/node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" + "node": ">=18" }, "peerDependencies": { - "@angular/core": "13.4.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular/cdk": { - "version": "13.3.9", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.9.tgz", - "integrity": "sha512-XCuCbeuxWFyo3EYrgEYx7eHzwl76vaWcxtWXl00ka8d+WAOtMQ6Tf1D98ybYT5uwF9889fFpXAPw98mVnlo3MA==", + "node_modules/@angular-devkit/build-angular/node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" }, - "optionalDependencies": { - "parse5": "^5.0.0" + "engines": { + "node": ">=18" }, "peerDependencies": { - "@angular/common": "^13.0.0 || ^14.0.0-0", - "@angular/core": "^13.0.0 || ^14.0.0-0", - "rxjs": "^6.5.3 || ^7.4.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular/cli": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.3.11.tgz", - "integrity": "sha512-LTuQ1wC/VJiHqHx8nYJCx0EJv1Ek7R6VvP/5vmr/+M8oVvJ2zSh/aIbcPg6BTL0YEfMI6nX41mUjPBUfF0q2OA==", + "node_modules/@angular-devkit/build-angular/node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, - "hasInstallScript": true, - "dependencies": { - "@angular-devkit/architect": "0.1303.11", - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "@schematics/angular": "13.3.11", - "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.1", - "debug": "4.3.3", - "ini": "2.0.0", - "inquirer": "8.2.0", - "jsonc-parser": "3.0.0", - "npm-package-arg": "8.1.5", - "npm-pick-manifest": "6.1.1", - "open": "8.4.0", - "ora": "5.4.1", - "pacote": "12.0.3", - "resolve": "1.22.0", - "semver": "7.3.5", - "symbol-observable": "4.0.0", - "uuid": "8.3.2" + "license": "MIT", + "engines": { + "node": ">=18" }, - "bin": { - "ng": "bin/ng.js" + "peerDependencies": { + "@types/node": ">=18" }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular/common": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.4.0.tgz", - "integrity": "sha512-DHbPqRaxW7GmnkxqZaaasgC5OaFTeTBrmr7MJUsqsSGePHWuJYWU4QS3Fn86zd/VESJgBGmq2aCDEUmzfjnRQA==", + "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular/core": "13.4.0", - "rxjs": "^6.5.3 || ^7.4.0" + "undici-types": ">=7.24.0 <7.24.7" } }, - "node_modules/@angular/compiler": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.4.0.tgz", - "integrity": "sha512-tPWoq2RC/VIrJtynEnMRWQZemBIC/ypuVfuUf3p8IIXCZHjuGnibdlZTtFYkexc4/sR1ug9xk1cJWvbOPwilng==", - "dependencies": { - "tslib": "^2.3.0" - }, + "node_modules/@angular-devkit/build-angular/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" + "node": ">= 14" } }, - "node_modules/@angular/compiler-cli": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.4.0.tgz", - "integrity": "sha512-OQD0w9aZXbpcyWDEaozoHH/n3eYDLhBsmJcIBVqUN8Awx8m17v2u2R6m7DIEpVRbBzYtTscAMTKONNVwsTolHA==", + "node_modules/@angular-devkit/build-angular/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/core": "^7.17.2", - "chokidar": "^3.0.0", - "convert-source-map": "^1.5.1", - "dependency-graph": "^0.11.0", - "magic-string": "^0.26.0", - "reflect-metadata": "^0.1.2", - "semver": "^7.0.0", - "sourcemap-codec": "^1.4.8", - "tslib": "^2.3.0", - "yargs": "^17.2.1" + "ajv": "^8.0.0" }, - "bin": { - "ng-xi18n": "bundles/src/bin/ng_xi18n.js", - "ngc": "bundles/src/bin/ngc.js", - "ngcc": "bundles/ngcc/main-ngcc.js" + "peerDependencies": { + "ajv": "^8.0.0" }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular/compiler": "13.4.0", - "typescript": ">=4.4.2 <4.7" + "node": ">=8" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "node_modules/@angular-devkit/build-angular/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" + "node": ">=8.0.0" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@angular-devkit/build-angular/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "node_modules/@angular-devkit/build-angular/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "agent-base": "^7.1.2", + "debug": "4" }, "engines": { - "node": ">=6.9.0" + "node": ">= 14" } }, - "node_modules/@angular/compiler-cli/node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@angular-devkit/build-angular/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@angular/compiler-cli/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@angular-devkit/build-angular/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } + "license": "MIT" }, - "node_modules/@angular/compiler-cli/node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "node_modules/@angular-devkit/build-angular/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 0.6" } }, - "node_modules/@angular/compiler-cli/node_modules/magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", + "node_modules/@angular-devkit/build-angular/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { - "sourcemap-codec": "^1.4.8" + "mime-db": "1.52.0" }, "engines": { - "node": ">=12" + "node": ">= 0.6" } }, - "node_modules/@angular/core": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.4.0.tgz", - "integrity": "sha512-RE9KL7pRj+3lkJjdSR2uKmqiG0gqjnoVCMbSLG93pWrmzNIhElmlkiDaK39aMHGl836dc68Usv9CEisyVnRqHQ==", + "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" + "node": ">= 10.13.0" }, - "peerDependencies": { - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.11.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/@angular/forms": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.4.0.tgz", - "integrity": "sha512-vWd438sPlESLAv+cPFEZwF5aa8cF9Gt9zofLe3Ep9v9YIv2naVkv7pxCu0KFyvbBHAT7THbZfyypuvYsYNI3rw==", + "node_modules/@angular-devkit/build-angular/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular/common": "13.4.0", - "@angular/core": "13.4.0", - "@angular/platform-browser": "13.4.0", - "rxjs": "^6.5.3 || ^7.4.0" + "node": ">=8" } }, - "node_modules/@angular/language-service": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-13.4.0.tgz", - "integrity": "sha512-2aaqc5iKOT4gXcEY2iJloOjy2WJBFdDeuHKSt8FqnlNhi5FJpklN0HjycRTP02yfIHscQR+3dwJi2Bv9mbBw2w==", + "node_modules/@angular-devkit/build-angular/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" + "node": ">=8" } }, - "node_modules/@angular/platform-browser": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.4.0.tgz", - "integrity": "sha512-kq4TpdkSS0Z/7ToFzWhyBbh4Ai1uOKFVdL9/TAm19dLnYNIInrN3KYW6GRxZ+pkJJA9Vkq4NtgcxysQ42VFotA==", - "dependencies": { - "tslib": "^2.3.0" - }, + "node_modules/@angular-devkit/build-angular/node_modules/undici": { + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", + "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", + "dev": true, + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular/animations": "13.4.0", - "@angular/common": "13.4.0", - "@angular/core": "13.4.0" - }, - "peerDependenciesMeta": { - "@angular/animations": { - "optional": true - } + "node": ">=20.18.1" } }, - "node_modules/@angular/platform-browser-dynamic": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.4.0.tgz", - "integrity": "sha512-vYxaLF098RTGL2tugG6s0ZQU4G1XYU5tw0/C4RCIbNLHS1rk/s9AzSnbr3zFSOQ33NWSixU0Z4EPl4hU88hghA==", + "node_modules/@angular-devkit/build-angular/node_modules/webpack": { + "version": "5.105.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", + "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.3" + }, + "bin": { + "webpack": "bin/webpack.js" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" + "node": ">=10.13.0" }, - "peerDependencies": { - "@angular/common": "13.4.0", - "@angular/compiler": "13.4.0", - "@angular/core": "13.4.0", - "@angular/platform-browser": "13.4.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } } }, - "node_modules/@angular/router": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.4.0.tgz", - "integrity": "sha512-YlPAf3tPqD04rAMPAwW+XqFQaBXT9fY2Mh7J/9MXeyLZau59afBIcVNbeQxW5RxDajmfyFy437Qh22qFP2l0Hw==", + "node_modules/@angular-devkit/build-angular/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^2.3.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "peerDependencies": { - "@angular/common": "13.4.0", - "@angular/core": "13.4.0", - "@angular/platform-browser": "13.4.0", - "rxjs": "^6.5.3 || ^7.4.0" + "node": ">=8" } }, - "node_modules/@ant-design/colors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-5.1.1.tgz", - "integrity": "sha512-Txy4KpHrp3q4XZdfgOBqLl+lkQIc3tEvHXOimRN1giX1AEC7mGtyrO9p8iRGJ3FLuVMGa2gNEzQyghVymLttKQ==", + "node_modules/@angular-devkit/build-webpack": { + "version": "0.2102.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2102.13.tgz", + "integrity": "sha512-xnGq62JImcvPUM5r7Uvj7Y243fepwhbTG3zaIR2JKR+4EwF5pS5moXuVf+xVvxRqQkNcmLGfr7uJogmpw+dUgA==", + "dev": true, + "license": "MIT", "dependencies": { - "@ctrl/tinycolor": "^3.3.1" + "@angular-devkit/architect": "0.2102.13", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^5.0.2" } }, - "node_modules/@ant-design/icons-angular": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@ant-design/icons-angular/-/icons-angular-13.1.0.tgz", - "integrity": "sha512-bQ1pxiDmR8Hx7kUwQImxLGAtexv0uDCCMlKSWdyaw39TnNAPz+Hls0XL+UqVIjHgt/D4R8tkmSMpx3eBGFIY/Q==", + "node_modules/@angular-devkit/core": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.13.tgz", + "integrity": "sha512-9jLaHcUr6BumIY9nCsBib1q62p259nf++gd2igYJ7mLm1w/0wEacsZ1cC8wCGEe6vx8a+DrD+EVCQ6zivePG2A==", + "dev": true, + "license": "MIT", "dependencies": { - "@ant-design/colors": "^5.0.0", - "tslib": "^2.0.0" + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" }, "peerDependencies": { - "@angular/common": "^13.0.1", - "@angular/core": "^13.0.0", - "@angular/platform-browser": "^13.0.1", - "rxjs": "^6.4.0 || ^7.4.0" + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } } }, - "node_modules/@antv/adjust": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz", - "integrity": "sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==", + "node_modules/@angular-devkit/schematics": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.13.tgz", + "integrity": "sha512-gifpOcMNiAy49lQmQKhzpxoSfS3qJQSEdJSF5m7RVFkAcmllfcCD76GPN4dhho3wdAnbZ3qr54LtDqrGY4xNjw==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/util": "~1.3.1" + "@angular-devkit/core": "21.2.13", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.21", + "ora": "9.3.0", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@antv/attr": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.1.2.tgz", - "integrity": "sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==", + "node_modules/@angular-eslint/builder": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.4.0.tgz", + "integrity": "sha512-3kgGmrVaCYbLtDjC8g4BmMBbdz4thsOB8/NYly8JtXM8EuDZEk5Pz6VTRpJR02ARprwayraTTmhyvq6OGBlQ9w==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/util": "~1.3.1" + "@angular-devkit/architect": ">= 0.2100.0 < 0.2200.0", + "@angular-devkit/core": ">= 21.0.0 < 22.0.0" + }, + "peerDependencies": { + "@angular/cli": ">= 21.0.0 < 22.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "*" } }, - "node_modules/@antv/component": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.3.10.tgz", - "integrity": "sha512-8HLkgdhc0jXrnNrkaACPrWx2JB/51VGscL9t0pH2xoLdxiDQVtTUad2geWxbac5k/ZZHG+bDPWWb83CZIR9A9w==", + "node_modules/@angular-eslint/bundled-angular-compiler": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-21.4.0.tgz", + "integrity": "sha512-/3H4BPbQ1BHJkkrUsfusZtmHc+qiFWBBZ9UDPWah4xZMjflexOK9U4GYeH7nMjcuyqFnIlMMeJJNwNLGt/hmdg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-eslint/eslint-plugin": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-21.4.0.tgz", + "integrity": "sha512-mow2DMj+xBvGl5t7jzC34R8YfbHbaGNyCNFzpovtl9qc0JbuqLyg6htmt8xb05f8ZjATOr4nz0ESt6HV4c51hw==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/attr": "~0.1.2", - "@antv/g": "~3.3.5", - "@antv/util": "~1.3.1", - "wolfy87-eventemitter": "~5.1.0" + "@angular-eslint/bundled-angular-compiler": "21.4.0", + "@angular-eslint/utils": "21.4.0", + "ts-api-utils": "^2.1.0" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "*" } }, - "node_modules/@antv/component/node_modules/@antv/g": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.3.6.tgz", - "integrity": "sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==", + "node_modules/@angular-eslint/eslint-plugin-template": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-21.4.0.tgz", + "integrity": "sha512-sJEHx2WYnvOgPpzP1eHnUdRS06zgKmRxbiIR0JiCcaSen5iv1HlsMieXy//FS9TtNW+abHOy4UtDuGuSPflPFA==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/gl-matrix": "~2.7.1", - "@antv/util": "~1.3.1", - "d3-ease": "~1.0.3", - "d3-interpolate": "~1.1.5", - "d3-timer": "~1.0.6", - "wolfy87-eventemitter": "~5.1.0" + "@angular-eslint/bundled-angular-compiler": "21.4.0", + "@angular-eslint/utils": "21.4.0", + "aria-query": "5.3.2", + "axobject-query": "4.1.0" + }, + "peerDependencies": { + "@angular-eslint/template-parser": "21.4.0", + "@typescript-eslint/types": "^7.11.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "*" } }, - "node_modules/@antv/coord": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.1.0.tgz", - "integrity": "sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==", + "node_modules/@angular-eslint/schematics": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-21.4.0.tgz", + "integrity": "sha512-crD6Hfxs7x5bN9FCqTZI7uVSiGvprfCS3MCPOpyIQl87bRr/9aNhnicJ3ROUHv+2A713BgPHIgiCII/bxzrfPw==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/util": "~1.3.1" + "@angular-devkit/core": ">= 21.0.0 < 22.0.0", + "@angular-devkit/schematics": ">= 21.0.0 < 22.0.0", + "@angular-eslint/eslint-plugin": "21.4.0", + "@angular-eslint/eslint-plugin-template": "21.4.0", + "ignore": "7.0.5", + "semver": "7.7.4", + "strip-json-comments": "3.1.1" + }, + "peerDependencies": { + "@angular/cli": ">= 21.0.0 < 22.0.0" } }, - "node_modules/@antv/data-set": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@antv/data-set/-/data-set-0.10.2.tgz", - "integrity": "sha512-FFWG5tiTiFiUrLDRwulraU5XfOdDjkYOlZna+AMT9FJw406D/gfS8eXM9YibscBH28M/+KLAVO8xEwuD1sc3bw==", + "node_modules/@angular-eslint/template-parser": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-21.4.0.tgz", + "integrity": "sha512-BaUSLSyS+43fzDoJkTMkGqNdCXq3fGnUZsfXTmrlZPJf5AYFbgAlAPGZXDJyoNWw43fux+DafdlrlKcYUSgSIw==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/hierarchy": "~0.4.0", - "@antv/util": "~1.3.1", - "d3-array": "~1.2.0", - "d3-composite-projections": "~1.2.0", - "d3-dsv": "~1.0.5", - "d3-geo": "~1.6.4", - "d3-geo-projection": "~2.1.2", - "d3-hexjson": "~1.0.1", - "d3-hierarchy": "~1.1.5", - "d3-sankey": "~0.7.1", - "d3-voronoi": "~1.1.2", - "dagre": "~0.8.2", - "point-at-length": "~1.0.2", - "regression": "~2.0.0", - "simple-statistics": "~6.1.0", - "topojson-client": "~3.0.0", - "wolfy87-eventemitter": "~5.1.0" + "@angular-eslint/bundled-angular-compiler": "21.4.0", + "eslint-scope": "9.1.2" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "*" } }, - "node_modules/@antv/g": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.4.10.tgz", - "integrity": "sha512-pKy/L1SyRBsXuujdkggqrdBA0/ciAgHiArYBdIJsxHRxCneUP01wGwHdGfDayh2+S0gcSBHynjhoEahsaZaLkw==", + "node_modules/@angular-eslint/utils": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-21.4.0.tgz", + "integrity": "sha512-7pi+Ga7QmdH5Ig/diau6fR5L4yubgKr9TOjdCg7OeuE/zo0O3osTCNT6JOodzS/iQM1kSCJFDoIBKFeUOttiNw==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/gl-matrix": "~2.7.1", - "@antv/util": "~1.3.1", - "d3-ease": "~1.0.3", - "d3-interpolate": "~1.1.5", - "d3-timer": "~1.0.6", - "detect-browser": "^5.1.0" + "@angular-eslint/bundled-angular-compiler": "21.4.0" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "*" } }, - "node_modules/@antv/g2": { - "version": "3.5.19", - "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-3.5.19.tgz", - "integrity": "sha512-OWWDJof1ghfsxDYO20TxVF9TUhDsyOE/yzbSdSu+N9Ft1zQxKJQlgG43/FO+rOsdC/k1dXoYOBRPQ7kk5EBaJA==", + "node_modules/@angular/animations": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.15.tgz", + "integrity": "sha512-Z8AsLTwc++Fcu0fJnclAF9zMfumAd5KXrwtSdyECqLpqd+lEmmsOpeOl6P7loqdDz99KYh/8UF4eJxdMvnsaKw==", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@antv/adjust": "~0.1.0", - "@antv/attr": "~0.1.2", - "@antv/component": "~0.3.3", - "@antv/coord": "~0.1.0", - "@antv/g": "~3.4.10", - "@antv/scale": "~0.1.1", - "@antv/util": "~1.3.1", - "core-js": "2", - "venn.js": "~0.2.20", - "wolfy87-eventemitter": "~5.1.0" + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "21.2.15" } }, - "node_modules/@antv/gl-matrix": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz", - "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==" - }, - "node_modules/@antv/hierarchy": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.4.0.tgz", - "integrity": "sha512-ols+m+Z8QA4895SWMTOSjVImOX4tEbWQTwJ0NE+WATc0WLSKs6D9y2yaR+ZWt6P60BMGVIKS6lIfabO3CwGgnQ==", + "node_modules/@angular/cdk": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.13.tgz", + "integrity": "sha512-nQGGJ6Efqi8n0qhT/PllsaIIY+vz+TL7/tpR7F2QKiqzS/9l4m7ea0vvS6fSMGrjEbqbkzTHbjLDsIg6X2hK+w==", + "license": "MIT", "dependencies": { - "@antv/util": "~1.3.1" + "parse5": "^8.0.0", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/platform-browser": "^21.0.0 || ^22.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@antv/scale": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.1.5.tgz", - "integrity": "sha512-7RAu4iH5+Hk21h6+aBMiDTfmLf4IibK2SWjx/+E4f4AXRpqucO+8u7IbZdFkakAWxvqhJtN3oePJuTKqOMcmlg==", - "dependencies": { - "@antv/util": "~1.3.1", - "fecha": "~2.3.3" + "node_modules/@angular/cdk/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/@antv/util": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz", - "integrity": "sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==", + "node_modules/@angular/cdk/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "license": "MIT", "dependencies": { - "@antv/gl-matrix": "^2.7.1" + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "node_modules/@angular/cli": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.13.tgz", + "integrity": "sha512-j1kOV/f0og/3xCwG7Y8RyPd6V7uYfX2NuvXbvN1mzgxLLN2mu6CTsvPg5l/9Pu9SJI3KOPRgDxWyuP3k8KuzMg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" + "@angular-devkit/architect": "0.2102.13", + "@angular-devkit/core": "21.2.13", + "@angular-devkit/schematics": "21.2.13", + "@inquirer/prompts": "7.10.1", + "@listr2/prompt-adapter-inquirer": "3.0.5", + "@modelcontextprotocol/sdk": "1.26.0", + "@schematics/angular": "21.2.13", + "@yarnpkg/lockfile": "1.1.0", + "algoliasearch": "5.48.1", + "ini": "6.0.0", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "npm-package-arg": "13.0.2", + "pacote": "21.3.1", + "parse5-html-rewriting-stream": "8.0.0", + "semver": "7.7.4", + "yargs": "18.0.0", + "zod": "4.3.6" + }, + "bin": { + "ng": "bin/ng.js" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "node_modules/@angular/cli/node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.16.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", - "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.12", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.10", - "@babel/types": "^7.16.8", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", - "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", + "node_modules/@angular/cli/node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.16.8", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "node_modules/@angular/cli/node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "node_modules/@angular/cli/node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.16.7" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "node_modules/@angular/cli/node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "node_modules/@angular/cli/node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, + "license": "MIT", "dependencies": { - "@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.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "node_modules/@angular/cli/node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "node_modules/@angular/cli/node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "node_modules/@angular/cli/node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "node_modules/@angular/cli/node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "node_modules/@angular/cli/node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "node_modules/@angular/cli/node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "node_modules/@angular/cli/node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": ">=6.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "node_modules/@angular/cli/node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=18" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "node_modules/@angular/cli/node_modules/@listr2/prompt-adapter-inquirer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", + "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@inquirer/type": "^3.0.8" }, "engines": { - "node": ">=6.9.0" + "node": ">=20.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8", + "listr2": "9.0.5" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "node_modules/@angular/cli/node_modules/@types/node": { + "version": "25.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", + "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" + "undici-types": ">=7.24.0 <7.24.7" } }, - "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "node_modules/@angular/cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "@babel/types": "^7.27.3" - }, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "node_modules/@angular/cli/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "node": ">=0.10.0" }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "node_modules/@angular/cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "node_modules/@angular/cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helper-wrap-function/node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@angular/cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "node_modules/@angular/cli/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/@babel/helpers/node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, + "node_modules/@angular/common": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.15.tgz", + "integrity": "sha512-PHbICQe4YCXnax2FcmKUpiffs8XPW9A0KlZF35qgJoQyBMBZx5F8c8geCh25jxtq77n3eBTmOa/WIAdSqiitkQ==", + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "21.2.15", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, + "node_modules/@angular/compiler": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.15.tgz", + "integrity": "sha512-nwpNb+NbVUNzR3cck0QXbU/oFK7BpmXOXVnN/w7+P4+TsFUYeTtO1Ojbc15jkqe6mSM0lBvGlcoztVblHQkqcw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "node_modules/@angular/compiler-cli": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.15.tgz", + "integrity": "sha512-/MU7OA9d/e9P5SthR+N6JJObBmzcGsgNQaeQ2YfSUnU0lCRVQweTWwxLFDbfU6UX8MZFWB6pdI57zod8r5kXUw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/core": "7.29.0", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^5.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^18.0.0" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@angular/compiler": "21.2.15", + "typescript": ">=5.9 <6.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, + "node_modules/@angular/core": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.15.tgz", + "integrity": "sha512-J5JsUnNtQURdeA7EA3DoCsMBizW3l01gfqM326Al72Ou3woFWmRb5P3LOXpIOzAeMQhO6Z5tW+B1t+4qmoq7uw==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.13.0" + "@angular/compiler": "21.2.15", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0 || ~0.16.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } } }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", - "dev": true, + "node_modules/@angular/forms": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.15.tgz", + "integrity": "sha512-swGUHgbBrPNvODPR9qBP6+vT2EHiyW361iEgS3HpTmvDhF/kD4l8NE0vh3P5N0DnEtGh4umOCKfQ1w6hPJ7lqA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@standard-schema/spec": "^1.0.0", + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@angular/common": "21.2.15", + "@angular/core": "21.2.15", + "@angular/platform-browser": "21.2.15", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", - "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.", + "node_modules/@angular/language-service": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-21.2.15.tgz", + "integrity": "sha512-xR2dH1xpd3zojdVztFFTS87f6SOp2SAC6ri09eIpxbHpLXl0ruuDgYFs/ug2JOWC2rIfc7UnoQjdSMs1u0XEbw==", "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, + "license": "MIT", "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-static-block instead.", - "dev": true, + "node_modules/@angular/platform-browser": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.15.tgz", + "integrity": "sha512-O4ZHVV/rxkK1AuiD9M3UssL/HkoQvBcZy2+U421IMNibclGhwH9aRwc/0ZlQ7zpseS9+KPZ23FebvN4/92IbPg==", + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.12.0" + "@angular/animations": "21.2.15", + "@angular/common": "21.2.15", + "@angular/core": "21.2.15" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } } }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-dynamic-import instead.", - "dev": true, + "node_modules/@angular/platform-browser-dynamic": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.15.tgz", + "integrity": "sha512-3xvlWLZlsWjPyJFGatOOsod/f5AFjmSUDoOXo0zsr2ckHc4TxbDTnkLULhRSWv6m68fKOdQb8Si8rI15gC5yqA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@angular/common": "21.2.15", + "@angular/compiler": "21.2.15", + "@angular/core": "21.2.15", + "@angular/platform-browser": "21.2.15" } }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-export-namespace-from instead.", - "dev": true, + "node_modules/@angular/router": { + "version": "21.2.15", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.15.tgz", + "integrity": "sha512-Cej4hYkmaTB6wXn1xQPlr4O1wHgUD0WLv//Oue1IssKqL8vkzic5f5x/H/bxtxxGlSnc+i6uIUF/lvjdGoWk/A==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "tslib": "^2.3.0" }, "engines": { - "node": ">=6.9.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@angular/common": "21.2.15", + "@angular/core": "21.2.15", + "@angular/platform-browser": "21.2.15", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-json-strings instead.", - "dev": true, + "node_modules/@ant-design/colors": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.2.1.tgz", + "integrity": "sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@ant-design/fast-color": "^2.0.6" } }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-logical-assignment-operators instead.", - "dev": true, + "node_modules/@ant-design/fast-color": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@ant-design/fast-color/-/fast-color-2.0.6.tgz", + "integrity": "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/runtime": "^7.24.7" }, "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "node": ">=8.x" } }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", - "dev": true, + "node_modules/@ant-design/icons-angular": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@ant-design/icons-angular/-/icons-angular-21.0.0.tgz", + "integrity": "sha512-Io1DSg0JyzsxQtF2T9LfQSZL22d7zSYyNz0RiUCOhtMoDnnGis1oU6mPs5JzZTRtVdgpuLUhS6GVTlT+dmP1nA==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" + "@ant-design/colors": "^7.0.0", + "tslib": "^2.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@angular/common": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-numeric-separator instead.", - "dev": true, + "node_modules/@antv/adjust": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz", + "integrity": "sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/util": "~1.3.1" } }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", - "dev": true, + "node_modules/@antv/attr": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.1.2.tgz", + "integrity": "sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==", + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/util": "~1.3.1" } }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", - "dev": true, + "node_modules/@antv/component": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.3.10.tgz", + "integrity": "sha512-8HLkgdhc0jXrnNrkaACPrWx2JB/51VGscL9t0pH2xoLdxiDQVtTUad2geWxbac5k/ZZHG+bDPWWb83CZIR9A9w==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/attr": "~0.1.2", + "@antv/g": "~3.3.5", + "@antv/util": "~1.3.1", + "wolfy87-eventemitter": "~5.1.0" } }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", - "dev": true, + "node_modules/@antv/component/node_modules/@antv/g": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.3.6.tgz", + "integrity": "sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==", "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/gl-matrix": "~2.7.1", + "@antv/util": "~1.3.1", + "d3-ease": "~1.0.3", + "d3-interpolate": "~1.1.5", + "d3-timer": "~1.0.6", + "wolfy87-eventemitter": "~5.1.0" } }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", - "dev": true, + "node_modules/@antv/coord": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.1.0.tgz", + "integrity": "sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==", + "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/util": "~1.3.1" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", - "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", - "dev": true, + "node_modules/@antv/data-set": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@antv/data-set/-/data-set-0.10.2.tgz", + "integrity": "sha512-FFWG5tiTiFiUrLDRwulraU5XfOdDjkYOlZna+AMT9FJw406D/gfS8eXM9YibscBH28M/+KLAVO8xEwuD1sc3bw==", + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/hierarchy": "~0.4.0", + "@antv/util": "~1.3.1", + "d3-array": "~1.2.0", + "d3-composite-projections": "~1.2.0", + "d3-dsv": "~1.0.5", + "d3-geo": "~1.6.4", + "d3-geo-projection": "~2.1.2", + "d3-hexjson": "~1.0.1", + "d3-hierarchy": "~1.1.5", + "d3-sankey": "~0.7.1", + "d3-voronoi": "~1.1.2", + "dagre": "~0.8.2", + "point-at-length": "~1.0.2", + "regression": "~2.0.0", + "simple-statistics": "~6.1.0", + "topojson-client": "~3.0.0", + "wolfy87-eventemitter": "~5.1.0" } }, - "node_modules/@babel/plugin-proposal-private-property-in-object/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, + "node_modules/@antv/g": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.4.10.tgz", + "integrity": "sha512-pKy/L1SyRBsXuujdkggqrdBA0/ciAgHiArYBdIJsxHRxCneUP01wGwHdGfDayh2+S0gcSBHynjhoEahsaZaLkw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" + "@antv/gl-matrix": "~2.7.1", + "@antv/util": "~1.3.1", + "d3-ease": "~1.0.3", + "d3-interpolate": "~1.1.5", + "d3-timer": "~1.0.6", + "detect-browser": "^5.1.0" } }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", - "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-unicode-property-regex instead.", - "dev": true, + "node_modules/@antv/g2": { + "version": "3.5.19", + "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-3.5.19.tgz", + "integrity": "sha512-OWWDJof1ghfsxDYO20TxVF9TUhDsyOE/yzbSdSu+N9Ft1zQxKJQlgG43/FO+rOsdC/k1dXoYOBRPQ7kk5EBaJA==", + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/adjust": "~0.1.0", + "@antv/attr": "~0.1.2", + "@antv/component": "~0.3.3", + "@antv/coord": "~0.1.0", + "@antv/g": "~3.4.10", + "@antv/scale": "~0.1.1", + "@antv/util": "~1.3.1", + "core-js": "2", + "venn.js": "~0.2.20", + "wolfy87-eventemitter": "~5.1.0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, + "node_modules/@antv/gl-matrix": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz", + "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==", + "license": "MIT" + }, + "node_modules/@antv/hierarchy": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.4.0.tgz", + "integrity": "sha512-ols+m+Z8QA4895SWMTOSjVImOX4tEbWQTwJ0NE+WATc0WLSKs6D9y2yaR+ZWt6P60BMGVIKS6lIfabO3CwGgnQ==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/util": "~1.3.1" } }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, + "node_modules/@antv/scale": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.1.5.tgz", + "integrity": "sha512-7RAu4iH5+Hk21h6+aBMiDTfmLf4IibK2SWjx/+E4f4AXRpqucO+8u7IbZdFkakAWxvqhJtN3oePJuTKqOMcmlg==", + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/util": "~1.3.1", + "fecha": "~2.3.3" } }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, + "node_modules/@antv/util": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz", + "integrity": "sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==", + "license": "ISC", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@antv/gl-matrix": "^2.7.1" } }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@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.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } + "license": "MIT" }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/types": "^7.27.3" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/@babel/helper-create-class-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@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" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">=6.9.0" + "node": ">= 0.4" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-computed-properties/node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@babel/helper-remap-async-to-generator/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.13.0" } }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" }, @@ -2624,16 +3106,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2642,14 +3122,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2658,14 +3138,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2674,13 +3155,14 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2689,14 +3171,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.0.tgz", + "integrity": "sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -2705,14 +3189,16 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.28.6.tgz", + "integrity": "sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2721,13 +3207,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2736,13 +3223,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2751,13 +3239,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2766,33 +3256,36 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.12.0" } }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz", - "integrity": "sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w==", + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "semver": "^6.3.0" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2801,22 +3294,28 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@babel/plugin-transform-classes/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2825,14 +3324,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2841,13 +3341,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2856,13 +3358,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2871,28 +3374,31 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@babel/core": "^7.0.0" } }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2901,14 +3407,15 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2917,86 +3424,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -3005,2152 +3440,2426 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-env/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", - "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", "dev": true, + "license": "MIT", "dependencies": { - "regenerator-runtime": "^0.13.4" + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", - "integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==", + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", "dev": true, + "license": "MIT", "dependencies": { - "core-js-pure": "^3.43.0" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse/node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@babel/traverse/node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=6" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/postcss-progressive-custom-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", - "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", "dev": true, + "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.2.0" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": "^12 || ^14 || >=16" + "node": ">=6.9.0" }, "peerDependencies": { - "postcss": "^8.3" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=10" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=10.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@epic-web/invariant": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", - "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", - "dev": true - }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.50.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", - "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "^1.0.6", - "@typescript-eslint/types": "^8.11.0", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.1.0" + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { - "node": ">=18" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@es-joy/jsdoccomment/node_modules/@typescript-eslint/types": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", - "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=6.9.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=6.9.0" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", "dev": true, + "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/eslint" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", "dev": true, + "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/@babel/plugin-transform-private-property-in-object/node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@babel/types": "^7.29.7" }, "engines": { - "node": "*" + "node": ">=6.9.0" } }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", "dev": true, + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" + "node": ">=6.9.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.29.0.tgz", + "integrity": "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@jridgewell/remapping/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", "dev": true, - "license": "MIT" - }, - "node_modules/@ljharb/resumer": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.0.1.tgz", - "integrity": "sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==", + "license": "MIT", "dependencies": { - "@ljharb/through": "^2.3.9" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@ljharb/through": { - "version": "2.3.14", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.14.tgz", - "integrity": "sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A==", + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.8" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">= 0.4" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@ngtools/webpack": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.11.tgz", - "integrity": "sha512-gB33hTbc/RJmHyIgSUYj8ErPazhYYm7yfapOnvwHdYhCjrj1TKkR1ierOlhJtpfBYUQg6FChdl2YpyIQNPjWMA==", + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=6.9.0" }, "peerDependencies": { - "@angular/compiler-cli": "^13.0.0", - "typescript": ">=4.4.3 <4.7", - "webpack": "^5.30.0" + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@babel/preset-env": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.2.tgz", + "integrity": "sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^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/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.6", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.28.6", + "@babel/plugin-syntax-import-attributes": "^7.28.6", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.29.0", + "@babel/plugin-transform-async-to-generator": "^7.28.6", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.6", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-class-static-block": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-computed-properties": "^7.28.6", + "@babel/plugin-transform-destructuring": "^7.28.5", + "@babel/plugin-transform-dotall-regex": "^7.28.6", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.6", + "@babel/plugin-transform-exponentiation-operator": "^7.28.6", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.28.6", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.28.6", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.28.6", + "@babel/plugin-transform-modules-systemjs": "^7.29.0", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.0", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-numeric-separator": "^7.28.6", + "@babel/plugin-transform-object-rest-spread": "^7.28.6", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.28.6", + "@babel/plugin-transform-private-property-in-object": "^7.28.6", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.29.0", + "@babel/plugin-transform-regexp-modifiers": "^7.28.6", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.28.6", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.28.6", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.28.6", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, "engines": { - "node": ">= 8" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@npmcli/git": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", - "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, + "license": "MIT", "dependencies": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/@npmcli/git/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, + "license": "MIT", "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" }, "engines": { - "node": ">= 10" + "node": ">=6.9.0" } }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, + "license": "MIT", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { - "node": ">=10" + "node": ">=6.9.0" } }, - "node_modules/@npmcli/node-gyp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", - "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", - "dev": true - }, - "node_modules/@npmcli/promise-spawn": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", - "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, + "license": "MIT", "dependencies": { - "infer-owner": "^1.0.4" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@npmcli/run-script": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-2.0.0.tgz", - "integrity": "sha512-fSan/Pu11xS/TdaTpTB0MRn9guwGU8dye+x56mEVgBEd/QsybBbYcAL0phPXi8SGWFEChkQd6M9qL4y6VOpFig==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^8.2.0", - "read-package-json-fast": "^2.0.1" + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" } }, - "node_modules/@nrwl/cli": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-15.9.7.tgz", - "integrity": "sha512-1jtHBDuJzA57My5nLzYiM372mJW0NY6rFKxlWt5a0RLsAZdPTHsd8lE3Gs9XinGC1jhXbruWmhhnKyYtZvX/zA==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { - "nx": "15.9.7" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@nrwl/cli/node_modules/@nrwl/tao": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-15.9.7.tgz", - "integrity": "sha512-OBnHNvQf3vBH0qh9YnvBQQWyyFZ+PWguF6dJ8+1vyQYlrLVk/XZ8nJ4ukWFb+QfPv/O8VBmqaofaOI9aFC4yTw==", - "dev": true, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", "license": "MIT", - "dependencies": { - "nx": "15.9.7" - }, - "bin": { - "tao": "index.js" + "engines": { + "node": ">=10" } }, - "node_modules/@nrwl/cli/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/@nrwl/cli/node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "node_modules/@discoveryjs/json-ext": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14.17.0" } }, - "node_modules/@nrwl/cli/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" } }, - "node_modules/@nrwl/cli/node_modules/dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=10" + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" } }, - "node_modules/@nrwl/cli/node_modules/fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8" + "tslib": "^2.4.0" } }, - "node_modules/@nrwl/cli/node_modules/fs-extra": { - "version": "11.3.4", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", - "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "node_modules/@epic-web/invariant": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", + "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { - "node": ">=14.14" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "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", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/glob/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@nrwl/cli/node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/nx": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/nx/-/nx-15.9.7.tgz", - "integrity": "sha512-1qlEeDjX9OKZEryC8i4bA+twNg+lB5RKrozlNwWx/lLJHqWPUfvUTvxh+uxlPYL9KzVReQjUuxMLFMsHNqWUrA==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], "dev": true, - "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@nrwl/cli": "15.9.7", - "@nrwl/tao": "15.9.7", - "@parcel/watcher": "2.0.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.0.0", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^7.0.2", - "dotenv": "~10.0.0", - "enquirer": "~2.3.6", - "fast-glob": "3.2.7", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "3.0.5", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.5.4", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "v8-compile-cache": "2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js" - }, - "optionalDependencies": { - "@nrwl/nx-darwin-arm64": "15.9.7", - "@nrwl/nx-darwin-x64": "15.9.7", - "@nrwl/nx-linux-arm-gnueabihf": "15.9.7", - "@nrwl/nx-linux-arm64-gnu": "15.9.7", - "@nrwl/nx-linux-arm64-musl": "15.9.7", - "@nrwl/nx-linux-x64-gnu": "15.9.7", - "@nrwl/nx-linux-x64-musl": "15.9.7", - "@nrwl/nx-win32-arm64-msvc": "15.9.7", - "@nrwl/nx-win32-x64-msvc": "15.9.7" - }, - "peerDependencies": { - "@swc-node/register": "^1.4.2", - "@swc/core": "^1.2.173" - }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=18" } }, - "node_modules/@nrwl/cli/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "ISC" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@nrwl/cli/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">=18" } }, - "node_modules/@nrwl/devkit": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-13.1.3.tgz", - "integrity": "sha512-TAAsZJvVc/obeH0rZKY6miVhyM2GHGb8qIWp9MAIdLlXf4VDcNC7rxwb5OrGVSwuTTjqGYBGPUx0yEogOOJthA==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "@nrwl/tao": "13.1.3", - "ejs": "^3.1.5", - "ignore": "^5.0.4", - "rxjs": "^6.5.4", - "semver": "7.3.4", - "tslib": "^2.0.0" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@nrwl/devkit/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@nrwl/devkit/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/@nrwl/devkit/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@nrwl/nx-darwin-arm64": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-arm64/-/nx-darwin-arm64-15.9.7.tgz", - "integrity": "sha512-aBUgnhlkrgC0vu0fK6eb9Vob7eFnkuknrK+YzTjmLrrZwj7FGNAeyGXSlyo1dVokIzjVKjJg2saZZ0WQbfuCJw==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "darwin" + "netbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-darwin-x64": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-x64/-/nx-darwin-x64-15.9.7.tgz", - "integrity": "sha512-L+elVa34jhGf1cmn38Z0sotQatmLovxoASCIw5r1CBZZeJ5Tg7Y9nOwjRiDixZxNN56hPKXm6xl9EKlVHVeKlg==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "darwin" + "netbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-linux-arm-gnueabihf": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-15.9.7.tgz", - "integrity": "sha512-pqmfqqEUGFu6PmmHKyXyUw1Al0Ki8PSaR0+ndgCAb1qrekVDGDfznJfaqxN0JSLeolPD6+PFtLyXNr9ZyPFlFg==", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", "cpu": [ - "arm" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-linux-arm64-gnu": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-15.9.7.tgz", - "integrity": "sha512-NYOa/eRrqmM+In5g3M0rrPVIS9Z+q6fvwXJYf/KrjOHqqan/KL+2TOfroA30UhcBrwghZvib7O++7gZ2hzwOnA==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", "cpu": [ - "arm64" + "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openbsd" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-linux-arm64-musl": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-musl/-/nx-linux-arm64-musl-15.9.7.tgz", - "integrity": "sha512-zyStqjEcmbvLbejdTOrLUSEdhnxNtdQXlmOuymznCzYUEGRv+4f7OAepD3yRoR0a/57SSORZmmGQB7XHZoYZJA==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-linux-x64-gnu": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-gnu/-/nx-linux-x64-gnu-15.9.7.tgz", - "integrity": "sha512-saNK5i2A8pKO3Il+Ejk/KStTApUpWgCxjeUz9G+T8A+QHeDloZYH2c7pU/P3jA9QoNeKwjVO9wYQllPL9loeVg==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "sunos" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-linux-x64-musl": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-musl/-/nx-linux-x64-musl-15.9.7.tgz", - "integrity": "sha512-extIUThYN94m4Vj4iZggt6hhMZWQSukBCo8pp91JHnDcryBg7SnYmnikwtY1ZAFyyRiNFBLCKNIDFGkKkSrZ9Q==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", "cpu": [ - "x64" + "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-win32-arm64-msvc": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-15.9.7.tgz", - "integrity": "sha512-GSQ54hJ5AAnKZb4KP4cmBnJ1oC4ILxnrG1mekxeM65c1RtWg9NpBwZ8E0gU3xNrTv8ZNsBeKi/9UhXBxhsIh8A==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", "cpu": [ - "arm64" + "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/nx-win32-x64-msvc": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-x64-msvc/-/nx-win32-x64-msvc-15.9.7.tgz", - "integrity": "sha512-x6URof79RPd8AlapVbPefUD3ynJZpmah3tYaYZ9xZRMXojVtEHV8Qh5vysKXQ1rNYJiiB8Ah6evSKWLbAH60tw==", + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">= 10" + "node": ">=18" } }, - "node_modules/@nrwl/tao": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-13.1.3.tgz", - "integrity": "sha512-/IwJgSgCBD1SaF+n8RuXX2OxDAh8ut/+P8pMswjm8063ac30UlAHjQ4XTYyskLH8uoUmNi2hNaGgHUrkwt7tQA==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "4.1.0", - "enquirer": "~2.3.6", - "fs-extra": "^9.1.0", - "jsonc-parser": "3.0.0", - "nx": "13.1.3", - "rxjs": "^6.5.4", - "rxjs-for-await": "0.0.2", - "semver": "7.3.4", - "tmp": "~0.2.1", - "tslib": "^2.0.0", - "yargs-parser": "20.0.0" + "eslint-visitor-keys": "^3.4.3" }, - "bin": { - "tao": "index.js" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@nrwl/tao/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@nrwl/tao/node_modules/semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" }, "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@nrwl/tao/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" }, - "node_modules/@parcel/watcher": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", - "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, - "hasInstallScript": true, "license": "MIT", "dependencies": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@playwright/test": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", - "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "Apache-2.0", + "license": "ISC", "dependencies": { - "playwright": "1.55.1" - }, - "bin": { - "playwright": "cli.js" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@rollup/pluginutils": "^3.0.8" + "@eslint/core": "^0.17.0" }, - "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">= 10.0.0" - }, - "peerDependencies": { - "rollup": "^2.42.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">= 8.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, - "node_modules/@schematics/angular": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.11.tgz", - "integrity": "sha512-imKBnKYEse0SBVELZO/753nkpt3eEgpjrYkB+AFWF9YfO/4RGnYXDHoH8CFkzxPH9QQCgNrmsVFNiYGS+P/S1A==", + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, + "license": "MIT", "dependencies": { - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "jsonc-parser": "3.0.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 4" + } }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, - "node_modules/@types/angular": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.9.tgz", - "integrity": "sha512-Z0HukqZkx0fotsV3QO00yqU9NzcQI+tMcrum+8MvfB4ePqCawZctF/gz6QiuII+T1ax+LitNoPx/eICTgnF4sg==", - "dev": true - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { - "@types/connect": "*", - "@types/node": "*" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@types/diff-match-patch": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", - "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", - "dev": true + "node_modules/@gar/promise-retry": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", + "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" + "license": "Apache-2.0", + "optional": true + }, + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" } }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true - }, - "node_modules/@types/express": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.24.tgz", - "integrity": "sha512-Mbrt4SRlXSTWryOnHAh2d4UQ/E7n9lZyGSi6KgX+4hkuL9soYbLOVXVhnk/ODp12YsGc95f4pOvqywJ6kngUwg==", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@types/express/node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@types/highlight.js": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", - "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, - "node_modules/@types/http-proxy": { - "version": "1.17.17", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", - "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "node_modules/@types/jquery": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", - "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, + "license": "ISC", "dependencies": { - "@types/sizzle": "*" + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" } }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/lodash": { - "version": "4.14.144", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", - "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", - "dev": true - }, - "node_modules/@types/mathjax": { - "version": "0.0.35", - "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.35.tgz", - "integrity": "sha512-flo9bVJE2Lzv3X5NQXVhNhv7srqk//Ngr8MT+/jRErkWGYkk8EBm42J5W0XUH6p4nWF1iLGe+atSuIkR5wA2yw==", - "dev": true - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/@types/node": { - "version": "12.19.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.16.tgz", - "integrity": "sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==", - "dev": true + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } }, - "node_modules/@types/node-forge": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", - "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, - "node_modules/@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==", - "dev": true - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "MIT", + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, - "node_modules/@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, - "dependencies": { - "@types/express": "*" - } + "license": "MIT" }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "node_modules/@jsonjoy.com/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@types/sizzle": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", - "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", - "dev": true - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "node_modules/@jsonjoy.com/buffers": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-17.67.0.tgz", + "integrity": "sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@types/webpack-env": { - "version": "1.18.8", - "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", - "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", - "dev": true - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "node_modules/@jsonjoy.com/codegen": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-1.0.0.tgz", + "integrity": "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==", "dev": true, - "dependencies": { - "@types/node": "*" + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "node_modules/@jsonjoy.com/fs-core": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.3.tgz", + "integrity": "sha512-IvO50vkGydDZwS1e9rz/JXEtCCt9XvqxoGI6FlrVIvVm4/HpygMKW4ETtREWtMTsN5CLJ9FR6GuCduoQPZLBiw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@jsonjoy.com/fs-node-builtins": "4.57.3", + "@jsonjoy.com/fs-node-utils": "4.57.3", + "thingies": "^2.5.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "tslib": "2" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@jsonjoy.com/fs-fsa": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.3.tgz", + "integrity": "sha512-JlIDGUWPl7Y6zl+/ISnZuh8z2aMr/xoR66D18zlaVAuL192CvlNJEzOlzp27x4P52HRtDnCSOk6f59vTsmp5vw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ms": "^2.1.3" + "@jsonjoy.com/fs-core": "4.57.3", + "@jsonjoy.com/fs-node-builtins": "4.57.3", + "@jsonjoy.com/fs-node-utils": "4.57.3", + "thingies": "^2.5.0" }, "engines": { - "node": ">=6.0" + "node": ">=10.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@jsonjoy.com/fs-node": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.3.tgz", + "integrity": "sha512-089gZoKvbeOsT2jeBaVKSz91oFXQWFG7a62sMY6gVMHnoWbyGzTb6OVUP/V7G3wLQLJ555BEsHt8SD1nj1dgaQ==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.3", + "@jsonjoy.com/fs-node-builtins": "4.57.3", + "@jsonjoy.com/fs-node-utils": "4.57.3", + "@jsonjoy.com/fs-print": "4.57.3", + "@jsonjoy.com/fs-snapshot": "4.57.3", + "glob-to-regex.js": "^1.0.0", + "thingies": "^2.5.0" }, "engines": { - "node": ">=10" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.27.1.tgz", - "integrity": "sha512-Vd8uewIixGP93sEnmTRIH6jHZYRQRkGPDPpapACMvitJKX8335VHNyqKTE+mZ+m3E2c5VznTZfSsSsS5IF7vUA==", + "node_modules/@jsonjoy.com/fs-node-builtins": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.3.tgz", + "integrity": "sha512-JAI3PqNuY8BR7ovy4h0bADLrqJLIcUauONNZfyTxUnj3Wf3tpTYe39eJ6z7FzYyA+tdMt33VpiQQUikGr3QOBw==", "dev": true, - "dependencies": { - "@typescript-eslint/utils": "5.27.1" - }, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz", - "integrity": "sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg==", + "node_modules/@jsonjoy.com/fs-node-to-fsa": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.3.tgz", + "integrity": "sha512-uZGxyC0zDmcmW5bfHd4YivAZ54BLlbF9G0K5rBaksI/tZdJSGM7/AC+1TY7yvFu0Wc6gUHR7mFwf6SbQ3J1BTQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1" + "@jsonjoy.com/fs-fsa": "4.57.3", + "@jsonjoy.com/fs-node-builtins": "4.57.3", + "@jsonjoy.com/fs-node-utils": "4.57.3" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.1.tgz", - "integrity": "sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg==", + "node_modules/@jsonjoy.com/fs-node-utils": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.3.tgz", + "integrity": "sha512-quCil8AvfcOxob4pn0drGdcQWpkPVgkt9q1+EjeyXXT40/L3l5lvYrr6hR8LmHu0eg+DNNaUwqjLT6Hr7V4sdQ==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-node-builtins": "4.57.3" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz", - "integrity": "sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw==", + "node_modules/@jsonjoy.com/fs-print": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.3.tgz", + "integrity": "sha512-ITwaLZpGIqD9jHndwMvDFZDIvbVzGRsJZDQ5HKln0vyMculu1c1nb7zbEBgY8BVSBZ9S2xO138OWIBGeRsrF3Q==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "@jsonjoy.com/fs-node-utils": "4.57.3", + "tree-dump": "^1.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.1.tgz", - "integrity": "sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w==", + "node_modules/@jsonjoy.com/fs-snapshot": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.3.tgz", + "integrity": "sha512-wdNaG2DxCtvj9lKldAnEV3ycYPEpk+p2cP2lHD1qdxkoQGlWUtQverqvG9KZSkm6BHFha4PP6XRZbpARNfHRxA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@jsonjoy.com/buffers": "^17.65.0", + "@jsonjoy.com/fs-node-utils": "4.57.3", + "@jsonjoy.com/json-pack": "^17.65.0", + "@jsonjoy.com/util": "^17.65.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz", - "integrity": "sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ==", + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/base64": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-17.67.0.tgz", + "integrity": "sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.27.1", - "eslint-visitor-keys": "^3.3.0" - }, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/codegen": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/codegen/-/codegen-17.67.0.tgz", + "integrity": "sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==", "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, + "license": "Apache-2.0", "engines": { - "node": ">=6.0" + "node": ">=10.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pack": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-17.67.0.tgz", + "integrity": "sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/base64": "17.67.0", + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0", + "@jsonjoy.com/json-pointer": "17.67.0", + "@jsonjoy.com/util": "17.67.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/json-pointer": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-17.67.0.tgz", + "integrity": "sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" + "@jsonjoy.com/util": "17.67.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "tslib": "2" } }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@jsonjoy.com/fs-snapshot/node_modules/@jsonjoy.com/util": { + "version": "17.67.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-17.67.0.tgz", + "integrity": "sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ms": "^2.1.3" + "@jsonjoy.com/buffers": "17.67.0", + "@jsonjoy.com/codegen": "17.67.0" }, "engines": { - "node": ">=6.0" + "node": ">=10.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "node_modules/@jsonjoy.com/json-pack": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.21.0.tgz", + "integrity": "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@jsonjoy.com/base64": "^1.1.2", + "@jsonjoy.com/buffers": "^1.2.0", + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/json-pointer": "^1.0.2", + "@jsonjoy.com/util": "^1.9.0", + "hyperdyperid": "^1.2.0", + "thingies": "^2.5.0", + "tree-dump": "^1.1.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "node_modules/@jsonjoy.com/json-pack/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "tslib": "2" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@jsonjoy.com/json-pointer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pointer/-/json-pointer-1.0.2.tgz", + "integrity": "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ms": "^2.1.3" + "@jsonjoy.com/codegen": "^1.0.0", + "@jsonjoy.com/util": "^1.9.0" }, "engines": { - "node": ">=6.0" + "node": ">=10.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "node_modules/@jsonjoy.com/util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.9.0.tgz", + "integrity": "sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/buffers": "^1.0.0", + "@jsonjoy.com/codegen": "^1.0.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "node_modules/@jsonjoy.com/util/node_modules/@jsonjoy.com/buffers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/buffers/-/buffers-1.2.1.tgz", + "integrity": "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "github", + "url": "https://github.com/sponsors/streamich" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "tslib": "2" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", "dev": true, + "license": "MIT" + }, + "node_modules/@ljharb/resumer": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.0.1.tgz", + "integrity": "sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==", + "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "@ljharb/through": "^2.3.9" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 0.4" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node_modules/@ljharb/through": { + "version": "2.3.14", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.14.tgz", + "integrity": "sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8" }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", + "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", + "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", + "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", + "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", + "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", + "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", + "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=18" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@module-federation/bridge-react-webpack-plugin": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/bridge-react-webpack-plugin/-/bridge-react-webpack-plugin-2.5.0.tgz", + "integrity": "sha512-Ux9XVW//K6K+KHKPdc0Jnc7RtTpZaEXgbVhp5yovtFkCJVt8hEClcTeuI18MvvLiV/q2hUpCU5Wsf9zNaIYStQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@module-federation/sdk": "2.5.0", + "@types/semver": "7.5.8", + "semver": "7.6.3" } }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "node_modules/@module-federation/bridge-react-webpack-plugin/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, + "license": "ISC", + "peer": true, "bin": { "semver": "bin/semver.js" }, @@ -5158,12317 +5867,3733 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "node_modules/@module-federation/cli": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/cli/-/cli-2.5.0.tgz", + "integrity": "sha512-+czXA6yoiiF9W6+YEOCpQE6zpGZpA89X0oCEz3EaWPTkL4chEbxurjpME8CMnJk9iuFxl167+cBQiQlVBiHGGg==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@module-federation/dts-plugin": "2.5.0", + "@module-federation/sdk": "2.5.0", + "commander": "11.1.0", + "jiti": "2.4.2" }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "bin": { + "mf": "bin/mf.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "node_modules/@module-federation/dts-plugin": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/dts-plugin/-/dts-plugin-2.5.0.tgz", + "integrity": "sha512-q7KDhJ5tn2HrUV7uMuh/L3TaaztUosE+4LAb90sxx0pPPqWRwlpBpxu1REubv5BWXmU1K/Ozn14u6jRbjLVaGA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + "@module-federation/error-codes": "2.5.0", + "@module-federation/managers": "2.5.0", + "@module-federation/sdk": "2.5.0", + "@module-federation/third-party-dts-extractor": "2.5.0", + "adm-zip": "0.5.10", + "ansi-colors": "4.1.3", + "isomorphic-ws": "5.0.0", + "node-schedule": "2.1.1", + "undici": "7.24.7", + "ws": "8.18.0" + }, + "peerDependencies": { + "typescript": "^4.9.0 || ^5.0.0", + "vue-tsc": ">=1.0.24" + }, + "peerDependenciesMeta": { + "vue-tsc": { + "optional": true + } } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "node_modules/@module-federation/enhanced": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/enhanced/-/enhanced-2.5.0.tgz", + "integrity": "sha512-P91tzwyKSCQ6AwirqvAvTqWqmTY79ndpH0uenejFw+bbLpWrjuY0q+iZUXCV/7CSNmqwH2bkA/ssuyZljmcMVQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" + "@module-federation/bridge-react-webpack-plugin": "2.5.0", + "@module-federation/cli": "2.5.0", + "@module-federation/dts-plugin": "2.5.0", + "@module-federation/error-codes": "2.5.0", + "@module-federation/inject-external-runtime-core-plugin": "2.5.0", + "@module-federation/managers": "2.5.0", + "@module-federation/manifest": "2.5.0", + "@module-federation/rspack": "2.5.0", + "@module-federation/runtime-tools": "2.5.0", + "@module-federation/sdk": "2.5.0", + "@module-federation/webpack-bundler-runtime": "2.5.0", + "schema-utils": "4.3.0", + "tapable": "2.3.0", + "upath": "2.0.1" + }, + "bin": { + "mf": "bin/mf.js" + }, + "peerDependencies": { + "typescript": "^4.9.0 || ^5.0.0", + "vue-tsc": ">=1.0.24", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + }, + "webpack": { + "optional": true + } } }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "node_modules/@module-federation/error-codes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-2.5.0.tgz", + "integrity": "sha512-sq05/8Gp3csy1nr2/f76K3vLy0/xRqVtP71ibGy8BiLg7h1UxWN7G4EwAKSrPZ4FnsERGeFlIszg5Z+MqlwhFg==", "dev": true, + "license": "MIT", "peer": true }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "node_modules/@module-federation/inject-external-runtime-core-plugin": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/inject-external-runtime-core-plugin/-/inject-external-runtime-core-plugin-2.5.0.tgz", + "integrity": "sha512-e2KyTHpesBrPXGHMh4d4+s2xBiNoxbiFJkPRYHMCl81a/Gu+byrMkriZcV4VM/TFvBIlrgOJisVc1nnBI5UDRQ==", "dev": true, + "license": "MIT", "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" + "peerDependencies": { + "@module-federation/runtime-tools": "2.5.0" } }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "node_modules/@module-federation/managers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/managers/-/managers-2.5.0.tgz", + "integrity": "sha512-9b5mU/7OYbKrYUJmhZ1kkfeJCZqR7qX6/FWp+oOfZMzUynN7Rb41dwoUs3TdnOKzbZ3CCwtZ2WsR4pF9ZNvuJA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@xtuc/ieee754": "^1.2.0" + "@module-federation/sdk": "2.5.0", + "find-pkg": "2.0.0" } }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "node_modules/@module-federation/manifest": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/manifest/-/manifest-2.5.0.tgz", + "integrity": "sha512-pmwQCGWjM2oKY7CkR7nEDOfMK0bNFJUifuDxuOB5iOWhU+Rp92UyyBI9IbJAtiISTSFGtuKRy40peJGvQq2VcQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@xtuc/long": "4.2.2" + "@module-federation/dts-plugin": "2.5.0", + "@module-federation/managers": "2.5.0", + "@module-federation/sdk": "2.5.0", + "find-pkg": "2.0.0" } }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "node_modules/@module-federation/rspack": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/rspack/-/rspack-2.5.0.tgz", + "integrity": "sha512-OAFMpMXuLEQFmWBuC1I7LNDQ8N3CDANXe0YGPWkIPNxKq5Tj/KNfDidmutoYgvXlZKOM4yKBKBsL6Xt/UvtOIw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" + "@module-federation/bridge-react-webpack-plugin": "2.5.0", + "@module-federation/dts-plugin": "2.5.0", + "@module-federation/inject-external-runtime-core-plugin": "2.5.0", + "@module-federation/managers": "2.5.0", + "@module-federation/manifest": "2.5.0", + "@module-federation/runtime-tools": "2.5.0", + "@module-federation/sdk": "2.5.0" + }, + "peerDependencies": { + "@rspack/core": "^0.7.0 || ^1.0.0 || ^2.0.0-0", + "typescript": "^4.9.0 || ^5.0.0", + "vue-tsc": ">=1.0.24" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } } }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "node_modules/@module-federation/runtime": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-2.5.0.tgz", + "integrity": "sha512-dOc7pFEf8aruHBk5hoJLnvwkCa5ELT78q3o9dqcdaa/TT74X5z0FT0BsaGaRBPcse/iP6czK3fWd7RLv5ZKP5g==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "@module-federation/error-codes": "2.5.0", + "@module-federation/runtime-core": "2.5.0", + "@module-federation/sdk": "2.5.0" } }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "node_modules/@module-federation/runtime-core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-2.5.0.tgz", + "integrity": "sha512-STmhQ3c6/hunba2FMP6GrHazXU/8GuN7Gk4dOkWNRpnqYIoD8Wx4MNl76j3HdCzBESC7uSMXTniksVaM1+xxyA==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" + "@module-federation/error-codes": "2.5.0", + "@module-federation/sdk": "2.5.0" } }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "node_modules/@module-federation/runtime-tools": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-2.5.0.tgz", + "integrity": "sha512-fR3Na6V78ov3/O17Mev+1vydfmqlYWP4ZNxD/bBkmqKhCO7jMdthNTT02yDljlCyhYl6+X90UJlFhwFle6rIsw==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "@module-federation/runtime": "2.5.0", + "@module-federation/webpack-bundler-runtime": "2.5.0" } }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "node_modules/@module-federation/sdk": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-2.5.0.tgz", + "integrity": "sha512-ScU22XDyV77l50njjzewMpMlNN1CYo0tHS1D6iy+vNKWrHGq8DWVB0vwG8dmvx/WZ4uq+sXgUsQet17MoKsfZw==", "dev": true, + "license": "MIT", "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" + "peerDependencies": { + "node-fetch": "^2.7.0 || ^3.3.2" + }, + "peerDependenciesMeta": { + "node-fetch": { + "optional": true + } } }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "node_modules/@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "node_modules/@module-federation/third-party-dts-extractor": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/third-party-dts-extractor/-/third-party-dts-extractor-2.5.0.tgz", + "integrity": "sha512-5di43LGk2ies86Cj8QyzYr540Ijc+nyPqYziyFotL6Pparnu+uf3b3ERfEyQfBmEcyGk1MpitQIO2J3bd9BcNw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "peer": true, "dependencies": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.15.0" + "find-pkg": "2.0.0", + "resolve": "1.22.8" } }, - "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "node_modules/@module-federation/webpack-bundler-runtime": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-2.5.0.tgz", + "integrity": "sha512-UxVad+tNZYkBnZzqJQsZa0pB5gO5cJoCjMumOo3bhzXBJVqHsFupfeHa8Nk7WrRVbJE6zRT9ZHK0s0NDWBMyJw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "@module-federation/error-codes": "2.5.0", + "@module-federation/runtime": "2.5.0", + "@module-federation/sdk": "2.5.0" } }, - "node_modules/@zkochan/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Python-2.0" - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "node_modules/abs-svg-path": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", - "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], "dev": true, - "engines": { - "node": ">= 0.6" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "deprecated": "package has been renamed to acorn-import-attributes", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], "dev": true, - "peer": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, "engines": { - "node": ">=10.13.0" + "node": ">= 10" }, - "peerDependencies": { - "acorn": "^8.14.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.4.0" + "node": ">= 10" } }, - "node_modules/adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8.9" + "node": ">= 10" } }, - "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8.9.0" + "node": ">= 10" } }, - "node_modules/adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "adler32": "bin/adler32.njs" - }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.8" + "node": ">= 10" } }, - "node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4.0.0" + "node": ">= 10" } }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8.0.0" + "node": ">= 10" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">= 10" } }, - "node_modules/ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "dependencies": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 10" } }, - "node_modules/align-text/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "dependencies": { - "is-buffer": "^1.1.5" - }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 10" } }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.4.2" + "node": ">= 10" } }, - "node_modules/angular": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz", - "integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==", - "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward." - }, - "node_modules/ansi_up": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-6.0.6.tgz", - "integrity": "sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==", + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "*" + "node": ">= 10" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6" + "node": ">= 10" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.7.tgz", + "integrity": "sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==", "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "type-fest": "^0.21.3" - }, + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@tybys/wasm-util": "^0.10.1" + } + }, + "node_modules/@ngtools/webpack": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-21.2.13.tgz", + "integrity": "sha512-Y3W1x5+P8mHXRIkeSxGdj10ipQjJkTT6/bc/Sz5BN2qacbNIYIDg0fnk/ikvl9KAvI/49gUwYxfq4QBodS5ktQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@angular/compiler-cli": "^21.0.0", + "typescript": ">=5.9 <6.0", + "webpack": "^5.54.0" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 16" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://paulmillr.com/funding/" } }, - "node_modules/ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "node_modules/@npmcli/agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.2.tgz", + "integrity": "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg==", "dev": true, - "engines": [ - "node >= 0.8.0" - ], - "bin": { - "ansi-html": "bin/ansi-html" + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@npmcli/agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 14" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "agent-base": "^7.1.2", + "debug": "4" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 14" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 8" + "node": "20 || >=22" } }, - "node_modules/aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "dev": true - }, - "node_modules/are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "node_modules/@npmcli/fs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", + "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, "engines": { - "node": ">=14" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", + "node_modules/@npmcli/git": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz", + "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==", "dev": true, + "license": "ISC", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", "dev": true, - "license": "MIT" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, - "node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "node_modules/@npmcli/git/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", "dev": true, + "license": "ISC", "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">=6.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz", + "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==", + "dev": true, + "license": "ISC", "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "installed-package-contents": "bin/index.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true + "node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", + "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "node_modules/@npmcli/package-json": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz", + "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==", "dev": true, + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", + "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=8" + "node": ">=20" } }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", "dev": true, + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" + "isexe": "^4.0.0" }, - "engines": { - "node": ">= 0.4" + "bin": { + "node-which": "bin/which.js" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "node_modules/@npmcli/redact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", + "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz", + "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==", "dev": true, + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0" }, "engines": { - "node": ">= 0.4" - }, + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.113.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", + "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", + "dev": true, + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 0.4" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.10.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.4" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], "dev": true, - "bin": { - "atob": "bin/atob.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 4.5.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/autoprefixer": { - "version": "10.4.21", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", - "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" ], - "dependencies": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">= 10.0.0" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/axios": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", - "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "node_modules/babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8.9" + "node": ">= 10.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/babel-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "node": ">= 10.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "node_modules/@peculiar/asn1-cms": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.7.0.tgz", + "integrity": "sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.14", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.14.tgz", - "integrity": "sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==", + "node_modules/@peculiar/asn1-csr": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.7.0.tgz", + "integrity": "sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA==", "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/@peculiar/asn1-ecc": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.7.0.tgz", + "integrity": "sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw==", "dev": true, - "engines": { - "node": "*" + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "node_modules/@peculiar/asn1-pfx": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.7.0.tgz", + "integrity": "sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-rsa": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.7.0.tgz", + "integrity": "sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw==", "dev": true, + "license": "MIT", "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.7.0.tgz", + "integrity": "sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pfx": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/@peculiar/asn1-rsa": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.7.0.tgz", + "integrity": "sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/body-parser/node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "node_modules/@peculiar/asn1-schema": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz", + "integrity": "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==", "dev": true, "license": "MIT", "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/body-parser/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "node_modules/@peculiar/asn1-x509": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.7.0.tgz", + "integrity": "sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.8" + "dependencies": { + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/utils": "^2.0.2", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/bonjour": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.1.tgz", - "integrity": "sha512-xONzj4PfpPJw6xSqCcT2SmQkBOXpUINUz3o3qXcWJwYlXbkZNcNaUae0o5lle7tKt4HHV6dTgkIRhAXZ3nBMsQ==", + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.7.0.tgz", + "integrity": "sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w==", "dev": true, "license": "MIT", "dependencies": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^7.2.3", - "multicast-dns-service-types": "^1.1.0" + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "tslib": "^2.8.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.1.1" + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" }, "engines": { - "node": ">=8" + "node": ">=20.0.0" } }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "node_modules/@playwright/test": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", + "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" + "playwright": "1.55.1" }, "bin": { - "browserslist": "cli.js" + "playwright": "cli.js" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + "node": ">=18" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", + "cpu": [ + "arm64" + ], "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } + "license": "MIT", + "optional": true, + "os": [ + "android" ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "dev": true - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", + "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001785", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001785.tgz", - "integrity": "sha512-blhOL/WNR+Km1RI/LCVAvA73xplXA7ZbjzI4YkMK9pa6T/P3F2GxjNpEkyw5repTw9IvkyrjyHpwjnhZ5FOvYQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", + "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", + "cpu": [ + "wasm32" ], - "license": "CC-BY-4.0" - }, - "node_modules/center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "@napi-rs/wasm-runtime": "^1.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=14.0.0" } }, - "node_modules/cfb": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", - "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0" + "@tybys/wasm-util": "^0.10.1" }, - "engines": { - "node": ">=0.8" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/cfb/node_modules/adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.8" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", + "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", + "dev": true, + "license": "MIT" }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", "dev": true, + "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "@rollup/pluginutils": "^5.1.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">=14.0.0" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true, - "engines": { - "node": ">=6.0" + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/circular-dependency-plugin": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", - "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", + "node_modules/@rollup/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">=6.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "webpack": ">=4.0.1" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], "dev": true, - "engines": { - "node": ">=6" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": ">= 10" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], "dev": true, - "engines": { - "node": ">=0.8" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/codepage": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", - "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==", - "dependencies": { - "commander": "~2.14.1", - "exit-on-epipe": "~1.0.1" - }, - "bin": { - "codepage": "bin/codepage.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/codepage/node_modules/commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], "dev": true, - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], "dev": true, "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], "dev": true, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "mime-db": ">= 1.43.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/compression/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/compression/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] }, - "node_modules/concurrently": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", - "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.3", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/concurrently/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/concurrently/node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/@rollup/wasm-node": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/wasm-node/-/wasm-node-4.60.4.tgz", + "integrity": "sha512-j6qaRjdDujJ5utX5l6+8eiWlvMLmBfPMBht8mHP2au3xuzf+4deu6PuCquH5GvDIvIOsWHZhA1UVz/s0FvvgAA==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "node_modules/@rollup/wasm-node/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, - "engines": { - "node": ">=0.8" - } + "license": "MIT" }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/@rspack/binding": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.7.11.tgz", + "integrity": "sha512-2MGdy2s2HimsDT444Bp5XnALzNRxuBNc7y0JzyuqKbHBywd4x2NeXyhWXXoxufaCFu5PBc9Qq9jyfjW2Aeh06Q==", "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } + "license": "MIT", + "peer": true, + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "1.7.11", + "@rspack/binding-darwin-x64": "1.7.11", + "@rspack/binding-linux-arm64-gnu": "1.7.11", + "@rspack/binding-linux-arm64-musl": "1.7.11", + "@rspack/binding-linux-x64-gnu": "1.7.11", + "@rspack/binding-linux-x64-musl": "1.7.11", + "@rspack/binding-wasm32-wasi": "1.7.11", + "@rspack/binding-win32-arm64-msvc": "1.7.11", + "@rspack/binding-win32-ia32-msvc": "1.7.11", + "@rspack/binding-win32-x64-msvc": "1.7.11" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.7.11.tgz", + "integrity": "sha512-oduECiZVqbO5zlVw+q7Vy65sJFth99fWPTyucwvLJJtJkPL5n17Uiql2cYP6Ijn0pkqtf1SXgK8WjiKLG5bIig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "node_modules/@rspack/binding-darwin-x64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.7.11.tgz", + "integrity": "sha512-a1+TtTE9ap6RalgFi7FGIgkJP6O4Vy6ctv+9WGJy53E4kuqHR0RygzaiVxCI/GMc/vBT9vY23hyrpWb3d1vtXA==", + "cpu": [ + "x64" + ], "dev": true, - "engines": { - "node": ">= 0.6" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true }, - "node_modules/contour_plot": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", - "integrity": "sha512-Nil2HI76Xux6sVGORvhSS8v66m+/h5CwFkBJDO+U5vWaMdNC0yXNCsGDPbzPhvqOEU5koebhdEvD372LI+IyLw==" + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.7.11.tgz", + "integrity": "sha512-P0QrGRPbTWu6RKWfN0bDtbnEps3rXH0MWIMreZABoUrVmNQKtXR6e73J3ub6a+di5s2+K0M2LJ9Bh2/H4UsDUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.7.11.tgz", + "integrity": "sha512-6ky7R43VMjWwmx3Yx7Jl7faLBBMAgMDt+/bN35RgwjiPgsIByz65EwytUVuW9rikB43BGHvA/eqlnjLrUzNBqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true }, - "node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.7.11.tgz", + "integrity": "sha512-cuOJMfCOvb2Wgsry5enXJ3iT1FGUjdPqtGUBVupQlEG4ntSYsQ2PtF4wIDVasR3wdxC5nQbipOrDiN/u6fYsdQ==", + "cpu": [ + "x64" + ], "dev": true, - "engines": { - "node": ">= 0.6" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.7.11.tgz", + "integrity": "sha512-CoK37hva4AmHGh3VCsQXmGr40L36m1/AdnN5LEjUX6kx5rEH7/1nEBN6Ii72pejqDVvk9anEROmPDiPw10tpFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true }, - "node_modules/copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.7.11.tgz", + "integrity": "sha512-OtrmnPUVJMxjNa3eDMfHyPdtlLRmmp/aIm0fQHlAOATbZvlGm12q7rhPW5BXTu1yh+1rQ1/uqvz+SzKEZXuJaQ==", + "cpu": [ + "wasm32" + ], "dev": true, + "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "is-what": "^3.14.1" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" + "@napi-rs/wasm-runtime": "1.0.7" } }, - "node_modules/copy-webpack-plugin": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.1.tgz", - "integrity": "sha512-nr81NhCAIpAWXGCK5thrKmfCQ6GDY0L5RN0U+BnIn/7Us55+UCex5ANNsNKmIVtDRnk0Ecf+/kzp9SUVrrBMLg==", + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.7.11.tgz", + "integrity": "sha512-lObFW6e5lCWNgTBNwT//yiEDbsxm9QG4BYUojqeXxothuzJ/L6ibXz6+gLMvbOvLGV3nKgkXmx8GvT9WDKR0mA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.7.11.tgz", + "integrity": "sha512-0pYGnZd8PPqNR68zQ8skamqNAXEA1sUfXuAdYcknIIRq2wsbiwFzIc0Pov1cIfHYab37G7sSIPBiOUdOWF5Ivw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.7.11.tgz", + "integrity": "sha512-EeQXayoQk/uBkI3pdoXfQBXNIUrADq56L3s/DFyM2pJeUDrWmhfIw2UFIGkYPTMSCo8F2JcdcGM32FGJrSnU0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@rspack/core": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.7.11.tgz", + "integrity": "sha512-rsD9b+Khmot5DwCMiB3cqTQo53ioPG3M/A7BySu8+0+RS7GCxKm+Z+mtsjtG/vsu4Tn2tcqCdZtA3pgLoJB+ew==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "fast-glob": "^3.2.7", - "glob-parent": "^6.0.1", - "globby": "^12.0.2", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" + "@module-federation/runtime-tools": "0.22.0", + "@rspack/binding": "1.7.11", + "@rspack/lite-tapable": "1.1.0" }, "engines": { - "node": ">= 12.20.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "^5.1.0" + "@swc/helpers": ">=0.5.1" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } } }, - "node_modules/copy-webpack-plugin/node_modules/array-union": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", - "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "node_modules/@rspack/core/node_modules/@module-federation/error-codes": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.22.0.tgz", + "integrity": "sha512-xF9SjnEy7vTdx+xekjPCV5cIHOGCkdn3pIxo9vU7gEZMIw0SvAEdsy6Uh17xaCpm8V0FWvR0SZoK9Ik6jGOaug==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT", + "peer": true }, - "node_modules/copy-webpack-plugin/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/@rspack/core/node_modules/@module-federation/runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.22.0.tgz", + "integrity": "sha512-38g5iPju2tPC3KHMPxRKmy4k4onNp6ypFPS1eKGsNLUkXgHsPMBFqAjDw96iEcjri91BrahG4XcdyKi97xZzlA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" + "@module-federation/error-codes": "0.22.0", + "@module-federation/runtime-core": "0.22.0", + "@module-federation/sdk": "0.22.0" } }, - "node_modules/copy-webpack-plugin/node_modules/globby": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", - "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", + "node_modules/@rspack/core/node_modules/@module-federation/runtime-core": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.22.0.tgz", + "integrity": "sha512-GR1TcD6/s7zqItfhC87zAp30PqzvceoeDGYTgF3Vx2TXvsfDrhP6Qw9T4vudDQL3uJRne6t7CzdT29YyVxlgIA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "array-union": "^3.0.1", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.7", - "ignore": "^5.1.9", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "@module-federation/error-codes": "0.22.0", + "@module-federation/sdk": "0.22.0" } }, - "node_modules/copy-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/@rspack/core/node_modules/@module-federation/runtime-tools": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.22.0.tgz", + "integrity": "sha512-4ScUJ/aUfEernb+4PbLdhM/c60VHl698Gn1gY21m9vyC1Ucn69fPCA1y2EwcCB7IItseRMoNhdcWQnzt/OPCNA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "@module-federation/runtime": "0.22.0", + "@module-federation/webpack-bundler-runtime": "0.22.0" } }, - "node_modules/copy-webpack-plugin/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "node_modules/@rspack/core/node_modules/@module-federation/sdk": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.22.0.tgz", + "integrity": "sha512-x4aFNBKn2KVQRuNVC5A7SnrSCSqyfIWmm1DvubjbO9iKFe7ith5niw8dqSFBekYBg2Fwy+eMg4sEFNVvCAdo6g==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", - "hasInstallScript": true + "license": "MIT", + "peer": true }, - "node_modules/core-js-compat": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", - "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", + "node_modules/@rspack/core/node_modules/@module-federation/webpack-bundler-runtime": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.22.0.tgz", + "integrity": "sha512-aM8gCqXu+/4wBmJtVeMeeMN5guw3chf+2i6HajKtQv7SJfxV/f4IyNQJUeUQu9HfiAZHjqtMV5Lvq/Lvh8LdyA==", "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "browserslist": "^4.26.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" + "@module-federation/runtime": "0.22.0", + "@module-federation/sdk": "0.22.0" } }, - "node_modules/core-js-pure": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.46.0.tgz", - "integrity": "sha512-NMCW30bHNofuhwLhYPt66OLOKTMbOhgTTatKVbaQC3KRHpTCiRIBYvtshr+NBYSnBxwAFhjW/RfJ0XbIjS16rw==", + "node_modules/@rspack/lite-tapable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.1.0.tgz", + "integrity": "sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==", "dev": true, - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } + "license": "MIT", + "peer": true }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "node_modules/@schematics/angular": { + "version": "21.2.13", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.13.tgz", + "integrity": "sha512-e5guslSLKbb3PJ6gUuVqM+V9xgn68cJkG1IyBohho34shbpOeoWW2eYdWQQjxvn0KUdgEhYSRBluBamCHngaUA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "@angular-devkit/core": "21.2.13", + "@angular-devkit/schematics": "21.2.13", + "jsonc-parser": "3.3.1" }, "engines": { - "node": ">=10" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, - "node_modules/cosmiconfig/node_modules/yaml": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "node_modules/@sigstore/bundle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", + "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==", "dev": true, - "license": "ISC", + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, "engines": { - "node": ">= 6" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "bin": { - "crc32": "bin/crc32.njs" - }, + "node_modules/@sigstore/core": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.1.tgz", + "integrity": "sha512-qRsxPnCrbC/puegGxKuynfnxgLiHqWStrSjxkoB4YKqq3Z3s4cyZyj42ZdWFAEblNP65C+rBH8EuREHIXoi83g==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=0.8" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "node_modules/@sigstore/protobuf-specs": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.1.tgz", + "integrity": "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, - "node_modules/critters": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", - "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "node_modules/@sigstore/sign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.1.tgz", + "integrity": "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "chalk": "^4.1.0", - "css-select": "^4.2.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "postcss": "^8.3.7", - "pretty-bytes": "^5.3.0" + "@gar/promise-retry": "^1.0.2", + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.4", + "proc-log": "^6.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/critters/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/cross-env": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", - "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "node_modules/@sigstore/tuf": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.2.tgz", + "integrity": "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@epic-web/invariant": "^1.0.0", - "cross-spawn": "^7.0.6" - }, - "bin": { - "cross-env": "dist/bin/cross-env.js", - "cross-env-shell": "dist/bin/cross-env-shell.js" + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" }, "engines": { - "node": ">=20" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/@sigstore/verify": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.1.tgz", + "integrity": "sha512-qv7+G3J2cc6wwFj3yKvXOamzqhMwSk1ogPGmhpS8iXllcPrJaIIBA+4HbttlHVu1pqWTdmaCH/WE7UOC51kdoA==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.1", + "@sigstore/protobuf-specs": "^0.5.0" }, "engines": { - "node": ">= 8" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } + "license": "MIT" }, - "node_modules/css-blank-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", - "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-blank-pseudo": "dist/cli.cjs" - }, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "node_modules/@tufjs/models": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.1.0.tgz", + "integrity": "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==", "dev": true, + "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.1.1" }, "engines": { - "node": ">=4" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/css-has-pseudo": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", - "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "bin": { - "css-has-pseudo": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "tslib": "^2.4.0" } }, - "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "node_modules/@types/angular": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.9.tgz", + "integrity": "sha512-Z0HukqZkx0fotsV3QO00yqU9NzcQI+tMcrum+8MvfB4ePqCawZctF/gz6QiuII+T1ax+LitNoPx/eICTgnF4sg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", "dev": true, + "license": "MIT", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/css-loader": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz", - "integrity": "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==", + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, + "license": "MIT", "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "@types/node": "*" } }, - "node_modules/css-prefers-color-scheme": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "bin": { - "css-prefers-color-scheme": "dist/cli.cjs" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, + "license": "MIT", "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" + "@types/express-serve-static-core": "*", + "@types/node": "*" } }, - "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "node_modules/@types/diff-match-patch": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", + "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } + "license": "MIT" }, - "node_modules/css/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" } }, - "node_modules/cssdb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-5.1.0.tgz", - "integrity": "sha512-/vqjXhv1x9eGkE/zO6o8ZOI7dgdZbLVLUGyVRbPgk6YipXbW87YzUCcO+Jrmi5bwJlAH6oD+MNeZyRgXea1GZw==", - "dev": true - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" } }, - "node_modules/cuint": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", - "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", - "dev": true - }, - "node_modules/d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==" - }, - "node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - }, - "node_modules/d3-collection": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" }, - "node_modules/d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" }, - "node_modules/d3-composite-projections": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/d3-composite-projections/-/d3-composite-projections-1.2.3.tgz", - "integrity": "sha512-RxNBoRGf3epTnQBUKeEpaXpD8BA/Ud0xRuLwWxyI7dWfuuYgJZMKw6ZsZOwfDNC0ZbMWaU0eBFlL05A2jlcsWg==", + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-geo": "^1.11.6", - "d3-path": "^1.0.7" + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" } }, - "node_modules/d3-composite-projections/node_modules/d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "license": "MIT", "dependencies": { - "d3-array": "1" + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" } }, - "node_modules/d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" - }, - "node_modules/d3-dsv": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.10.tgz", - "integrity": "sha512-vqklfpxmtO2ZER3fq/B33R/BIz3A1PV0FaZRuFM8w6jLo7sUX1BZDh73fPlr0s327rzq4H6EN1q9U+eCBCSN8g==", - "dependencies": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json", - "csv2tsv": "bin/dsv2dsv", - "dsv2dsv": "bin/dsv2dsv", - "dsv2json": "bin/dsv2json", - "json2csv": "bin/json2dsv", - "json2dsv": "bin/json2dsv", - "json2tsv": "bin/json2dsv", - "tsv2csv": "bin/dsv2dsv", - "tsv2json": "bin/dsv2json" - } - }, - "node_modules/d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" - }, - "node_modules/d3-geo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.6.4.tgz", - "integrity": "sha512-O5Q3iftLc6/EdU1MHUm+O29NoKKN/cyQtySnD9/yEEcinN+q4ng+H56e2Yn1YWdfZBoiaRVtR2NoJ3ivKX5ptQ==", - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/d3-geo-projection": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.1.2.tgz", - "integrity": "sha512-zft6RRvPaB1qplTodBVcSH5Ftvmvvg0qoDiqpt+fyNthGr/qr+DD30cizNDluXjW7jmo7EKUTjvFCAHofv08Ow==", - "dependencies": { - "commander": "2", - "d3-array": "1", - "d3-geo": "^1.1.0" - }, - "bin": { - "geo2svg": "bin/geo2svg", - "geograticule": "bin/geograticule", - "geoproject": "bin/geoproject", - "geostitch": "bin/geostitch" - } - }, - "node_modules/d3-hexjson": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d3-hexjson/-/d3-hexjson-1.0.1.tgz", - "integrity": "sha512-TeH4T0PSbDazMm3gHgc4ulO0PfrZpz0Uk3y5tCGz+NgC7HnX7KBdem7uAN+j9x3ZshTh7raN3V/bFhaLB2C8DA==", - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/d3-hierarchy": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" - }, - "node_modules/d3-interpolate": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", - "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", - "dependencies": { - "d3-color": "1" - } - }, - "node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - }, - "node_modules/d3-sankey": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.7.1.tgz", - "integrity": "sha512-KAyowBWtTLQxyXq1UhXcdCXKbuCQvL51FgqOS+fKlNTQ/4FfSWabRlWs2DezzwKyredAsOhBSQZN/i0XdeE2tQ==", - "dependencies": { - "d3-array": "1", - "d3-collection": "1", - "d3-shape": "^1.2.0" - } - }, - "node_modules/d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" - }, - "node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" - }, - "node_modules/d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "dependencies": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "node_modules/d3-voronoi": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", - "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" - }, - "node_modules/dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", - "dependencies": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/default-gateway": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/default-gateway/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-gateway/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/default-gateway/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/default-gateway/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/default-gateway/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-gateway/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/default-gateway/node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", - "dev": true, - "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/detect-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", - "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true - }, - "node_modules/diff": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.1.tgz", - "integrity": "sha512-Z3u54A8qGyqFOSr2pk0ijYs8mOE9Qz8kTvtKeBI+upoG9j04Sq+oI7W8zAJiQybDcESET8/uIdHzs0p3k4fZlw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", - "dev": true - }, - "node_modules/dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@leichtgewicht/ip-codec": "^2.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", - "dev": true, - "dependencies": { - "buffer-indexof": "^1.0.0" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "dependencies": { - "minimatch": "^3.0.4" - }, - "bin": { - "ignored": "bin/ignored" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true, - "license": "MIT" - }, - "node_modules/editions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", - "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", - "dev": true, - "dependencies": { - "version-range": "^4.15.0" - }, - "engines": { - "ecmascript": ">= es5", - "node": ">=4" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.331", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.331.tgz", - "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==", - "dev": true, - "license": "ISC" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", - "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", - "dev": true, - "optional": true, - "dependencies": { - "prr": "~1.0.1" - }, - "bin": { - "errno": "cli.js" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "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.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dev": true, - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/esbuild": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz", - "integrity": "sha512-CjFCFGgYtbFOPrwZNJf7wsuzesx8kqwAffOlbYcFDLFuUtP8xloK1GH+Ai13Qr0RZQf9tE7LMTHJ2iVGJ1SKZA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "esbuild-android-arm64": "0.14.22", - "esbuild-darwin-64": "0.14.22", - "esbuild-darwin-arm64": "0.14.22", - "esbuild-freebsd-64": "0.14.22", - "esbuild-freebsd-arm64": "0.14.22", - "esbuild-linux-32": "0.14.22", - "esbuild-linux-64": "0.14.22", - "esbuild-linux-arm": "0.14.22", - "esbuild-linux-arm64": "0.14.22", - "esbuild-linux-mips64le": "0.14.22", - "esbuild-linux-ppc64le": "0.14.22", - "esbuild-linux-riscv64": "0.14.22", - "esbuild-linux-s390x": "0.14.22", - "esbuild-netbsd-64": "0.14.22", - "esbuild-openbsd-64": "0.14.22", - "esbuild-sunos-64": "0.14.22", - "esbuild-windows-32": "0.14.22", - "esbuild-windows-64": "0.14.22", - "esbuild-windows-arm64": "0.14.22" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.22.tgz", - "integrity": "sha512-k1Uu4uC4UOFgrnTj2zuj75EswFSEBK+H6lT70/DdS4mTAOfs2ECv2I9ZYvr3w0WL0T4YItzJdK7fPNxcPw6YmQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.22.tgz", - "integrity": "sha512-d8Ceuo6Vw6HM3fW218FB6jTY6O3r2WNcTAU0SGsBkXZ3k8SDoRLd3Nrc//EqzdgYnzDNMNtrWegK2Qsss4THhw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.22.tgz", - "integrity": "sha512-YAt9Tj3SkIUkswuzHxkaNlT9+sg0xvzDvE75LlBo4DI++ogSgSmKNR6B4eUhU5EUUepVXcXdRIdqMq9ppeRqfw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.22.tgz", - "integrity": "sha512-ek1HUv7fkXMy87Qm2G4IRohN+Qux4IcnrDBPZGXNN33KAL0pEJJzdTv0hB/42+DCYWylSrSKxk3KUXfqXOoH4A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.22.tgz", - "integrity": "sha512-zPh9SzjRvr9FwsouNYTqgqFlsMIW07O8mNXulGeQx6O5ApgGUBZBgtzSlBQXkHi18WjrosYfsvp5nzOKiWzkjQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.22.tgz", - "integrity": "sha512-SnpveoE4nzjb9t2hqCIzzTWBM0RzcCINDMBB67H6OXIuDa4KqFqaIgmTchNA9pJKOVLVIKd5FYxNiJStli21qg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.22.tgz", - "integrity": "sha512-Zcl9Wg7gKhOWWNqAjygyqzB+fJa19glgl2JG7GtuxHyL1uEnWlpSMytTLMqtfbmRykIHdab797IOZeKwk5g0zg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.22.tgz", - "integrity": "sha512-soPDdbpt/C0XvOOK45p4EFt8HbH5g+0uHs5nUKjHVExfgR7du734kEkXR/mE5zmjrlymk5AA79I0VIvj90WZ4g==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.22.tgz", - "integrity": "sha512-8q/FRBJtV5IHnQChO3LHh/Jf7KLrxJ/RCTGdBvlVZhBde+dk3/qS9fFsUy+rs3dEi49aAsyVitTwlKw1SUFm+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.22.tgz", - "integrity": "sha512-SiNDfuRXhGh1JQLLA9JPprBgPVFOsGuQ0yDfSPTNxztmVJd8W2mX++c4FfLpAwxuJe183mLuKf7qKCHQs5ZnBQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.22.tgz", - "integrity": "sha512-6t/GI9I+3o1EFm2AyN9+TsjdgWCpg2nwniEhjm2qJWtJyJ5VzTXGUU3alCO3evopu8G0hN2Bu1Jhz2YmZD0kng==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.22.tgz", - "integrity": "sha512-AyJHipZKe88sc+tp5layovquw5cvz45QXw5SaDgAq2M911wLHiCvDtf/07oDx8eweCyzYzG5Y39Ih568amMTCQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.22.tgz", - "integrity": "sha512-Sz1NjZewTIXSblQDZWEFZYjOK6p8tV6hrshYdXZ0NHTjWE+lwxpOpWeElUGtEmiPcMT71FiuA9ODplqzzSxkzw==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.22.tgz", - "integrity": "sha512-TBbCtx+k32xydImsHxvFgsOCuFqCTGIxhzRNbgSL1Z2CKhzxwT92kQMhxort9N/fZM2CkRCPPs5wzQSamtzEHA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.22.tgz", - "integrity": "sha512-vK912As725haT313ANZZZN+0EysEEQXWC/+YE4rQvOQzLuxAQc2tjbzlAFREx3C8+uMuZj/q7E5gyVB7TzpcTA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.22.tgz", - "integrity": "sha512-/mbJdXTW7MTcsPhtfDsDyPEOju9EOABvCjeUU2OJ7fWpX/Em/H3WYDa86tzLUbcVg++BScQDzqV/7RYw5XNY0g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-wasm": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.22.tgz", - "integrity": "sha512-FOSAM29GN1fWusw0oLMv6JYhoheDIh5+atC72TkJKfIUMID6yISlicoQSd9gsNSFsNBvABvtE2jR4JB1j4FkFw==", - "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.22.tgz", - "integrity": "sha512-1vRIkuvPTjeSVK3diVrnMLSbkuE36jxA+8zGLUOrT4bb7E/JZvDRhvtbWXWaveUc/7LbhaNFhHNvfPuSw2QOQg==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.22.tgz", - "integrity": "sha512-AxjIDcOmx17vr31C5hp20HIwz1MymtMjKqX4qL6whPj0dT9lwxPexmLj6G1CpR3vFhui6m75EnBEe4QL82SYqw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.22.tgz", - "integrity": "sha512-5wvQ+39tHmRhNpu2Fx04l7QfeK3mQ9tKzDqqGR8n/4WUxsFxnVLfDRBGirIfk4AfWlxk60kqirlODPoT5LqMUg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "funding": { - "url": "https://opencollective.com/eslint-config-prettier" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", - "dev": true, - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "50.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", - "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.50.2", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.4.1", - "escape-string-regexp": "^4.0.0", - "espree": "^10.3.0", - "esquery": "^1.6.0", - "parse-imports-exports": "^0.2.4", - "semver": "^7.7.2", - "spdx-expression-parse": "^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/eslint-plugin-jsdoc/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", - "dev": true, - "peerDependencies": { - "eslint": ">=2.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventemitter-asyncresource": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fecha": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, - "node_modules/fmin": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", - "integrity": "sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A==", - "dependencies": { - "contour_plot": "^0.0.1", - "json2module": "^0.0.3", - "rollup": "^0.25.8", - "tape": "^4.5.1", - "uglify-js": "^2.6.2" - } - }, - "node_modules/fmin/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fmin/node_modules/rollup": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", - "integrity": "sha512-a2S4Bh3bgrdO4BhKr2E4nZkjTvrJ2m2bWjMTzVYtoqSCn0HnuxosXnaJUHrMEziOWr3CzL9GjilQQKcyCQpJoA==", - "dependencies": { - "chalk": "^1.1.1", - "minimist": "^1.2.0", - "source-map-support": "^0.3.2" - }, - "bin": { - "rollup": "bin/rollup" - } - }, - "node_modules/fmin/node_modules/source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", - "dependencies": { - "amdefine": ">=0.0.4" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/fmin/node_modules/source-map-support": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", - "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", - "dependencies": { - "source-map": "0.1.32" - } - }, - "node_modules/fmin/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fmin/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/frac": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", - "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-monkey": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", - "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gauge/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/github-markdown-css": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-3.0.1.tgz", - "integrity": "sha512-9G5CIPsHoyk5ObDsb/H4KTi23J8KE1oDd4KYU51qwqeM+lKWAiO7abpSgCkyWswgmSKBiuE7/4f8xUz7f2qAiQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "dependencies": { - "lodash": "^4.17.15" - } - }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", - "dev": true, - "dependencies": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" - } - }, - "node_modules/hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true - }, - "node_modules/highlight.js": { - "version": "9.18.5", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz", - "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==", - "deprecated": "Support has ended for 9.x series. Upgrade to @latest", - "hasInstallScript": true, - "engines": { - "node": "*" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/hosted-git-info/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ] - }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true - }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", - "dev": true, - "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", - "dev": true, - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } - }, - "node_modules/http-proxy/node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - }, - "node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/ignore-walk": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-4.0.1.tgz", - "integrity": "sha512-rzDQLaW4jQbh2YrOFlJdCtX8qgJTehFRYiUB2r1osqTeDzV/3+Jh8fz1oAPzUThf3iku8Ds4IDqawI5d8mUiQw==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ignorefs": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/ignorefs/-/ignorefs-5.0.4.tgz", - "integrity": "sha512-vObKs/ga6E6TIfnQyxpShXVvUnlMZ+eoB2aGrvLuFGgnMqMVjZP3xW08WXJKocHmQL48WsDy6kUOisLp3gb8vg==", - "dev": true, - "dependencies": { - "editions": "^6.21.0", - "ignorepatterns": "^5.6.0" - }, - "engines": { - "node": ">=4" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/ignorepatterns": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-5.6.0.tgz", - "integrity": "sha512-6stRjchHcZwYfRkE2bVA9hCe+HFS1TWRrEYyEOPIeTnKyhKaqMg00AJPmAZ8EmVG/eUpALTkIM+ev1uTKY3PkQ==", - "dev": true, - "engines": { - "node": ">=4" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", - "dev": true, - "optional": true, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/immutable": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", - "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/injection-js": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.6.1.tgz", - "integrity": "sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==", - "dev": true, - "dependencies": { - "tslib": "^2.0.0" - } - }, - "node_modules/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", - "dev": true, - "dependencies": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" - }, - "node_modules/jquery-ui": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.14.0.tgz", - "integrity": "sha512-mPfYKBoRCf0MzaT2cyW5i3IuZ7PfTITaasO5OFLAQxrHuI+ZxruPa+4/K1OMNT8oElLWGtIxc9aRbyw20BKr8g==", - "dependencies": { - "jquery": ">=1.12.0 <5.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", - "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json2module": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", - "integrity": "sha512-qYGxqrRrt4GbB8IEOy1jJGypkNsjWoIMlZt4bAsmUScCA507Hbc2p1JOhBzqn45u3PWafUgH2OnzyNU7udO/GA==", - "dependencies": { - "rw": "^1.3.2" - }, - "bin": { - "json2module": "bin/json2module" - } - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, - "engines": [ - "node >= 0.2.0" - ] - }, - "node_modules/karma-source-map-support": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", - "dev": true, - "dependencies": { - "source-map-support": "^0.5.5" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/less": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", - "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", - "dev": true, - "dependencies": { - "copy-anything": "^2.0.1", - "parse-node-version": "^1.0.1", - "tslib": "^2.3.0" - }, - "bin": { - "lessc": "bin/lessc" - }, - "engines": { - "node": ">=6" - }, - "optionalDependencies": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^2.5.2", - "source-map": "~0.6.0" - } - }, - "node_modules/less-loader": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", - "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", - "dev": true, - "dependencies": { - "klona": "^2.0.4" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "less": "^3.5.0 || ^4.0.0", - "webpack": "^5.0.0" - } - }, - "node_modules/less/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/less/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/less/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/less/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/license-webpack-plugin": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", - "dev": true, - "dependencies": { - "webpack-sources": "^3.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-sources": { - "optional": true - } - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/lint-staged": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", - "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", - "dev": true, - "dependencies": { - "chalk": "^5.4.1", - "commander": "^13.1.0", - "debug": "^4.4.0", - "execa": "^8.0.1", - "lilconfig": "^3.1.3", - "listr2": "^8.2.5", - "micromatch": "^4.0.8", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.7.0" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=18.12.0" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/lint-staged/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/lint-staged/node_modules/commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/lint-staged/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/lint-staged/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/listr2": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", - "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", - "dev": true, - "dependencies": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "dev": true, - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-escapes": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", - "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", - "dev": true, - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", - "dev": true, - "dependencies": { - "sourcemap-codec": "^1.4.4" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mathjax": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", - "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "dependencies": { - "fs-monkey": "^1.0.4" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mini-css-extract-plugin": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", - "integrity": "sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==", - "dev": true, - "dependencies": { - "schema-utils": "^4.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-json-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.2.tgz", - "integrity": "sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==", - "dev": true, - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mock-property": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.3.tgz", - "integrity": "sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ==", - "dependencies": { - "define-data-property": "^1.1.1", - "functions-have-names": "^1.2.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "hasown": "^2.0.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mock-property/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/monaco-editor": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", - "integrity": "sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg==" - }, - "node_modules/monaco-editor-webpack-plugin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-6.0.0.tgz", - "integrity": "sha512-vC886Mzpd2AkSM35XLkfQMjH+Ohz6RISVwhAejDUzZDheJAiz6G34lky1vyO8fZ702v7IrcKmsGwL1rRFnwvUA==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0" - }, - "peerDependencies": { - "monaco-editor": "0.30.x", - "webpack": "^4.5.0 || 5.x" - } - }, - "node_modules/monaco-editor-webpack-plugin/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "license": "MIT", - "dependencies": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - }, - "bin": { - "multicast-dns": "cli.js" - } - }, - "node_modules/multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", - "dev": true, - "optional": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, - "engines": { - "node": ">= 4.4.x" - } - }, - "node_modules/needle/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "optional": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/ng-packagr": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-13.3.1.tgz", - "integrity": "sha512-RFB6+03qPlhsOZc0wPenkyCceUYU0kRymbO7fIZ4Uz3y7RltXeknfjWKVcN6o5o42Md/lbNabt4gViXNzahhjA==", - "dev": true, - "dependencies": { - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", - "ajv": "^8.0.0", - "ansi-colors": "^4.1.1", - "browserslist": "^4.16.1", - "cacache": "^15.0.6", - "chokidar": "^3.5.1", - "commander": "^8.0.0", - "dependency-graph": "^0.11.0", - "esbuild-wasm": "^0.14.0", - "find-cache-dir": "^3.3.1", - "glob": "^7.1.6", - "injection-js": "^2.4.0", - "jsonc-parser": "^3.0.0", - "less": "^4.1.0", - "ora": "^5.1.0", - "postcss": "^8.2.4", - "postcss-preset-env": "^7.0.0", - "postcss-url": "^10.1.1", - "rollup": "^2.45.1", - "rollup-plugin-sourcemaps": "^0.6.3", - "rxjs": "^7.0.0", - "sass": "^1.32.8", - "stylus": "^0.56.0" - }, - "bin": { - "ng-packagr": "cli/main.js" - }, - "engines": { - "node": "^12.20.0 || ^14.15.0 || >=16.10.0" - }, - "optionalDependencies": { - "esbuild": "^0.14.0" - }, - "peerDependencies": { - "@angular/compiler-cli": "^13.0.0", - "tslib": "^2.3.0", - "typescript": ">=4.4.0 <4.7" - } - }, - "node_modules/ng-packagr/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ng-packagr/node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/ng-zorro-antd": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/ng-zorro-antd/-/ng-zorro-antd-13.4.0.tgz", - "integrity": "sha512-ZIXeeXtTUNg3mdXNg2A3gJGh0aqN/pM3Ii61FiUhwkVwmVzIIDwYfGZZNNOl+cURL5HGzrwQ10nrYgdfFfZ20g==", - "dependencies": { - "@angular/cdk": "^13.0.1", - "@ant-design/icons-angular": "^13.0.1", - "date-fns": "^2.16.1", - "tslib": "^2.3.0" - }, - "peerDependencies": { - "@angular/animations": "^13.0.1", - "@angular/common": "^13.0.1", - "@angular/core": "^13.0.1", - "@angular/forms": "^13.0.1", - "@angular/platform-browser": "^13.0.1", - "@angular/router": "^13.0.1" - } - }, - "node_modules/ng-zorro-antd/node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/ng-zorro-antd/node_modules/date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dependencies": { - "@babel/runtime": "^7.21.0" - }, - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/ngx-build-plus": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-13.0.1.tgz", - "integrity": "sha512-3wuQ0/xyTC4+CU2wROgKe1TPCnghTj5aGcLCxbmWFZDrAneMW6t2QmAg0nJpapXzxhcL7JJnVYKnh2c/ARr62A==", - "dev": true, - "dependencies": { - "@angular-devkit/build-angular": "^13.0.0", - "@schematics/angular": "^13.0.0", - "webpack-merge": "^5.0.0" - }, - "peerDependencies": { - "@angular-devkit/build-angular": ">=12.0.0", - "rxjs": ">= 6.0.0" - } - }, - "node_modules/nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], - "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-forge": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", - "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", - "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", - "engines": { - "node": ">= 6.13.0" - } - }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "dev": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "dev": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", - "dev": true, - "license": "MIT" - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", - "dev": true, - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/npm-install-checks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", - "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true - }, - "node_modules/npm-package-arg": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", - "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-packlist": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-3.0.0.tgz", - "integrity": "sha512-L/cbzmutAwII5glUcf2DBRNY/d0TFd4e/FnaZigJV6JD85RHZXJFGwCndjMWiiViiWSsWt3tiOLpI3ByTnIdFQ==", - "dev": true, - "dependencies": { - "glob": "^7.1.6", - "ignore-walk": "^4.0.1", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "npm-packlist": "bin/index.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-pick-manifest": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", - "dev": true, - "dependencies": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - } - }, - "node_modules/npm-registry-fetch": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz", - "integrity": "sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA==", - "dev": true, - "dependencies": { - "make-fetch-happen": "^10.0.1", - "minipass": "^3.1.6", - "minipass-fetch": "^1.4.1", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^8.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } - }, - "node_modules/npm-registry-fetch/node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm-registry-fetch/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm-registry-fetch/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm-registry-fetch/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/npm-registry-fetch/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/make-fetch-happen/node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm-registry-fetch/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm-registry-fetch/node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm-registry-fetch/node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/nvd3": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.6.tgz", - "integrity": "sha512-YGQ9hAQHuQCF0JmYkT2GhNMHb5pA+vDfQj6C2GdpQPzdRPj/srPG3mh/3fZzUFt+at1NusLk/RqICUWkxm4viQ==", - "peerDependencies": { - "d3": "^3.4.4" - } - }, - "node_modules/nx": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/nx/-/nx-13.1.3.tgz", - "integrity": "sha512-clM0NQhQKYkqcNz2E3uYRMLwhp2L/9dBhJhQi9XBX4IAyA2gWAomhRIlLm5Xxg3g4h1xwSpP3eJ5t89VikY8Pw==", - "dev": true, - "dependencies": { - "@nrwl/cli": "*" - }, - "bin": { - "nx": "bin/nx.js" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", - "dev": true, - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pacote": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-12.0.3.tgz", - "integrity": "sha512-CdYEl03JDrRO3x18uHjBYA9TyoW8gy+ThVcypcDkxPtKlw76e4ejhYB6i9lJ+/cebbjpqPW/CijjqxwDTts8Ow==", - "dev": true, - "dependencies": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^2.0.0", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^3.0.0", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^12.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" - }, - "bin": { - "pacote": "lib/bin.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-imports-exports": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", - "dev": true, - "dependencies": { - "parse-statements": "1.0.11" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-statements": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "dev": true - }, - "node_modules/parse-svg-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", - "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==" - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "node_modules/parse5-html-rewriting-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1", - "parse5-sax-parser": "^6.0.1" - } - }, - "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-sax-parser": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/parse5-sax-parser/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", - "dev": true, - "dependencies": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" - }, - "optionalDependencies": { - "nice-napi": "^1.0.2" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/playwright": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", - "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.55.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", - "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/point-at-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/point-at-length/-/point-at-length-1.0.2.tgz", - "integrity": "sha512-DSGca2Q7A/4rGS6324Z+0hCVAPT729RFjsISPc6N11D6+r1TpP6KjktGL7HxN8XRYY0Z7EG8n9dBJ5dbrEP4SQ==", - "dependencies": { - "abs-svg-path": "~0.1.1", - "isarray": "~0.0.1", - "parse-svg-path": "~0.1.1" - } - }, - "node_modules/portfinder": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", - "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", - "dev": true, - "dependencies": { - "async": "^3.2.6", - "debug": "^4.3.6" - }, - "engines": { - "node": ">= 10.12" - } - }, - "node_modules/portfinder/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/portfinder/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dev": true, - "dependencies": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-attribute-case-insensitive": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", - "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-color-functional-notation": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", - "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-color-hex-alpha": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", - "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-color-rebeccapurple": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", - "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-custom-media": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", - "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-custom-properties": { - "version": "12.1.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", - "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-custom-selectors": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", - "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.3" - } - }, - "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-dir-pseudo-class": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", - "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-double-position-gradients": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", - "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-env-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", - "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-visible": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", - "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-focus-within": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", - "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-gap-properties": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", - "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-image-set-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", - "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-import": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.2.tgz", - "integrity": "sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-lab-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", - "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", - "dev": true, - "dependencies": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", - "dev": true, - "dependencies": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" - } - }, - "node_modules/postcss-logical": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "dev": true, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-media-minmax": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", - "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-nesting": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", - "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", - "dev": true, - "dependencies": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-nesting/node_modules/@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss-selector-parser": "^6.0.10" - } - }, - "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-overflow-shorthand": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", - "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", - "dev": true, - "peerDependencies": { - "postcss": "^8" - } - }, - "node_modules/postcss-place": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", - "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-preset-env": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.2.3.tgz", - "integrity": "sha512-Ok0DhLfwrcNGrBn8sNdy1uZqWRk/9FId0GiQ39W4ILop5GHtjJs8bu1MY9isPwHInpVEPWjb4CEcEaSbBLpfwA==", - "dev": true, - "dependencies": { - "autoprefixer": "^10.4.2", - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001299", - "css-blank-pseudo": "^3.0.2", - "css-has-pseudo": "^3.0.3", - "css-prefers-color-scheme": "^6.0.2", - "cssdb": "^5.0.0", - "postcss-attribute-case-insensitive": "^5.0.0", - "postcss-color-functional-notation": "^4.2.1", - "postcss-color-hex-alpha": "^8.0.2", - "postcss-color-rebeccapurple": "^7.0.2", - "postcss-custom-media": "^8.0.0", - "postcss-custom-properties": "^12.1.2", - "postcss-custom-selectors": "^6.0.0", - "postcss-dir-pseudo-class": "^6.0.3", - "postcss-double-position-gradients": "^3.0.4", - "postcss-env-function": "^4.0.4", - "postcss-focus-visible": "^6.0.3", - "postcss-focus-within": "^5.0.3", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.2", - "postcss-image-set-function": "^4.0.4", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.0.3", - "postcss-logical": "^5.0.3", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.2", - "postcss-overflow-shorthand": "^3.0.2", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.3", - "postcss-pseudo-class-any-link": "^7.0.2", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^5.0.0" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-pseudo-class-any-link": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", - "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.10" - }, - "engines": { - "node": "^12 || ^14 || >=16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - }, - "peerDependencies": { - "postcss": "^8.2" - } - }, - "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "peerDependencies": { - "postcss": "^8.0.3" - } - }, - "node_modules/postcss-selector-not": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", - "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-url": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", - "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", - "dev": true, - "dependencies": { - "make-dir": "~3.1.0", - "mime": "~2.5.2", - "minimatch": "~3.0.4", - "xxhashjs": "~0.2.2" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-url/node_modules/mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/raw-body/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", - "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", - "dev": true - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regex-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", - "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==", - "dev": true - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "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" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/regression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", - "integrity": "sha512-A4XYsc37dsBaNOgEjkJKzfJlE394IMmUPlI/p3TTI9u3T+2a+eox5Pr/CPUqF0eszeWZJPAc6QkroAhuUpWDJQ==" - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-url-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", - "dev": true, - "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/resolve-url-loader/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/restore-cursor/node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/restore-cursor/node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true - }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", - "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", - "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-sourcemaps": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz", - "integrity": "sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.0.9", - "source-map-resolve": "^0.6.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "@types/node": ">=10.0.0", - "rollup": ">=0.31.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" - }, - "node_modules/rxjs": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", - "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs-for-await": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/rxjs-for-await/-/rxjs-for-await-0.0.2.tgz", - "integrity": "sha512-IJ8R/ZCFMHOcDIqoABs82jal00VrZx8Xkgfe7TOKoaRPAW5nH/VFlG23bXpeGdrmtqI9UobFPgUKgCuFc7Lncw==", - "dev": true, - "peerDependencies": { - "rxjs": "^6.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-push-apply/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/sass": { - "version": "1.49.9", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", - "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", - "dev": true, - "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/sass-loader": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz", - "integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==", - "dev": true, - "dependencies": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", - "sass": "^1.3.0", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "dev": true, - "optional": true - }, - "node_modules/scandirectory": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/scandirectory/-/scandirectory-8.1.1.tgz", - "integrity": "sha512-1AfRS0+UPNIgzlJCABCOww9F6bK9d432K2Gx6vy8KRpymbNB6KRDPnYrq4wKc67TYw/CXW6dFeOBuWrd4v1YZg==", - "dev": true, - "dependencies": { - "editions": "^6.21.0", - "ignorefs": "^5.0.4" - }, - "bin": { - "scandirectory": "bin.cjs" - }, - "engines": { - "node": ">=4" - }, - "funding": { - "url": "https://bevry.me/fund" - } - }, - "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/schema-utils/node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/schema-utils/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/schema-utils/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true - }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", - "dev": true, - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", - "dev": true, - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "dev": true, - "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/@types/highlight.js": { + "version": "9.12.4", + "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", + "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/node": "*" } }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "node_modules/@types/jquery": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", + "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@types/sizzle": "*" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "MIT" }, - "node_modules/simple-statistics": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-6.1.1.tgz", - "integrity": "sha512-zGwn0DDRa9Zel4H4n2pjTFIyGoAGpnpjrGIctreCxj5XWrcx9v7Xy7270FkC967WMmcvuc8ZU7m0ZG+hGN7gAA==", - "engines": { - "node": "*" - } + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/@types/lodash": { + "version": "4.14.144", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", + "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "node_modules/@types/mathjax": { + "version": "0.0.35", + "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.35.tgz", + "integrity": "sha512-flo9bVJE2Lzv3X5NQXVhNhv7srqk//Ngr8MT+/jRErkWGYkk8EBm42J5W0XUH6p4nWF1iLGe+atSuIkR5wA2yw==", "dev": true, - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } + "license": "MIT" }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } + "license": "MIT" }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "node_modules/@types/node": { + "version": "12.19.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.16.tgz", + "integrity": "sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==", "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } + "license": "MIT" }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "node_modules/@types/parse5": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", + "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==", "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } + "license": "MIT" }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "dev": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } + "license": "MIT" }, - "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } + "license": "MIT" }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } + "license": "MIT" }, - "node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true, - "engines": { - "node": ">= 8" - } + "license": "MIT", + "peer": true }, - "node_modules/source-map-js": { + "node_modules/@types/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/source-map-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", - "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, + "license": "MIT", "dependencies": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" + "@types/express": "*" } }, - "node_modules/source-map-loader/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", "dev": true, + "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" } }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", "dev": true, + "license": "MIT", "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" + "@types/mime": "^1", + "@types/node": "*" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/@types/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } + "license": "MIT" }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "@types/node": "*" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true + "node_modules/@types/webpack-env": { + "version": "1.18.8", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", + "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", + "dev": true, + "license": "MIT" }, - "node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, + "license": "MIT", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "@types/node": "*" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "dev": true - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.0.tgz", + "integrity": "sha512-QYb/sa74/s7OKMbACMjrYnGspj9Hs5YI5aaffSL65UfeBUzVzBJfVo3oWSpbzPurvm7yaCCo2Lk7lVj610HqKw==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/type-utils": "8.60.0", + "@typescript-eslint/utils": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=6.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.60.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "node_modules/@typescript-eslint/parser": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.0.tgz", + "integrity": "sha512-fcqpj/MyK4sxDPcbe7STNPbpQL4RLZOPWuaTmwZYuc+hJKzRf58yRxfhqGpc6PIq9ZyfSBpfHgmUHmHs0KwHwg==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/ssf": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz", - "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==", + "node_modules/@typescript-eslint/project-service": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.0.tgz", + "integrity": "sha512-aZu74NNKJeUWqCjDddzdiKaS82dgYgV/vmf+Ui3ZdZejmgfXR/q+pRumgobnQ2cCJTgGTWp4ypiwsuofFubavg==", + "dev": true, + "license": "MIT", "dependencies": { - "frac": "~1.1.2" - }, - "bin": { - "ssf": "bin/ssf.njs" + "@typescript-eslint/tsconfig-utils": "^8.60.0", + "@typescript-eslint/types": "^8.60.0", + "debug": "^4.4.3" }, "engines": { - "node": ">=0.8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.0.tgz", + "integrity": "sha512-pFzqhllJMs+jghLQWzV00ds39xLzuyqPSev5pd8f4Ir0rtKR3ZLUB4/4dhjOFighWb9larvtfJvqL+4yKDI3Xw==", "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^3.1.1" + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0" }, "engines": { - "node": ">= 8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.0.tgz", + "integrity": "sha512-BZPR3RGYlAXnly6ymAxfkVn5rCbZzQNou0rxv3GfWZ8cTQp+hhVd73khbGLAd8k1TlAPLISH337M+tAgAnaJDQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "engines": { - "node": ">= 0.4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/@typescript-eslint/type-utils": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.0.tgz", + "integrity": "sha512-SX46wEUtitCpq7AN38HkUU/+zvUpdKf7ephtWAFgckH8O7PQIyL5gvrhQgBLuEYgLfuKWOVvWVskMbuFHAz5xg==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "~5.2.0" + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "node_modules/@typescript-eslint/types": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.0.tgz", + "integrity": "sha512-AsE7x2XaAK+CVbeih0Fvbn+r1qHxtpLDJ3XUuFcIinT318T90yHMJC+Zgv+jUuDjQQd06HKwxnDu6sz1IcTilA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.6.19" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.0.tgz", + "integrity": "sha512-3AcZNBGMClm6CXDyo8kYvVGT/sx29sS0oBsIb9oZI2gunA4Vm2M3YHzRLPvsUBBsl+yB5FPtltq7gGH0iTlp9g==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@typescript-eslint/project-service": "8.60.0", + "@typescript-eslint/tsconfig-utils": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/visitor-keys": "8.60.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/string-width/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/@typescript-eslint/utils": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.0.tgz", + "integrity": "sha512-HtXuPfrHTyBDkameWpl+vJb1Uevu2tznAyahM1Oc4AENidCLTPiZDWIo4GfcxNdC/RcfGcadzzkqbRG87dUrQA==", "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.60.0", + "@typescript-eslint/types": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.0.tgz", + "integrity": "sha512-9WI52t8ZGLVGrPMBet25yAftqY/n95+zmoUUtJBBQTKDSKUu7OsPTroT2op7U9JatkoRccL0YkWDNMFfC4Sjxg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "@typescript-eslint/types": "8.60.0", + "eslint-visitor-keys": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://opencollective.com/eslint" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" } }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" - }, - "engines": { - "node": ">=4" + "@xtuc/long": "4.2.2" } }, - "node_modules/stylus": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.56.0.tgz", - "integrity": "sha512-Ev3fOb4bUElwWu4F9P9WjnnaSpc8XB9OFHSFZSKMFL1CE1oM+oFXWEgAqPmmZIyhBihuqIQlFsVTypiiS9RxeA==", + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, + "license": "MIT", "dependencies": { - "css": "^3.0.0", - "debug": "^4.3.2", - "glob": "^7.1.6", - "safer-buffer": "^2.1.2", - "sax": "~1.2.4", - "source-map": "^0.7.3" - }, - "bin": { - "stylus": "bin/stylus" - }, - "engines": { - "node": "*" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, - "node_modules/stylus-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-6.2.0.tgz", - "integrity": "sha512-5dsDc7qVQGRoc6pvCL20eYgRUxepZ9FpeK28XhdXaIPP6kXr6nI1zAAKFQgP5OBkOfKaURp4WUpJzspg1f01Gg==", + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, + "license": "MIT", "dependencies": { - "fast-glob": "^3.2.7", - "klona": "^2.0.4", - "normalize-path": "^3.0.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "stylus": ">=0.52.4", - "webpack": "^5.0.0" + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" } }, - "node_modules/stylus/node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "Apache-2.0" }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" }, - "node_modules/symbol-observable": { + "node_modules/abbrev": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", "dev": true, + "license": "ISC", "engines": { - "node": ">=0.10" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/systemjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-5.0.0.tgz", - "integrity": "sha512-hnD/IMQhH0UmawiIGlYVnkCPUbbO/WDQjOC+Q4PewHBdsagI1OHH1re1sg1AYFqq7p9ps6b1Bsx4xCeoeIZSCw==" + "node_modules/abs-svg-path": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", + "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==", + "license": "MIT" }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, - "engines": { - "node": ">=6" + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "engines": { + "node": ">= 0.6" } }, - "node_modules/tape": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.17.0.tgz", - "integrity": "sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw==", - "dependencies": { - "@ljharb/resumer": "~0.0.1", - "@ljharb/through": "~2.3.9", - "call-bind": "~1.0.2", - "deep-equal": "~1.1.1", - "defined": "~1.0.1", - "dotignore": "~0.1.2", - "for-each": "~0.3.3", - "glob": "~7.2.3", - "has": "~1.0.3", - "inherits": "~2.0.4", - "is-regex": "~1.1.4", - "minimist": "~1.2.8", - "mock-property": "~1.0.0", - "object-inspect": "~1.12.3", - "resolve": "~1.22.6", - "string.prototype.trim": "~1.2.8" - }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", "bin": { - "tape": "bin/tape" + "acorn": "bin/acorn" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.4.0" } }, - "node_modules/tape/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">=10.13.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "acorn": "^8.14.0" } }, - "node_modules/tape/node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/tape/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "acorn": "^8.11.0" }, "engines": { - "node": "*" - } - }, - "node_modules/tape/node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.4.0" } }, - "node_modules/tape/node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8.9" } }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=10" + "node": ">=8.9.0" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", + "node_modules/adler-32": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", + "license": "Apache-2.0", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + }, + "bin": { + "adler32": "bin/adler32.njs" }, "engines": { - "node": ">=6" + "node": ">=0.8" } }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "node_modules/adm-zip": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", + "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", "dev": true, + "license": "MIT", + "peer": true, "engines": { - "node": ">=8" + "node": ">=6.0" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "license": "MIT", + "dependencies": { + "es6-promisify": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">= 4.0.0" } }, - "node_modules/terser-webpack-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", - "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" - }, - "engines": { - "node": ">= 10.13.0" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "ajv": "^8.0.0" }, - "engines": { - "node": ">= 10.13.0" + "peerDependencies": { + "ajv": "^8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", - "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" + "fast-deep-equal": "^3.1.3" }, - "engines": { - "node": ">=10" + "peerDependencies": { + "ajv": "^8.8.2" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/algoliasearch": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.48.1.tgz", + "integrity": "sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg==", "dev": true, + "license": "MIT", "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "@algolia/abtesting": "1.14.1", + "@algolia/client-abtesting": "5.48.1", + "@algolia/client-analytics": "5.48.1", + "@algolia/client-common": "5.48.1", + "@algolia/client-insights": "5.48.1", + "@algolia/client-personalization": "5.48.1", + "@algolia/client-query-suggestions": "5.48.1", + "@algolia/client-search": "5.48.1", + "@algolia/ingestion": "1.48.1", + "@algolia/monitoring": "1.48.1", + "@algolia/recommend": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" }, "engines": { - "node": ">=8" + "node": ">= 14.0.0" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, + "node_modules/align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", + "license": "MIT", "dependencies": { - "rimraf": "^3.0.0" + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" }, "engines": { - "node": ">=8.17.0" + "node": ">=0.10.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, + "node_modules/align-text/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">=8.0" + "node": ">=0.10.0" } }, - "node_modules/toidentifier": { + "node_modules/amdefine": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "license": "BSD-3-Clause OR MIT", "engines": { - "node": ">=0.6" + "node": ">=0.4.2" } }, - "node_modules/topojson-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.1.tgz", - "integrity": "sha512-rfGGzyqefpxOaxvV9OTF9t+1g+WhjGEbAIuCcmKYrQkxr0nttjMMyzZsK+NhLW4cTl2g1bz2jQczPUtEshpbVQ==", + "node_modules/angular": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz", + "integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==", + "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward.", + "license": "MIT" + }, + "node_modules/angular-eslint": { + "version": "21.4.0", + "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-21.4.0.tgz", + "integrity": "sha512-LH7bWmtJvsubzwPoztnl1pWgI5X0VrfGTUITGSYcwn2J+SXuN/avzrKrxJmhUiIrNvLtfV+18GG6xZS1IGZdKg==", + "dev": true, + "license": "MIT", "dependencies": { - "commander": "2" + "@angular-devkit/core": ">= 21.0.0 < 22.0.0", + "@angular-devkit/schematics": ">= 21.0.0 < 22.0.0", + "@angular-eslint/builder": "21.4.0", + "@angular-eslint/eslint-plugin": "21.4.0", + "@angular-eslint/eslint-plugin-template": "21.4.0", + "@angular-eslint/schematics": "21.4.0", + "@angular-eslint/template-parser": "21.4.0", + "@typescript-eslint/types": "^8.0.0", + "@typescript-eslint/utils": "^8.0.0" }, - "bin": { - "topo2geo": "bin/topo2geo", - "topomerge": "bin/topomerge", - "topoquantize": "bin/topoquantize" + "peerDependencies": { + "@angular/cli": ">= 21.0.0 < 22.0.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "*", + "typescript-eslint": "^8.0.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" + "node_modules/ansi_up": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-6.0.6.tgz", + "integrity": "sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==", + "license": "MIT", + "engines": { + "node": "*" } }, - "node_modules/ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, - "dependencies": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - }, - "bin": { - "ts-node": "dist/bin.js" - }, + "license": "MIT", "engines": { - "node": ">=4.2.0" + "node": ">=6" } }, - "node_modules/ts-node/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, + "license": "MIT", "dependencies": { - "minimist": "^1.2.6" + "environment": "^1.0.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, - "dependencies": { - "minimist": "^1.2.0" + "license": "MIT", + "engines": { + "node": ">=12" }, - "bin": { - "json5": "lib/cli.js" + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "^1.8.1" + "color-convert": "^2.0.1" }, "engines": { - "node": ">= 6" + "node": ">=8" }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { - "prelude-ls": "^1.2.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 8" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", "dev": true, - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, + "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=14" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "license": "MIT", "dependencies": { "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -17477,18 +9602,20 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -17497,17 +9624,17 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -17516,95 +9643,124 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true - }, - "node_modules/typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { - "node": ">=4.2.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "license": "MIT", "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { - "node": ">=0.8.0" + "node": ">= 0.4" }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/uglify-js/node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/uglify-js/node_modules/cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", + "node_modules/asn1js": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.5", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" } }, - "node_modules/uglify-js/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" } }, - "node_modules/uglify-js/node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", + "node_modules/autoprefixer": { + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "optional": true + "browserslist": "^4.28.1", + "caniuse-lite": "^1.0.30001774", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" + "possible-typed-array-names": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -17613,847 +9769,936 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=4" + "node": ">= 0.4" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/babel-loader": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", + "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", "dev": true, + "license": "MIT", "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" + "find-up": "^5.0.0" }, "engines": { - "node": ">=4" + "node": "^18.20.0 || ^20.10.0 || >=22.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5.61.0" } }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">=4" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", "dev": true, + "license": "MIT", "dependencies": { - "unique-slug": "^2.0.0" + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", "dev": true, + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4" + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": "18 || 20 || >=22" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/baseline-browser-mapping": { + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, "engines": { - "node": ">= 0.8" + "node": ">=6.0.0" } }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", + "license": "MIT" + }, + "node_modules/beasties": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", + "integrity": "sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" + "css-select": "^6.0.0", + "css-what": "^7.0.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3", + "postcss-safe-parser": "^7.0.1" }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "engines": { + "node": ">=18.0.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "engines": { + "node": "*" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, "engines": { - "node": ">= 0.4.0" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "node_modules/bonjour-service": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", + "integrity": "sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true, - "license": "MIT" + "license": "ISC" }, - "node_modules/validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, + "license": "MIT", "dependencies": { - "builtins": "^1.0.3" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/venn.js": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", - "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "dependencies": { - "d3-selection": "^1.0.2", - "d3-transition": "^1.0.1", - "fmin": "0.0.2" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/version-range": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", - "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, "engines": { - "node": ">=4" + "node": ">=18" }, "funding": { - "url": "https://bevry.me/fund" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.8" } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "node_modules/bytestreamjs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", + "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=6.0.0" } }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "node_modules/cacache": { + "version": "20.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz", + "integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==", "dev": true, + "license": "ISC", "dependencies": { - "defaults": "^1.0.3" + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "node_modules/cacache/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, - "license": "BSD-2-Clause" + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, - "node_modules/webpack": { - "version": "5.105.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", - "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", - "dev": true, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "license": "MIT", - "peer": true, "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.16.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.28.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.20.0", - "es-module-lexer": "^2.0.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.17", - "watchpack": "^2.5.1", - "webpack-sources": "^3.3.4" - }, - "bin": { - "webpack": "bin/webpack.js" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" }, "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/webpack-dev-middleware": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz", - "integrity": "sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg==", - "dev": true, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.2.2", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": ">= 0.4" } }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/webpack-dev-server": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.3.tgz", - "integrity": "sha512-mlxq2AsIw2ag016nixkzUkdyOE8ST2GTy34uKSABp1c4nhjZvH90D5ZRR+UOLSsG4Z3TFahAi72a3ymRtfRm+Q==", + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", + "license": "MIT", "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.2", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.0", - "ws": "^8.1.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" }, "engines": { - "node": ">= 12.13.0" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "node": ">=0.10.0" + } + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "engines": { + "node": ">=0.8" } }, - "node_modules/webpack-dev-server/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, + "node_modules/cfb/node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=0.8" } }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">=10" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/webpack-dev-server/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, + "license": "MIT", "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" + "readdirp": "^5.0.0" }, "engines": { - "node": ">=10.0.0" + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">=6.0" } }, - "node_modules/webpack-subresource-integrity": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, + "license": "MIT", "dependencies": { - "typed-assert": "^1.0.8" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", - "webpack": "^5.12.0" + "node": ">=18" }, - "peerDependenciesMeta": { - "html-webpack-plugin": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", "dev": true, - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, + "license": "MIT", "engines": { - "node": ">= 10.13.0" + "node": ">=18.20" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "dev": true, + "license": "MIT", "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" }, "engines": { - "node": ">=0.8.0" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, + "license": "ISC", "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node": ">= 12" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, + "license": "ISC", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">= 8" + "node": ">=20" } }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/which-builtin-type/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" + "isobject": "^3.0.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "node_modules/codepage": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", + "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==", + "license": "Apache-2.0", "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" + "commander": "~2.14.1", + "exit-on-epipe": "~1.0.1" }, - "engines": { - "node": ">= 0.4" + "bin": { + "codepage": "bin/codepage.njs" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.8" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } + "node_modules/codepage/node_modules/commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", + "license": "MIT" }, - "node_modules/wildcard": { + "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true - }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">= 0.8.0" + "node": ">=7.0.0" } }, - "node_modules/wolfy87-eventemitter": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz", - "integrity": "sha512-VakY4+17DbamV2VW4nZERrSuilclCRcYtfchPWe6jlma8k0AeLJxBR+C5OSFFtICArDFdXk0yw67HUGrTCdrEg==" + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, + "license": "MIT", + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=16" } }, - "node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">= 12.0.0" } }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true, + "license": "ISC" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "mime-db": ">= 1.43.0 < 2" }, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">= 0.6" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/compression/node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">= 0.6" } }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" }, "engines": { "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "node_modules/concurrently/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { - "ansi-regex": "^6.0.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "node_modules/concurrently/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "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 - } + "node": ">=8" } }, - "node_modules/xlsx": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz", - "integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==", + "node_modules/concurrently/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", "dependencies": { - "adler-32": "~1.2.0", - "cfb": "^1.1.2", - "codepage": "~1.14.0", - "commander": "~2.17.1", - "crc-32": "~1.2.0", - "exit-on-epipe": "~1.0.1", - "ssf": "~0.10.2" - }, - "bin": { - "xlsx": "bin/xlsx.njs" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.8" + "node": ">=8" } }, - "node_modules/xlsx/node_modules/commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" - }, - "node_modules/xxhashjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", - "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "node_modules/concurrently/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { - "cuint": "^0.2.2" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", + "node_modules/concurrently/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 14.6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/eemeli" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/yargs": { + "node_modules/concurrently/node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -18467,13109 +10712,10570 @@ "node": ">=12" } }, - "node_modules/yargs-parser": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.0.0.tgz", - "integrity": "sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { + "node_modules/concurrently/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } }, - "node_modules/yn": { + "node_modules/connect-history-api-fallback": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.8" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/zone.js": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", - "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", - "dependencies": { - "tslib": "^2.3.0" + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + }, + "node_modules/contour_plot": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", + "integrity": "sha512-Nil2HI76Xux6sVGORvhSS8v66m+/h5CwFkBJDO+U5vWaMdNC0yXNCsGDPbzPhvqOEU5koebhdEvD372LI+IyLw==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "@angular-architects/module-federation": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@angular-architects/module-federation/-/module-federation-13.0.1.tgz", - "integrity": "sha512-NFf/UOsP/MjyzaqgDynVYvtoaBKogXTQNAVYGNra/dKwrr2O9gJ7njrjzUih5M2KuG6oJaOvl0D/Dop4PES1FQ==", + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, - "requires": { - "@angular-architects/module-federation-runtime": "^13.0.1", - "callsite": "^1.0.0", - "ngx-build-plus": "^13.0.0", - "node-fetch": "^2.6.1", - "rxjs": "~6.6.3", - "semver": "^7.3.5", - "word-wrap": "^1.2.3" + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-what": "^3.14.1" }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-14.0.0.tgz", + "integrity": "sha512-3JLW90aBGeaTLpM7mYQKpnVdgsUZRExY55giiZgLuX/xTQRUs1dOCwbBnWnvY6Q6rfZoXMNwzOQJCSZPppfqXA==", + "dev": true, + "license": "MIT", "dependencies": { - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "glob-parent": "^6.0.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^7.0.3", + "tinyglobby": "^0.2.12" + }, + "engines": { + "node": ">= 20.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" } }, - "@angular-architects/module-federation-runtime": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/@angular-architects/module-federation-runtime/-/module-federation-runtime-13.0.1.tgz", - "integrity": "sha512-lvXmdCN+/JJMDm3h+FlNPc+lwFgNC3/J7Dr5h6ZHXT6sGgelcUQPpGxO1QUiE87XmUG8/Gdo57CebS0TKCklyQ==", + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", "dev": true, - "requires": { - "tslib": "^2.0.0" + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" } }, - "@angular-builders/custom-webpack": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@angular-builders/custom-webpack/-/custom-webpack-13.1.0.tgz", - "integrity": "sha512-qhtnAv1i7agk14zeKZZfXjrckYt37OZ+3tsTBLhf3ZFbwREK8L1SNi8xhZ1j1JLGsf2Dp0GEcZrSYeFDweo0WA==", + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true, - "requires": { - "@angular-devkit/architect": ">=0.1300.0 < 0.1400.0", - "@angular-devkit/build-angular": "^13.0.0", - "@angular-devkit/core": "^13.0.0", - "lodash": "^4.17.15", - "ts-node": "^10.0.0", - "tsconfig-paths": "^3.9.0", - "webpack-merge": "^5.7.3" + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "dev": true, + "license": "MIT", "dependencies": { - "diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true - }, - "ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true } } }, - "@angular-devkit/architect": { - "version": "0.1303.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.11.tgz", - "integrity": "sha512-JwrWomNqNGjAeKlqV2pimUFlCgFxQy+Vioz9+QAPIrUkvvjbkQ1dZKOe8Ul8eosb1N3Ln282U6qzOpHKfJ4TOg==", + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cron-parser": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.9.0.tgz", + "integrity": "sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==", "dev": true, - "requires": { - "@angular-devkit/core": "13.3.11", - "rxjs": "6.6.7" + "license": "MIT", + "peer": true, + "dependencies": { + "luxon": "^3.2.1" }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/cross-env": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", + "dev": true, + "license": "MIT", "dependencies": { - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "@epic-web/invariant": "^1.0.0", + "cross-spawn": "^7.0.6" + }, + "bin": { + "cross-env": "dist/bin/cross-env.js", + "cross-env-shell": "dist/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=20" } }, - "@angular-devkit/build-angular": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.3.11.tgz", - "integrity": "sha512-H4tpdmRu+6HSjsL+swV/8qj8v0YSDq6lpb31EYajlBB6fDj+YJQvHgaWvexSWl6eIqgDKXcujhNUjNi1enjwHw==", - "dev": true, - "requires": { - "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1303.11", - "@angular-devkit/build-webpack": "0.1303.11", - "@angular-devkit/core": "13.3.11", - "@babel/core": "7.16.12", - "@babel/generator": "7.16.8", - "@babel/helper-annotate-as-pure": "7.16.7", - "@babel/plugin-proposal-async-generator-functions": "7.16.8", - "@babel/plugin-transform-async-to-generator": "7.16.8", - "@babel/plugin-transform-runtime": "7.16.10", - "@babel/preset-env": "7.16.11", - "@babel/runtime": "7.16.7", - "@babel/template": "7.16.7", - "@discoveryjs/json-ext": "0.5.6", - "@ngtools/webpack": "13.3.11", - "ansi-colors": "4.1.1", - "babel-loader": "8.2.5", - "babel-plugin-istanbul": "6.1.1", - "browserslist": "^4.9.1", - "cacache": "15.3.0", - "circular-dependency-plugin": "5.2.2", - "copy-webpack-plugin": "10.2.1", - "core-js": "3.20.3", - "critters": "0.0.16", - "css-loader": "6.5.1", - "esbuild": "0.14.22", - "esbuild-wasm": "0.14.22", - "glob": "7.2.0", - "https-proxy-agent": "5.0.0", - "inquirer": "8.2.0", - "jsonc-parser": "3.0.0", - "karma-source-map-support": "1.4.0", - "less": "4.1.2", - "less-loader": "10.2.0", - "license-webpack-plugin": "4.0.2", - "loader-utils": "3.2.1", - "mini-css-extract-plugin": "2.5.3", - "minimatch": "3.0.5", - "open": "8.4.0", - "ora": "5.4.1", - "parse5-html-rewriting-stream": "6.0.1", - "piscina": "3.2.0", - "postcss": "8.4.5", - "postcss-import": "14.0.2", - "postcss-loader": "6.2.1", - "postcss-preset-env": "7.2.3", - "regenerator-runtime": "0.13.9", - "resolve-url-loader": "5.0.0", - "rxjs": "6.6.7", - "sass": "1.49.9", - "sass-loader": "12.4.0", - "semver": "7.3.5", - "source-map-loader": "3.0.1", - "source-map-support": "0.5.21", - "stylus": "0.56.0", - "stylus-loader": "6.2.0", - "terser": "5.14.2", - "text-table": "0.2.0", - "tree-kill": "1.2.2", - "tslib": "2.3.1", - "webpack": "5.76.1", - "webpack-dev-middleware": "5.3.0", - "webpack-dev-server": "4.7.3", - "webpack-merge": "5.8.0", - "webpack-subresource-integrity": "5.1.0" + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.3.tgz", + "integrity": "sha512-frbERmjT0UC5lMheWpJmMilnt9GEhbZJN/heUb7/zaJYeIzj5St9HvDcfshzzOqbsS+rYpMk++2SD3vGETDSyA==", + "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "core-js": { - "version": "3.20.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.20.3.tgz", - "integrity": "sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag==", - "dev": true - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true + "icss-utils": "^5.1.0", + "postcss": "^8.4.40", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true }, "webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" - } + "optional": true } } }, - "@angular-devkit/build-webpack": { - "version": "0.1303.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1303.11.tgz", - "integrity": "sha512-599pWAQLq7i/fmEZLb7PaNU6nmPC3EZbJk1nU/UBcpx7FWs9e0o2XQE2PCAs0buqtQxVjSgY6kMO8ex5dUmgUQ==", + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", "dev": true, - "requires": { - "@angular-devkit/architect": "0.1303.11", - "rxjs": "6.6.7" - }, + "license": "BSD-2-Clause", "dependencies": { - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "@angular-devkit/core": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.11.tgz", - "integrity": "sha512-rfqoLMRYhlz0wzKlHx7FfyIyQq8dKTsmbCoIVU1cEIH0gyTMVY7PbVzwRRcO6xp5waY+0hA+0Brriujpuhkm4w==", - "dev": true, - "requires": { - "ajv": "8.9.0", - "ajv-formats": "2.1.1", - "fast-json-stable-stringify": "2.1.0", - "magic-string": "0.25.7", - "rxjs": "6.6.7", - "source-map": "0.7.3" - }, - "dependencies": { - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "@angular-devkit/schematics": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-13.3.11.tgz", - "integrity": "sha512-ben+EGXpCrClnIVAAnEQmhQdKmnnqFhMp5BqMxgOslSYBAmCutLA6rBu5vsc8kZcGian1wt+lueF7G1Uk5cGBg==", + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", "dev": true, - "requires": { - "@angular-devkit/core": "13.3.11", - "jsonc-parser": "3.0.0", - "magic-string": "0.25.7", - "ora": "5.4.1", - "rxjs": "6.6.7" + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" }, - "dependencies": { - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/fb55" } }, - "@angular-eslint/builder": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-13.5.0.tgz", - "integrity": "sha512-IYY/HYS4fSddJLs2pAkMkKhHL07driUILPxGnGLblfWuoJBhRspyrVL3uZc3Q4iJXc1RJfaOno9oRw11FGyL6Q==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, - "requires": { - "@nrwl/devkit": "13.1.3" + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" } }, - "@angular-eslint/bundled-angular-compiler": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-13.5.0.tgz", - "integrity": "sha512-7M/5ilxqPD3ydgqqdLsYs3kBwZgNg2Y6C01B5SEHZNLqLT9kAJa7I4y6GlxCZqejCIh554kdXGeV3abIxFccSg==", - "dev": true + "node_modules/d3": { + "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==", + "license": "BSD-3-Clause" }, - "@angular-eslint/eslint-plugin": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-13.5.0.tgz", - "integrity": "sha512-k9o9WIqUkdO8tdYFCJ54PUWsNd9HHflih/GmA13EWciBYx8QxciwBh0u4NSAnbtOwp4Y7juGZ/Dta5ZrT/2VBA==", - "dev": true, - "requires": { - "@angular-eslint/utils": "13.5.0", - "@typescript-eslint/experimental-utils": "5.27.1" + "node_modules/d3-array": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", + "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-collection": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", + "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-color": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", + "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-composite-projections": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/d3-composite-projections/-/d3-composite-projections-1.2.3.tgz", + "integrity": "sha512-RxNBoRGf3epTnQBUKeEpaXpD8BA/Ud0xRuLwWxyI7dWfuuYgJZMKw6ZsZOwfDNC0ZbMWaU0eBFlL05A2jlcsWg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-geo": "^1.11.6", + "d3-path": "^1.0.7" } }, - "@angular-eslint/eslint-plugin-template": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-13.5.0.tgz", - "integrity": "sha512-ZVSXayn8MqYOhYomH2Cjc0azhuUQbY9fp9dKjJZOD64KhP8BYHw8+Ogc9E/FU5oZQ9fKw6A+23NAYKmLNqSAgA==", - "dev": true, - "requires": { - "@angular-eslint/bundled-angular-compiler": "13.5.0", - "@typescript-eslint/experimental-utils": "5.27.1", - "aria-query": "^4.2.2", - "axobject-query": "^2.2.0" + "node_modules/d3-composite-projections/node_modules/d3-geo": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", + "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" } }, - "@angular-eslint/schematics": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-13.5.0.tgz", - "integrity": "sha512-0LvdalNpYb0oWwptwkeK2PVokfQ9itMIp8/aMjbOLH1RQ3eHFZgBtVvVm3G5EpPKzbL0llaeTifZvH2z70qVYQ==", - "dev": true, - "requires": { - "@angular-eslint/eslint-plugin": "13.5.0", - "@angular-eslint/eslint-plugin-template": "13.5.0", - "ignore": "5.2.0", - "strip-json-comments": "3.1.1", - "tmp": "0.2.1" + "node_modules/d3-dispatch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", + "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-dsv": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.10.tgz", + "integrity": "sha512-vqklfpxmtO2ZER3fq/B33R/BIz3A1PV0FaZRuFM8w6jLo7sUX1BZDh73fPlr0s327rzq4H6EN1q9U+eCBCSN8g==", + "license": "BSD-3-Clause", + "dependencies": { + "commander": "2", + "iconv-lite": "0.4", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json", + "csv2tsv": "bin/dsv2dsv", + "dsv2dsv": "bin/dsv2dsv", + "dsv2json": "bin/dsv2json", + "json2csv": "bin/json2dsv", + "json2dsv": "bin/json2dsv", + "json2tsv": "bin/json2dsv", + "tsv2csv": "bin/dsv2dsv", + "tsv2json": "bin/dsv2json" } }, - "@angular-eslint/template-parser": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-13.5.0.tgz", - "integrity": "sha512-k+24+kBjaOuthfp9RBQB0zH6UqeizZuFQFEuZEQbvirPbdQ2SqNBw7IcmW2Qw1v7fjFe6/6gqK7wm2g7o9ZZvA==", - "dev": true, - "requires": { - "@angular-eslint/bundled-angular-compiler": "13.5.0", - "eslint-scope": "^5.1.0" + "node_modules/d3-dsv/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-geo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.6.4.tgz", + "integrity": "sha512-O5Q3iftLc6/EdU1MHUm+O29NoKKN/cyQtySnD9/yEEcinN+q4ng+H56e2Yn1YWdfZBoiaRVtR2NoJ3ivKX5ptQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" } }, - "@angular-eslint/utils": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-13.5.0.tgz", - "integrity": "sha512-wX3W6STSDJDJ7ZyEsUdBp4HUPwmillMmKcdnFsy+qxbpJFzFOxOFpK1zet4ELsq1XpB89i9vRvC3vYbpHn3CSw==", - "dev": true, - "requires": { - "@angular-eslint/bundled-angular-compiler": "13.5.0", - "@typescript-eslint/experimental-utils": "5.27.1" + "node_modules/d3-geo-projection": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.1.2.tgz", + "integrity": "sha512-zft6RRvPaB1qplTodBVcSH5Ftvmvvg0qoDiqpt+fyNthGr/qr+DD30cizNDluXjW7jmo7EKUTjvFCAHofv08Ow==", + "license": "BSD-3-Clause", + "dependencies": { + "commander": "2", + "d3-array": "1", + "d3-geo": "^1.1.0" + }, + "bin": { + "geo2svg": "bin/geo2svg", + "geograticule": "bin/geograticule", + "geoproject": "bin/geoproject", + "geostitch": "bin/geostitch" } }, - "@angular/animations": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-13.4.0.tgz", - "integrity": "sha512-PkEmDd5zpbz/7fudxyb6qL9sBMTPlzpSIh85AapGhjgRSUSRSGuJLj49R35fQ/44c4K5bHMPEsGZjMR0oDsGdg==", - "requires": { - "tslib": "^2.3.0" + "node_modules/d3-geo-projection/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/d3-hexjson": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d3-hexjson/-/d3-hexjson-1.0.1.tgz", + "integrity": "sha512-TeH4T0PSbDazMm3gHgc4ulO0PfrZpz0Uk3y5tCGz+NgC7HnX7KBdem7uAN+j9x3ZshTh7raN3V/bFhaLB2C8DA==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1" } }, - "@angular/cdk": { - "version": "13.3.9", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.9.tgz", - "integrity": "sha512-XCuCbeuxWFyo3EYrgEYx7eHzwl76vaWcxtWXl00ka8d+WAOtMQ6Tf1D98ybYT5uwF9889fFpXAPw98mVnlo3MA==", - "requires": { - "parse5": "^5.0.0", - "tslib": "^2.3.0" + "node_modules/d3-hierarchy": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", + "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1" } }, - "@angular/cli": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.3.11.tgz", - "integrity": "sha512-LTuQ1wC/VJiHqHx8nYJCx0EJv1Ek7R6VvP/5vmr/+M8oVvJ2zSh/aIbcPg6BTL0YEfMI6nX41mUjPBUfF0q2OA==", - "dev": true, - "requires": { - "@angular-devkit/architect": "0.1303.11", - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "@schematics/angular": "13.3.11", - "@yarnpkg/lockfile": "1.1.0", - "ansi-colors": "4.1.1", - "debug": "4.3.3", - "ini": "2.0.0", - "inquirer": "8.2.0", - "jsonc-parser": "3.0.0", - "npm-package-arg": "8.1.5", - "npm-pick-manifest": "6.1.1", - "open": "8.4.0", - "ora": "5.4.1", - "pacote": "12.0.3", - "resolve": "1.22.0", - "semver": "7.3.5", - "symbol-observable": "4.0.0", - "uuid": "8.3.2" - } - }, - "@angular/common": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-13.4.0.tgz", - "integrity": "sha512-DHbPqRaxW7GmnkxqZaaasgC5OaFTeTBrmr7MJUsqsSGePHWuJYWU4QS3Fn86zd/VESJgBGmq2aCDEUmzfjnRQA==", - "requires": { - "tslib": "^2.3.0" + "node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.7.1.tgz", + "integrity": "sha512-KAyowBWtTLQxyXq1UhXcdCXKbuCQvL51FgqOS+fKlNTQ/4FfSWabRlWs2DezzwKyredAsOhBSQZN/i0XdeE2tQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1", + "d3-collection": "1", + "d3-shape": "^1.2.0" } }, - "@angular/compiler": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-13.4.0.tgz", - "integrity": "sha512-tPWoq2RC/VIrJtynEnMRWQZemBIC/ypuVfuUf3p8IIXCZHjuGnibdlZTtFYkexc4/sR1ug9xk1cJWvbOPwilng==", - "requires": { - "tslib": "^2.3.0" + "node_modules/d3-selection": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", + "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" } }, - "@angular/compiler-cli": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-13.4.0.tgz", - "integrity": "sha512-OQD0w9aZXbpcyWDEaozoHH/n3eYDLhBsmJcIBVqUN8Awx8m17v2u2R6m7DIEpVRbBzYtTscAMTKONNVwsTolHA==", - "dev": true, - "requires": { - "@babel/core": "^7.17.2", - "chokidar": "^3.0.0", - "convert-source-map": "^1.5.1", - "dependency-graph": "^0.11.0", - "magic-string": "^0.26.0", - "reflect-metadata": "^0.1.2", - "semver": "^7.0.0", - "sourcemap-codec": "^1.4.8", - "tslib": "^2.3.0", - "yargs": "^17.2.1" - }, - "dependencies": { - "@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "dependencies": { - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - } - }, - "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true - }, - "magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", - "dev": true, - "requires": { - "sourcemap-codec": "^1.4.8" - } - } + "node_modules/d3-timer": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", + "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==", + "license": "BSD-3-Clause" + }, + "node_modules/d3-transition": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", + "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-color": "1", + "d3-dispatch": "1", + "d3-ease": "1", + "d3-interpolate": "1", + "d3-selection": "^1.1.0", + "d3-timer": "1" } }, - "@angular/core": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-13.4.0.tgz", - "integrity": "sha512-RE9KL7pRj+3lkJjdSR2uKmqiG0gqjnoVCMbSLG93pWrmzNIhElmlkiDaK39aMHGl836dc68Usv9CEisyVnRqHQ==", - "requires": { - "tslib": "^2.3.0" + "node_modules/d3-voronoi": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", + "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==", + "license": "BSD-3-Clause" + }, + "node_modules/dagre": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", + "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", + "license": "MIT", + "dependencies": { + "graphlib": "^2.1.8", + "lodash": "^4.17.15" } }, - "@angular/forms": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-13.4.0.tgz", - "integrity": "sha512-vWd438sPlESLAv+cPFEZwF5aa8cF9Gt9zofLe3Ep9v9YIv2naVkv7pxCu0KFyvbBHAT7THbZfyypuvYsYNI3rw==", - "requires": { - "tslib": "^2.3.0" + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" } }, - "@angular/language-service": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-13.4.0.tgz", - "integrity": "sha512-2aaqc5iKOT4gXcEY2iJloOjy2WJBFdDeuHKSt8FqnlNhi5FJpklN0HjycRTP02yfIHscQR+3dwJi2Bv9mbBw2w==", - "dev": true + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "@angular/platform-browser": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.4.0.tgz", - "integrity": "sha512-kq4TpdkSS0Z/7ToFzWhyBbh4Ai1uOKFVdL9/TAm19dLnYNIInrN3KYW6GRxZ+pkJJA9Vkq4NtgcxysQ42VFotA==", - "requires": { - "tslib": "^2.3.0" + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" } }, - "@angular/platform-browser-dynamic": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-13.4.0.tgz", - "integrity": "sha512-vYxaLF098RTGL2tugG6s0ZQU4G1XYU5tw0/C4RCIbNLHS1rk/s9AzSnbr3zFSOQ33NWSixU0Z4EPl4hU88hghA==", - "requires": { - "tslib": "^2.3.0" + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@angular/router": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-13.4.0.tgz", - "integrity": "sha512-YlPAf3tPqD04rAMPAwW+XqFQaBXT9fY2Mh7J/9MXeyLZau59afBIcVNbeQxW5RxDajmfyFy437Qh22qFP2l0Hw==", - "requires": { - "tslib": "^2.3.0" + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" } }, - "@ant-design/colors": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-5.1.1.tgz", - "integrity": "sha512-Txy4KpHrp3q4XZdfgOBqLl+lkQIc3tEvHXOimRN1giX1AEC7mGtyrO9p8iRGJ3FLuVMGa2gNEzQyghVymLttKQ==", - "requires": { - "@ctrl/tinycolor": "^3.3.1" + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "@ant-design/icons-angular": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@ant-design/icons-angular/-/icons-angular-13.1.0.tgz", - "integrity": "sha512-bQ1pxiDmR8Hx7kUwQImxLGAtexv0uDCCMlKSWdyaw39TnNAPz+Hls0XL+UqVIjHgt/D4R8tkmSMpx3eBGFIY/Q==", - "requires": { - "@ant-design/colors": "^5.0.0", - "tslib": "^2.0.0" + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@antv/adjust": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@antv/adjust/-/adjust-0.1.1.tgz", - "integrity": "sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==", - "requires": { - "@antv/util": "~1.3.1" + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "license": "MIT", + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@antv/attr": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@antv/attr/-/attr-0.1.2.tgz", - "integrity": "sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==", - "requires": { - "@antv/util": "~1.3.1" - } + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" }, - "@antv/component": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.3.10.tgz", - "integrity": "sha512-8HLkgdhc0jXrnNrkaACPrWx2JB/51VGscL9t0pH2xoLdxiDQVtTUad2geWxbac5k/ZZHG+bDPWWb83CZIR9A9w==", - "requires": { - "@antv/attr": "~0.1.2", - "@antv/g": "~3.3.5", - "@antv/util": "~1.3.1", - "wolfy87-eventemitter": "~5.1.0" - }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", "dependencies": { - "@antv/g": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.3.6.tgz", - "integrity": "sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==", - "requires": { - "@antv/gl-matrix": "~2.7.1", - "@antv/util": "~1.3.1", - "d3-ease": "~1.0.3", - "d3-interpolate": "~1.1.5", - "d3-timer": "~1.0.6", - "wolfy87-eventemitter": "~5.1.0" - } - } + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@antv/coord": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.1.0.tgz", - "integrity": "sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==", - "requires": { - "@antv/util": "~1.3.1" + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@antv/data-set": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@antv/data-set/-/data-set-0.10.2.tgz", - "integrity": "sha512-FFWG5tiTiFiUrLDRwulraU5XfOdDjkYOlZna+AMT9FJw406D/gfS8eXM9YibscBH28M/+KLAVO8xEwuD1sc3bw==", - "requires": { - "@antv/hierarchy": "~0.4.0", - "@antv/util": "~1.3.1", - "d3-array": "~1.2.0", - "d3-composite-projections": "~1.2.0", - "d3-dsv": "~1.0.5", - "d3-geo": "~1.6.4", - "d3-geo-projection": "~2.1.2", - "d3-hexjson": "~1.0.1", - "d3-hierarchy": "~1.1.5", - "d3-sankey": "~0.7.1", - "d3-voronoi": "~1.1.2", - "dagre": "~0.8.2", - "point-at-length": "~1.0.2", - "regression": "~2.0.0", - "simple-statistics": "~6.1.0", - "topojson-client": "~3.0.0", - "wolfy87-eventemitter": "~5.1.0" + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@antv/g": { - "version": "3.4.10", - "resolved": "https://registry.npmjs.org/@antv/g/-/g-3.4.10.tgz", - "integrity": "sha512-pKy/L1SyRBsXuujdkggqrdBA0/ciAgHiArYBdIJsxHRxCneUP01wGwHdGfDayh2+S0gcSBHynjhoEahsaZaLkw==", - "requires": { - "@antv/gl-matrix": "~2.7.1", - "@antv/util": "~1.3.1", - "d3-ease": "~1.0.3", - "d3-interpolate": "~1.1.5", - "d3-timer": "~1.0.6", - "detect-browser": "^5.1.0" + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@antv/g2": { - "version": "3.5.19", - "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-3.5.19.tgz", - "integrity": "sha512-OWWDJof1ghfsxDYO20TxVF9TUhDsyOE/yzbSdSu+N9Ft1zQxKJQlgG43/FO+rOsdC/k1dXoYOBRPQ7kk5EBaJA==", - "requires": { - "@antv/adjust": "~0.1.0", - "@antv/attr": "~0.1.2", - "@antv/component": "~0.3.3", - "@antv/coord": "~0.1.0", - "@antv/g": "~3.4.10", - "@antv/scale": "~0.1.1", - "@antv/util": "~1.3.1", - "core-js": "2", - "venn.js": "~0.2.20", - "wolfy87-eventemitter": "~5.1.0" + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@antv/gl-matrix": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz", - "integrity": "sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==" - }, - "@antv/hierarchy": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@antv/hierarchy/-/hierarchy-0.4.0.tgz", - "integrity": "sha512-ols+m+Z8QA4895SWMTOSjVImOX4tEbWQTwJ0NE+WATc0WLSKs6D9y2yaR+ZWt6P60BMGVIKS6lIfabO3CwGgnQ==", - "requires": { - "@antv/util": "~1.3.1" + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@antv/scale": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.1.5.tgz", - "integrity": "sha512-7RAu4iH5+Hk21h6+aBMiDTfmLf4IibK2SWjx/+E4f4AXRpqucO+8u7IbZdFkakAWxvqhJtN3oePJuTKqOMcmlg==", - "requires": { - "@antv/util": "~1.3.1", - "fecha": "~2.3.3" + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "@antv/util": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@antv/util/-/util-1.3.1.tgz", - "integrity": "sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==", - "requires": { - "@antv/gl-matrix": "^2.7.1" + "node_modules/dependency-graph": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz", + "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, - "@assemblyscript/loader": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true - }, - "@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true - }, - "@babel/core": { - "version": "7.16.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.12.tgz", - "integrity": "sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.16.7", - "@babel/parser": "^7.16.12", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.10", - "@babel/types": "^7.16.8", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - } - } + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "license": "MIT" }, - "@babel/generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", - "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, - "requires": { - "@babel/types": "^7.16.8", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - } + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" } }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } + "license": "MIT" }, - "@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "node_modules/diff": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.1.tgz", + "integrity": "sha512-Z3u54A8qGyqFOSr2pk0ijYs8mOE9Qz8kTvtKeBI+upoG9j04Sq+oI7W8zAJiQybDcESET8/uIdHzs0p3k4fZlw==", "dev": true, - "requires": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" } }, - "@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "requires": { - "@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.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" - }, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "requires": { - "@babel/types": "^7.27.3" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" } }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, + "license": "Apache-2.0", "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "requires": { - "@babel/types": "^7.27.3" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" } }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.17.7", - "@babel/helper-plugin-utils": "^7.16.7", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, + "license": "MIT", "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "requires": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, - "requires": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" }, - "@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", "dev": true, - "requires": { - "@babel/types": "^7.27.1" + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" }, - "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "requires": { - "@babel/types": "^7.27.3" - } - } - } - }, - "@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "requires": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - } - }, - "@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", - "dev": true, - "requires": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" - }, - "dependencies": { - "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - } - } + "funding": { + "url": "https://dotenvx.com" } }, - "@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "requires": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, + "node_modules/dotignore": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", + "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", + "license": "MIT", "dependencies": { - "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - } - } + "minimatch": "^3.0.4" + }, + "bin": { + "ignored": "bin/ignored" } }, - "@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, - "requires": { - "@babel/types": "^7.28.5" - } + "node_modules/dotignore/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "node_modules/dotignore/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" + "node_modules/dotignore/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz", - "integrity": "sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-proposal-class-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz", - "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==", + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } + "license": "MIT" }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "node_modules/electron-to-chromium": { + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } + "license": "ISC" }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.9", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } + "license": "MIT" }, - "@babel/plugin-proposal-json-strings": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz", - "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==", + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "node_modules/enhanced-resolve": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "node_modules/enhanced-resolve/node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", - "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.20.7" + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", - "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/plugin-proposal-private-methods": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - } + "license": "MIT" }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", - "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-create-class-features-plugin": "^7.21.0", - "@babel/helper-plugin-utils": "^7.20.2", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, + "license": "MIT", + "optional": true, "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "requires": { - "@babel/types": "^7.27.3" - } - } + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" } }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" } }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "license": "MIT", + "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.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } + "license": "MIT" }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" } }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "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" } }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "node_modules/esbuild-wasm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.27.3.tgz", + "integrity": "sha512-AUXuOxZ145/5Az+lIqk6TdJbxKTyDGkXMJpTExmBdbnHR6n6qAFx+F4oG9ORpVYJ9dQYeQAqzv51TO4DFKsbXw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" } }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } + "license": "MIT" }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz", - "integrity": "sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==", + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-remap-async-to-generator": "^7.16.8" + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" } }, - "@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "requires": { - "@babel/types": "^7.27.3" - } - } + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "node_modules/eslint-module-utils": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.13.0.tgz", + "integrity": "sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, + "license": "MIT", "dependencies": { - "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - } + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true } } }, - "@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "node_modules/eslint-plugin-import/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } + "license": "MIT" }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" } }, - "@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" } }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "node_modules/eslint-plugin-jsdoc": { + "version": "50.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", + "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.50.2", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.4.1", + "escape-string-regexp": "^4.0.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "node_modules/eslint-plugin-prefer-arrow": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", + "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "license": "MIT", + "peerDependencies": { + "eslint": ">=2.0.0" } }, - "@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "node_modules/eslint-scope": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "node_modules/eslint/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - } + "license": "MIT" }, - "@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } + "license": "MIT" }, - "@babel/plugin-transform-runtime": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.10.tgz", - "integrity": "sha512-9nwTiqETv2G7xI4RvXHNfpGdr8pAA+Q/YtN3yLK7OoK7n9OibVm/xymJ838a9A6E/IciOLPj82lZk0fW6O4O7w==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "semver": "^6.3.0" - }, + "license": "ISC", "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.27.1" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - } - }, - "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-async-generator-functions": "^7.16.8", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.16.7", - "@babel/plugin-proposal-json-strings": "^7.16.7", - "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.16.7", - "@babel/plugin-proposal-private-methods": "^7.16.11", - "@babel/plugin-proposal-private-property-in-object": "^7.16.7", - "@babel/plugin-proposal-unicode-property-regex": "^7.16.7", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.16.7", - "@babel/plugin-transform-async-to-generator": "^7.16.8", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.16.7", - "@babel/plugin-transform-classes": "^7.16.7", - "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.16.7", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.16.7", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.16.7", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", - "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", - "@babel/plugin-transform-new-target": "^7.16.7", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.16.7", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", - "@babel/plugin-transform-reserved-words": "^7.16.7", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.16.7", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.16.7", - "@babel/plugin-transform-typeof-symbol": "^7.16.7", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "@babel/preset-modules": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6.tgz", - "integrity": "sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@babel/runtime": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz", - "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==", + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "@babel/runtime-corejs3": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.28.4.tgz", - "integrity": "sha512-h7iEYiW4HebClDEhtvFObtPmIvrd1SSfpI9EhOeKk4CtIK/ngBWFpuhCzhdmRKtg71ylcue+9I6dv54XYO1epQ==", + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, - "requires": { - "core-js-pure": "^3.43.0" + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" } }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" } }, - "@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "dependencies": { - "@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - } - }, - "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true - } + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" } }, - "@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - } + "license": "MIT" }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "dependencies": { - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - } + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" } }, - "@csstools/postcss-progressive-custom-properties": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", - "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==" - }, - "@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", - "dev": true - }, - "@epic-web/invariant": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz", - "integrity": "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==", - "dev": true - }, - "@es-joy/jsdoccomment": { - "version": "0.50.2", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", - "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, - "requires": { - "@types/estree": "^1.0.6", - "@typescript-eslint/types": "^8.11.0", - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.1.0" - }, - "dependencies": { - "@typescript-eslint/types": { - "version": "8.46.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.2.tgz", - "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", - "dev": true - } - } + "license": "MIT" }, - "@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, - "requires": { - "eslint-visitor-keys": "^3.4.3" + "license": "MIT", + "engines": { + "node": ">=0.8.x" } }, - "@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "license": "MIT", "dependencies": { - "ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" } }, - "@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true - }, - "@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "node_modules/eventsource-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "license": "MIT", + "engines": { + "node": ">=18.0.0" } }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" + "node_modules/exit-on-epipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", + "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" } }, - "@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, + "license": "MIT", + "peer": true, "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - } + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" }, - "@jridgewell/source-map": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", - "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - }, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - } + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@leichtgewicht/ip-codec": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", - "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true - }, - "@ljharb/resumer": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@ljharb/resumer/-/resumer-0.0.1.tgz", - "integrity": "sha512-skQiAOrCfO7vRTq53cxznMpks7wS1va95UCidALlOVWqvBAzwPVErwizDwoMqNVMEn1mDq0utxZd02eIrvF1lw==", - "requires": { - "@ljharb/through": "^2.3.9" - } - }, - "@ljharb/through": { - "version": "2.3.14", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.14.tgz", - "integrity": "sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A==", - "requires": { - "call-bind": "^1.0.8" + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" } }, - "@ngtools/webpack": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.11.tgz", - "integrity": "sha512-gB33hTbc/RJmHyIgSUYj8ErPazhYYm7yfapOnvwHdYhCjrj1TKkR1ierOlhJtpfBYUQg6FChdl2YpyIQNPjWMA==", - "dev": true, - "requires": {} - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "license": "MIT" }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } + "license": "MIT" }, - "@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, - "requires": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } + "license": "MIT" }, - "@npmcli/git": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", - "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^1.3.2", - "lru-cache": "^6.0.0", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^6.1.1", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" } - } + ], + "license": "BSD-3-Clause" }, - "@npmcli/installed-package-contents": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", - "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" } }, - "@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "@npmcli/node-gyp": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", - "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", - "dev": true + "node_modules/fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==", + "license": "MIT" }, - "@npmcli/promise-spawn": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", - "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "dev": true, - "requires": { - "infer-owner": "^1.0.4" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" } }, - "@npmcli/run-script": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-2.0.0.tgz", - "integrity": "sha512-fSan/Pu11xS/TdaTpTB0MRn9guwGU8dye+x56mEVgBEd/QsybBbYcAL0phPXi8SGWFEChkQd6M9qL4y6VOpFig==", + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, - "requires": { - "@npmcli/node-gyp": "^1.0.2", - "@npmcli/promise-spawn": "^1.3.2", - "node-gyp": "^8.2.0", - "read-package-json-fast": "^2.0.1" + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" } }, - "@nrwl/cli": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-15.9.7.tgz", - "integrity": "sha512-1jtHBDuJzA57My5nLzYiM372mJW0NY6rFKxlWt5a0RLsAZdPTHsd8lE3Gs9XinGC1jhXbruWmhhnKyYtZvX/zA==", + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "requires": { - "nx": "15.9.7" - }, + "license": "MIT", "dependencies": { - "@nrwl/tao": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-15.9.7.tgz", - "integrity": "sha512-OBnHNvQf3vBH0qh9YnvBQQWyyFZ+PWguF6dJ8+1vyQYlrLVk/XZ8nJ4ukWFb+QfPv/O8VBmqaofaOI9aFC4yTw==", - "dev": true, - "requires": { - "nx": "15.9.7" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "dotenv": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", - "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", - "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - } - }, - "fs-extra": { - "version": "11.3.4", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", - "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nx": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/nx/-/nx-15.9.7.tgz", - "integrity": "sha512-1qlEeDjX9OKZEryC8i4bA+twNg+lB5RKrozlNwWx/lLJHqWPUfvUTvxh+uxlPYL9KzVReQjUuxMLFMsHNqWUrA==", - "dev": true, - "requires": { - "@nrwl/cli": "15.9.7", - "@nrwl/nx-darwin-arm64": "15.9.7", - "@nrwl/nx-darwin-x64": "15.9.7", - "@nrwl/nx-linux-arm-gnueabihf": "15.9.7", - "@nrwl/nx-linux-arm64-gnu": "15.9.7", - "@nrwl/nx-linux-arm64-musl": "15.9.7", - "@nrwl/nx-linux-x64-gnu": "15.9.7", - "@nrwl/nx-linux-x64-musl": "15.9.7", - "@nrwl/nx-win32-arm64-msvc": "15.9.7", - "@nrwl/nx-win32-x64-msvc": "15.9.7", - "@nrwl/tao": "15.9.7", - "@parcel/watcher": "2.0.4", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.0.0", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^7.0.2", - "dotenv": "~10.0.0", - "enquirer": "~2.3.6", - "fast-glob": "3.2.7", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "3.0.5", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.5.4", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "v8-compile-cache": "2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - } - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "requires": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "@nrwl/devkit": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-13.1.3.tgz", - "integrity": "sha512-TAAsZJvVc/obeH0rZKY6miVhyM2GHGb8qIWp9MAIdLlXf4VDcNC7rxwb5OrGVSwuTTjqGYBGPUx0yEogOOJthA==", + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, - "requires": { - "@nrwl/tao": "13.1.3", - "ejs": "^3.1.5", - "ignore": "^5.0.4", - "rxjs": "^6.5.4", - "semver": "7.3.4", - "tslib": "^2.0.0" - }, + "license": "MIT", "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "@nrwl/nx-darwin-arm64": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-arm64/-/nx-darwin-arm64-15.9.7.tgz", - "integrity": "sha512-aBUgnhlkrgC0vu0fK6eb9Vob7eFnkuknrK+YzTjmLrrZwj7FGNAeyGXSlyo1dVokIzjVKjJg2saZZ0WQbfuCJw==", - "dev": true, - "optional": true - }, - "@nrwl/nx-darwin-x64": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-x64/-/nx-darwin-x64-15.9.7.tgz", - "integrity": "sha512-L+elVa34jhGf1cmn38Z0sotQatmLovxoASCIw5r1CBZZeJ5Tg7Y9nOwjRiDixZxNN56hPKXm6xl9EKlVHVeKlg==", + "node_modules/find-cache-directory": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-cache-directory/-/find-cache-directory-6.0.0.tgz", + "integrity": "sha512-CvFd5ivA6HcSHbD+59P7CyzINHXzwhuQK8RY7CxJZtgDSAtRlHiCaQpZQ2lMR/WRyUIEmzUvL6G2AGurMfegZA==", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "@nrwl/nx-linux-arm-gnueabihf": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-15.9.7.tgz", - "integrity": "sha512-pqmfqqEUGFu6PmmHKyXyUw1Al0Ki8PSaR0+ndgCAb1qrekVDGDfznJfaqxN0JSLeolPD6+PFtLyXNr9ZyPFlFg==", + "node_modules/find-file-up": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-2.0.1.tgz", + "integrity": "sha512-qVdaUhYO39zmh28/JLQM5CoYN9byEOKEH4qfa8K1eNV17W0UUMJ9WgbR/hHFH+t5rcl+6RTb5UC7ck/I+uRkpQ==", "dev": true, - "optional": true + "license": "MIT", + "peer": true, + "dependencies": { + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">=8" + } }, - "@nrwl/nx-linux-arm64-gnu": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-15.9.7.tgz", - "integrity": "sha512-NYOa/eRrqmM+In5g3M0rrPVIS9Z+q6fvwXJYf/KrjOHqqan/KL+2TOfroA30UhcBrwghZvib7O++7gZ2hzwOnA==", + "node_modules/find-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-2.0.0.tgz", + "integrity": "sha512-WgZ+nKbELDa6N3i/9nrHeNznm+lY3z4YfhDDWgW+5P0pdmMj26bxaxU11ookgY3NyP9GC7HvZ9etp0jRFqGEeQ==", "dev": true, - "optional": true + "license": "MIT", + "peer": true, + "dependencies": { + "find-file-up": "^2.0.1" + }, + "engines": { + "node": ">=8" + } }, - "@nrwl/nx-linux-arm64-musl": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-musl/-/nx-linux-arm64-musl-15.9.7.tgz", - "integrity": "sha512-zyStqjEcmbvLbejdTOrLUSEdhnxNtdQXlmOuymznCzYUEGRv+4f7OAepD3yRoR0a/57SSORZmmGQB7XHZoYZJA==", + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "@nrwl/nx-linux-x64-gnu": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-gnu/-/nx-linux-x64-gnu-15.9.7.tgz", - "integrity": "sha512-saNK5i2A8pKO3Il+Ejk/KStTApUpWgCxjeUz9G+T8A+QHeDloZYH2c7pU/P3jA9QoNeKwjVO9wYQllPL9loeVg==", + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "@nrwl/nx-linux-x64-musl": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-musl/-/nx-linux-x64-musl-15.9.7.tgz", - "integrity": "sha512-extIUThYN94m4Vj4iZggt6hhMZWQSukBCo8pp91JHnDcryBg7SnYmnikwtY1ZAFyyRiNFBLCKNIDFGkKkSrZ9Q==", + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, - "optional": true + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } }, - "@nrwl/nx-win32-arm64-msvc": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-15.9.7.tgz", - "integrity": "sha512-GSQ54hJ5AAnKZb4KP4cmBnJ1oC4ILxnrG1mekxeM65c1RtWg9NpBwZ8E0gU3xNrTv8ZNsBeKi/9UhXBxhsIh8A==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } }, - "@nrwl/nx-win32-x64-msvc": { - "version": "15.9.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-x64-msvc/-/nx-win32-x64-msvc-15.9.7.tgz", - "integrity": "sha512-x6URof79RPd8AlapVbPefUD3ynJZpmah3tYaYZ9xZRMXojVtEHV8Qh5vysKXQ1rNYJiiB8Ah6evSKWLbAH60tw==", + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, - "optional": true + "license": "ISC" }, - "@nrwl/tao": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-13.1.3.tgz", - "integrity": "sha512-/IwJgSgCBD1SaF+n8RuXX2OxDAh8ut/+P8pMswjm8063ac30UlAHjQ4XTYyskLH8uoUmNi2hNaGgHUrkwt7tQA==", - "dev": true, - "requires": { - "chalk": "4.1.0", - "enquirer": "~2.3.6", - "fs-extra": "^9.1.0", - "jsonc-parser": "3.0.0", - "nx": "13.1.3", - "rxjs": "^6.5.4", - "rxjs-for-await": "0.0.2", - "semver": "7.3.4", - "tmp": "~0.2.1", - "tslib": "^2.0.0", - "yargs-parser": "20.0.0" - }, + "node_modules/fmin": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", + "integrity": "sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A==", + "license": "BSD-3-Clause", "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "contour_plot": "^0.0.1", + "json2module": "^0.0.3", + "rollup": "^0.25.8", + "tape": "^4.5.1", + "uglify-js": "^2.6.2" } }, - "@parcel/watcher": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.0.4.tgz", - "integrity": "sha512-cTDi+FUDBIUOBKEtj+nhiJ71AZVlkAsQFuGQTun5tV9mwQBQgZvhCzG+URPQc8myeN32yRVZEfVAPCs1RW+Jvg==", - "dev": true, - "requires": { - "node-addon-api": "^3.2.1", - "node-gyp-build": "^4.3.0" + "node_modules/fmin/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@playwright/test": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", - "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", - "dev": true, - "requires": { - "playwright": "1.55.1" + "node_modules/fmin/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.0.8" + "node_modules/fmin/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fmin/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "@rollup/plugin-node-resolve": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz", - "integrity": "sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==", - "dev": true, - "requires": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.1.0", - "is-module": "^1.0.0", - "resolve": "^1.19.0" + "node_modules/fmin/node_modules/rollup": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", + "integrity": "sha512-a2S4Bh3bgrdO4BhKr2E4nZkjTvrJ2m2bWjMTzVYtoqSCn0HnuxosXnaJUHrMEziOWr3CzL9GjilQQKcyCQpJoA==", + "license": "MIT", + "dependencies": { + "chalk": "^1.1.1", + "minimist": "^1.2.0", + "source-map-support": "^0.3.2" + }, + "bin": { + "rollup": "bin/rollup" } }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", - "dev": true, - "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" - }, + "node_modules/fmin/node_modules/source-map": { + "version": "0.1.32", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", "dependencies": { - "@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", - "dev": true - } + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" } }, - "@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, - "@schematics/angular": { - "version": "13.3.11", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-13.3.11.tgz", - "integrity": "sha512-imKBnKYEse0SBVELZO/753nkpt3eEgpjrYkB+AFWF9YfO/4RGnYXDHoH8CFkzxPH9QQCgNrmsVFNiYGS+P/S1A==", - "dev": true, - "requires": { - "@angular-devkit/core": "13.3.11", - "@angular-devkit/schematics": "13.3.11", - "jsonc-parser": "3.0.0" + "node_modules/fmin/node_modules/source-map-support": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", + "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", + "license": "MIT", + "dependencies": { + "source-map": "0.1.32" } }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "@types/angular": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.9.tgz", - "integrity": "sha512-Z0HukqZkx0fotsV3QO00yqU9NzcQI+tMcrum+8MvfB4ePqCawZctF/gz6QiuII+T1ax+LitNoPx/eICTgnF4sg==", - "dev": true - }, - "@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" + "node_modules/fmin/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "@types/bonjour": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", - "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", - "dev": true, - "requires": { - "@types/node": "*" + "node_modules/fmin/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, - "requires": { - "@types/node": "*" + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, - "@types/connect-history-api-fallback": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", - "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/node": "*" + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@types/diff-match-patch": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", - "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg==", - "dev": true - }, - "@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" } }, - "@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true - }, - "@types/express": { - "version": "4.17.24", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.24.tgz", - "integrity": "sha512-Mbrt4SRlXSTWryOnHAh2d4UQ/E7n9lZyGSi6KgX+4hkuL9soYbLOVXVhnk/ODp12YsGc95f4pOvqywJ6kngUwg==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - }, - "dependencies": { - "@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - } + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" } }, - "@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" } }, - "@types/highlight.js": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@types/highlight.js/-/highlight.js-9.12.4.tgz", - "integrity": "sha512-t2szdkwmg2JJyuCM20e8kR2X59WCE5Zkl4bzm1u1Oukjm79zpbiAv+QjnwLnuuV0WHEcX2NgUItu0pAMKuOPww==", - "dev": true - }, - "@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true - }, - "@types/http-proxy": { - "version": "1.17.17", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", - "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, - "requires": { - "@types/node": "*" + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "@types/jquery": { - "version": "3.5.16", - "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.16.tgz", - "integrity": "sha512-bsI7y4ZgeMkmpG9OM710RRzDFp+w4P1RGiIt30C1mSBT+ExCleeh4HObwgArnDFELmRrOpXgSYN9VF1hj+f1lw==", + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, - "requires": { - "@types/sizzle": "*" + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/lodash": { - "version": "4.14.144", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.144.tgz", - "integrity": "sha512-ogI4g9W5qIQQUhXAclq6zhqgqNUr7UlFaqDHbch7WLSLeeM/7d3CRaw7GLajxvyFvhJqw4Rpcz5bhoaYtIx6Tg==", - "dev": true - }, - "@types/mathjax": { - "version": "0.0.35", - "resolved": "https://registry.npmjs.org/@types/mathjax/-/mathjax-0.0.35.tgz", - "integrity": "sha512-flo9bVJE2Lzv3X5NQXVhNhv7srqk//Ngr8MT+/jRErkWGYkk8EBm42J5W0XUH6p4nWF1iLGe+atSuIkR5wA2yw==", - "dev": true - }, - "@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "@types/node": { - "version": "12.19.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.16.tgz", - "integrity": "sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==", - "dev": true + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, - "@types/node-forge": { - "version": "1.3.14", - "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", - "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, - "@types/parse5": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz", - "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==", - "dev": true - }, - "@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "dev": true + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "requires": { - "@types/node": "*" + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "@types/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", - "dev": true + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "requires": { - "@types/node": "*" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "@types/serve-index": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", - "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "requires": { - "@types/express": "*" + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" } }, - "@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "node_modules/get-east-asian-width": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "dev": true, - "requires": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" + "license": "MIT", + "engines": { + "node": ">=18" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - } + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@types/sizzle": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", - "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", - "dev": true + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, - "requires": { - "@types/node": "*" + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@types/webpack-env": { - "version": "1.18.8", - "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.8.tgz", - "integrity": "sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==", - "dev": true + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "requires": { - "@types/node": "*" + "node_modules/github-markdown-css": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-3.0.1.tgz", + "integrity": "sha512-9G5CIPsHoyk5ObDsb/H4KTi23J8KE1oDd4KYU51qwqeM+lKWAiO7abpSgCkyWswgmSKBiuE7/4f8xUz7f2qAiQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, + "license": "BlueOak-1.0.0", "dependencies": { - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true - } + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "@typescript-eslint/experimental-utils": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.27.1.tgz", - "integrity": "sha512-Vd8uewIixGP93sEnmTRIH6jHZYRQRkGPDPpapACMvitJKX8335VHNyqKTE+mZ+m3E2c5VznTZfSsSsS5IF7vUA==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "requires": { - "@typescript-eslint/utils": "5.27.1" - }, + "license": "ISC", "dependencies": { - "@typescript-eslint/scope-manager": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.27.1.tgz", - "integrity": "sha512-fQEOSa/QroWE6fAEg+bJxtRZJTH8NTskggybogHt4H9Da8zd4cJji76gA5SBlR0MgtwF7rebxTbDKB49YUCpAg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1" - } - }, - "@typescript-eslint/types": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.27.1.tgz", - "integrity": "sha512-LgogNVkBhCTZU/m8XgEYIWICD6m4dmEDbKXESCbqOXfKZxRKeqpiJXQIErv66sdopRKZPo5l32ymNqibYEH/xg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.27.1.tgz", - "integrity": "sha512-DnZvvq3TAJ5ke+hk0LklvxwYsnXpRdqUY5gaVS0D4raKtbznPz71UJGnPTHEFo0GDxqLOLdMkkmVZjSpET1hFw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/visitor-keys": "5.27.1", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.27.1.tgz", - "integrity": "sha512-mZ9WEn1ZLDaVrhRaYgzbkXBkTPghPFsup8zDbbsYTxC5OmqrFE7skkKS/sraVsLP3TcT3Ki5CSyEFBRkLH/H/w==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.27.1", - "@typescript-eslint/types": "5.27.1", - "@typescript-eslint/typescript-estree": "5.27.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.27.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.27.1.tgz", - "integrity": "sha512-xYs6ffo01nhdJgPieyk7HAOpjhTsx7r/oB9LWEhwAXgwn33tkr+W8DI2ChboqhZlC4q3TC6geDYPoiX8ROqyOQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.27.1", - "eslint-visitor-keys": "^3.3.0" - } - }, - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true - } + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" } }, - "@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "node_modules/glob-to-regex.js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/glob-to-regex.js/-/glob-to-regex.js-1.2.0.tgz", + "integrity": "sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==", "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" }, - "dependencies": { - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true, - "requires": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - } + "license": "BSD-2-Clause" }, - "@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" + "license": "MIT", + "peer": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" } }, - "@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "peer": true }, - "@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, - "requires": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, + "license": "ISC", + "peer": true, "dependencies": { - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true - } + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "dependencies": { - "semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, - "peer": true + "license": "ISC" }, - "@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "dev": true, - "peer": true + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15" + } }, - "@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", "dev": true, - "peer": true + "license": "MIT" }, - "@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" } }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "dev": true, - "peer": true + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "dev": true, - "peer": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "peer": true, - "requires": { - "@xtuc/long": "4.2.2" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "dev": true, - "peer": true + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "dev": true, - "peer": true, - "requires": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "9.18.5", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz", + "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==", + "deprecated": "Support has ended for 9.x series. Upgrade to @latest", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" } }, - "@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, + "license": "MIT", "peer": true, - "requires": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "@yarnpkg/lockfile": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true - }, - "@yarnpkg/parsers": { - "version": "3.0.0-rc.46", - "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", - "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", + "node_modules/hono": { + "version": "4.12.23", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", + "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "dev": true, - "requires": { - "js-yaml": "^3.10.0", - "tslib": "^2.4.0" + "license": "MIT", + "engines": { + "node": ">=16.9.0" } }, - "@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", "dev": true, - "requires": { - "argparse": "^2.0.1" - }, + "license": "ISC", "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - } + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "abs-svg-path": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/abs-svg-path/-/abs-svg-path-0.1.1.tgz", - "integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==" + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, + "license": "MIT", "dependencies": { - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true - } + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" } }, - "acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", - "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true, - "requires": {} + "license": "MIT" }, - "acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "peer": true, - "requires": {} + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, - "requires": {} + "license": "MIT" }, - "acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "requires": { - "acorn": "^8.11.0" + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "adjust-sourcemap-loader": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "regex-parser": "^2.2.11" - }, - "dependencies": { - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" } }, - "adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - } - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, - "requires": { - "es6-promisify": "^5.0.0" + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true, - "requires": { - "humanize-ms": "^1.2.1" - } + "license": "BSD-2-Clause" }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } + "license": "MIT" }, - "ajv": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.9.0.tgz", - "integrity": "sha512-qOKJyNj/h+OWx7s5DePL6Zu1KeM9jPZhwBqs+7DzP6bGOvqzVCSf0xueYmVuaC/oQ/VtS2zLMLHdQFbkka+XDQ==", + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", "dev": true, - "requires": { - "ajv": "^8.0.0" - } + "license": "MIT" }, - "ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3" - } - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha512-GrTZLRpmp6wIC2ztrWW9MjjTgSKccffgFagbNDOX95/dcjEcYZibYTeaOntySQLcdw1ztBoFkviiUvTMbb9MYg==", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, + "license": "MIT", "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "requires": { - "is-buffer": "^1.1.5" - } - } + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" } }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==" - }, - "angular": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz", - "integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==" - }, - "ansi_up": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-6.0.6.tgz", - "integrity": "sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==" - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, + "license": "MIT", "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" } }, - "ansi-html-community": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", - "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", - "dev": true - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/http-proxy-middleware": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz", + "integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==", "dev": true, - "requires": { - "color-convert": "^2.0.1" + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "license": "MIT", + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" } }, - "aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "dev": true - }, - "are-docs-informative": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", - "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", - "dev": true - }, - "are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" } }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, - "requires": { - "sprintf-js": "~1.0.2" + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" } }, - "aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" } }, - "array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "requires": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" + "node_modules/hyperdyperid": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", + "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.18" } }, - "array-flatten": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", - "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", - "dev": true + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } }, - "array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.findlastindex": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", - "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-shim-unscopables": "^1.1.0" + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "node_modules/ignore-walk": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", + "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", "dev": true, - "requires": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "node_modules/ignorefs": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/ignorefs/-/ignorefs-5.0.4.tgz", + "integrity": "sha512-vObKs/ga6E6TIfnQyxpShXVvUnlMZ+eoB2aGrvLuFGgnMqMVjZP3xW08WXJKocHmQL48WsDy6kUOisLp3gb8vg==", "dev": true, - "requires": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0", + "ignorepatterns": "^5.6.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "requires": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" + "node_modules/ignorepatterns": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-5.6.0.tgz", + "integrity": "sha512-6stRjchHcZwYfRkE2bVA9hCe+HFS1TWRrEYyEOPIeTnKyhKaqMg00AJPmAZ8EmVG/eUpALTkIM+ev1uTKY3PkQ==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true - }, - "async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true - }, - "async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "autoprefixer": { - "version": "10.4.21", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", - "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", - "dev": true, - "requires": { - "browserslist": "^4.24.4", - "caniuse-lite": "^1.0.30001702", - "fraction.js": "^4.3.7", - "normalize-range": "^0.1.2", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" } }, - "available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "requires": { - "possible-typed-array-names": "^1.0.0" - } + "node_modules/immutable": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "dev": true, + "license": "MIT" }, - "axios": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.14.0.tgz", - "integrity": "sha512-3Y8yrqLSwjuzpXuZ0oIYZ/XGgLwUIBU3uLvbcpb0pidD9ctpShJd43KSlEEkVQg6DS0G9NKyzOvBfUtDKEyHvQ==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, - "requires": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", - "proxy-from-env": "^2.1.0" + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "axobject-query": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", - "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", - "dev": true - }, - "babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "dependencies": { - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - } + "license": "MIT", + "engines": { + "node": ">=0.8.19" } }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "node_modules/injection-js": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.6.1.tgz", + "integrity": "sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==", "dev": true, - "requires": { - "@babel/compat-data": "^7.17.7", - "@babel/helper-define-polyfill-provider": "^0.3.3", - "semver": "^6.1.1" - }, + "license": "MIT", "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "tslib": "^2.0.0" } }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", - "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.2", - "core-js-compat": "^3.21.0" + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "license": "MIT", + "engines": { + "node": ">= 12" } }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "baseline-browser-mapping": { - "version": "2.10.14", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.14.tgz", - "integrity": "sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" + "license": "MIT", + "engines": { + "node": ">= 0.10" } }, - "body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", - "dev": true, - "requires": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "requires": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true - } + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "bonjour": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.1.tgz", - "integrity": "sha512-xONzj4PfpPJw6xSqCcT2SmQkBOXpUINUz3o3qXcWJwYlXbkZNcNaUae0o5lle7tKt4HHV6dTgkIRhAXZ3nBMsQ==", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^7.2.3", - "multicast-dns-service-types": "^1.1.0" + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" }, - "brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { - "fill-range": "^7.1.1" + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "requires": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "buffer-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true - }, - "builtins": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "dev": true + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, - "requires": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "requires": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "call-bind-apply-helpers": { + "node_modules/is-data-view": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "requires": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - } - }, - "call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "requires": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - } - }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001785", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001785.tgz", - "integrity": "sha512-blhOL/WNR+Km1RI/LCVAvA73xplXA7ZbjzI4YkMK9pa6T/P3F2GxjNpEkyw5repTw9IvkyrjyHpwjnhZ5FOvYQ==", - "dev": true - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha512-Baz3aNe2gd2LP2qk5U+sDk/m4oSuwSDcBfayTCTBoWpfIGO5XFxPmjILQII4NGiZjD6DoDI6kf7gKaxkf7s3VQ==", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cfb": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", - "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", - "requires": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0" - }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", "dependencies": { - "adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==" - } + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true - }, - "chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "dev": true + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "circular-dependency-plugin": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.2.tgz", - "integrity": "sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==", + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "requires": { - "restore-cursor": "^3.1.0" + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "dev": true - }, - "cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", "dev": true, - "requires": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" + "license": "MIT", + "engines": { + "node": ">=20" }, - "dependencies": { - "ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true - }, - "emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true - }, - "string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "requires": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - } - }, - "strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, + "license": "MIT", "dependencies": { - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "codepage": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", - "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==", - "requires": { - "commander": "~2.14.1", - "exit-on-epipe": "~1.0.1" + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "node_modules/is-network-error": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", "dev": true, - "requires": { - "delayed-stream": "~1.0.0" + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "comment-parser": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", - "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" + "license": "MIT", + "engines": { + "node": ">=0.12.0" } }, - "compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "compressible": "~2.0.18", - "debug": "2.6.9", - "negotiator": "~0.6.4", - "on-headers": "~1.1.0", - "safe-buffer": "5.2.1", - "vary": "~1.1.2" - }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "concurrently": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", - "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, - "requires": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.8.3", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" + "license": "MIT", + "engines": { + "node": ">=10" }, - "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "connect-history-api-fallback": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", - "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true, - "requires": { - "safe-buffer": "5.2.1" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true - }, - "contour_plot": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/contour_plot/-/contour_plot-0.0.1.tgz", - "integrity": "sha512-Nil2HI76Xux6sVGORvhSS8v66m+/h5CwFkBJDO+U5vWaMdNC0yXNCsGDPbzPhvqOEU5koebhdEvD372LI+IyLw==" - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" }, - "cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", - "dev": true + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "copy-anything": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", - "dev": true, - "requires": { - "is-what": "^3.14.1" + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "copy-webpack-plugin": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.1.tgz", - "integrity": "sha512-nr81NhCAIpAWXGCK5thrKmfCQ6GDY0L5RN0U+BnIn/7Us55+UCex5ANNsNKmIVtDRnk0Ecf+/kzp9SUVrrBMLg==", + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, - "requires": { - "fast-glob": "^3.2.7", - "glob-parent": "^6.0.1", - "globby": "^12.0.2", - "normalize-path": "^3.0.0", - "schema-utils": "^4.0.0", - "serialize-javascript": "^6.0.0" + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "dependencies": { - "array-union": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", - "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", - "dev": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globby": { - "version": "12.2.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", - "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", - "dev": true, - "requires": { - "array-union": "^3.0.1", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.7", - "ignore": "^5.1.9", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "core-js": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" - }, - "core-js-compat": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.46.0.tgz", - "integrity": "sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==", - "dev": true, - "requires": { - "browserslist": "^4.26.3" + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "core-js-pure": { - "version": "3.46.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.46.0.tgz", - "integrity": "sha512-NMCW30bHNofuhwLhYPt66OLOKTMbOhgTTatKVbaQC3KRHpTCiRIBYvtshr+NBYSnBxwAFhjW/RfJ0XbIjS16rw==", - "dev": true + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "license": "MIT", + "engines": { + "node": ">=18" }, - "dependencies": { - "yaml": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "create-require": { + "node_modules/is-weakref": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "critters": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", - "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "css-select": "^4.2.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "postcss": "^8.3.7", - "pretty-bytes": "^5.3.0" - }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cross-env": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", - "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", - "dev": true, - "requires": { - "@epic-web/invariant": "^1.0.0", - "cross-spawn": "^7.0.6" + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" } }, - "css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", "dev": true, - "requires": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - }, + "license": "MIT", "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "css-blank-pseudo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", - "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } - } + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" }, - "css-has-pseudo": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", - "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } - } + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" }, - "css-loader": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz", - "integrity": "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==", + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, - "requires": { - "icss-utils": "^5.1.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "semver": "^7.3.5" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "css-prefers-color-scheme": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", - "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", "dev": true, - "requires": {} + "license": "MIT", + "peer": true, + "peerDependencies": { + "ws": "*" + } }, - "css-select": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.0.1", - "domhandler": "^4.3.1", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" } }, - "css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", - "dev": true - }, - "cssdb": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-5.1.0.tgz", - "integrity": "sha512-/vqjXhv1x9eGkE/zO6o8ZOI7dgdZbLVLUGyVRbPgk6YipXbW87YzUCcO+Jrmi5bwJlAH6oD+MNeZyRgXea1GZw==", - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "cuint": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", - "integrity": "sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==", - "dev": true - }, - "d3": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", - "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==" - }, - "d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - }, - "d3-collection": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" - }, - "d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "d3-composite-projections": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/d3-composite-projections/-/d3-composite-projections-1.2.3.tgz", - "integrity": "sha512-RxNBoRGf3epTnQBUKeEpaXpD8BA/Ud0xRuLwWxyI7dWfuuYgJZMKw6ZsZOwfDNC0ZbMWaU0eBFlL05A2jlcsWg==", - "requires": { - "d3-geo": "^1.11.6", - "d3-path": "^1.0.7" - }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", - "requires": { - "d3-array": "1" - } - } - } - }, - "d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" - }, - "d3-dsv": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.10.tgz", - "integrity": "sha512-vqklfpxmtO2ZER3fq/B33R/BIz3A1PV0FaZRuFM8w6jLo7sUX1BZDh73fPlr0s327rzq4H6EN1q9U+eCBCSN8g==", - "requires": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - } - }, - "d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" - }, - "d3-geo": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.6.4.tgz", - "integrity": "sha512-O5Q3iftLc6/EdU1MHUm+O29NoKKN/cyQtySnD9/yEEcinN+q4ng+H56e2Yn1YWdfZBoiaRVtR2NoJ3ivKX5ptQ==", - "requires": { - "d3-array": "1" + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" } }, - "d3-geo-projection": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/d3-geo-projection/-/d3-geo-projection-2.1.2.tgz", - "integrity": "sha512-zft6RRvPaB1qplTodBVcSH5Ftvmvvg0qoDiqpt+fyNthGr/qr+DD30cizNDluXjW7jmo7EKUTjvFCAHofv08Ow==", - "requires": { - "commander": "2", - "d3-array": "1", - "d3-geo": "^1.1.0" + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" } }, - "d3-hexjson": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d3-hexjson/-/d3-hexjson-1.0.1.tgz", - "integrity": "sha512-TeH4T0PSbDazMm3gHgc4ulO0PfrZpz0Uk3y5tCGz+NgC7HnX7KBdem7uAN+j9x3ZshTh7raN3V/bFhaLB2C8DA==", - "requires": { - "d3-array": "1" + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "d3-hierarchy": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" - }, - "d3-interpolate": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", - "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", - "requires": { - "d3-color": "1" + "node_modules/jose": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", + "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "license": "MIT" }, - "d3-sankey": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.7.1.tgz", - "integrity": "sha512-KAyowBWtTLQxyXq1UhXcdCXKbuCQvL51FgqOS+fKlNTQ/4FfSWabRlWs2DezzwKyredAsOhBSQZN/i0XdeE2tQ==", - "requires": { - "d3-array": "1", - "d3-collection": "1", - "d3-shape": "^1.2.0" + "node_modules/jquery-ui": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.14.0.tgz", + "integrity": "sha512-mPfYKBoRCf0MzaT2cyW5i3IuZ7PfTITaasO5OFLAQxrHuI+ZxruPa+4/K1OMNT8oElLWGtIxc9aRbyw20BKr8g==", + "license": "MIT", + "dependencies": { + "jquery": ">=1.12.0 <5.0.0" } }, - "d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" }, - "d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "requires": { - "d3-path": "1" + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" - }, - "d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "requires": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" } }, - "d3-voronoi": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", - "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" - }, - "dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", - "requires": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, - "data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "requires": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - } + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" }, - "data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "requires": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" + "node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", + "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "data-view-byte-offset": { + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - } + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" }, - "date-fns": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", - "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==" + "node_modules/json2module": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", + "integrity": "sha512-qYGxqrRrt4GbB8IEOy1jJGypkNsjWoIMlZt4bAsmUScCA507Hbc2p1JOhBzqn45u3PWafUgH2OnzyNU7udO/GA==", + "license": "BSD-3-Clause", + "dependencies": { + "rw": "^1.3.2" + }, + "bin": { + "json2module": "bin/json2module" + } }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "requires": { - "ms": "2.1.2" + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" }, - "decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" }, - "deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "requires": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map-support": "^0.5.5" } }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } }, - "default-gateway": { + "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", - "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", - "dev": true, - "requires": { - "execa": "^5.0.0" - }, - "dependencies": { - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - } + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "node_modules/launch-editor": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.0.tgz", + "integrity": "sha512-Pj3ZOx9dD1BClS7YcSQx0An1PCF9wz4JpvbEmKvDxQtm0jxlkk5NhW8x0SBAKA/acHBKZaqdd5FFOWlXo500JA==", "dev": true, - "requires": { - "clone": "^1.0.2" + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.4" } }, - "define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "node_modules/launch-editor/node_modules/shell-quote": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true - }, - "define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "requires": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" + "node_modules/lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "defined": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", - "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==" - }, - "del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "node_modules/less": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/less/-/less-4.4.2.tgz", + "integrity": "sha512-j1n1IuTX1VQjIy3tT7cyGbX7nvQOsFLoIqobZv4ttI5axP923gA44zUj6miiA6R5Aoms4sEGVIIcucXUbRI14g==", "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" + "license": "Apache-2.0", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" } }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "dependency-graph": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", - "dev": true + "node_modules/less-loader": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-12.3.1.tgz", + "integrity": "sha512-JZZmG7gMzoDP3VGeEG8Sh6FW5wygB5jYL7Wp29FFihuRTsIBacqO3LbRPr2yStYD11riVf13selLm/CPFRDBRQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } }, - "detect-browser": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", - "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==" + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } }, - "detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "license": "ISC", + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } }, - "diff": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.1.tgz", - "integrity": "sha512-Z3u54A8qGyqFOSr2pk0ijYs8mOE9Qz8kTvtKeBI+upoG9j04Sq+oI7W8zAJiQybDcESET8/uIdHzs0p3k4fZlw==", - "dev": true + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } }, - "diff-match-patch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", - "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==" + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/lint-staged": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", + "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", "dev": true, - "requires": { - "path-type": "^4.0.0" + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0", + "debug": "^4.4.0", + "execa": "^8.0.1", + "lilconfig": "^3.1.3", + "listr2": "^8.2.5", + "micromatch": "^4.0.8", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.7.0" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" } }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", - "dev": true - }, - "dns-packet": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", - "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "node_modules/lint-staged/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, - "requires": { - "@leichtgewicht/ip-codec": "^2.0.1" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", + "node_modules/lint-staged/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/lint-staged/node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, - "requires": { - "esutils": "^2.0.2" + "license": "MIT", + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "dom-serializer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "node_modules/lint-staged/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true + "node_modules/lint-staged/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" }, - "domhandler": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "node_modules/lint-staged/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "dev": true, - "requires": { - "domelementtype": "^2.2.0" + "license": "MIT" + }, + "node_modules/lint-staged/node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "node_modules/lint-staged/node_modules/listr2": { + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", + "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" + "license": "MIT", + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" } }, - "dotenv": { - "version": "17.2.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", - "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", - "dev": true + "node_modules/lint-staged/node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } }, - "dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "requires": { - "minimatch": "^3.0.4" + "node_modules/lint-staged/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "requires": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" } }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" }, - "editions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", - "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "node_modules/lmdb": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.1.tgz", + "integrity": "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==", "dev": true, - "requires": { - "version-range": "^4.15.0" + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@harperfast/extended-iterable": "^1.0.3", + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.5.1", + "@lmdb/lmdb-darwin-x64": "3.5.1", + "@lmdb/lmdb-linux-arm": "3.5.1", + "@lmdb/lmdb-linux-arm64": "3.5.1", + "@lmdb/lmdb-linux-x64": "3.5.1", + "@lmdb/lmdb-win32-arm64": "3.5.1", + "@lmdb/lmdb-win32-x64": "3.5.1" } }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true + "node_modules/lmdb/node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT", + "optional": true }, - "ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "node_modules/loader-runner": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, - "requires": { - "jake": "^10.8.5" + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "electron-to-chromium": { - "version": "1.5.331", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.331.tgz", - "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } + "license": "MIT" }, - "end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, - "requires": { - "once": "^1.4.0" - } + "license": "MIT" }, - "enhanced-resolve": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", - "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", + "node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, - "requires": { - "ansi-colors": "^4.1.1" + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true - }, - "environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true - }, - "err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "errno": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, - "optional": true, - "requires": { - "prr": "~1.0.1" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "error-ex": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", - "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "requires": { - "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.19" + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" - }, - "es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" - }, - "es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "node_modules/long-timeout": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", + "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==", "dev": true, + "license": "MIT", "peer": true }, - "es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "requires": { - "es-errors": "^1.3.0" - } - }, - "es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "requires": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "node_modules/longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "requires": { - "hasown": "^2.0.2" + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" } }, - "es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "requires": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" } }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, - "requires": { - "es6-promise": "^4.0.3" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "esbuild": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz", - "integrity": "sha512-CjFCFGgYtbFOPrwZNJf7wsuzesx8kqwAffOlbYcFDLFuUtP8xloK1GH+Ai13Qr0RZQf9tE7LMTHJ2iVGJ1SKZA==", + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "optional": true, - "requires": { - "esbuild-android-arm64": "0.14.22", - "esbuild-darwin-64": "0.14.22", - "esbuild-darwin-arm64": "0.14.22", - "esbuild-freebsd-64": "0.14.22", - "esbuild-freebsd-arm64": "0.14.22", - "esbuild-linux-32": "0.14.22", - "esbuild-linux-64": "0.14.22", - "esbuild-linux-arm": "0.14.22", - "esbuild-linux-arm64": "0.14.22", - "esbuild-linux-mips64le": "0.14.22", - "esbuild-linux-ppc64le": "0.14.22", - "esbuild-linux-riscv64": "0.14.22", - "esbuild-linux-s390x": "0.14.22", - "esbuild-netbsd-64": "0.14.22", - "esbuild-openbsd-64": "0.14.22", - "esbuild-sunos-64": "0.14.22", - "esbuild-windows-32": "0.14.22", - "esbuild-windows-64": "0.14.22", - "esbuild-windows-arm64": "0.14.22" - } - }, - "esbuild-android-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.22.tgz", - "integrity": "sha512-k1Uu4uC4UOFgrnTj2zuj75EswFSEBK+H6lT70/DdS4mTAOfs2ECv2I9ZYvr3w0WL0T4YItzJdK7fPNxcPw6YmQ==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.22.tgz", - "integrity": "sha512-d8Ceuo6Vw6HM3fW218FB6jTY6O3r2WNcTAU0SGsBkXZ3k8SDoRLd3Nrc//EqzdgYnzDNMNtrWegK2Qsss4THhw==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.22.tgz", - "integrity": "sha512-YAt9Tj3SkIUkswuzHxkaNlT9+sg0xvzDvE75LlBo4DI++ogSgSmKNR6B4eUhU5EUUepVXcXdRIdqMq9ppeRqfw==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.22.tgz", - "integrity": "sha512-ek1HUv7fkXMy87Qm2G4IRohN+Qux4IcnrDBPZGXNN33KAL0pEJJzdTv0hB/42+DCYWylSrSKxk3KUXfqXOoH4A==", - "dev": true, - "optional": true + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } }, - "esbuild-freebsd-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.22.tgz", - "integrity": "sha512-zPh9SzjRvr9FwsouNYTqgqFlsMIW07O8mNXulGeQx6O5ApgGUBZBgtzSlBQXkHi18WjrosYfsvp5nzOKiWzkjQ==", + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, - "optional": true + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } }, - "esbuild-linux-32": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.22.tgz", - "integrity": "sha512-SnpveoE4nzjb9t2hqCIzzTWBM0RzcCINDMBB67H6OXIuDa4KqFqaIgmTchNA9pJKOVLVIKd5FYxNiJStli21qg==", + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, - "optional": true + "license": "ISC" }, - "esbuild-linux-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.22.tgz", - "integrity": "sha512-Zcl9Wg7gKhOWWNqAjygyqzB+fJa19glgl2JG7GtuxHyL1uEnWlpSMytTLMqtfbmRykIHdab797IOZeKwk5g0zg==", + "node_modules/make-fetch-happen": { + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.6.tgz", + "integrity": "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw==", "dev": true, - "optional": true + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^4.0.0", + "@npmcli/redact": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } }, - "esbuild-linux-arm": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.22.tgz", - "integrity": "sha512-soPDdbpt/C0XvOOK45p4EFt8HbH5g+0uHs5nUKjHVExfgR7du734kEkXR/mE5zmjrlymk5AA79I0VIvj90WZ4g==", - "dev": true, - "optional": true + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "esbuild-linux-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.22.tgz", - "integrity": "sha512-8q/FRBJtV5IHnQChO3LHh/Jf7KLrxJ/RCTGdBvlVZhBde+dk3/qS9fFsUy+rs3dEi49aAsyVitTwlKw1SUFm+A==", - "dev": true, - "optional": true + "node_modules/mathjax": { + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", + "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==", + "license": "Apache-2.0" }, - "esbuild-linux-mips64le": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.22.tgz", - "integrity": "sha512-SiNDfuRXhGh1JQLLA9JPprBgPVFOsGuQ0yDfSPTNxztmVJd8W2mX++c4FfLpAwxuJe183mLuKf7qKCHQs5ZnBQ==", + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "esbuild-linux-ppc64le": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.22.tgz", - "integrity": "sha512-6t/GI9I+3o1EFm2AyN9+TsjdgWCpg2nwniEhjm2qJWtJyJ5VzTXGUU3alCO3evopu8G0hN2Bu1Jhz2YmZD0kng==", + "node_modules/memfs": { + "version": "4.57.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.3.tgz", + "integrity": "sha512-dlvqataP1zUOlfj6pv9wgCSC5pRIooNntXgdLfR7FWlcKi1p8fMfJADtHp/+8Dhu5JFvMHNh7L0QVcuaaBKqqA==", "dev": true, - "optional": true + "license": "Apache-2.0", + "dependencies": { + "@jsonjoy.com/fs-core": "4.57.3", + "@jsonjoy.com/fs-fsa": "4.57.3", + "@jsonjoy.com/fs-node": "4.57.3", + "@jsonjoy.com/fs-node-builtins": "4.57.3", + "@jsonjoy.com/fs-node-to-fsa": "4.57.3", + "@jsonjoy.com/fs-node-utils": "4.57.3", + "@jsonjoy.com/fs-print": "4.57.3", + "@jsonjoy.com/fs-snapshot": "4.57.3", + "@jsonjoy.com/json-pack": "^1.11.0", + "@jsonjoy.com/util": "^1.9.0", + "glob-to-regex.js": "^1.0.1", + "thingies": "^2.5.0", + "tree-dump": "^1.0.3", + "tslib": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" + } }, - "esbuild-linux-riscv64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.22.tgz", - "integrity": "sha512-AyJHipZKe88sc+tp5layovquw5cvz45QXw5SaDgAq2M911wLHiCvDtf/07oDx8eweCyzYzG5Y39Ih568amMTCQ==", + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "esbuild-linux-s390x": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.22.tgz", - "integrity": "sha512-Sz1NjZewTIXSblQDZWEFZYjOK6p8tV6hrshYdXZ0NHTjWE+lwxpOpWeElUGtEmiPcMT71FiuA9ODplqzzSxkzw==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true, - "optional": true + "license": "MIT" }, - "esbuild-netbsd-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.22.tgz", - "integrity": "sha512-TBbCtx+k32xydImsHxvFgsOCuFqCTGIxhzRNbgSL1Z2CKhzxwT92kQMhxort9N/fZM2CkRCPPs5wzQSamtzEHA==", + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "esbuild-openbsd-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.22.tgz", - "integrity": "sha512-vK912As725haT313ANZZZN+0EysEEQXWC/+YE4rQvOQzLuxAQc2tjbzlAFREx3C8+uMuZj/q7E5gyVB7TzpcTA==", + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } }, - "esbuild-sunos-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.22.tgz", - "integrity": "sha512-/mbJdXTW7MTcsPhtfDsDyPEOju9EOABvCjeUU2OJ7fWpX/Em/H3WYDa86tzLUbcVg++BScQDzqV/7RYw5XNY0g==", + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, - "optional": true - }, - "esbuild-wasm": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.22.tgz", - "integrity": "sha512-FOSAM29GN1fWusw0oLMv6JYhoheDIh5+atC72TkJKfIUMID6yISlicoQSd9gsNSFsNBvABvtE2jR4JB1j4FkFw==", - "dev": true + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "esbuild-windows-32": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.22.tgz", - "integrity": "sha512-1vRIkuvPTjeSVK3diVrnMLSbkuE36jxA+8zGLUOrT4bb7E/JZvDRhvtbWXWaveUc/7LbhaNFhHNvfPuSw2QOQg==", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "optional": true + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } }, - "esbuild-windows-64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.22.tgz", - "integrity": "sha512-AxjIDcOmx17vr31C5hp20HIwz1MymtMjKqX4qL6whPj0dT9lwxPexmLj6G1CpR3vFhui6m75EnBEe4QL82SYqw==", + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "esbuild-windows-arm64": { - "version": "0.14.22", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.22.tgz", - "integrity": "sha512-5wvQ+39tHmRhNpu2Fx04l7QfeK3mQ9tKzDqqGR8n/4WUxsFxnVLfDRBGirIfk4AfWlxk60kqirlODPoT5LqMUg==", + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, - "optional": true - }, - "escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, + "license": "MIT", "dependencies": { - "ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - } + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "eslint-config-prettier": { - "version": "10.1.8", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", - "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", - "dev": true, - "requires": {} - }, - "eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" + "license": "MIT", + "engines": { + "node": ">=12" }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "dev": true, - "requires": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-module-utils": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", - "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", "dev": true, - "requires": { - "debug": "^3.2.7" + "license": "MIT", + "engines": { + "node": ">=18" }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "eslint-plugin-import": { - "version": "2.32.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", - "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "node_modules/mini-css-extract-plugin": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.0.tgz", + "integrity": "sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==", "dev": true, - "requires": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.9", - "array.prototype.findlastindex": "^1.2.6", - "array.prototype.flat": "^1.3.3", - "array.prototype.flatmap": "^1.3.3", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.1", - "hasown": "^2.0.2", - "is-core-module": "^2.16.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.1", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.9", - "tsconfig-paths": "^3.15.0" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, - "eslint-plugin-jsdoc": { - "version": "50.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", - "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true, - "requires": { - "@es-joy/jsdoccomment": "~0.50.2", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.4.1", - "escape-string-regexp": "^4.0.0", - "espree": "^10.3.0", - "esquery": "^1.6.0", - "parse-imports-exports": "^0.2.4", - "semver": "^7.7.2", - "spdx-expression-parse": "^4.0.0" - }, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true - }, - "espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "requires": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true - } + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "requires": {} + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "node_modules/minipass-fetch": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.2.tgz", + "integrity": "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==", "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" } }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "node_modules/minipass-fetch/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "node_modules/minipass-flush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz", + "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==", "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, + "license": "BlueOak-1.0.0", "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" } }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, + "license": "ISC", "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true - }, - "eventemitter-asyncresource": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true - }, - "eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, - "execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" }, - "express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "node_modules/minipass-sized": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz", + "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==", "dev": true, - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.14.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, + "license": "ISC", "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" } }, - "external-editor": { + "node_modules/minizlib": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "dependencies": { - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - } + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" } }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" } }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "node_modules/mock-property": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.3.tgz", + "integrity": "sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.1", + "functions-have-names": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "hasown": "^2.0.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "node_modules/mock-property/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" }, - "fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } + "node_modules/monaco-editor": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.31.1.tgz", + "integrity": "sha512-FYPwxGZAeP6mRRyrr5XTGHD9gRXVjy7GUzF4IPChnyt3fS5WrNxIkS8DNujWf6EQy0Zlzpxw8oTVE+mWI2/D1Q==", + "license": "MIT" }, - "faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "node_modules/monaco-editor-webpack-plugin": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.0.1.tgz", + "integrity": "sha512-M8qIqizltrPlIbrb73cZdTWfU9sIsUVFvAZkL3KGjAHmVWEJ0hZKa/uad14JuOckc0GwnCaoGHvMoYtJjVyCzw==", "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.2" + }, + "peerDependencies": { + "monaco-editor": ">= 0.31.0", + "webpack": "^4.5.0 || 5.x" } }, - "fecha": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "node_modules/monaco-editor-webpack-plugin/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - } + "engines": { + "node": ">=8.9.0" } }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "dev": true, - "requires": { - "flat-cache": "^3.0.4" + "license": "MIT", + "engines": { + "node": ">=10" } }, - "filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "requires": { - "minimatch": "^5.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } + "license": "MIT" }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/msgpackr": { + "version": "1.11.12", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.12.tgz", + "integrity": "sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==", "dev": true, - "requires": { - "to-regex-range": "^5.0.1" + "license": "MIT", + "optional": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" } }, - "finalhandler": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", - "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "node_modules/msgpackr-extract": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" } }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, - "requires": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true - }, - "fmin": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/fmin/-/fmin-0.0.2.tgz", - "integrity": "sha512-sSi6DzInhl9d8yqssDfGZejChO8d2bAGIpysPsvYsxFe898z89XhCZg6CPNV3nhUhFefeC/AXZK2bAJxlBjN6A==", - "requires": { - "contour_plot": "^0.0.1", - "json2module": "^0.0.3", - "rollup": "^0.25.8", - "tape": "^4.5.1", - "uglify-js": "^2.6.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" - }, - "rollup": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.25.8.tgz", - "integrity": "sha512-a2S4Bh3bgrdO4BhKr2E4nZkjTvrJ2m2bWjMTzVYtoqSCn0HnuxosXnaJUHrMEziOWr3CzL9GjilQQKcyCQpJoA==", - "requires": { - "chalk": "^1.1.1", - "minimist": "^1.2.0", - "source-map-support": "^0.3.2" - } - }, - "source-map": { - "version": "0.1.32", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", - "integrity": "sha512-htQyLrrRLkQ87Zfrir4/yN+vAUd6DNjVayEjTSHXu29AYQJw57I4/xEL/M6p6E/woPNJwvZt6rVlzc7gFEJccQ==", - "requires": { - "amdefine": ">=0.0.4" - } - }, - "source-map-support": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.3.3.tgz", - "integrity": "sha512-9O4+y9n64RewmFoKUZ/5Tx9IHIcXM6Q+RTSw6ehnqybUz4a7iwR3Eaw80uLtqqQ5D0C+5H03D4KKGo9PdP33Gg==", - "requires": { - "source-map": "0.1.32" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "dev": true - }, - "for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "requires": { - "is-callable": "^1.2.7" - } - }, - "form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "frac": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", - "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==" - }, - "fraction.js": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "license": "MIT" }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "node_modules/needle": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.5.0.tgz", + "integrity": "sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==", "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" } }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "requires": { - "minipass": "^3.0.0" + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "fs-monkey": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", - "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", - "dev": true - }, - "fs.realpath": { + "node_modules/negotiator": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" - }, - "function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" }, - "gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, + "node_modules/ng-packagr": { + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-21.2.3.tgz", + "integrity": "sha512-jGq6yu0G6KReVK0i5RYVoV9HDL0mU626HrLBu5xvc8ZJ92n/+rLrFJuXdCnkroB9um+FBTQe/or6/A/2GAKhLw==", + "dev": true, + "license": "MIT", "dependencies": { - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "@ampproject/remapping": "^2.3.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/wasm-node": "^4.24.0", + "ajv": "^8.17.1", + "ansi-colors": "^4.1.3", + "browserslist": "^4.26.0", + "chokidar": "^5.0.0", + "commander": "^14.0.0", + "dependency-graph": "^1.0.0", + "esbuild": "^0.27.0", + "find-cache-directory": "^6.0.0", + "injection-js": "^2.4.0", + "jsonc-parser": "^3.3.1", + "less": "^4.2.0", + "ora": "^9.0.0", + "piscina": "^5.0.0", + "postcss": "^8.4.47", + "rollup-plugin-dts": "^6.4.0", + "rxjs": "^7.8.1", + "sass": "^1.81.0", + "tinyglobby": "^0.2.12" + }, + "bin": { + "ng-packagr": "src/cli/main.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "optionalDependencies": { + "rollup": "^4.24.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^21.0.0 || ^21.2.0-next", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.9 <6.0" + }, + "peerDependenciesMeta": { + "tailwindcss": { + "optional": true } } }, - "generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "dev": true - }, - "get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "requires": { - "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-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "requires": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" + "node_modules/ng-packagr/node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" } }, - "get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true - }, - "get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "requires": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" + "node_modules/ng-zorro-antd": { + "version": "21.3.0", + "resolved": "https://registry.npmjs.org/ng-zorro-antd/-/ng-zorro-antd-21.3.0.tgz", + "integrity": "sha512-XH+y+BHPVYQxHcVcRDCjgYtlBkYOJ//9+qcy2RJx8EJTpUj5FLXNW0kOA351dIvD+hMn2Xeivb8QPQ4UubE3yg==", + "license": "MIT", + "dependencies": { + "@angular/cdk": "^21.0.0", + "@ant-design/icons-angular": "^21.0.0", + "@ctrl/tinycolor": "^3.6.0", + "date-fns": "^2.16.1", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/forms": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/router": "^21.0.0" } }, - "github-markdown-css": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-3.0.1.tgz", - "integrity": "sha512-9G5CIPsHoyk5ObDsb/H4KTi23J8KE1oDd4KYU51qwqeM+lKWAiO7abpSgCkyWswgmSKBiuE7/4f8xUz7f2qAiQ==" - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "node_modules/ng-zorro-antd/node_modules/date-fns": { + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.21.0" + }, + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" } }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/ngx-build-plus": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-20.0.0.tgz", + "integrity": "sha512-cm1ZMTACAN3DEqBt/alS84zwVGgL5HAl5Dk/wh7CPyGUBQnLaxiAhjFZ6iykxgSO3e9ebIZmDBvTC480piC1eA==", "dev": true, - "requires": { - "is-glob": "^4.0.1" + "license": "MIT", + "dependencies": { + "webpack-merge": "^6.0.0" + }, + "peerDependencies": { + "@angular-devkit/build-angular": ">=20.0.0", + "@schematics/angular": ">=20.0.0", + "rxjs": ">= 6.0.0" } }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", "dev": true, - "requires": { - "type-fest": "^0.20.2" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" } }, - "globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "requires": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/node-exports-info/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "requires": { - "lodash": "^4.17.15" + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true - }, - "has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", - "requires": { - "ansi-regex": "^2.0.0" - }, + "node_modules/node-gyp": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", + "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==" - } + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "undici": "^6.25.0", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==" + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } }, - "has-flag": { + "node_modules/node-gyp/node_modules/isexe": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "requires": { - "es-define-property": "^1.0.0" + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" } }, - "has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "requires": { - "dunder-proto": "^1.0.0" + "node_modules/node-gyp/node_modules/undici": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", + "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" } }, - "has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" - }, - "has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "requires": { - "has-symbols": "^1.0.3" + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true + "node_modules/node-releases": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, - "hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "requires": { - "function-bind": "^1.1.2" + "node_modules/node-schedule": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/node-schedule/-/node-schedule-2.1.1.tgz", + "integrity": "sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cron-parser": "^4.2.0", + "long-timeout": "0.1.1", + "sorted-array-functions": "^1.3.0" + }, + "engines": { + "node": ">=6" } }, - "hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", "dev": true, - "requires": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "hdr-histogram-percentiles-obj": { + "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true - }, - "highlight.js": { - "version": "9.18.5", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz", - "integrity": "sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA==" - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "node_modules/npm-bundled": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", + "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==", "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - }, + "license": "ISC", "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true - }, - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "npm-normalize-package-bin": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/npm-install-checks": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", + "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true + "node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } }, - "http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/npm-package-arg": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", + "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", "dev": true, - "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-packlist": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz", + "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==", + "dev": true, + "license": "ISC", "dependencies": { - "eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true - } + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/npm-pick-manifest": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", + "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", + "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", + "dev": true, + "license": "ISC", "dependencies": { - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - } + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, - "requires": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "license": "MIT", + "engines": { + "node": ">=12" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true + "node_modules/nvd3": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.6.tgz", + "integrity": "sha512-YGQ9hAQHuQCF0JmYkT2GhNMHb5pA+vDfQj6C2GdpQPzdRPj/srPG3mh/3fZzUFt+at1NusLk/RqICUWkxm4viQ==", + "license": "Apache-2.0", + "peerDependencies": { + "d3": "^3.4.4" + } }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "requires": { - "ms": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "ignore-walk": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-4.0.1.tgz", - "integrity": "sha512-rzDQLaW4jQbh2YrOFlJdCtX8qgJTehFRYiUB2r1osqTeDzV/3+Jh8fz1oAPzUThf3iku8Ds4IDqawI5d8mUiQw==", + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", "dev": true, - "requires": { - "minimatch": "^3.0.4" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" } }, - "ignorefs": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/ignorefs/-/ignorefs-5.0.4.tgz", - "integrity": "sha512-vObKs/ga6E6TIfnQyxpShXVvUnlMZ+eoB2aGrvLuFGgnMqMVjZP3xW08WXJKocHmQL48WsDy6kUOisLp3gb8vg==", + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, - "requires": { - "editions": "^6.21.0", - "ignorepatterns": "^5.6.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "ignorepatterns": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/ignorepatterns/-/ignorepatterns-5.6.0.tgz", - "integrity": "sha512-6stRjchHcZwYfRkE2bVA9hCe+HFS1TWRrEYyEOPIeTnKyhKaqMg00AJPmAZ8EmVG/eUpALTkIM+ev1uTKY3PkQ==", - "dev": true + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", "dev": true, - "optional": true + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "immutable": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.8.tgz", - "integrity": "sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==", - "dev": true + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" }, - "import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - } + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { "wrappy": "1" } }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "injection-js": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/injection-js/-/injection-js-2.6.1.tgz", - "integrity": "sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==", + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, - "requires": { - "tslib": "^2.0.0" + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.2.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - } + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "requires": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" } }, - "ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "dev": true - }, - "ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "dev": true - }, - "is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "requires": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "node_modules/ora": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", + "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "requires": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - } + "node_modules/ordered-binary": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz", + "integrity": "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==", + "dev": true, + "license": "MIT", + "optional": true }, - "is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "requires": { - "has-bigints": "^1.0.2" + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "requires": { - "binary-extensions": "^2.0.0" + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "requires": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, - "requires": { - "builtin-modules": "^3.3.0" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" - }, - "is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "requires": { - "hasown": "^2.0.2" + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "requires": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "requires": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" + "node_modules/pacote": { + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz", + "integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "requires": { - "call-bound": "^1.0.3" + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "dev": true - }, - "is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "requires": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" } }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true + "node_modules/parse-json/node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" }, - "is-lambda": { + "node_modules/parse-node-version": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==" + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "is-module": { + "node_modules/parse-passwd": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==" + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" }, - "is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "requires": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - } + "node_modules/parse-svg-path": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", + "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==", + "license": "MIT" }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "license": "MIT" }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true + "node_modules/parse5-html-rewriting-stream": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", + "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0", + "parse5": "^8.0.0", + "parse5-sax-parser": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, - "is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true + "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/parse5-html-rewriting-stream/node_modules/parse5/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, - "requires": { - "isobject": "^3.0.1" + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "requires": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" + "node_modules/parse5-sax-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", + "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==" + "node_modules/parse5-sax-parser/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } }, - "is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "requires": { - "call-bound": "^1.0.3" + "node_modules/parse5-sax-parser/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "requires": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "requires": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "requires": { - "which-typed-array": "^1.1.16" + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" }, - "is-weakmap": { + "node_modules/path-scurry": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==" - }, - "is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "requires": { - "call-bound": "^1.0.3" + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "requires": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" } }, - "is-what": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "dev": true, - "requires": { - "is-docker": "^2.0.0" + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, - "istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "engines": { + "node": ">=0.10" } }, - "jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, - "requires": { - "async": "^3.2.6", - "filelist": "^1.0.4", - "picocolors": "^1.1.1" + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" } }, - "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "node_modules/piscina": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.4.tgz", + "integrity": "sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg==", "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" + "license": "MIT", + "engines": { + "node": ">=20.x" }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } + "optionalDependencies": { + "@napi-rs/nice": "^1.0.4" } }, - "jquery": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } }, - "jquery-ui": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.14.0.tgz", - "integrity": "sha512-mPfYKBoRCf0MzaT2cyW5i3IuZ7PfTITaasO5OFLAQxrHuI+ZxruPa+4/K1OMNT8oElLWGtIxc9aRbyw20BKr8g==", - "requires": { - "jquery": ">=1.12.0 <5.0.0" + "node_modules/pkg-dir": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-8.0.0.tgz", + "integrity": "sha512-4peoBq4Wks0riS0z8741NVv+/8IiTvqnZAr8QGgtdifrtpdXbNw/FxRS1l6NFqm4EMzuS0EDqNNx4XGaz8cuyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "node_modules/pkijs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@noble/hashes": "1.4.0", + "asn1js": "^3.0.6", + "bytestreamjs": "^2.0.1", + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=16.0.0" + } }, - "js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "node_modules/playwright": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", + "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.55.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" } }, - "jsdoc-type-pratt-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", - "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", - "dev": true + "node_modules/playwright-core": { + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", + "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "node_modules/point-at-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/point-at-length/-/point-at-length-1.0.2.tgz", + "integrity": "sha512-DSGca2Q7A/4rGS6324Z+0hCVAPT729RFjsISPc6N11D6+r1TpP6KjktGL7HxN8XRYY0Z7EG8n9dBJ5dbrEP4SQ==", + "license": "MIT", + "dependencies": { + "abs-svg-path": "~0.1.1", + "isarray": "~0.0.1", + "parse-svg-path": "~0.1.1" + } }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "node_modules/postcss": { + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", + "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "node_modules/postcss-loader": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.2.0.tgz", + "integrity": "sha512-tHX+RkpsXVcc7st4dSdDGliI+r4aAQDuv+v3vFYHixb6YgjreG5AG4SEB0kDK8u2s6htqEEpKlkhSBUTvWKYnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^2.5.1", + "semver": "^7.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } }, - "json2module": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json2module/-/json2module-0.0.3.tgz", - "integrity": "sha512-qYGxqrRrt4GbB8IEOy1jJGypkNsjWoIMlZt4bAsmUScCA507Hbc2p1JOhBzqn45u3PWafUgH2OnzyNU7udO/GA==", - "requires": { - "rw": "^1.3.2" + "node_modules/postcss-loader/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true, + "license": "MIT" }, - "jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", - "dev": true + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } }, - "jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", "dev": true, - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true - }, - "karma-source-map-support": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dev": true, - "requires": { - "source-map-support": "^0.5.5" + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, - "requires": { - "json-buffer": "3.0.1" + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "dev": true - }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==" - }, - "less": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.2.tgz", - "integrity": "sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA==", + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, - "requires": { - "copy-anything": "^2.0.1", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^2.5.2", - "parse-node-version": "^1.0.1", - "source-map": "~0.6.0", - "tslib": "^2.3.0" - }, - "dependencies": { - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "optional": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "optional": true + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "optional": true + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" } }, - "less-loader": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", - "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", + "node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, - "requires": { - "klona": "^2.0.4" + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" } }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } + "license": "MIT" }, - "license-webpack-plugin": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", "dev": true, - "requires": { - "webpack-sources": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } }, - "lint-staged": { - "version": "15.5.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.5.2.tgz", - "integrity": "sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==", + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, - "requires": { - "chalk": "^5.4.1", - "commander": "^13.1.0", - "debug": "^4.4.0", - "execa": "^8.0.1", - "lilconfig": "^3.1.3", - "listr2": "^8.2.5", - "micromatch": "^4.0.8", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.7.0" + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" }, - "dependencies": { - "chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true - }, - "commander": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", - "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", - "dev": true - }, - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "listr2": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.3.3.tgz", - "integrity": "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==", + "node_modules/printj": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", + "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==", + "license": "Apache-2.0", + "bin": { + "printj": "bin/printj.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", "dev": true, - "requires": { - "cli-truncate": "^4.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "dev": true + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" }, - "loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", - "dev": true + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "requires": { - "p-locate": "^4.1.0" + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" } }, - "lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==" + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "license": "MIT", + "optional": true }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "license": "MIT", + "engines": { + "node": ">=16.0.0" } }, - "log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, - "requires": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, + "license": "BSD-3-Clause", "dependencies": { - "ansi-escapes": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.1.1.tgz", - "integrity": "sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==", - "dev": true, - "requires": { - "environment": "^1.0.0" - } - }, - "ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true - }, - "ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true - }, - "cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "requires": { - "restore-cursor": "^5.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "requires": { - "get-east-asian-width": "^1.3.1" - } - }, - "onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "requires": { - "mimic-function": "^5.0.0" - } - }, - "restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "requires": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - } - }, - "slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "requires": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - } - }, - "strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg==" - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "requires": { - "yallist": "^3.0.2" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, - "requires": { - "sourcemap-codec": "^1.4.4" + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" } }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, - "requires": { - "semver": "^6.0.0" + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, - "requires": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "dependencies": { - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0" }, - "mathjax": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", - "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" }, - "memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", "dev": true, - "requires": { - "fs-monkey": "^1.0.4" + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" } }, - "merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "dev": true + "node_modules/regex-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", + "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==", + "dev": true, + "license": "MIT" }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "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" + }, + "engines": { + "node": ">=4" + } }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" }, - "micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", "dev": true, - "requires": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" } }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true + "node_modules/regression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", + "integrity": "sha512-A4XYsc37dsBaNOgEjkJKzfJlE394IMmUPlI/p3TTI9u3T+2a+eox5Pr/CPUqF0eszeWZJPAc6QkroAhuUpWDJQ==", + "license": "MIT" }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "license": "MIT", + "engines": { + "node": ">=0.10" + } }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, - "requires": { - "mime-db": "1.52.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true - }, - "mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true - }, - "mini-css-extract-plugin": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.3.tgz", - "integrity": "sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, - "requires": { - "schema-utils": "^4.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" }, - "minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "requires": { - "brace-expansion": "^1.1.7" + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, - "requires": { - "yallist": "^4.0.0" - }, + "license": "MIT", + "peer": true, "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "requires": { - "minipass": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, - "requires": { - "encoding": "^0.1.12", - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" + "license": "MIT", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" } }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, - "requires": { - "minipass": "^3.0.0" + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" } }, - "minipass-json-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.2.tgz", - "integrity": "sha512-myxeeTm57lYs8pH2nxPzmEEg8DGIgW+9mv6D4JZD2pa81I/OBjeU7PtICXV6c9eRGTA5JMDsuIPUZRCyBMYNhg==", + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, - "requires": { - "minipass": "^3.0.0" + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", "dev": true, - "requires": { - "minipass": "^3.0.0" + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" }, - "mock-property": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mock-property/-/mock-property-1.0.3.tgz", - "integrity": "sha512-2emPTb1reeLLYwHxyVx993iYyCHEiRRO+y8NFXFPL5kl5q14sgTK76cXyEKkeKCHeRw35SfdkUJ10Q1KfHuiIQ==", - "requires": { - "define-data-property": "^1.1.1", - "functions-have-names": "^1.2.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "hasown": "^2.0.0", - "isarray": "^2.0.5" - }, + "node_modules/right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", + "license": "MIT", "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } - } - }, - "monaco-editor": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz", - "integrity": "sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg==" - }, - "monaco-editor-webpack-plugin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-6.0.0.tgz", - "integrity": "sha512-vC886Mzpd2AkSM35XLkfQMjH+Ohz6RISVwhAejDUzZDheJAiz6G34lky1vyO8fZ702v7IrcKmsGwL1rRFnwvUA==", - "dev": true, - "requires": { - "loader-utils": "^2.0.0" - }, - "dependencies": { - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - } + "align-text": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "node_modules/rolldown": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", + "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", "dev": true, - "requires": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.113.0", + "@rolldown/pluginutils": "1.0.0-rc.4" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-x64": "1.0.0-rc.4", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" } }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "needle": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.9.1.tgz", - "integrity": "sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==", + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "ng-packagr": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-13.3.1.tgz", - "integrity": "sha512-RFB6+03qPlhsOZc0wPenkyCceUYU0kRymbO7fIZ4Uz3y7RltXeknfjWKVcN6o5o42Md/lbNabt4gViXNzahhjA==", - "dev": true, - "requires": { - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.0.0", - "ajv": "^8.0.0", - "ansi-colors": "^4.1.1", - "browserslist": "^4.16.1", - "cacache": "^15.0.6", - "chokidar": "^3.5.1", - "commander": "^8.0.0", - "dependency-graph": "^0.11.0", - "esbuild": "^0.14.0", - "esbuild-wasm": "^0.14.0", - "find-cache-dir": "^3.3.1", - "glob": "^7.1.6", - "injection-js": "^2.4.0", - "jsonc-parser": "^3.0.0", - "less": "^4.1.0", - "ora": "^5.1.0", - "postcss": "^8.2.4", - "postcss-preset-env": "^7.0.0", - "postcss-url": "^10.1.1", - "rollup": "^2.45.1", - "rollup-plugin-sourcemaps": "^0.6.3", - "rxjs": "^7.0.0", - "sass": "^1.32.8", - "stylus": "^0.56.0" - }, - "dependencies": { - "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", - "dev": true - }, - "rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - } - } - }, - "ng-zorro-antd": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/ng-zorro-antd/-/ng-zorro-antd-13.4.0.tgz", - "integrity": "sha512-ZIXeeXtTUNg3mdXNg2A3gJGh0aqN/pM3Ii61FiUhwkVwmVzIIDwYfGZZNNOl+cURL5HGzrwQ10nrYgdfFfZ20g==", - "requires": { - "@angular/cdk": "^13.0.1", - "@ant-design/icons-angular": "^13.0.1", - "date-fns": "^2.16.1", - "tslib": "^2.3.0" + "@types/estree": "1.0.8" }, - "dependencies": { - "@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==" - }, - "date-fns": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "requires": { - "@babel/runtime": "^7.21.0" - } - } + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" } }, - "ngx-build-plus": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/ngx-build-plus/-/ngx-build-plus-13.0.1.tgz", - "integrity": "sha512-3wuQ0/xyTC4+CU2wROgKe1TPCnghTj5aGcLCxbmWFZDrAneMW6t2QmAg0nJpapXzxhcL7JJnVYKnh2c/ARr62A==", + "node_modules/rollup-plugin-dts": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-6.4.1.tgz", + "integrity": "sha512-l//F3Zf7ID5GoOfLfD8kroBjQKEKpy1qfhtAdnpibFZMffPaylrg1CoDC2vGkPeTeyxUe4bVFCln2EFuL7IGGg==", "dev": true, - "requires": { - "@angular-devkit/build-angular": "^13.0.0", - "@schematics/angular": "^13.0.0", - "webpack-merge": "^5.0.0" + "license": "LGPL-3.0-only", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "convert-source-map": "^2.0.0", + "magic-string": "^0.30.21" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/Swatinem" + }, + "optionalDependencies": { + "@babel/code-frame": "^7.29.0" + }, + "peerDependencies": { + "rollup": "^3.29.4 || ^4", + "typescript": "^4.5 || ^5.0 || ^6.0" } }, - "nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "node_modules/rollup-plugin-dts/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, - "optional": true, - "requires": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" - } + "license": "MIT" }, - "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" }, - "node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, - "requires": { - "whatwg-url": "^5.0.0" + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" } }, - "node-forge": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", - "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", - "dev": true - }, - "node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", "dev": true, - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "dev": true - }, - "node-releases": { - "version": "2.0.37", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", - "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==", - "dev": true + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" }, - "nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "requires": { - "abbrev": "1" + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" }, - "npm-bundled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", - "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "npm-install-checks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", - "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", - "dev": true, - "requires": { - "semver": "^7.1.1" + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" }, - "npm-package-arg": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", - "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", - "dev": true, - "requires": { - "hosted-git-info": "^4.0.1", - "semver": "^7.3.4", - "validate-npm-package-name": "^3.0.0" + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "npm-packlist": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-3.0.0.tgz", - "integrity": "sha512-L/cbzmutAwII5glUcf2DBRNY/d0TFd4e/FnaZigJV6JD85RHZXJFGwCndjMWiiViiWSsWt3tiOLpI3ByTnIdFQ==", + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", "dev": true, - "requires": { - "glob": "^7.1.6", - "ignore-walk": "^4.0.1", - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "npm-pick-manifest": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", - "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", - "dev": true, - "requires": { - "npm-install-checks": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^8.1.2", - "semver": "^7.3.4" - } - }, - "npm-registry-fetch": { - "version": "12.0.2", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-12.0.2.tgz", - "integrity": "sha512-Df5QT3RaJnXYuOwtXBXS9BWs+tHH2olvkCLh6jcR/b/u3DvPMlp3J0TvvYwplPKxHMOwfg287PYih9QqaVFoKA==", - "dev": true, - "requires": { - "make-fetch-happen": "^10.0.1", - "minipass": "^3.1.6", - "minipass-fetch": "^1.4.1", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^8.1.5" - }, - "dependencies": { - "@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "requires": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - } - }, - "@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "requires": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - } - }, - "glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "dependencies": { - "minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } - } - } - }, - "minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } + "node_modules/sass-loader": { + "version": "16.0.7", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.7.tgz", + "integrity": "sha512-w6q+fRHourZ+e+xA1kcsF27iGM6jdB8teexYCfdUw0sYgcDNeZESnDNT9sUmmPm3ooziwUJXGwZJSTF3kOdBfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true }, - "socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - } + "node-sass": { + "optional": true }, - "ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "requires": { - "minipass": "^3.1.1" - } + "sass": { + "optional": true }, - "unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "requires": { - "unique-slug": "^3.0.0" - } + "sass-embedded": { + "optional": true }, - "unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } + "webpack": { + "optional": true } } }, - "npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, - "requires": { - "path-key": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true - } + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "node_modules/sass/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "requires": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "dev": true, - "requires": { - "boolbase": "^1.0.0" + "license": "BlueOak-1.0.0", + "optional": true, + "engines": { + "node": ">=11.0.0" } }, - "nvd3": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.6.tgz", - "integrity": "sha512-YGQ9hAQHuQCF0JmYkT2GhNMHb5pA+vDfQj6C2GdpQPzdRPj/srPG3mh/3fZzUFt+at1NusLk/RqICUWkxm4viQ==", - "requires": {} - }, - "nx": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/nx/-/nx-13.1.3.tgz", - "integrity": "sha512-clM0NQhQKYkqcNz2E3uYRMLwhp2L/9dBhJhQi9XBX4IAyA2gWAomhRIlLm5Xxg3g4h1xwSpP3eJ5t89VikY8Pw==", + "node_modules/scandirectory": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/scandirectory/-/scandirectory-8.1.1.tgz", + "integrity": "sha512-1AfRS0+UPNIgzlJCABCOww9F6bK9d432K2Gx6vy8KRpymbNB6KRDPnYrq4wKc67TYw/CXW6dFeOBuWrd4v1YZg==", "dev": true, - "requires": { - "@nrwl/cli": "*" - } - }, - "object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==" - }, - "object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "requires": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0", + "ignorefs": "^5.0.4" + }, + "bin": { + "scandirectory": "bin.cjs" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" + "node_modules/schema-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "node_modules/schema-utils/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, - "requires": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } } }, - "object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true, - "requires": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - } + "license": "MIT" }, - "object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "node_modules/selfsigned": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", + "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", "dev": true, - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "license": "MIT", + "dependencies": { + "@peculiar/x509": "^1.14.2", + "pkijs": "^3.3.3" + }, + "engines": { + "node": ">=18" } }, - "obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, - "requires": { - "mimic-fn": "^4.0.0" + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "node_modules/serialize-javascript": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz", + "integrity": "sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==", "dev": true, - "requires": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=20.0.0" } }, - "optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "node_modules/serve-index/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, - "requires": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true - }, - "own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "requires": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, - "requires": { - "p-try": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, - "requires": { - "p-limit": "^2.2.0" + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" } }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/serve-index/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, - "requires": { - "aggregate-error": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "node_modules/serve-index/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, - "requires": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, + "license": "MIT", "dependencies": { - "retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true - } - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "pacote": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-12.0.3.tgz", - "integrity": "sha512-CdYEl03JDrRO3x18uHjBYA9TyoW8gy+ThVcypcDkxPtKlw76e4ejhYB6i9lJ+/cebbjpqPW/CijjqxwDTts8Ow==", - "dev": true, - "requires": { - "@npmcli/git": "^2.1.0", - "@npmcli/installed-package-contents": "^1.0.6", - "@npmcli/promise-spawn": "^1.2.0", - "@npmcli/run-script": "^2.0.0", - "cacache": "^15.0.5", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.3", - "mkdirp": "^1.0.3", - "npm-package-arg": "^8.0.1", - "npm-packlist": "^3.0.0", - "npm-pick-manifest": "^6.0.0", - "npm-registry-fetch": "^12.0.0", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^2.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.1.0" + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/serve-index/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, - "requires": { - "callsites": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "parse-imports-exports": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", - "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, - "requires": { - "parse-statements": "1.0.11" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true - }, - "parse-statements": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", - "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", - "dev": true - }, - "parse-svg-path": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/parse-svg-path/-/parse-svg-path-0.1.2.tgz", - "integrity": "sha512-JyPSBnkTJ0AI8GGJLfMXvKq42cj5c006fnLz6fXy6zfoVjJizi8BNTpu8on8ziI1cKy9d9DGNuY17Ce7wuejpQ==" - }, - "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==" - }, - "parse5-html-rewriting-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", - "dev": true, - "requires": { - "parse5": "^6.0.1", - "parse5-sax-parser": "^6.0.1" + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, - "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } + "engines": { + "node": ">= 0.4" } }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "parse5-sax-parser": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "license": "MIT", "dependencies": { - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - } + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" } }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true - }, - "pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "piscina": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, - "requires": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0", - "nice-napi": "^1.0.2" - } + "license": "ISC" }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, - "requires": { - "find-up": "^4.0.0" + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" } }, - "playwright": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", - "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": { - "fsevents": "2.3.2", - "playwright-core": "1.55.1" - }, + "license": "MIT", "dependencies": { - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - } + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "playwright-core": { - "version": "1.55.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", - "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", - "dev": true - }, - "point-at-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/point-at-length/-/point-at-length-1.0.2.tgz", - "integrity": "sha512-DSGca2Q7A/4rGS6324Z+0hCVAPT729RFjsISPc6N11D6+r1TpP6KjktGL7HxN8XRYY0Z7EG8n9dBJ5dbrEP4SQ==", - "requires": { - "abs-svg-path": "~0.1.1", - "isarray": "~0.0.1", - "parse-svg-path": "~0.1.1" + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "portfinder": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.38.tgz", - "integrity": "sha512-rEwq/ZHlJIKw++XtLAO8PPuOQA/zaPJOZJ37BVuN97nLpMJeuDVLVGRwbFoBgLudgdTMP2hdRJP++H+8QOA3vg==", + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, - "requires": { - "async": "^3.2.6", - "debug": "^4.3.6" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, - "dependencies": { - "debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "possible-typed-array-names": { + "node_modules/side-channel": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==" - }, - "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dev": true, - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "postcss-attribute-case-insensitive": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", - "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.10" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "postcss-color-functional-notation": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", - "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "postcss-color-hex-alpha": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", - "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "postcss-color-rebeccapurple": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", - "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "postcss-custom-media": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", - "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "node_modules/sigstore": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.1.tgz", + "integrity": "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.1", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.1", + "@sigstore/tuf": "^4.0.2", + "@sigstore/verify": "^3.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "postcss-custom-properties": { - "version": "12.1.11", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz", - "integrity": "sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "node_modules/simple-statistics": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-6.1.1.tgz", + "integrity": "sha512-zGwn0DDRa9Zel4H4n2pjTFIyGoAGpnpjrGIctreCxj5XWrcx9v7Xy7270FkC967WMmcvuc8ZU7m0ZG+hGN7gAA==", + "license": "ISC", + "engines": { + "node": "*" } }, - "postcss-custom-selectors": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", - "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.4" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, - "postcss-dir-pseudo-class": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", - "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.10" + "license": "MIT", + "engines": { + "node": ">=12" }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "postcss-double-position-gradients": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", - "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "postcss-env-function": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", - "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" } }, - "postcss-focus-visible": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", - "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - }, + "license": "MIT", "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } - } - }, - "postcss-focus-within": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", - "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" } }, - "postcss-font-variant": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", - "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", - "dev": true, - "requires": {} - }, - "postcss-gap-properties": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", - "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", - "dev": true, - "requires": {} - }, - "postcss-image-set-function": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", - "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" } }, - "postcss-import": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.2.tgz", - "integrity": "sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g==", + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" + "license": "MIT", + "engines": { + "node": ">= 14" } }, - "postcss-initial": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", - "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "node_modules/sorted-array-functions": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz", + "integrity": "sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==", "dev": true, - "requires": {} + "license": "MIT", + "peer": true }, - "postcss-lab-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", - "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, - "requires": { - "@csstools/postcss-progressive-custom-properties": "^1.1.0", - "postcss-value-parser": "^4.2.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" } }, - "postcss-loader": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", - "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "requires": { - "cosmiconfig": "^7.0.0", - "klona": "^2.0.5", - "semver": "^7.3.5" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "postcss-logical": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", - "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", - "dev": true, - "requires": {} - }, - "postcss-media-minmax": { + "node_modules/source-map-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", - "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } }, - "postcss-modules-extract-imports": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", - "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "postcss-modules-local-by-default": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", - "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, - "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.1.0" + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "postcss-modules-scope": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", - "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, - "requires": { - "postcss-selector-parser": "^7.0.0" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, - "requires": { - "icss-utils": "^5.0.0" - } + "license": "CC-BY-3.0" }, - "postcss-nesting": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", - "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, - "requires": { - "@csstools/selector-specificity": "^2.0.0", - "postcss-selector-parser": "^6.0.10" - }, + "license": "MIT", "dependencies": { - "@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", - "dev": true, - "requires": {} - }, - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "postcss-overflow-shorthand": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", - "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } + "license": "CC0-1.0" }, - "postcss-page-break": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", - "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } }, - "postcss-place": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", - "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" } }, - "postcss-preset-env": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.2.3.tgz", - "integrity": "sha512-Ok0DhLfwrcNGrBn8sNdy1uZqWRk/9FId0GiQ39W4ILop5GHtjJs8bu1MY9isPwHInpVEPWjb4CEcEaSbBLpfwA==", - "dev": true, - "requires": { - "autoprefixer": "^10.4.2", - "browserslist": "^4.19.1", - "caniuse-lite": "^1.0.30001299", - "css-blank-pseudo": "^3.0.2", - "css-has-pseudo": "^3.0.3", - "css-prefers-color-scheme": "^6.0.2", - "cssdb": "^5.0.0", - "postcss-attribute-case-insensitive": "^5.0.0", - "postcss-color-functional-notation": "^4.2.1", - "postcss-color-hex-alpha": "^8.0.2", - "postcss-color-rebeccapurple": "^7.0.2", - "postcss-custom-media": "^8.0.0", - "postcss-custom-properties": "^12.1.2", - "postcss-custom-selectors": "^6.0.0", - "postcss-dir-pseudo-class": "^6.0.3", - "postcss-double-position-gradients": "^3.0.4", - "postcss-env-function": "^4.0.4", - "postcss-focus-visible": "^6.0.3", - "postcss-focus-within": "^5.0.3", - "postcss-font-variant": "^5.0.0", - "postcss-gap-properties": "^3.0.2", - "postcss-image-set-function": "^4.0.4", - "postcss-initial": "^4.0.1", - "postcss-lab-function": "^4.0.3", - "postcss-logical": "^5.0.3", - "postcss-media-minmax": "^5.0.0", - "postcss-nesting": "^10.1.2", - "postcss-overflow-shorthand": "^3.0.2", - "postcss-page-break": "^3.0.4", - "postcss-place": "^7.0.3", - "postcss-pseudo-class-any-link": "^7.0.2", - "postcss-replace-overflow-wrap": "^4.0.0", - "postcss-selector-not": "^5.0.0" - } - }, - "postcss-pseudo-class-any-link": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", - "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.10" - }, - "dependencies": { - "postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - } + "node_modules/ssf": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz", + "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "bin": { + "ssf": "bin/ssf.njs" + }, + "engines": { + "node": ">=0.8" } }, - "postcss-replace-overflow-wrap": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", - "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", - "dev": true, - "requires": {} - }, - "postcss-selector-not": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-5.0.0.tgz", - "integrity": "sha512-/2K3A4TCP9orP4TNS7u3tGdRFVKqz/E6pX3aGnriPG0jU78of8wsUcqE4QAhWEU0d+WnMSF93Ah3F//vUtK+iQ==", + "node_modules/ssri": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", + "integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==", "dev": true, - "requires": { - "balanced-match": "^1.0.0" + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "postcss-url": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-10.1.3.tgz", - "integrity": "sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==", + "node_modules/stdin-discarder": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", + "integrity": "sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==", "dev": true, - "requires": { - "make-dir": "~3.1.0", - "mime": "~2.5.2", - "minimatch": "~3.0.4", - "xxhashjs": "~0.2.2" + "license": "MIT", + "engines": { + "node": ">=18" }, - "dependencies": { - "mime": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", - "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", - "dev": true - }, - "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true - }, - "printj": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", - "integrity": "sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==" - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" + "license": "MIT", + "engines": { + "node": ">=0.6.19" } }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, + "license": "MIT", "dependencies": { - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true - } + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "prr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", - "dev": true, - "optional": true + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, - "requires": { - "side-channel": "^1.1.0" + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "requires": { - "safe-buffer": "^5.1.0" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "requires": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" + "license": "MIT", + "engines": { + "node": ">=12" }, - "dependencies": { - "http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "requires": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - } - }, - "statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "requires": { - "pify": "^2.3.0" + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "read-package-json-fast": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", - "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "node_modules/style-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-4.0.0.tgz", + "integrity": "sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==", "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" + "license": "MIT", + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.27.0" } }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "reflect-metadata": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", - "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", - "dev": true + "node_modules/systemjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-5.0.0.tgz", + "integrity": "sha512-hnD/IMQhH0UmawiIGlYVnkCPUbbO/WDQjOC+Q4PewHBdsagI1OHH1re1sg1AYFqq7p9ps6b1Bsx4xCeoeIZSCw==", + "license": "MIT" }, - "reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "requires": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tape": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/tape/-/tape-4.17.0.tgz", + "integrity": "sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw==", + "license": "MIT", + "dependencies": { + "@ljharb/resumer": "~0.0.1", + "@ljharb/through": "~2.3.9", + "call-bind": "~1.0.2", + "deep-equal": "~1.1.1", + "defined": "~1.0.1", + "dotignore": "~0.1.2", + "for-each": "~0.3.3", + "glob": "~7.2.3", + "has": "~1.0.3", + "inherits": "~2.0.4", + "is-regex": "~1.1.4", + "minimist": "~1.2.8", + "mock-property": "~1.0.0", + "object-inspect": "~1.12.3", + "resolve": "~1.22.6", + "string.prototype.trim": "~1.2.8" + }, + "bin": { + "tape": "bin/tape" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "node_modules/tape/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, - "regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "requires": { - "regenerate": "^1.4.2" + "node_modules/tape/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "regex-parser": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz", - "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "requires": { - "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" + "node_modules/tape/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "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", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "requires": { - "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" + "node_modules/tape/node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true - }, - "regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, - "requires": { - "jsesc": "~3.1.0" - }, + "node_modules/tape/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", "dependencies": { - "jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true - } + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "regression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regression/-/regression-2.0.1.tgz", - "integrity": "sha512-A4XYsc37dsBaNOgEjkJKzfJlE394IMmUPlI/p3TTI9u3T+2a+eox5Pr/CPUqF0eszeWZJPAc6QkroAhuUpWDJQ==" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "node_modules/tape/node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "node_modules/tar": { + "version": "7.5.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", "dev": true, - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, - "resolve-from": { + "node_modules/tar/node_modules/yallist": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } }, - "resolve-url-loader": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, - "requires": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" - }, + "license": "BSD-2-Clause", "dependencies": { - "loader-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" } }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "node_modules/terser-webpack-plugin": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, + "license": "MIT", "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "uglify-js": { + "optional": true } } }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true - }, - "reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true - }, - "rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha512-yqINtL/G7vs2v+dFIZmFUDbnVyFUJFKd6gK22Kgo6R4jfJGFtisKyncWDDULgjfqf4ASQuIQyjJ7XZ+3aWpsAg==", - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true, - "requires": { - "glob": "^7.1.3" - } + "license": "MIT" }, - "rollup": { - "version": "2.80.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.80.0.tgz", - "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", + "node_modules/thingies": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz", + "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==", "dev": true, - "requires": { - "fsevents": "~2.3.2" + "license": "MIT", + "engines": { + "node": ">=10.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "^2" } }, - "rollup-plugin-sourcemaps": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.6.3.tgz", - "integrity": "sha512-paFu+nT1xvuO1tPFYXGe+XnQvg4Hjqv/eIhG8i5EspfYYPBKL57X7iVbfv55aNVASg3dzWvES9dmWsL2KhfByw==", + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true, - "requires": { - "@rollup/pluginutils": "^3.0.9", - "source-map-resolve": "^0.6.0" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true + "license": "MIT" }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, - "requires": { - "queue-microtask": "^1.2.2" + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" - }, - "rxjs": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", - "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", - "requires": { - "tslib": "^1.9.0" - }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - } + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" } }, - "rxjs-for-await": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/rxjs-for-await/-/rxjs-for-await-0.0.2.tgz", - "integrity": "sha512-IJ8R/ZCFMHOcDIqoABs82jal00VrZx8Xkgfe7TOKoaRPAW5nH/VFlG23bXpeGdrmtqI9UobFPgUKgCuFc7Lncw==", + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, - "requires": {} - }, - "safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } + "license": "MIT", + "engines": { + "node": ">=0.6" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "requires": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, + "node_modules/topojson-client": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.1.tgz", + "integrity": "sha512-rfGGzyqefpxOaxvV9OTF9t+1g+WhjGEbAIuCcmKYrQkxr0nttjMMyzZsK+NhLW4cTl2g1bz2jQczPUtEshpbVQ==", + "license": "BSD-3-Clause", "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } - } - }, - "safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" + "commander": "2" + }, + "bin": { + "topo2geo": "bin/topo2geo", + "topomerge": "bin/topomerge", + "topoquantize": "bin/topoquantize" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "node_modules/topojson-client/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" }, - "sass": { - "version": "1.49.9", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", - "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", + "node_modules/tree-dump": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", + "integrity": "sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==", "dev": true, - "requires": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" + "license": "Apache-2.0", + "engines": { + "node": ">=10.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/streamich" + }, + "peerDependencies": { + "tslib": "2" } }, - "sass-loader": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz", - "integrity": "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==", + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, - "requires": { - "klona": "^2.0.4", - "neo-async": "^2.6.2" + "license": "MIT", + "bin": { + "tree-kill": "cli.js" } }, - "sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } }, - "scandirectory": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/scandirectory/-/scandirectory-8.1.1.tgz", - "integrity": "sha512-1AfRS0+UPNIgzlJCABCOww9F6bK9d432K2Gx6vy8KRpymbNB6KRDPnYrq4wKc67TYw/CXW6dFeOBuWrd4v1YZg==", + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", "dev": true, - "requires": { - "editions": "^6.21.0", - "ignorefs": "^5.0.4" + "license": "MIT", + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" } }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, + "license": "MIT", "dependencies": { - "ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, - "selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", "dev": true, - "requires": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } + "license": "0BSD" }, - "send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "node_modules/tuf-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz", + "integrity": "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==", "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { - "randombytes": "^2.1.0" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - }, + "license": "MIT", "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "dev": true - }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "dev": true - } + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "serve-static": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", - "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "dev": true, - "requires": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.19.0" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "requires": { - "define-data-property": "^1.1.4", + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" } }, - "set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "requires": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "requires": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true, + "license": "MIT" }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, - "requires": { - "kind-of": "^6.0.2" + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" } }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/typescript-eslint": { + "version": "8.60.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.0.tgz", + "integrity": "sha512-9f65qWLZdAW9m1JaxBDUHcqRUfL8bkxxXL7XxEfI+F09q56PkBvIfCjLF3yInsDM/BBmwkqmCQdCZe/RYlIWEw==", "dev": true, - "requires": { - "shebang-regex": "^3.0.0" + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.60.0", + "@typescript-eslint/parser": "8.60.0", + "@typescript-eslint/typescript-estree": "8.60.0", + "@typescript-eslint/utils": "8.60.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true - }, - "side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "requires": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" + "node_modules/uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", + "license": "BSD-2-Clause", + "dependencies": { + "source-map": "~0.5.1", + "yargs": "~3.10.0" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + }, + "optionalDependencies": { + "uglify-to-browserify": "~1.0.0" } }, - "side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "requires": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "node_modules/uglify-js/node_modules/cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", + "license": "ISC", + "dependencies": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" } }, - "side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "requires": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" + "node_modules/uglify-js/node_modules/yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", + "license": "MIT", + "dependencies": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - }, - "simple-statistics": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-6.1.1.tgz", - "integrity": "sha512-zGwn0DDRa9Zel4H4n2pjTFIyGoAGpnpjrGIctreCxj5XWrcx9v7Xy7270FkC967WMmcvuc8ZU7m0ZG+hGN7gAA==" + "node_modules/uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", + "license": "MIT", + "optional": true }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "node_modules/undici": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.7.tgz", + "integrity": "sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==", "dev": true, - "requires": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true - } + "license": "MIT", + "peer": true, + "engines": { + "node": ">=20.18.1" } }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true }, - "sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, - "requires": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, - "requires": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "dependencies": { - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - } + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - }, - "source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "source-map-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.1.tgz", - "integrity": "sha512-Vp1UsfyPvgujKQzi4pyDiTOnE3E4H+yHvkVRN3c/9PJmQS4CQJExvcDvaX/D+RV+xQben9HJ56jMJS3CgUeWyA==", + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, - "requires": { - "abab": "^2.0.5", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.1" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4", + "yarn": "*" } }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, - "spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "dev": true + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" }, - "spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, - "requires": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.4.0" } }, - "spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, - "requires": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" }, - "ssf": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz", - "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==", - "requires": { - "frac": "~1.1.2" + "node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, - "requires": { - "minipass": "^3.1.1" + "license": "MIT", + "engines": { + "node": ">= 0.8" } }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - }, - "stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "requires": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" + "node_modules/venn.js": { + "version": "0.2.20", + "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", + "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", + "license": "MIT", + "dependencies": { + "d3-selection": "^1.0.2", + "d3-transition": "^1.0.1", + "fmin": "0.0.2" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", "dev": true, - "requires": { - "safe-buffer": "~5.2.0" + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" } }, - "string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, + "license": "MIT", "dependencies": { - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - } - } - }, - "string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - } - }, - "string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "requires": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - } - }, - "string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "requires": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" } }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "requires": { - "ansi-regex": "^5.0.1" + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" } }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true, + "license": "MIT", + "optional": true }, - "strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "dev": true, - "requires": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" + "license": "MIT", + "engines": { + "node": ">= 8" } }, - "stylus": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.56.0.tgz", - "integrity": "sha512-Ev3fOb4bUElwWu4F9P9WjnnaSpc8XB9OFHSFZSKMFL1CE1oM+oFXWEgAqPmmZIyhBihuqIQlFsVTypiiS9RxeA==", + "node_modules/webpack": { + "version": "5.107.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", + "integrity": "sha512-v7RhXaJbpMlV0D7hC7lb2EbnxkoeUqf9qhKr6lozx3Q48pmFrqqNRmZFUEGmi7pSwm6fCQ2H1IjvCkHqdpVdjQ==", "dev": true, - "requires": { - "css": "^3.0.0", - "debug": "^4.3.2", - "glob": "^7.1.6", - "safer-buffer": "^2.1.2", - "sax": "~1.2.4", - "source-map": "^0.7.3" + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.22.0", + "es-module-lexer": "^2.1.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.5.0", + "watchpack": "^2.5.1", + "webpack-sources": "^3.5.0" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, - "dependencies": { - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true } } }, - "stylus-loader": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-6.2.0.tgz", - "integrity": "sha512-5dsDc7qVQGRoc6pvCL20eYgRUxepZ9FpeK28XhdXaIPP6kXr6nI1zAAKFQgP5OBkOfKaURp4WUpJzspg1f01Gg==", - "dev": true, - "requires": { - "fast-glob": "^3.2.7", - "klona": "^2.0.4", - "normalize-path": "^3.0.0" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/webpack-dev-middleware": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", + "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", - "dev": true - }, - "systemjs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-5.0.0.tgz", - "integrity": "sha512-hnD/IMQhH0UmawiIGlYVnkCPUbbO/WDQjOC+Q4PewHBdsagI1OHH1re1sg1AYFqq7p9ps6b1Bsx4xCeoeIZSCw==" - }, - "tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true - }, - "tape": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/tape/-/tape-4.17.0.tgz", - "integrity": "sha512-KCuXjYxCZ3ru40dmND+oCLsXyuA8hoseu2SS404Px5ouyS0A99v8X/mdiLqsR5MTAyamMBN7PRwt2Dv3+xGIxw==", - "requires": { - "@ljharb/resumer": "~0.0.1", - "@ljharb/through": "~2.3.9", - "call-bind": "~1.0.2", - "deep-equal": "~1.1.1", - "defined": "~1.0.1", - "dotignore": "~0.1.2", - "for-each": "~0.3.3", - "glob": "~7.2.3", - "has": "~1.0.3", - "inherits": "~2.0.4", - "is-regex": "~1.1.4", - "minimist": "~1.2.8", - "mock-property": "~1.0.0", - "object-inspect": "~1.12.3", - "resolve": "~1.22.6", - "string.prototype.trim": "~1.2.8" - }, + "license": "MIT", "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" - }, - "resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "requires": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } + "colorette": "^2.0.10", + "memfs": "^4.43.1", + "mime-types": "^3.0.1", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true } } }, - "tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, + "node_modules/webpack-dev-server": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.3.tgz", + "integrity": "sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==", + "dev": true, + "license": "MIT", "dependencies": { - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.25", + "@types/express-serve-static-core": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", + "colorette": "^2.0.10", + "compression": "^1.8.1", + "connect-history-api-fallback": "^2.0.0", + "express": "^4.22.1", + "graceful-fs": "^4.2.6", + "http-proxy-middleware": "^2.0.9", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "schema-utils": "^4.2.0", + "selfsigned": "^5.5.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^7.4.2", + "ws": "^8.18.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "webpack-cli": { + "optional": true } } }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/webpack-dev-server/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" } }, - "terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "node_modules/webpack-dev-server/node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, - "terser-webpack-plugin": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", - "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.25", - "jest-worker": "^27.4.5", - "schema-utils": "^4.3.0", - "terser": "^5.31.1" - }, + "license": "MIT", "dependencies": { - "schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - }, - "terser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", - "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.15.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - } - } + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/webpack-dev-server/node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "node_modules/webpack-dev-server/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", "dev": true, - "requires": { - "rimraf": "^3.0.0" - } + "license": "MIT" }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/webpack-dev-server/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "topojson-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.0.1.tgz", - "integrity": "sha512-rfGGzyqefpxOaxvV9OTF9t+1g+WhjGEbAIuCcmKYrQkxr0nttjMMyzZsK+NhLW4cTl2g1bz2jQczPUtEshpbVQ==", - "requires": { - "commander": "2" + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true + "node_modules/webpack-dev-server/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" }, - "ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "node_modules/webpack-dev-server/node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", "dev": true, - "requires": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" }, - "dependencies": { - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/webpack-dev-server/node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, + "license": "MIT", "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + "node_modules/webpack-dev-server/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "node_modules/webpack-dev-server/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "requires": { - "tslib": "^1.8.1" - }, + "license": "ISC", "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", "dev": true, - "requires": { - "prelude-ls": "^1.2.1" + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/webpack-dev-server/node_modules/ipaddr.js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "license": "MIT", + "engines": { + "node": ">= 10" } }, - "typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "requires": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" + "node_modules/webpack-dev-server/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "typed-array-byte-length": { + "node_modules/webpack-dev-server/node_modules/merge-descriptors": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "requires": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - } - }, - "typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "requires": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - } - }, - "typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "requires": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - } - }, - "typed-assert": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true - }, - "typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha512-qLq/4y2pjcU3vhlhseXGGJ7VbFO4pBANu0kwl8VCa9KEI0V8VfZIx2Fy3w01iSTA/pGwKZSmu/+I4etLNDdt5w==", - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==" - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha512-GIOYRizG+TGoc7Wgc1LiOTLare95R3mzKgoln+Q/lE4ceiYH19gUpl0l0Ffq4lJDEf3FxujMe6IBfOCs7pfqNA==", - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha512-QFzUah88GAGy9lyDKGBqZdkYApt63rCXYBGYnEP4xDJPXNqXXnBDACnbrXnViV6jRSqAePwrATi2i8mfYm4L1A==", - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha512-vb2s1lYx2xBtUgy+ta+b2J/GLVUR+wmpINwHePmPRhOsIVCG2wDzKJ0n14GslH1BifsqVzSOwQhRaCAsZ/nI4Q==", - "optional": true - }, - "unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "requires": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" + "node_modules/webpack-dev-server/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/webpack-dev-server/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, - "unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "node_modules/webpack-dev-server/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, - "requires": { - "unique-slug": "^2.0.0" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4" + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "node_modules/webpack-dev-server/node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, - "requires": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - } + "license": "MIT" }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/webpack-dev-server/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, - "requires": { - "punycode": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "validate-npm-package-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", - "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "node_modules/webpack-dev-server/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, - "requires": { - "builtins": "^1.0.3" + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true - }, - "venn.js": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/venn.js/-/venn.js-0.2.20.tgz", - "integrity": "sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==", - "requires": { - "d3-selection": "^1.0.2", - "d3-transition": "^1.0.1", - "fmin": "0.0.2" + "node_modules/webpack-dev-server/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" } }, - "version-range": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", - "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", - "dev": true + "node_modules/webpack-dev-server/node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } }, - "watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "node_modules/webpack-dev-server/node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "node_modules/webpack-dev-server/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, - "wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "node_modules/webpack-dev-server/node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", "dev": true, - "requires": { - "defaults": "^1.0.3" + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } }, - "webpack": { - "version": "5.105.4", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", - "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", + "node_modules/webpack-sources": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "dev": true, - "peer": true, - "requires": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.16.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.28.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.20.0", - "es-module-lexer": "^2.0.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.17", - "watchpack": "^2.5.1", - "webpack-sources": "^3.3.4" - }, - "dependencies": { - "schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "peer": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - } + "license": "MIT", + "engines": { + "node": ">=10.13.0" } }, - "webpack-dev-middleware": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz", - "integrity": "sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg==", + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", "dev": true, - "requires": { - "colorette": "^2.0.10", - "memfs": "^3.2.2", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" - }, + "license": "MIT", "dependencies": { - "schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true } } }, - "webpack-dev-server": { - "version": "4.7.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.3.tgz", - "integrity": "sha512-mlxq2AsIw2ag016nixkzUkdyOE8ST2GTy34uKSABp1c4nhjZvH90D5ZRR+UOLSsG4Z3TFahAi72a3ymRtfRm+Q==", + "node_modules/webpack/node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, - "requires": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/serve-index": "^1.9.1", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.2.2", - "ansi-html-community": "^0.0.8", - "bonjour": "^3.5.0", - "chokidar": "^3.5.2", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^1.6.0", - "default-gateway": "^6.0.3", - "del": "^6.0.0", - "express": "^4.17.1", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.0", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "portfinder": "^1.0.28", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.21", - "spdy": "^4.0.2", - "strip-ansi": "^7.0.0", - "webpack-dev-middleware": "^5.3.0", - "ws": "^8.1.0" - }, + "license": "MIT", + "peer": true, "dependencies": { - "ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true - }, - "schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - } - }, - "strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true } } }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" } }, - "webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", - "dev": true + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=4.0" + } }, - "webpack-subresource-integrity": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "node_modules/webpack/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, - "requires": { - "typed-assert": "^1.0.8" + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "websocket-driver": { + "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "requires": { + "license": "Apache-2.0", + "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" } }, - "websocket-extensions": { + "node_modules/websocket-extensions": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" } }, - "which": { + "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "which-boxed-primitive": { + "node_modules/which-boxed-primitive": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "requires": { + "license": "MIT", + "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-builtin-type": { + "node_modules/which-builtin-type": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "requires": { + "license": "MIT", + "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", @@ -31584,143 +21290,205 @@ "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-collection": { + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, + "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "requires": { + "license": "MIT", + "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "requires": { + "node_modules/which-typed-array": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.21.tgz", + "integrity": "sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==", + "license": "MIT", + "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "wildcard": { + "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "window-size": { + "node_modules/window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==" + "integrity": "sha512-1pTPQDKTdd61ozlKGNCjhNRd+KPmgLSGa3mZTHoOliaGcESD8G1PXhh7c1fgiPjVbNVfgy2Faw4BI8/m0cC8Mg==", + "engines": { + "node": ">= 0.8.0" + } }, - "wolfy87-eventemitter": { + "node_modules/wolfy87-eventemitter": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz", - "integrity": "sha512-VakY4+17DbamV2VW4nZERrSuilclCRcYtfchPWe6jlma8k0AeLJxBR+C5OSFFtICArDFdXk0yw67HUGrTCdrEg==" + "integrity": "sha512-VakY4+17DbamV2VW4nZERrSuilclCRcYtfchPWe6jlma8k0AeLJxBR+C5OSFFtICArDFdXk0yw67HUGrTCdrEg==", + "license": "Unlicense" }, - "word-wrap": { + "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "wordwrap": { + "node_modules/wordwrap": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==" + "integrity": "sha512-xSBsCeh+g+dinoBv3GAOWM4LcVVO68wLXRanibtBSdUvkGWQRGeE9P7IwU9EmDDi4jA6L44lz15CGMwdw9N5+Q==", + "license": "MIT/X11", + "engines": { + "node": ">=0.4.0" + } }, - "wrap-ansi": { + "node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true - }, - "ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true - }, - "emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true - }, - "string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "requires": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - } - }, - "strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "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 + } + } }, - "ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "xlsx": { + "node_modules/xlsx": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.14.5.tgz", "integrity": "sha512-s/5f4/mjeWREmIWZ+HtDfh/rnz51ar+dZ4LWKZU3u9VBx2zLdSIWTdXgoa52/pnZ9Oe/Vu1W1qzcKzLVe+lq4w==", - "requires": { + "license": "Apache-2.0", + "dependencies": { "adler-32": "~1.2.0", "cfb": "^1.1.2", "codepage": "~1.14.0", @@ -31729,89 +21497,179 @@ "exit-on-epipe": "~1.0.1", "ssf": "~0.10.2" }, - "dependencies": { - "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" - } + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" } }, - "xxhashjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", - "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", - "dev": true, - "requires": { - "cuint": "^0.2.2" - } + "node_modules/xlsx/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "license": "MIT" }, - "y18n": { + "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "yallist": { + "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, - "yaml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", - "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", - "dev": true + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, - "requires": { - "cliui": "^8.0.1", + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, - "dependencies": { - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - } + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "yargs-parser": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.0.0.tgz", - "integrity": "sha512-8eblPHTL7ZWRkyjIZJjnGf+TijiKJSwA24svzLRVvtgoi/RZiKa9fFQTrlx0OKLnyHSdt/enrdadji6WFfESVA==", - "dev": true + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" }, - "yn": { + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "zone.js": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", - "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", - "requires": { - "tslib": "^2.3.0" + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/zone.js": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", + "license": "MIT" } } } diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 2bf5deaff5a..3d48881c831 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -27,21 +27,21 @@ "e2e:cleanup": "npx tsx e2e/cleanup-util.ts" }, "engines": { - "node": ">=18.0.0 <19.0.0" + "node": ">=22.12.0" }, "private": true, "dependencies": { - "@angular/animations": "~13.4.0", - "@angular/cdk": "~13.3.9", - "@angular/common": "~13.4.0", - "@angular/compiler": "~13.4.0", - "@angular/core": "~13.4.0", - "@angular/forms": "~13.4.0", - "@angular/platform-browser": "~13.4.0", - "@angular/platform-browser-dynamic": "~13.4.0", - "@angular/router": "~13.4.0", + "@angular/cdk": "^21.2.13", + "@angular/common": "^21.2.15", + "@angular/compiler": "^21.2.15", + "@angular/core": "^21.2.15", + "@angular/forms": "^21.2.15", + "@angular/platform-browser": "^21.2.15", + "@angular/platform-browser-dynamic": "^21.2.15", + "@angular/router": "^21.2.15", "@antv/data-set": "^0.10.2", "@antv/g2": "^3.5.4", + "@ctrl/tinycolor": "^3.6.1", "angular": "^1.8.2", "ansi_up": "^6.0.6", "core-js": "^2.5.4", @@ -54,28 +54,25 @@ "jquery-ui": "1.14.0", "lodash": "^4.17.21", "mathjax": "2.7.5", - "monaco-editor": "0.30.1", - "ng-zorro-antd": "^13.4.0", + "monaco-editor": "0.31.1", + "ng-zorro-antd": "^21.3.0", "nvd3": "1.8.6", "parse5": "^5.1.1", - "rxjs": "~6.5.3", + "rxjs": "~7.8.2", "systemjs": "^5.0.0", "tslib": "^2.0.0", "xlsx": "^0.14.3", - "zone.js": "~0.11.4" + "zone.js": "~0.15.1" }, "devDependencies": { - "@angular-architects/module-federation": "13.0.1", - "@angular-builders/custom-webpack": "13.1.0", - "@angular-devkit/build-angular": "^13.3.11", - "@angular-eslint/builder": "13.5.0", - "@angular-eslint/eslint-plugin": "13.5.0", - "@angular-eslint/eslint-plugin-template": "13.5.0", - "@angular-eslint/schematics": "13.5.0", - "@angular-eslint/template-parser": "13.5.0", - "@angular/cli": "~13.3.11", - "@angular/compiler-cli": "~13.4.0", - "@angular/language-service": "~13.4.0", + "@angular-architects/module-federation": "^21.2.2", + "@angular-builders/custom-webpack": "^21.0.3", + "@angular-devkit/build-angular": "^21.2.13", + "@angular-eslint/builder": "21.4.0", + "@angular-eslint/schematics": "21.4.0", + "@angular/cli": "^21.2.13", + "@angular/compiler-cli": "^21.2.15", + "@angular/language-service": "^21.2.15", "@playwright/test": "1.55.1", "@types/angular": "^1.8.0", "@types/diff-match-patch": "^1.0.36", @@ -86,12 +83,11 @@ "@types/node": "~12.19.16", "@types/parse5": "^5.0.2", "@types/webpack-env": "^1.18.8", - "@typescript-eslint/eslint-plugin": "5.62.0", - "@typescript-eslint/parser": "5.62.0", + "angular-eslint": "21.4.0", "concurrently": "9.2.1", "cross-env": "^10.1.0", "dotenv": "^17.2.3", - "eslint": "^8.57.1", + "eslint": "^9.28.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.32.0", "eslint-plugin-jsdoc": "^50.8.0", @@ -99,13 +95,18 @@ "https-proxy-agent": "^2.2.1", "husky": "9.1.7", "lint-staged": "^15.5.2", - "monaco-editor-webpack-plugin": "6.0.0", - "ng-packagr": "^13.3.1", - "ngx-build-plus": "^13.0.1", + "monaco-editor-webpack-plugin": "7.0.1", + "ng-packagr": "^21.2.3", + "ngx-build-plus": "^20.0.0", "prettier": "^3.6.2", "scandirectory": "8.1.1", + "style-loader": "^4.0.0", "ts-node": "~7.0.0", - "typescript": "4.6.4" + "typescript": "~5.9.3", + "typescript-eslint": "^8.33.1" + }, + "overrides": { + "@babel/runtime": "^7.27.0" }, "lint-staged": { "**/*.ts": [ diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml index 1498e85218f..113bb69e792 100644 --- a/zeppelin-web-angular/pom.xml +++ b/zeppelin-web-angular/pom.xml @@ -39,8 +39,8 @@ https://nodejs.org/dist/ https://registry.npmjs.org/npm/-/ - v18.20.8 - 8.19.4 + v22.21.1 + 10.9.4 diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/.eslintrc.json b/zeppelin-web-angular/projects/zeppelin-sdk/.eslintrc.json deleted file mode 100644 index 05c39dda0b8..00000000000 --- a/zeppelin-web-angular/projects/zeppelin-sdk/.eslintrc.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "extends": "../../.eslintrc.json", - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "parserOptions": { - "project": true, - "createDefaultProgram": true - }, - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "lib", - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "lib", - "style": "camelCase" - } - ] - } - }, - { - "files": ["*.html"], - "rules": {} - } - ] -} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts index 29a05ddf8ca..4f8c5e625ba 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts @@ -135,7 +135,7 @@ export class Message { } close() { - this.close$.next(); + this.close$.next(new CloseEvent('close', { code: this.normalCloseCode })); } opened(): Observable { diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.json b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.json index 213290db31d..ef3e5400b87 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.json +++ b/zeppelin-web-angular/projects/zeppelin-sdk/tsconfig.json @@ -5,8 +5,7 @@ "target": "es2015", "declaration": true, "inlineSources": true, - "types": [], - "lib": ["dom", "es2018"] + "types": [] }, "angularCompilerOptions": { "annotateForClosureCompiler": true, diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/.eslintrc.json b/zeppelin-web-angular/projects/zeppelin-visualization/.eslintrc.json deleted file mode 100644 index 05c39dda0b8..00000000000 --- a/zeppelin-web-angular/projects/zeppelin-visualization/.eslintrc.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "extends": "../../.eslintrc.json", - "ignorePatterns": ["!**/*"], - "overrides": [ - { - "files": ["*.ts"], - "parserOptions": { - "project": true, - "createDefaultProgram": true - }, - "rules": { - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "lib", - "style": "kebab-case" - } - ], - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "lib", - "style": "camelCase" - } - ] - } - }, - { - "files": ["*.html"], - "rules": {} - } - ] -} diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts index b898e697f36..3a1f3da43c2 100644 --- a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts @@ -17,7 +17,10 @@ import * as G2 from '@antv/g2'; import { GraphConfig } from '@zeppelin/sdk'; import { Visualization } from './visualization'; -@Component({ template: '' }) +@Component({ + template: '', + standalone: false +}) // eslint-disable-next-line @angular-eslint/component-class-suffix export abstract class G2VisualizationComponentBase implements OnDestroy { abstract container: ElementRef; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts index dbc487bea89..fccfcd6b3f0 100644 --- a/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/visualization-component-portal.ts @@ -10,8 +10,8 @@ * limitations under the License. */ -import { CdkPortalOutlet, ComponentPortal, ComponentType, PortalInjector } from '@angular/cdk/portal'; -import { ComponentFactoryResolver, InjectionToken, ViewContainerRef } from '@angular/core'; +import { CdkPortalOutlet, ComponentPortal, ComponentType } from '@angular/cdk/portal'; +import { InjectionToken, Injector, ViewContainerRef } from '@angular/core'; import { Visualization } from './visualization'; @@ -22,20 +22,20 @@ export class VisualizationComponentPortal { private visualization: T, private component: ComponentType, private portalOutlet: CdkPortalOutlet, - private viewContainerRef: ViewContainerRef, - private componentFactoryResolver?: ComponentFactoryResolver + private viewContainerRef: ViewContainerRef ) {} createInjector() { const userInjector = this.viewContainerRef && this.viewContainerRef.injector; - // eslint-disable-next-line - const injectionTokens = new WeakMap([[VISUALIZATION, this.visualization]]); - return new PortalInjector(userInjector, injectionTokens); + return Injector.create({ + providers: [{ provide: VISUALIZATION, useValue: this.visualization }], + parent: userInjector + }); } getComponentPortal() { const injector = this.createInjector(); - return new ComponentPortal(this.component, null, injector, this.componentFactoryResolver); + return new ComponentPortal(this.component, null, injector); } attachComponentPortal() { diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.json b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.json index 4f0d4758cb8..4ffff974dbe 100644 --- a/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.json +++ b/zeppelin-web-angular/projects/zeppelin-visualization/tsconfig.json @@ -5,8 +5,7 @@ "target": "es2015", "declaration": true, "inlineSources": true, - "types": [], - "lib": ["dom", "es2018"] + "types": [] }, "angularCompilerOptions": { "annotateForClosureCompiler": true, diff --git a/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts b/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts index 9627982fa96..dff8d8507b7 100644 --- a/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts +++ b/zeppelin-web-angular/src/app/app-runtime-compiler.providers.ts @@ -21,7 +21,6 @@ import { import { JitCompilerFactory } from '@angular/platform-browser-dynamic'; const compilerOptions: CompilerOptions = { - useJit: true, defaultEncapsulation: ViewEncapsulation.None }; diff --git a/zeppelin-web-angular/src/app/app.component.html b/zeppelin-web-angular/src/app/app.component.html index e4792e9322e..d376a33c9b6 100644 --- a/zeppelin-web-angular/src/app/app.component.html +++ b/zeppelin-web-angular/src/app/app.component.html @@ -1,15 +1,19 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> -Getting Ticket Data ... -Logging out ... +@if (loading$ | async) { + Getting Ticket Data ... +} +@if (logout$ | async) { + Logging out ... +} diff --git a/zeppelin-web-angular/src/app/app.component.ts b/zeppelin-web-angular/src/app/app.component.ts index ef9805fabef..c590a746f3d 100644 --- a/zeppelin-web-angular/src/app/app.component.ts +++ b/zeppelin-web-angular/src/app/app.component.ts @@ -19,7 +19,8 @@ import { ThemeService, TicketService } from '@zeppelin/services'; @Component({ selector: 'zeppelin-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.less'] + styleUrls: ['./app.component.less'], + standalone: false }) export class AppComponent implements OnInit { logout$ = this.ticketService.logout$; diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts index 4ef3c8e065a..af099ac17e5 100644 --- a/zeppelin-web-angular/src/app/app.module.ts +++ b/zeppelin-web-angular/src/app/app.module.ts @@ -11,12 +11,11 @@ */ import { registerLocaleData } from '@angular/common'; -import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import en from '@angular/common/locales/en'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { Router, RouterModule } from '@angular/router'; import { en_US, NZ_I18N } from 'ng-zorro-antd/i18n'; @@ -42,15 +41,8 @@ registerLocaleData(en); @NgModule({ declarations: [AppComponent], - imports: [ - BrowserModule, - FormsModule, - HttpClientModule, - BrowserAnimationsModule, - ShareModule, - AppRoutingModule, - RouterModule - ], + bootstrap: [AppComponent], + imports: [BrowserModule, FormsModule, ShareModule, AppRoutingModule, RouterModule], providers: [ ...RUNTIME_COMPILER_PROVIDERS, { @@ -81,8 +73,8 @@ registerLocaleData(en); { provide: TRASH_FOLDER_ID_TOKEN, useValue: '~Trash' - } - ], - bootstrap: [AppComponent] + }, + provideHttpClient(withInterceptorsFromDi()) + ] }) export class AppModule {} diff --git a/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts b/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts index 736f9914ab5..b4a68f18326 100644 --- a/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts +++ b/zeppelin-web-angular/src/app/core/copy-text/copy-text-to-clipboard.ts @@ -57,7 +57,7 @@ export const copyTextToClipboard = (text: string): void => { try { document.execCommand('copy'); - } catch (err) { + } catch { window.prompt('Copy to clipboard: Ctrl+C, Enter', text); } diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts index 91ab7e4600b..97d15b2d7e0 100644 --- a/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts +++ b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts @@ -13,10 +13,13 @@ import { Component, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs'; -@Component({ template: '' }) +@Component({ + template: '', + standalone: false +}) // eslint-disable-next-line @angular-eslint/component-class-suffix export class DestroyHookComponent implements OnDestroy { - readonly destroy$ = new Subject(); + readonly destroy$ = new Subject(); ngOnDestroy() { this.destroy$.next(); diff --git a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts index 05dc0395815..12897460aef 100644 --- a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts +++ b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts @@ -15,7 +15,10 @@ import { Subscriber } from 'rxjs'; import { Message, MessageReceiveDataTypeMap, ReceiveArgumentsType } from '@zeppelin/sdk'; -@Component({ template: '' }) +@Component({ + template: '', + standalone: false +}) // eslint-disable-next-line @angular-eslint/component-class-suffix export class MessageListenersManager implements OnDestroy { __zeppelinMessageListeners__?: Array<() => void>; diff --git a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts index 588f615be8b..850c4cc3802 100644 --- a/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts +++ b/zeppelin-web-angular/src/app/core/runtime-dynamic-module/ng-zorro-antd-module.ts @@ -15,7 +15,6 @@ import { NzAlertModule } from 'ng-zorro-antd/alert'; import { NzAnchorModule } from 'ng-zorro-antd/anchor'; import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; import { NzAvatarModule } from 'ng-zorro-antd/avatar'; -import { NzBackTopModule } from 'ng-zorro-antd/back-top'; import { NzBadgeModule } from 'ng-zorro-antd/badge'; import { NzBreadCrumbModule } from 'ng-zorro-antd/breadcrumb'; import { NzButtonModule } from 'ng-zorro-antd/button'; @@ -26,7 +25,7 @@ import { NzCascaderModule } from 'ng-zorro-antd/cascader'; import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; import { NzCollapseModule } from 'ng-zorro-antd/collapse'; import { NzCommentModule } from 'ng-zorro-antd/comment'; -import { NzNoAnimationModule } from 'ng-zorro-antd/core/no-animation'; +import { NzNoAnimationModule } from 'ng-zorro-antd/core/animation'; import { NzTransButtonModule } from 'ng-zorro-antd/core/trans-button'; import { NzWaveModule } from 'ng-zorro-antd/core/wave'; import { NzDatePickerModule } from 'ng-zorro-antd/date-picker'; @@ -45,9 +44,7 @@ import { NzLayoutModule } from 'ng-zorro-antd/layout'; import { NzListModule } from 'ng-zorro-antd/list'; import { NzMentionModule } from 'ng-zorro-antd/mention'; import { NzMenuModule } from 'ng-zorro-antd/menu'; -import { NzMessageModule } from 'ng-zorro-antd/message'; import { NzModalModule } from 'ng-zorro-antd/modal'; -import { NzNotificationModule } from 'ng-zorro-antd/notification'; import { NzPageHeaderModule } from 'ng-zorro-antd/page-header'; import { NzPaginationModule } from 'ng-zorro-antd/pagination'; import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; @@ -68,7 +65,7 @@ import { NzTabsModule } from 'ng-zorro-antd/tabs'; import { NzTagModule } from 'ng-zorro-antd/tag'; import { NzTimePickerModule } from 'ng-zorro-antd/time-picker'; import { NzTimelineModule } from 'ng-zorro-antd/timeline'; -import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTooltipModule } from 'ng-zorro-antd/tooltip'; import { NzTransferModule } from 'ng-zorro-antd/transfer'; import { NzTreeModule } from 'ng-zorro-antd/tree'; import { NzTreeSelectModule } from 'ng-zorro-antd/tree-select'; @@ -83,7 +80,6 @@ import { NgModule } from './ngmodule.decorator'; NzAnchorModule, NzAutocompleteModule, NzAvatarModule, - NzBackTopModule, NzBadgeModule, NzButtonModule, NzBreadCrumbModule, @@ -110,10 +106,8 @@ import { NgModule } from './ngmodule.decorator'; NzListModule, NzMentionModule, NzMenuModule, - NzMessageModule, NzModalModule, NzNoAnimationModule, - NzNotificationModule, NzPageHeaderModule, NzPaginationModule, NzPopconfirmModule, @@ -134,7 +128,7 @@ import { NgModule } from './ngmodule.decorator'; NzTagModule, NzTimePickerModule, NzTimelineModule, - NzToolTipModule, + NzTooltipModule, NzTransButtonModule, NzTransferModule, NzTreeModule, diff --git a/zeppelin-web-angular/src/app/key-binding/key-binder.ts b/zeppelin-web-angular/src/app/key-binding/key-binder.ts index c21601affca..5267c78849a 100644 --- a/zeppelin-web-angular/src/app/key-binding/key-binder.ts +++ b/zeppelin-web-angular/src/app/key-binding/key-binder.ts @@ -12,7 +12,7 @@ import { ElementRef } from '@angular/core'; import { editor as MonacoEditor } from 'monaco-editor'; -import { from, Subject } from 'rxjs'; +import { from, Observable, Subject } from 'rxjs'; import { map, mergeMap, takeUntil } from 'rxjs/operators'; import { ShortcutService } from '@zeppelin/services'; @@ -28,7 +28,7 @@ export class KeyBinder { }>(); constructor( - private destroySubject: Subject, + private destroySubject: Observable, private host: ElementRef, private shortcutService: ShortcutService ) {} diff --git a/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts b/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts index b7098bcb53d..5ebffd8fedf 100644 --- a/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts +++ b/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts @@ -76,6 +76,8 @@ export const ParagraphActionToHandlerName = { // This allows checking both keys and values at the type level, // while preserving the binding between them. +// Referenced only via `typeof` below to derive a type; the runtime binding is intentionally unused. +// eslint-disable-next-line @typescript-eslint/no-unused-vars const MonacoHandledParagraphActions = [ ParagraphActions.MoveCursorUp, ParagraphActions.MoveCursorDown, diff --git a/zeppelin-web-angular/src/app/pages/login/login.component.ts b/zeppelin-web-angular/src/app/pages/login/login.component.ts index fb2da7f2d8a..9b4f70efcc1 100644 --- a/zeppelin-web-angular/src/app/pages/login/login.component.ts +++ b/zeppelin-web-angular/src/app/pages/login/login.component.ts @@ -19,7 +19,8 @@ import { TicketService } from '@zeppelin/services'; selector: 'zeppelin-login', templateUrl: './login.component.html', styleUrls: ['./login.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class LoginComponent implements OnInit { userName?: string; diff --git a/zeppelin-web-angular/src/app/pages/login/login.guard.ts b/zeppelin-web-angular/src/app/pages/login/login.guard.ts index aa5d3efe764..77cf762a530 100644 --- a/zeppelin-web-angular/src/app/pages/login/login.guard.ts +++ b/zeppelin-web-angular/src/app/pages/login/login.guard.ts @@ -11,7 +11,7 @@ */ import { Injectable } from '@angular/core'; -import { CanActivate, Router } from '@angular/router'; +import { Router } from '@angular/router'; import { of, Observable } from 'rxjs'; import { catchError, map } from 'rxjs/operators'; @@ -20,7 +20,7 @@ import { TicketService } from '@zeppelin/services'; @Injectable({ providedIn: 'root' }) -export class LoginGuard implements CanActivate { +export class LoginGuard { constructor( private ticketService: TicketService, private router: Router diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html index b1add8b6611..ee8f0dd1b95 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> @@ -25,10 +25,12 @@ - - {{ data[0] }} - {{ data[1] }} - + @for (data of configEntries; track data) { + + {{ data[0] }} + {{ data[1] }} + + }
  • diff --git a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts index 2cc9682b1fe..001e2212da1 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/configuration/configuration.component.ts @@ -16,7 +16,8 @@ import { ConfigurationService } from '@zeppelin/services'; selector: 'zeppelin-configuration', templateUrl: './configuration.component.html', styleUrls: ['./configuration.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class ConfigurationComponent implements OnInit { configEntries: Array<[string, string]> = []; diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html index 2293f217811..b005e6113dc 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> @@ -23,47 +23,51 @@ Add -
    - -

    Add new credential

    -
    - - Entity - - - - - {{ option }} - - - - - - Username - - - - - - Password - - - - +
    +
    + +

    Add new credential

    + + + Entity + + + + @for (option of interpreterFilteredNames; track option) { + + {{ option }} + + } + + + + + Username + + + + + + Password + + + + - - - - - - - + + + + + + + +
    @@ -77,46 +81,47 @@

    Add new credential

    - - - {{ entity }} - - - - - - - - - - - - {{ control.get('username')?.value }} - ********** - - - - - - - + @for (control of credentialControls; track control) { + + @if (control.get('entity')?.value; as entity) { + + {{ entity }} + @if (isEditing(control)) { + + + + + + + } @else { + {{ control.get('username')?.value }} + ********** + + + + + } + + } + + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less index 05a31ddb037..5d8d3f74775 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.less @@ -40,3 +40,12 @@ } } }); + +// Establish a block formatting context so the collapsed content's child +// margins (nz-divider, h2, ...) are contained. NzAnimationCollapseDirective +// measures the open height as the sum of its direct children's offsetHeight +// (margin-excluded); without this single margin-containing child the +// animation stops short of the final auto height and the layout jumps. +.collapse-content { + display: flow-root; +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts index 19c376106e9..76b3993864e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.component.ts @@ -11,11 +11,10 @@ */ import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core'; -import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { CredentialForm } from '@zeppelin/interfaces'; import { CredentialService, InterpreterService, TicketService } from '@zeppelin/services'; -import { collapseMotion } from 'ng-zorro-antd/core/animation'; import { NzMessageService } from 'ng-zorro-antd/message'; import { finalize } from 'rxjs/operators'; @@ -24,26 +23,26 @@ import { finalize } from 'rxjs/operators'; selector: 'zeppelin-credential', templateUrl: './credential.component.html', styleUrls: ['./credential.component.less'], - animations: [collapseMotion], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class CredentialComponent { - addForm: FormGroup; + addForm: UntypedFormGroup; showAdd = false; adding = false; interpreterNames: string[] = []; interpreterFilteredNames: string[] = []; editFlags: Map = new Map(); - credentialFormArray: FormArray = this.fb.array([]); + credentialFormArray: UntypedFormArray = this.fb.array([]); docsLink: string; - get credentialControls(): FormGroup[] { - return this.credentialFormArray.controls as FormGroup[]; + get credentialControls(): UntypedFormGroup[] { + return this.credentialFormArray.controls as UntypedFormGroup[]; } constructor( private cdr: ChangeDetectorRef, - private fb: FormBuilder, + private fb: UntypedFormBuilder, private nzMessageService: NzMessageService, private interpreterService: InterpreterService, private credentialService: CredentialService, @@ -71,17 +70,17 @@ export class CredentialComponent { } } - getEntityFromForm(form: FormGroup): string { + getEntityFromForm(form: UntypedFormGroup): string { const entity = form.get('entity'); return entity && entity.value; } - isEditing(form: FormGroup): boolean { + isEditing(form: UntypedFormGroup): boolean { const entity = this.getEntityFromForm(form); return !!entity && this.editFlags.has(entity); } - setEditable(form: FormGroup) { + setEditable(form: UntypedFormGroup) { const entity = this.getEntityFromForm(form); if (entity) { this.editFlags.set(entity, form.getRawValue()); @@ -89,7 +88,7 @@ export class CredentialComponent { this.cdr.markForCheck(); } - unsetEditable(form: FormGroup, reset = true) { + unsetEditable(form: UntypedFormGroup, reset = true) { const entity = this.getEntityFromForm(form); if (reset && entity && this.editFlags.has(entity)) { form.reset(this.editFlags.get(entity)); @@ -109,7 +108,7 @@ export class CredentialComponent { } } - saveCredential(form: FormGroup) { + saveCredential(form: UntypedFormGroup) { Object.keys(form.controls).forEach(key => { form.controls[key].markAsDirty(); form.controls[key].updateValueAndValidity(); @@ -122,7 +121,7 @@ export class CredentialComponent { } } - removeCredential(form: FormGroup) { + removeCredential(form: UntypedFormGroup) { const entity = this.getEntityFromForm(form); if (entity) { this.credentialService.removeCredential(entity).subscribe(() => { diff --git a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts index 39756edb9f4..ed7fa25d3b1 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/credential/credential.module.ts @@ -14,6 +14,7 @@ import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ShareModule } from '@zeppelin/share'; +import { NzAnimationCollapseDirective } from 'ng-zorro-antd/core/animation'; import { NzAutocompleteModule } from 'ng-zorro-antd/auto-complete'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzCardModule } from 'ng-zorro-antd/card'; @@ -22,10 +23,9 @@ import { NzFormModule } from 'ng-zorro-antd/form'; import { NzGridModule } from 'ng-zorro-antd/grid'; import { NzIconModule } from 'ng-zorro-antd/icon'; import { NzInputModule } from 'ng-zorro-antd/input'; -import { NzMessageModule } from 'ng-zorro-antd/message'; import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm'; import { NzTableModule } from 'ng-zorro-antd/table'; -import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTooltipModule } from 'ng-zorro-antd/tooltip'; import { CredentialRoutingModule } from './credential-routing.module'; import { CredentialComponent } from './credential.component'; @@ -37,6 +37,7 @@ import { CredentialComponent } from './credential.component'; FormsModule, ShareModule, ReactiveFormsModule, + NzAnimationCollapseDirective, NzFormModule, NzAutocompleteModule, NzButtonModule, @@ -44,11 +45,10 @@ import { CredentialComponent } from './credential.component'; NzIconModule, NzDividerModule, NzInputModule, - NzMessageModule, NzTableModule, NzPopconfirmModule, NzGridModule, - NzToolTipModule + NzTooltipModule ] }) export class CredentialModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts index cc2a8e6d57f..80b8a0c0b9a 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.ts @@ -20,7 +20,8 @@ import { MessageService, TicketService } from '@zeppelin/services'; selector: 'zeppelin-home', templateUrl: './home.component.html', styleUrls: ['./home.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class HomeComponent extends MessageListenersManager implements OnInit { loading = false; diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts index 49a29734486..a900c55a9bb 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.module.ts @@ -15,7 +15,7 @@ import { NgModule } from '@angular/core'; import { NzGridModule } from 'ng-zorro-antd/grid'; import { NzIconModule } from 'ng-zorro-antd/icon'; -import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTooltipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; @@ -24,6 +24,6 @@ import { HomeComponent } from './home.component'; @NgModule({ declarations: [HomeComponent], - imports: [CommonModule, HomeRoutingModule, NzGridModule, NzIconModule, NzToolTipModule, ShareModule] + imports: [CommonModule, HomeRoutingModule, NzGridModule, NzIconModule, NzTooltipModule, ShareModule] }) export class HomeModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts index dacea861d25..e254d6870dc 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts @@ -11,7 +11,7 @@ */ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { takeUntil } from 'rxjs/operators'; import { NzModalRef } from 'ng-zorro-antd/modal'; @@ -24,10 +24,11 @@ import { InterpreterService } from '@zeppelin/services'; selector: 'zeppelin-interpreter-create-repository-modal', templateUrl: './create-repository-modal.component.html', styleUrls: ['./create-repository-modal.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class InterpreterCreateRepositoryModalComponent extends DestroyHookComponent { - validateForm: FormGroup; + validateForm: UntypedFormGroup; submitting = false; urlProtocol = 'http://'; @@ -53,7 +54,7 @@ export class InterpreterCreateRepositoryModalComponent extends DestroyHookCompon } constructor( - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private nzModalRef: NzModalRef, private interpreterService: InterpreterService ) { diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html index 30d236cce09..d8b4d39a43e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> @@ -36,34 +36,39 @@ Repository -
    - -

    Repositories

    -

    Available repository lists. These repositories are used to resolve external dependencies of interpreter.

    - - {{ repo.id }} - - - - +
    +
    + +

    Repositories

    +

    Available repository lists. These repositories are used to resolve external dependencies of interpreter.

    + @for (repo of repositories; track repo) { + + {{ repo.id }} + + } + + + +
    - - - Create - - - + @if (!showCreateSetting) { + + + Create + + } + @if (showCreateSetting) { + + } + @for (item of filteredInterpreterSettings; track item) { + + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less index 01329357310..4f9f5b2899e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.less @@ -50,10 +50,19 @@ :host-context(.dark) { background: #141414; - + .editable-tag { background: #1f1f1f; border-style: dashed; border-color: #434343; } } + +// Establish a block formatting context so the collapsed content's child +// margins (nz-divider, h2, ...) are contained. NzAnimationCollapseDirective +// measures the open height as the sum of its direct children's offsetHeight +// (margin-excluded); without this single margin-containing child the +// animation stops short of the final auto height and the layout jumps. +.collapse-content { + display: flow-root; +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts index 7870ed6d3db..1c6a7a3e861 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts @@ -14,7 +14,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnIni import { Subject } from 'rxjs'; import { debounceTime } from 'rxjs/operators'; -import { collapseMotion } from 'ng-zorro-antd/core/animation'; import { NzMessageService } from 'ng-zorro-antd/message'; import { NzModalService } from 'ng-zorro-antd/modal'; @@ -27,8 +26,8 @@ import { InterpreterCreateRepositoryModalComponent } from './create-repository-m selector: 'zeppelin-interpreter', templateUrl: './interpreter.component.html', styleUrls: ['./interpreter.component.less'], - animations: [collapseMotion], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class InterpreterComponent implements OnInit, OnDestroy { searchInterpreter = ''; @@ -189,7 +188,6 @@ export class InterpreterComponent implements OnInit, OnDestroy { } ngOnDestroy(): void { - this.search$?.next(); this.search$?.complete(); this.search$ = null; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts index 7906bfcf570..45e128b7e10 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.module.ts @@ -14,6 +14,7 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NzAlertModule } from 'ng-zorro-antd/alert'; +import { NzAnimationCollapseDirective } from 'ng-zorro-antd/core/animation'; import { NzBadgeModule } from 'ng-zorro-antd/badge'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzCardModule } from 'ng-zorro-antd/card'; @@ -23,14 +24,13 @@ import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; import { NzFormModule } from 'ng-zorro-antd/form'; import { NzIconModule } from 'ng-zorro-antd/icon'; import { NzInputModule } from 'ng-zorro-antd/input'; -import { NzMessageModule } from 'ng-zorro-antd/message'; import { NzModalModule } from 'ng-zorro-antd/modal'; import { NzRadioModule } from 'ng-zorro-antd/radio'; import { NzSelectModule } from 'ng-zorro-antd/select'; import { NzSwitchModule } from 'ng-zorro-antd/switch'; import { NzTableModule } from 'ng-zorro-antd/table'; import { NzTagModule } from 'ng-zorro-antd/tag'; -import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTooltipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; @@ -47,10 +47,11 @@ import { InterpreterItemComponent } from './item/item.component'; ReactiveFormsModule, InterpreterRoutingModule, ShareModule, + NzAnimationCollapseDirective, NzFormModule, NzSelectModule, NzSwitchModule, - NzToolTipModule, + NzTooltipModule, NzCheckboxModule, NzRadioModule, NzBadgeModule, @@ -63,7 +64,6 @@ import { InterpreterItemComponent } from './item/item.component'; NzDropDownModule, NzIconModule, NzTableModule, - NzMessageModule, NzAlertModule ] }) diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html index 1cf16943d47..5d8b81b914a 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> -
    -

    - {{ interpreter.name }} - - , %{{ interpreter.name }}.{{ item.name }} - %{{ interpreter.name }} - - - - - - -

    -
    + @if (interpreter) { +
    +

    + {{ interpreter.name }} + @for (item of interpreter.interpreterGroup; track item; let isFirst = $first) { + + @if (!isFirst) { + , %{{ interpreter.name }}.{{ item.name }} + } + @if (isFirst) { + %{{ interpreter.name }} + } + + } + + @switch (interpreter.status) { + @case ('READY') { + + } + @case ('ERROR') { + + } + @default { + + } + } + +

    +
    + }
    - + @if (interpreter?.status === 'ERROR' && mode === 'view') { + + }
    @@ -63,7 +76,7 @@

    - + @if (mode === 'create') {

    Create new interpreter

    @@ -71,7 +84,9 @@

    Create new interpreter

    - {{ control.errors.message }} + @if (control.hasError('exist')) { + {{ control.errors.message }} + }
    @@ -79,16 +94,14 @@

    Create new interpreter

    Interpreter group - + @for (item of parent.availableInterpreters; track interpretersTrackFn($index, item)) { + + }
    -
    + }

    Option

    Option

  • Per Note
  • -
  • - Per User -
  • + @if (this.ticketService.originTicket.principal !== 'anonymous') { +
  • + Per User +
  • + } in @@ -124,47 +139,50 @@

    Option

    [nzDropdownMenu]="perUserMenu" [nzDisabled]="interpreterRunningOption === runningOptionMap.globallyModeName || mode === 'view'" > - - {{ optionFormGroup.get('perUser')?.value || '' }} - - + @if (interpreterRunningOption === runningOptionMap.perUserModeName) { + + {{ optionFormGroup.get('perUser')?.value || '' }} + + } @else { {{ optionFormGroup.get('perNote')?.value || '' }} - + } - process - + } . - - - + @if ( + interpreterRunningOption === runningOptionMap.perUserModeName && + ticketService.ticket.principal !== 'anonymous' && + mode !== 'view' + ) { + @if (optionFormGroup.get('perNote')?.value === sessionOptionMap.shared) { + + } @else { - - + } + }

    - - - - - + @if ( + interpreterRunningOption === runningOptionMap.perUserModeName && + optionFormGroup.get('perUser')?.value === sessionOptionMap.isolated + ) { + + + + + + } @@ -232,7 +245,7 @@

    Option

    - + @if (optionForm.control.get('isExistingProcess')?.value) { Host @@ -250,7 +263,7 @@

    Option

    />
    -
    + } @@ -260,7 +273,7 @@

    Option

    - + @if (optionForm.control.get('setPermission')?.value) { Owners Option [nzDisabled]="mode === 'view'" (nzOnSearch)="onUserSearch($event)" > - + @for (option of userList$ | async; track option) { + + } - + }
    - + @if (propertiesFormArray.controls?.length || mode !== 'view') {

    Properties

    @@ -293,97 +308,138 @@

    Properties

    Name Value - Description - Action + @if (mode === 'create') { + Description + } + @if (mode !== 'view') { + Action + } - - {{ control.get('key')?.value || '' }} - - - - - - - - - - - - ****** - - + @for (control of propertiesFormArray.controls; track control; let i = $index) { + + {{ control.get('key')?.value || '' }} + + @if (mode !== 'view') { + @switch (control.get('type')?.value) { + @case ('textarea') { + + } + @case ('string') { + + } + @case ('number') { + + } + @case ('url') { + + } + @case ('password') { + + } + @case ('checkbox') { + + } + } + } @else { + @switch (control.get('type')?.value) { + @case ('password') { + ****** + } + @case ('url') { + + {{ control.get('value')?.value || '' }} + + } + @default { {{ control.get('value')?.value || '' }} - - - {{ control.get('value')?.value || '' }} - - - - {{ control.get('description')?.value || '' }} - - - - - - - - - -
    - - - - - - - - - - - -
    - - N/A - - - - - + } + } + } + + @if (mode === 'create') { + {{ control.get('description')?.value || '' }} + } + @if (mode !== 'view') { + + + + } + + } + @if (mode !== 'view' && editingPropertiesFormGroup) { + + + + + +
    + @switch (editingForm.control.get('type')?.value) { + @case ('textarea') { + + } + @case ('string') { + + } + @case ('number') { + + } + @case ('url') { + + } + @case ('password') { + + } + @case ('checkbox') { + + } + } + + @for (item of parent.propertyTypes; track item) { + + } + +
    + + @if (mode === 'create') { + N/A + } + + + + + }
    -
    + } - + @if (dependenciesFormArray.controls?.length || mode !== 'view') {

    Dependencies

    @@ -391,64 +447,76 @@

    Dependencies

    Artifact Exclude - Action + @if (mode !== 'view') { + Action + } - - + @for (control of dependenciesFormArray.controls; track control; let i = $index) { + + @if (mode !== 'view') { + + + + + + + + + + } @else { + {{ control.get('groupArtifactVersion')?.value || '' }} + {{ control.get('exclusions')?.value || '' }} + } + + } + @if (mode !== 'view' && editingDependenceFormGroup) { + - + - + - - - - {{ control.get('groupArtifactVersion')?.value || '' }} - {{ control.get('exclusions')?.value || '' }} - - - - - - - - - - - - - + + }
    -
    + } - + @if (mode !== 'view') { + + } diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts index 4bd5c533bfe..15e10e7e12d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts @@ -13,9 +13,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; import { AbstractControl, - FormArray, - FormBuilder, - FormGroup, + UntypedFormArray, + UntypedFormBuilder, + UntypedFormGroup, ValidationErrors, Validators, ValidatorFn @@ -31,18 +31,19 @@ import { InterpreterComponent } from '../interpreter.component'; selector: 'zeppelin-interpreter-item', templateUrl: './item.component.html', styleUrls: ['./item.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class InterpreterItemComponent extends DestroyHookComponent implements OnInit, OnDestroy { @Input() mode: 'create' | 'view' | 'edit' = 'view'; @Input() interpreter?: Interpreter; - formGroup!: FormGroup; - optionFormGroup!: FormGroup; - editingPropertiesFormGroup?: FormGroup; - editingDependenceFormGroup?: FormGroup; - propertiesFormArray!: FormArray; - dependenciesFormArray!: FormArray; + formGroup!: UntypedFormGroup; + optionFormGroup!: UntypedFormGroup; + editingPropertiesFormGroup?: UntypedFormGroup; + editingDependenceFormGroup?: UntypedFormGroup; + propertiesFormArray!: UntypedFormArray; + dependenciesFormArray!: UntypedFormArray; userList$?: Observable; userSearchChange$: BehaviorSubject | null = new BehaviorSubject(''); runningOptionMap = { @@ -412,7 +413,7 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On public ticketService: TicketService, private securityService: SecurityService, private interpreterService: InterpreterService, - private formBuilder: FormBuilder, + private formBuilder: UntypedFormBuilder, private cdr: ChangeDetectorRef ) { super(); diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html index c4cdb694aa7..30188ad286d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> @@ -30,7 +30,9 @@ - + @for (item of interpreters; track item) { + + } @@ -38,7 +40,9 @@ Sort - + @for (item of sortKeys; track item) { + + } @@ -50,38 +54,39 @@ - + @for (item of jobStatusKeys; track item) { + + }
    - - - - - - - - - - - + @switch (status) { + @case ('loading') { + + + + } + @case ('success') { + @for (item of filteredJobs; track item) { + + } + @if (filteredJobs.length === 0) { + + } + } + @case ('disabled') { - - + } + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts index 7762ce40690..497a1c2a31f 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.component.ts @@ -11,7 +11,7 @@ */ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { NzModalService } from 'ng-zorro-antd/modal'; @@ -34,10 +34,11 @@ interface FilterForm { selector: 'zeppelin-job-manager', templateUrl: './job-manager.component.html', styleUrls: ['./job-manager.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class JobManagerComponent extends MessageListenersManager implements OnDestroy { - form: FormGroup; + form: UntypedFormGroup; jobStatusKeys: JobStatus[] = Object.values(JobStatus); sortKeys: JobDateSortKeys[] = Object.values(JobDateSortKeys); interpreters: string[] = []; @@ -118,7 +119,7 @@ export class JobManagerComponent extends MessageListenersManager implements OnDe constructor( public messageService: MessageService, private jobManagerService: JobManagerService, - private fb: FormBuilder, + private fb: UntypedFormBuilder, private cdr: ChangeDetectorRef, private nzModalService: NzModalService ) { diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts index 349c98d9367..4c4f62f896c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-manager.module.ts @@ -19,7 +19,7 @@ import { ClockCircleOutline, FileOutline, FileUnknownOutline, SearchOutline } fr import { NzAlertModule } from 'ng-zorro-antd/alert'; import { NzBadgeModule } from 'ng-zorro-antd/badge'; import { NzCardModule } from 'ng-zorro-antd/card'; -import { NzHighlightModule } from 'ng-zorro-antd/core/highlight'; +import { NzHighlightPipe } from 'ng-zorro-antd/core/highlight'; import { NzDividerModule } from 'ng-zorro-antd/divider'; import { NzEmptyModule } from 'ng-zorro-antd/empty'; import { NzFormModule } from 'ng-zorro-antd/form'; @@ -30,7 +30,7 @@ import { NzModalModule } from 'ng-zorro-antd/modal'; import { NzProgressModule } from 'ng-zorro-antd/progress'; import { NzSelectModule } from 'ng-zorro-antd/select'; import { NzSkeletonModule } from 'ng-zorro-antd/skeleton'; -import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTooltipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; @@ -47,7 +47,7 @@ const icons: IconDefinition[] = [SearchOutline, FileOutline, FileUnknownOutline, CommonModule, FormsModule, ReactiveFormsModule, - NzHighlightModule, + NzHighlightPipe, ShareModule, NzIconModule, NzInputModule, @@ -61,7 +61,7 @@ const icons: IconDefinition[] = [SearchOutline, FileOutline, FileUnknownOutline, JobManagerRoutingModule, NzDividerModule, NzCardModule, - NzToolTipModule, + NzTooltipModule, NzProgressModule, NzSkeletonModule, NzEmptyModule, diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts index 104081ca00d..bb997809641 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job-status/job-status.component.ts @@ -18,7 +18,8 @@ import { JobStatus } from '@zeppelin/sdk'; selector: 'zeppelin-job-manager-job-status', templateUrl: './job-status.component.html', styleUrls: ['./job-status.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class JobManagerJobStatusComponent { @Input() status!: JobStatus; diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html index 5a6ce7022ef..508bddbdc87 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    @@ -24,7 +24,9 @@ {{ relativeTime }} {{ note.isRunningJob ? 'RUNNING' : 'READY' }} - {{ progress | percent: '1.0-0' }} + @if (note.isRunningJob) { + {{ progress | percent: '1.0-0' }} + }
    - - - + @for (item of note.paragraphs; track item) { + + + + }
    - +@if (note.isRunningJob) { + +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts index 2724ef5c9fd..c656f286466 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/job-manager/job/job.component.ts @@ -29,7 +29,8 @@ import { JobsItem, JobStatus } from '@zeppelin/sdk'; selector: 'zeppelin-job-manager-job', templateUrl: './job.component.html', styleUrls: ['./job.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class JobManagerJobComponent implements OnInit, OnChanges { @Input() note!: JobsItem; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html index 0ba8522a452..58dd6a2af91 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.html @@ -1,33 +1,37 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> -
    - -
    -
    - - -
    + @if (!editMode) { +
    + +
    + } + @if (editMode) { +
    + + +
    + }

    Setting

    @@ -39,21 +43,28 @@

    Setting

    - - {{ setting.name }} - - {{ setting.selected }} - - - - - - - - - - - + @for (setting of repo.settings; track setting; let i = $index) { + + {{ setting.name }} + @if (!editMode) { + {{ setting.selected }} + } + @if (editMode) { + + @if (setting.type === 'INPUT') { + + } + @if (setting.type === 'DROPDOWN') { + + @for (option of setting.value; track option) { + + } + + } + + } + + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts index 5dc628190d8..ee578424d38 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/item/item.component.ts @@ -19,25 +19,26 @@ import { Output, SimpleChanges } from '@angular/core'; -import { FormArray, FormBuilder, FormControl, Validators } from '@angular/forms'; +import { UntypedFormArray, UntypedFormBuilder, UntypedFormControl, Validators } from '@angular/forms'; import { NotebookRepo } from '@zeppelin/interfaces'; @Component({ selector: 'zeppelin-notebook-repo-item', templateUrl: './item.component.html', styleUrls: ['./item.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookRepoItemComponent implements OnChanges { @Input() repo!: NotebookRepo; @Output() readonly repoChange = new EventEmitter(); - settingFormArray: FormArray; + settingFormArray: UntypedFormArray; editMode = false; constructor( private cdr: ChangeDetectorRef, - private fb: FormBuilder + private fb: UntypedFormBuilder ) { // Initialize an empty form array to avoid undefined type error in the template this.settingFormArray = this.fb.array([]); @@ -74,8 +75,8 @@ export class NotebookRepoItemComponent implements OnChanges { this.settingFormArray = this.fb.array(controls); } - getSettingControl(index: number): FormControl { - return this.settingFormArray.at(index) as FormControl; + getSettingControl(index: number): UntypedFormControl { + return this.settingFormArray.at(index) as UntypedFormControl; } ngOnChanges(changes: SimpleChanges): void { diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html index 833b68433b7..b3d37908e4c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.html @@ -1,20 +1,18 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> Manage your Notebook Repositories' settings.
    - + @for (repo of repositories; track repo) { + + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts index bc7d57fc4e8..afe62b26f38 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-repos/notebook-repos.component.ts @@ -17,7 +17,8 @@ import { NotebookRepoService } from '@zeppelin/services'; selector: 'zeppelin-notebook-repos', templateUrl: './notebook-repos.component.html', styleUrls: ['./notebook-repos.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookReposComponent implements OnInit { repositories: NotebookRepo[] = []; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html index 3e1612a1e0f..1e3d29ded8e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.html @@ -1,23 +1,24 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    - + @for (item of results; track item) { + + } -
    - - We couldn't find any notebook matching - '{{ searchTerm }}' -
    + @if (hasNoResults) { +
    + + We couldn't find any notebook matching + '{{ searchTerm }}' +
    + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts index dc46efa31f3..7cbd8d0ec4a 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts @@ -21,10 +21,11 @@ import { filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; selector: 'zeppelin-notebook-search', templateUrl: './notebook-search.component.html', styleUrls: ['./notebook-search.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookSearchComponent implements OnInit, OnDestroy { - private destroy$ = new Subject(); + private destroy$ = new Subject(); private searchAction$ = this.router.params.pipe( takeUntil(this.destroy$), map(params => params.queryStr), diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts index 1c8e10545ed..eb8a3cb5f81 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts @@ -18,7 +18,8 @@ import { NotebookSearchResultItem } from '@zeppelin/interfaces'; selector: 'zeppelin-notebook-search-result-item', templateUrl: './result-item.component.html', styleUrls: ['./result-item.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookSearchResultItemComponent implements OnChanges { @Input() result!: NotebookSearchResultItem; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html index 54f4e46853b..b829227fd93 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    @@ -21,7 +21,7 @@ >
    - + - - - - - - - - + @if (!viewOnly) { + + } + @if (!viewOnly) { + + } + @if (!viewOnly) { + + } + @if (!viewOnly) { + + } + @if (!viewOnly) { + + } + @if (!viewOnly) { + + } + @if (principal && principal !== 'anonymous' && !viewOnly) { + @switch (note.config.personalizedMode) { + @case ('true') { + + } + @default { + + } + } + } + + @if (isRevisionSupported) { + + @if (!viewOnly) { + } + + + + + + + + + @if (!viewOnly) { - - - - - - - - - - - - - - - - - -
      -
    • - {{ r.message }} - - - {{ r.time === undefined ? 'Current' : (r.time * 1000 | date: 'MMMM dd yyyy, h:mm:ss a') }} - -
    • -
    -
    -
    - + } + + + +
      + @for (r of noteRevisions; track r) { +
    • + {{ r.message }} + + + {{ r.time === undefined ? 'Current' : (r.time * 1000 | date: 'MMMM dd yyyy, h:mm:ss a') }} + +
    • + } +
    +
    + + } + -
    +
    - + - +
    - - - - - - - - - - - -
    - Run note with cron scheduler. Either choose from preset or write your own - + @if (!viewOnly) { + + @if (isTrash) { + + } + @if (!isTrash) { + + } + + } + @if (collaborativeMode) { + + + + } + @if (note.config.isZeppelinNotebookCronEnable && !viewOnly) { + + + +
    + Run note with cron scheduler. Either choose from preset or write your own - {{ cr.name }} + cron expression + . +
    + - Preset + @for (cr of cronOption; track cr) { + + {{ cr.name }} + + } +
    +
    + - Preset + + @if (note.info.cron) { +

    + {{ note.info.cron }} +

    + } +
    +
    + +
    -
    - - Preset - -

    - {{ note.info.cron }} -

    -
    -
    - -
    -
    -
    -
    + + + }
    - - - + + @if (!revisionView) { + + } + @if (!revisionView) { + + } @@ -319,9 +336,11 @@
      -
    • {{ lf }}
    • + @for (lf of lfOption; track lf) { +
    • {{ lf }}
    • + }
    -
    +
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less index e7c7fc69cce..698c17878fd 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.less @@ -92,7 +92,7 @@ .control { float: left; - nz-button-group { + nz-space-compact { margin-right: 24px; &:last-child { @@ -151,7 +151,7 @@ } } - nz-input-group + nz-button-group { + nz-input-group + nz-space-compact { margin-left: -1px; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts index 507a08e76ed..96ee1774e04 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts @@ -43,7 +43,8 @@ import { NoteCreateComponent, ShortcutComponent } from '@zeppelin/share'; selector: 'zeppelin-notebook-action-bar', templateUrl: './action-bar.component.html', styleUrls: ['./action-bar.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookActionBarComponent extends MessageListenersManager implements OnInit { @Input() note!: Exclude; @@ -190,7 +191,7 @@ export class NotebookActionBarComponent extends MessageListenersManager implemen this.nzModalService.create({ nzTitle: 'Clone Note', nzContent: NoteCreateComponent, - nzComponentParams: { + nzData: { cloneNote: this.note }, nzFooter: null diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts index bb77a832979..76a3d8c73a9 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/add-paragraph/add-paragraph.component.ts @@ -16,7 +16,8 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output selector: 'zeppelin-notebook-add-paragraph', templateUrl: './add-paragraph.component.html', styleUrls: ['./add-paragraph.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookAddParagraphComponent implements OnInit { @Output() readonly addParagraph = new EventEmitter(); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html index b01baa43d63..86595cc27e0 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    @@ -27,26 +27,40 @@

    Interpreter binding

    -
    - - - -
    - + @for (item of interpreterBindings; track item; let pFirst = $first) { +
    + + + +
    + +
    -
    + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts index 7f1cc8e1def..a050a9ca811 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/interpreter-binding/interpreter-binding.component.ts @@ -22,7 +22,8 @@ import { InterpreterService, MessageService } from '@zeppelin/services'; selector: 'zeppelin-notebook-interpreter-binding', templateUrl: './interpreter-binding.component.html', styleUrls: ['./interpreter-binding.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookInterpreterBindingComponent { private restarting = false; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts index c0d498a767a..e7c31fb4b6d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/note-form-block/note-form-block.component.ts @@ -16,7 +16,8 @@ import { DynamicForms, DynamicFormsItem, DynamicFormParams } from '@zeppelin/sdk selector: 'zeppelin-note-form-block', templateUrl: './note-form-block.component.html', styleUrls: ['./note-form-block.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NoteFormBlockComponent implements OnInit { @Input() noteTitle: string | undefined; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html index 18fd2f965e5..20a45920771 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -1,103 +1,116 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> -
    - -
    - -
    -
    - - - +@if (note) { +
    + +
    + -
    - -
    - +
    + @if (activatedExtension !== 'hide' && permissions) { +
    + @switch (activatedExtension) { + @case ('interpreter') { + + } + @case ('permissions') { + + } + @case ('revisions') { + + } + } +
    + } +
    + @if (isShowNoteForms) { + + } +
    + @for (p of note.paragraphs; track p; let first = $first; let last = $last; let i = $index) { + + } +
    -
    +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 6656945188a..7d86a019326 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -54,11 +54,12 @@ import { NotebookParagraphComponent } from './paragraph/paragraph.component'; selector: 'zeppelin-notebook', templateUrl: './notebook.component.html', styleUrls: ['./notebook.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookComponent extends MessageListenersManager implements OnInit, OnDestroy { @ViewChildren(NotebookParagraphComponent) listOfNotebookParagraphComponent!: QueryList; - private destroy$ = new Subject(); + private destroy$ = new Subject(); note?: Exclude; permissions?: Permissions; selectId: string | null = null; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts index 62899c39b5d..bb37b03b160 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts @@ -19,7 +19,7 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { NzButtonModule } from 'ng-zorro-antd/button'; import { NzCheckboxModule } from 'ng-zorro-antd/checkbox'; import { NzCodeEditorModule } from 'ng-zorro-antd/code-editor'; -import { NzNoAnimationModule } from 'ng-zorro-antd/core/no-animation'; +import { NzNoAnimationModule } from 'ng-zorro-antd/core/animation'; import { NzDividerModule } from 'ng-zorro-antd/divider'; import { NzDropDownModule } from 'ng-zorro-antd/dropdown'; import { NzFormModule } from 'ng-zorro-antd/form'; @@ -32,10 +32,11 @@ import { NzProgressModule } from 'ng-zorro-antd/progress'; import { NzRadioModule } from 'ng-zorro-antd/radio'; import { NzResizableModule } from 'ng-zorro-antd/resizable'; import { NzSelectModule } from 'ng-zorro-antd/select'; +import { NzSpaceModule } from 'ng-zorro-antd/space'; import { NzSwitchModule } from 'ng-zorro-antd/switch'; import { NzTableModule } from 'ng-zorro-antd/table'; import { NzTagModule } from 'ng-zorro-antd/tag'; -import { NzToolTipModule } from 'ng-zorro-antd/tooltip'; +import { NzTooltipModule } from 'ng-zorro-antd/tooltip'; import { ShareModule } from '@zeppelin/share'; @@ -84,7 +85,7 @@ import { NotebookSidebarComponent } from './sidebar/sidebar.component'; NzIconModule, NzDropDownModule, NzNoAnimationModule, - NzToolTipModule, + NzTooltipModule, NzPopconfirmModule, NzFormModule, NzPopoverModule, @@ -102,7 +103,8 @@ import { NotebookSidebarComponent } from './sidebar/sidebar.component'; NzCheckboxModule, NzResizableModule, NzTableModule, - NzTagModule + NzTagModule, + NzSpaceModule ] }) export class NotebookModule {} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index 27d39a13470..c212de77cf7 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -40,7 +40,8 @@ type DecorationIdentifier = ReturnType +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> - +@if (runtimeInfos && runtimeInfos.jobUrl) { + +}
    {{ status }}
    -
    {{ progress }}%
    - +@if (status === 'RUNNING') { +
    {{ progress }}%
    +} +@if (!revisionView) { - - + @if (status !== 'RUNNING' && status !== 'PENDING' && enabled) { + + } + @if (status === 'RUNNING' || status === 'PENDING') { + + } @@ -63,19 +69,21 @@ {{ pid }}
  • -
  • - - - Run on selection change - - - - -
  • + @if (runOnSelectionChange === true || runOnSelectionChange === false) { +
  • + + + Run on selection change + + + + +
  • + }
  • @@ -83,7 +91,9 @@
  • @@ -94,19 +104,23 @@ - -
  • - - - {{ menu.label }} - - {{ menu.shortCut }} -
  • -
    + @for (menu of listOfMenu; track menu) { + @if (menu.show) { +
  • + + + {{ menu.label }} + + {{ menu.shortCut }} +
  • + } + } -
    +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index 53576cba2f9..c54da56058d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -34,7 +34,8 @@ import { MessageService } from '@zeppelin/services'; exportAs: 'paragraphControl', templateUrl: './control.component.html', styleUrls: ['./control.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookParagraphControlComponent implements OnInit, OnChanges { @Input() status!: string; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html index fe5dbfb6afa..3b7e265b3b2 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.html @@ -1,16 +1,20 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts index c6298004b9c..6495742e26d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts @@ -18,7 +18,8 @@ import { format, formatDistanceStrict, formatDistanceToNow } from 'date-fns'; selector: 'zeppelin-notebook-paragraph-footer', templateUrl: './footer.component.html', styleUrls: ['./footer.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookParagraphFooterComponent implements OnChanges { @Input() dateStarted?: string; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html index 10917cc7999..579546a02f9 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -1,127 +1,133 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> -
    - -
    - - - - - - - - - +@if (paragraph) { +
    + @if (!revisionView && looknfeel !== 'report') { + + } +
    + @if (paragraph.config.title) { + + } + + @if (!paragraph.config.editorHide && !viewOnly) { + + } + @if (paragraph.status === 'RUNNING') { + + } + @if (!paragraph.config.tableHide) { + + @for (result of results; track trackByIndexFn(i); let i = $index) { + + } + } + +
    + @if (!viewOnly && !revisionView && last && looknfeel !== 'report') { + + }
    - -
    +} diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index 56a9d4c7f95..d55b94efc2c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -70,7 +70,8 @@ type Mode = 'edit' | 'command'; selector: 'zeppelin-notebook-paragraph', templateUrl: './paragraph.component.html', styleUrls: ['./paragraph.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookParagraphComponent extends ParagraphBase @@ -99,7 +100,7 @@ export class NotebookParagraphComponent @Output() readonly selectAtIndex = new EventEmitter(); @Output() readonly openSearchMenu = new EventEmitter(); - private destroy$ = new Subject(); + private destroy$ = new Subject(); private mode: Mode = 'command'; waitConfirmFromEdit = false; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts index ce205a0ad59..73b5a824617 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/progress/progress.component.ts @@ -16,7 +16,8 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/c selector: 'zeppelin-notebook-paragraph-progress', templateUrl: './progress.component.html', styleUrls: ['./progress.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookParagraphProgressComponent implements OnChanges { @Input() progress = 0; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html index bd8798a808b..37595eabb3d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    @@ -35,10 +35,16 @@

    Note Permissions (Only note owners can change)

    nzMode="multiple" name="owners" > - - - - + @for (item of permissions.owners; track item) { + + } + @for (item of listOfUserAndRole; track item) { + + @for (o of item.children; track o) { + + } + + } @@ -56,10 +62,16 @@

    Note Permissions (Only note owners can change)

    nzMode="multiple" name="writers" > - - - - + @for (item of permissions.writers; track item) { + + } + @for (item of listOfUserAndRole; track item) { + + @for (o of item.children; track o) { + + } + + }
    @@ -77,10 +89,16 @@

    Note Permissions (Only note owners can change)

    nzMode="multiple" name="runners" > - - - - + @for (item of permissions.runners; track item) { + + } + @for (item of listOfUserAndRole; track item) { + + @for (o of item.children; track o) { + + } + + }
    @@ -98,10 +116,16 @@

    Note Permissions (Only note owners can change)

    nzMode="multiple" name="readers" > - - - - + @for (item of permissions.readers; track item) { + + } + @for (item of listOfUserAndRole; track item) { + + @for (o of item.children; track o) { + + } + + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts index 3160b749ab1..f6015e09b31 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/permissions/permissions.component.ts @@ -31,7 +31,8 @@ import { SecurityService, TicketService } from '@zeppelin/services'; selector: 'zeppelin-notebook-permissions', templateUrl: './permissions.component.html', styleUrls: ['./permissions.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class NotebookPermissionsComponent implements OnInit, OnChanges { @Input() permissions!: Permissions; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html index 17dda5a0ffd..640efea58df 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    @@ -27,71 +27,87 @@ - - {{ revision.message }} - {{ formatRevisionDate(revision.time) }} - + @for (revision of revisionTable.data; track revision; let i = $index; let last = $last) { + + {{ revision.message }} + {{ formatRevisionDate(revision.time) }} + + }
    - - - + @if (noteRevisions.length > 0) { + + @for (revision of sortedRevisions; track revision) { + + } + + } compare with - - - + @if (noteRevisions.length > 0) { + + @for (revision of sortedRevisions; track revision) { + + } + + }
    -
    -
    - {{ p.paragraph.id }} - ({{ p.paragraph.title }}) - added - deleted - differences - identical - {{ p.firstString }} + @for (p of mergeNoteRevisionsDiff; track p) { +
    +
    + {{ p.paragraph.id }} + @if (p.paragraph.title) { + ({{ p.paragraph.title }}) + } + @if (p.type === 'added') { + added + } + @if (p.type === 'deleted') { + deleted + } + @if (p.type === 'compared' && !p.identical) { + differences + } + @if (p.type === 'compared' && p.identical) { + identical + } + {{ p.firstString }} +
    -
    -
    - Please select a revision -
    + } + @if (currentSecondRevisionLabel === 'Choose...') { +
    Please select a revision
    + }
    @@ -101,20 +117,25 @@ Revision: {{ currentFirstRevisionLabel }} --> {{ currentSecondRevisionLabel }} -
    {{
    -      currentParagraphDiffDisplay?.paragraph?.text
    -    }}
    -
    {{
    -      currentParagraphDiffDisplay?.paragraph?.text
    -    }}
    -
    {{ seg.text }}
    -
    -      
    Nothing to display
    -
    + @if (currentParagraphDiffDisplay?.type === 'added') { +
    {{ currentParagraphDiffDisplay?.paragraph?.text }}
    + } + @if (currentParagraphDiffDisplay?.type === 'deleted') { +
    {{ currentParagraphDiffDisplay?.paragraph?.text }}
    + } + @if (currentParagraphDiffDisplay?.type === 'compared') { +
    @for (seg of currentParagraphDiffDisplay?.segments; track seg) {
    +        {{ seg.text }}
    +      }
    + } + @if (currentParagraphDiffDisplay === null) { +
    +        
    Nothing to display
    +
    + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts index 3b45e77d44d..b29f42dad5e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/revisions-comparator/revisions-comparator.component.ts @@ -36,7 +36,8 @@ interface MergedParagraphDiff { templateUrl: './revisions-comparator.component.html', styleUrls: ['./revisions-comparator.component.less'], changeDetection: ChangeDetectionStrategy.OnPush, - providers: [DatePipe] + providers: [DatePipe], + standalone: false }) export class NotebookRevisionsComparatorComponent implements OnInit, OnDestroy { @Input() noteRevisions: RevisionListItem[] = []; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html index 4311075f5fc..26ecfba7b4e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.html @@ -1,25 +1,28 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +-->
    - -

    {{ value || defaultTitle }}

    + @if (showEditor) { + + } + @if (!showEditor) { +

    {{ value || defaultTitle }}

    + }
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts index 7b23e50f04e..f115d541221 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/share/elastic-input/elastic-input.component.ts @@ -27,7 +27,8 @@ import { selector: 'zeppelin-elastic-input', templateUrl: './elastic-input.component.html', styleUrls: ['./elastic-input.component.less'], - changeDetection: ChangeDetectionStrategy.OnPush + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: false }) export class ElasticInputComponent implements OnChanges { @Input() value?: string; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html index fde35656973..d77084ec305 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/sidebar/sidebar.component.html @@ -1,14 +1,14 @@ +~ Licensed under the Apache License, Version 2.0 (the "License"); +~ you may not use this file except in compliance with the License. +~ You may obtain a copy of the License at +~ http://www.apache.org/licenses/LICENSE-2.0 +~ Unless required by applicable law or agreed to in writing, software +~ distributed under the License is distributed on an "AS IS" BASIS, +~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +~ See the License for the specific language governing permissions and +~ limitations under the License. +--> @@ -241,8 +247,8 @@ class="fa fa-close" ng-click="removeGroup($index)" style="margin-left: 5px; cursor: pointer; color: #999" - onmouseover="this.style.color='#d9534f';" - onmouseout="this.style.color='#999';" + onmouseover="this.style.color = '#d9534f'" + onmouseout="this.style.color = '#999'" >
    @@ -326,7 +332,11 @@ " type="button" data-toggle="dropdown" - onclick="var menu = this.nextElementSibling; menu.style.display = menu.style.display === 'block' ? 'none' : 'block'; event.stopPropagation();" + onclick=" + var menu = this.nextElementSibling; + menu.style.display = menu.style.display === 'block' ? 'none' : 'block'; + event.stopPropagation(); + " > {{item.name | limitTo: 30}}{{item.name.length > 30 ? '...' : ''}} {{item.aggr}} @@ -334,8 +344,8 @@ class="fa fa-close" ng-click="removeValue($index); $event.stopPropagation();" style="margin-left: 5px; cursor: pointer; color: #999" - onmouseover="this.style.color='#d9534f';" - onmouseout="this.style.color='#999';" + onmouseover="this.style.color = '#d9534f'" + onmouseout="this.style.color = '#999'" >
    • sum
    • count
    • avg
    • min
    • max
    • diff --git a/zeppelin-web-angular/src/main.ts b/zeppelin-web-angular/src/main.ts index 81b410d13ed..ac3d63422f3 100644 --- a/zeppelin-web-angular/src/main.ts +++ b/zeppelin-web-angular/src/main.ts @@ -10,7 +10,7 @@ * limitations under the License. */ -import { enableProdMode } from '@angular/core'; +import { enableProdMode, provideZoneChangeDetection } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; @@ -21,5 +21,5 @@ if (environment.production) { } platformBrowserDynamic() - .bootstrapModule(AppModule) + .bootstrapModule(AppModule, { applicationProviders: [provideZoneChangeDetection()] }) .catch(err => console.error(err)); diff --git a/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css b/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css index df1106ec293..9568b0d7b75 100644 --- a/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css +++ b/zeppelin-web-angular/src/styles/theme/dark-theme-overrides.css @@ -63,7 +63,6 @@ .ant-space, .search { transition: none !important; - animation: none !important; } .ant-btn *, @@ -118,7 +117,6 @@ .ant-space *, .search * { transition: none !important; - animation: none !important; } /* Special handling for search area */ @@ -127,7 +125,6 @@ .search .ant-input, .search input { transition: none !important; - animation: none !important; } .search:hover, @@ -143,7 +140,6 @@ .search input:focus, .search input:active { transition: none !important; - animation: none !important; } /* Prevent dark mode dropdown menu flickering */ @@ -155,7 +151,6 @@ html.dark .ant-menu-submenu-title { background-color: #1f1f1f !important; color: rgba(255, 255, 255, 0.85) !important; transition: none !important; - animation: none !important; } html.dark .ant-dropdown-menu-item:hover, diff --git a/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less b/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less index b5575268bc6..34a1496f9c2 100644 --- a/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less +++ b/zeppelin-web-angular/src/styles/theme/dark/theme-dark.less @@ -30,18 +30,18 @@ // Color used by default to control hover and active backgrounds and for // alert info backgrounds. -@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) -@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) -@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused -@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-1: color(colorPalette('@{primary-color}', 1)); // replace tint(@primary-color, 90%) +@primary-2: color(colorPalette('@{primary-color}', 2)); // replace tint(@primary-color, 80%) +@primary-3: color(colorPalette('@{primary-color}', 3)); // unused +@primary-4: color(colorPalette('@{primary-color}', 4)); // unused @primary-5: color( - ~`colorPalette('@{primary-color}', 5) ` + colorPalette('@{primary-color}', 5) ); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) @primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color -@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) -@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused -@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused -@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused +@primary-7: color(colorPalette('@{primary-color}', 7)); // replace shade(@primary-color, 5%) +@primary-8: color(colorPalette('@{primary-color}', 8)); // unused +@primary-9: color(colorPalette('@{primary-color}', 9)); // unused +@primary-10: color(colorPalette('@{primary-color}', 10)); // unused // Base Scaffolding Variables // --- @@ -97,8 +97,8 @@ // LINK @link-color: @primary-color; -@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); -@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-hover-color: color(colorPalette('@{link-color}', 5)); +@link-active-color: color(colorPalette('@{link-color}', 7)); @link-decoration: none; @link-hover-decoration: none; @@ -620,17 +620,17 @@ // Alert // --- -@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; -@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-border-color: colorPalette('@{success-color}', 3); +@alert-success-bg-color: colorPalette('@{success-color}', 1); @alert-success-icon-color: @success-color; -@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; -@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-border-color: colorPalette('@{info-color}', 3); +@alert-info-bg-color: colorPalette('@{info-color}', 1); @alert-info-icon-color: @info-color; -@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; -@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-border-color: colorPalette('@{warning-color}', 3); +@alert-warning-bg-color: colorPalette('@{warning-color}', 1); @alert-warning-icon-color: @warning-color; -@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; -@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-border-color: colorPalette('@{error-color}', 3); +@alert-error-bg-color: colorPalette('@{error-color}', 1); @alert-error-icon-color: @error-color; // List diff --git a/zeppelin-web-angular/src/styles/theme/light/theme-light.less b/zeppelin-web-angular/src/styles/theme/light/theme-light.less index 72b28bda961..38bd04cb7cb 100644 --- a/zeppelin-web-angular/src/styles/theme/light/theme-light.less +++ b/zeppelin-web-angular/src/styles/theme/light/theme-light.less @@ -30,18 +30,18 @@ // Color used by default to control hover and active backgrounds and for // alert info backgrounds. -@primary-1: color(~`colorPalette('@{primary-color}', 1) `); // replace tint(@primary-color, 90%) -@primary-2: color(~`colorPalette('@{primary-color}', 2) `); // replace tint(@primary-color, 80%) -@primary-3: color(~`colorPalette('@{primary-color}', 3) `); // unused -@primary-4: color(~`colorPalette('@{primary-color}', 4) `); // unused +@primary-1: color(colorPalette('@{primary-color}', 1)); // replace tint(@primary-color, 90%) +@primary-2: color(colorPalette('@{primary-color}', 2)); // replace tint(@primary-color, 80%) +@primary-3: color(colorPalette('@{primary-color}', 3)); // unused +@primary-4: color(colorPalette('@{primary-color}', 4)); // unused @primary-5: color( - ~`colorPalette('@{primary-color}', 5) ` + colorPalette('@{primary-color}', 5) ); // color used to control the text color in many active and hover states, replace tint(@primary-color, 20%) @primary-6: @primary-color; // color used to control the text color of active buttons, don't use, use @primary-color -@primary-7: color(~`colorPalette('@{primary-color}', 7) `); // replace shade(@primary-color, 5%) -@primary-8: color(~`colorPalette('@{primary-color}', 8) `); // unused -@primary-9: color(~`colorPalette('@{primary-color}', 9) `); // unused -@primary-10: color(~`colorPalette('@{primary-color}', 10) `); // unused +@primary-7: color(colorPalette('@{primary-color}', 7)); // replace shade(@primary-color, 5%) +@primary-8: color(colorPalette('@{primary-color}', 8)); // unused +@primary-9: color(colorPalette('@{primary-color}', 9)); // unused +@primary-10: color(colorPalette('@{primary-color}', 10)); // unused // Base Scaffolding Variables // --- @@ -97,8 +97,8 @@ // LINK @link-color: @primary-color; -@link-hover-color: color(~`colorPalette('@{link-color}', 5) `); -@link-active-color: color(~`colorPalette('@{link-color}', 7) `); +@link-hover-color: color(colorPalette('@{link-color}', 5)); +@link-active-color: color(colorPalette('@{link-color}', 7)); @link-decoration: none; @link-hover-decoration: none; @@ -620,17 +620,17 @@ // Alert // --- -@alert-success-border-color: ~`colorPalette('@{success-color}', 3) `; -@alert-success-bg-color: ~`colorPalette('@{success-color}', 1) `; +@alert-success-border-color: colorPalette('@{success-color}', 3); +@alert-success-bg-color: colorPalette('@{success-color}', 1); @alert-success-icon-color: @success-color; -@alert-info-border-color: ~`colorPalette('@{info-color}', 3) `; -@alert-info-bg-color: ~`colorPalette('@{info-color}', 1) `; +@alert-info-border-color: colorPalette('@{info-color}', 3); +@alert-info-bg-color: colorPalette('@{info-color}', 1); @alert-info-icon-color: @info-color; -@alert-warning-border-color: ~`colorPalette('@{warning-color}', 3) `; -@alert-warning-bg-color: ~`colorPalette('@{warning-color}', 1) `; +@alert-warning-border-color: colorPalette('@{warning-color}', 3); +@alert-warning-bg-color: colorPalette('@{warning-color}', 1); @alert-warning-icon-color: @warning-color; -@alert-error-border-color: ~`colorPalette('@{error-color}', 3) `; -@alert-error-bg-color: ~`colorPalette('@{error-color}', 1) `; +@alert-error-border-color: colorPalette('@{error-color}', 3); +@alert-error-bg-color: colorPalette('@{error-color}', 1); @alert-error-icon-color: @error-color; // List diff --git a/zeppelin-web-angular/tsconfig.base.json b/zeppelin-web-angular/tsconfig.base.json index 7e6964461fb..7fee7c8e794 100644 --- a/zeppelin-web-angular/tsconfig.base.json +++ b/zeppelin-web-angular/tsconfig.base.json @@ -17,10 +17,10 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "module": "es2020", - "moduleResolution": "node", + "moduleResolution": "bundler", "skipLibCheck": true, "importHelpers": true, - "target": "es5", + "target": "es2020", "typeRoots": ["node_modules/@types"], "lib": ["es2018", "dom"] }, diff --git a/zeppelin-web-angular/webpack.config.js b/zeppelin-web-angular/webpack.config.js index 3f7e7436bc2..0e73411a6a1 100644 --- a/zeppelin-web-angular/webpack.config.js +++ b/zeppelin-web-angular/webpack.config.js @@ -14,42 +14,73 @@ const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); const webpack = require('@angular-devkit/build-angular/node_modules/webpack'); const ModuleFederationPlugin = webpack.container.ModuleFederationPlugin; -module.exports = { - output: { +const MONACO_DIR = /monaco-editor[\\/]/; + +module.exports = (config, options, targetOptions) => { + config.output = { + ...(config.output || {}), // Unique name for this microfrontend to avoid collisions with other apps uniqueName: 'shell', publicPath: '/', scriptType: 'text/javascript' - }, - optimization: { + }; + + config.optimization = { + ...(config.optimization || {}), // Disable runtime chunk to prevent conflicts with Module Federation's runtime runtimeChunk: false - }, - experiments: { + }; + + config.experiments = { + ...(config.experiments || {}), // Enable top-level await for async Module Federation container initialization topLevelAwait: true - }, + }; + // To avoid path conflict with websocket server path of ZeppelinServer - devServer: { + config.devServer = { + ...(config.devServer || {}), client: { - webSocketURL: { - pathname: '/wds-ws' - } + ...((config.devServer && config.devServer.client) || {}), + webSocketURL: { pathname: '/wds-ws' } }, webSocketServer: { type: 'ws', - options: { - path: '/wds-ws' - } + options: { path: '/wds-ws' } } - }, - plugins: [ + }; + + // monaco-editor imports `.css` files from its own JS modules. Angular 14's + // build-angular CSS pipeline (postcss + mini-css-extract) does not handle + // CSS requested from node_modules JS, and chaining style-loader on top of + // its rule produces a postcss collision. Exclude monaco from the existing + // CSS rules and add a dedicated rule that injects styles at runtime. + config.module = config.module || { rules: [] }; + config.module.rules = config.module.rules || []; + for (const rule of config.module.rules) { + if (!rule || !rule.test) continue; + const testStr = rule.test.toString(); + if (testStr.includes('css') || testStr.includes('CSS')) { + const existing = rule.exclude ? (Array.isArray(rule.exclude) ? rule.exclude : [rule.exclude]) : []; + rule.exclude = [...existing, MONACO_DIR]; + } + } + config.module.rules.push({ + test: /\.css$/, + include: MONACO_DIR, + use: ['style-loader', 'css-loader'] + }); + + config.plugins = config.plugins || []; + config.plugins.push( new ModuleFederationPlugin({ name: 'shell', remotes: { reactApp: 'reactApp@http://localhost:3001/remoteEntry.js' } - }), + }) + ); + config.plugins.push( new MonacoWebpackPlugin({ languages: [ 'bat', @@ -89,5 +120,7 @@ module.exports = { ], features: ['!accessibilityHelp'] }) - ] + ); + + return config; }; From 1d471c6c59a3fe0fc362619db21d48a8c874064f Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Wed, 3 Jun 2026 01:02:16 +0900 Subject: [PATCH 045/179] [ZEPPELIN-6423] Reload note when switching notebooks in the Angular UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Navigating between notes in the Angular UI changed the URL but left the page showing the previously opened note. The note fetch in `NotebookComponent` was bound only to the WebSocket `connectedStatus$` stream (introduced in ZEPPELIN-6387). Because Angular reuses `NotebookComponent` across `:noteId` route changes — so `ngOnInit` does not re-run — and the WebSocket stays connected, selecting another note from the header notebook list never re-fetched the note. The URL/route params updated, but `getNote()` was never called for the new `noteId`, so the page kept rendering the old note. This PR drives the fetch from a `combineLatest` of the connection status and the route params, so it fires on **both** a WebSocket (re)connect **and** a `noteId`/`revisionId` change. The reconnect-reload behavior from ZEPPELIN-6387 is preserved; `distinctUntilChanged` on the connection stream avoids a redundant fetch on init. ### What type of PR is it? Bug Fix ### Todos * [x] Re-fetch the note on `noteId`/`revisionId` route changes * [x] Preserve WebSocket reconnect-reload behavior * [x] Add e2e regression test ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6423 ### How should this be tested? * **Automated:** `zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts` opens one note, then navigates to a second note via the header "Notebook" dropdown and asserts the displayed note title (not just the URL) updates. Verified failing before the fix and passing after, against a live backend. * **Manual:** 1. Open a notebook. 2. From the header **Notebook** dropdown, click a different note. 3. The page content should switch to the newly selected note (previously it stayed on the old note while the URL changed). ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5259 from tbonelee/fix/notebook-reload-on-note-switch. Signed-off-by: ChanHo Lee --- .../notebook/main/notebook-navigation.spec.ts | 77 +++++++++++++++++++ .../workspace/notebook/notebook.component.ts | 46 ++++++----- 2 files changed, 103 insertions(+), 20 deletions(-) create mode 100644 zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts diff --git a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts new file mode 100644 index 00000000000..db259de8340 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts @@ -0,0 +1,77 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page, test } from '@playwright/test'; +import { HeaderPage } from '../../../models/header-page'; +import { HomePage } from '../../../models/home-page'; +import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; + +const noteIdFromUrl = (url: string): string => { + const match = url.match(/\/notebook\/([^/?]+)/); + if (!match) { + throw new Error(`Could not extract noteId from URL: ${url}`); + } + return match[1]; +}; + +const createRootNote = async (page: Page, homePage: HomePage, name: string): Promise => { + await page.goto('/#/'); + await waitForZeppelinReady(page); + await homePage.createNote(name); + await page.waitForURL(/\/notebook\//, { timeout: 45000 }); + return noteIdFromUrl(page.url()); +}; + +test.describe('Notebook Navigation', () => { + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); + + test.beforeEach(async ({ page }) => { + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + }); + + // Regression: ZEPPELIN-6387 moved the note fetch onto the WebSocket connectedStatus$ + // stream only. Because NotebookComponent is reused across :noteId param changes + // (ngOnInit does not re-run) and the socket stays connected, navigating between notes + // via the header list changed the URL but never re-fetched the note — the page kept + // showing the previous note. The fetch must also fire on route param changes. + test('Given the user is viewing a note, When they pick another note from the header list, Then the note content updates', async ({ + page + }) => { + const homePage = new HomePage(page); + const headerPage = new HeaderPage(page); + const stamp = Date.now(); + const nameA = `_e2e_nav_A_${stamp}`; + const nameB = `_e2e_nav_B_${stamp}`; + + // Create two distinct root-level notes. createNote lands on each new note's page. + const noteIdA = await createRootNote(page, homePage, nameA); + const noteIdB = await createRootNote(page, homePage, nameB); + + // We are now on note B (freshly mounted) — the URL and title must both reflect note B. + await expect(page).toHaveURL(new RegExp(`/notebook/${noteIdB}`)); + const title = page.locator('[data-testid="notebook-title"]'); + await expect(title).toContainText(nameB, { timeout: 15000 }); + + // In-app navigation to note A via the header notebook list — this reuses the + // already-mounted NotebookComponent, which is exactly what the regression broke. + await headerPage.clickNotebookMenu(); + const noteALink = page.locator(`a[href*="/notebook/${noteIdA}"]`).first(); + await noteALink.waitFor({ state: 'visible', timeout: 10000 }); + await noteALink.click(); + + // The URL changing alone never caught the bug — the content must change too. + await expect(page).toHaveURL(new RegExp(`/notebook/${noteIdA}`)); + await expect(title).toContainText(nameA, { timeout: 15000 }); + }); +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 7d86a019326..6905a5fc4e5 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -22,8 +22,8 @@ import { import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { isNil } from 'lodash'; -import { Subject } from 'rxjs'; -import { distinctUntilKeyChanged, startWith, takeUntil } from 'rxjs/operators'; +import { combineLatest, Subject } from 'rxjs'; +import { distinctUntilChanged, distinctUntilKeyChanged, startWith, takeUntil } from 'rxjs/operators'; import { NzResizeEvent } from 'ng-zorro-antd/resizable'; @@ -439,25 +439,31 @@ export class NotebookComponent extends MessageListenersManager implements OnInit }); this.revisionView = !!this.activatedRoute.snapshot.params.revisionId; - // Fetch note when WebSocket connects or reconnects - this.messageService.connectedStatus$ - .pipe(startWith(this.messageService.connectedStatus), takeUntil(this.destroy$)) - .subscribe(connected => { - console.log('connectedStatus$ changed to ', connected ? 'connected' : 'disconnected'); - if (connected) { - const { noteId, revisionId } = this.activatedRoute.snapshot.params; - if (!noteId) { - throw new Error('Route parameter `noteId` is required.'); - } - if (revisionId) { - this.messageService.noteRevision(noteId, revisionId); - } else { - this.messageService.getNote(noteId); - } - this.cdr.markForCheck(); - this.messageService.listRevisionHistory(noteId); - // TODO(hsuanxyz) scroll to current paragraph + // Fetch the note whenever the WebSocket (re)connects OR the route's noteId/revisionId changes. + // Navigating between notes reuses this component (ngOnInit does not re-run) and keeps the socket + // connected, so the fetch must be driven by route params too — connection status alone would + // leave the page showing the previously loaded note after navigation. + combineLatest([ + this.messageService.connectedStatus$.pipe(startWith(this.messageService.connectedStatus), distinctUntilChanged()), + this.activatedRoute.params + ]) + .pipe(takeUntil(this.destroy$)) + .subscribe(([connected, params]) => { + if (!connected) { + return; + } + const { noteId, revisionId } = params; + if (!noteId) { + throw new Error('Route parameter `noteId` is required.'); } + if (revisionId) { + this.messageService.noteRevision(noteId, revisionId); + } else { + this.messageService.getNote(noteId); + } + this.cdr.markForCheck(); + this.messageService.listRevisionHistory(noteId); + // TODO(hsuanxyz) scroll to current paragraph }); } From 4a551ed2c0f7ac7490fe10c89bb4554bd3dc49c6 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Wed, 3 Jun 2026 01:08:55 +0900 Subject: [PATCH 046/179] [ZEPPELIN-6421] Integrate zeppelin-react lint into root lint script ### What is this PR for? `zeppelin-react` has its own ESLint config with rules at `error` level (e.g. `typescript-eslint/no-explicit-any`, `react-hooks/exhaustive-deps`), but its lint script is not wired into the root `npm run lint` of `zeppelin-web-angular`. As a result, Maven's `npm lint` execution (`zeppelin-web-angular/pom.xml`) does not catch ESLint violations in `zeppelin-react`. ### What changes are proposed? Mirror the existing `build:react` pattern with `lint:react` / `lint:fix:react` scripts and include them in the root composite `lint` and `lint:fix` scripts. The `postinstall` hook already installs `projects/zeppelin-react/node_modules`, so no extra install step is needed. ### What type of PR is it? Improvement ### Todos * [x] - Update root lint scripts to include zeppelin-react ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6421 ### How should this be tested? Run `npm run lint` inside `zeppelin-web-angular/` and confirm that zeppelin-react ESLint errors are reported. ### Screenshots (if appropriate) N/A ### Questions: * Does the licenses files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5258 from tbonelee/ZEPPELIN-6421-lint-react. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/package.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 3d48881c831..aafb74bdc21 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -14,8 +14,10 @@ "build:projects": "npm run build-project:sdk && npm run build-project:vis", "build-project:sdk": "ng build --project zeppelin-sdk", "build-project:vis": "ng build --project zeppelin-visualization", - "lint": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint && prettier --check \"**/*.{ts,js,json,css,html}\"", - "lint:fix": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint --fix && prettier --write \"**/*.{ts,js,json,css,html}\"", + "lint": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint && npm run lint:react && prettier --check \"**/*.{ts,js,json,css,html}\"", + "lint:fix": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint --fix && npm run lint:fix:react && prettier --write \"**/*.{ts,js,json,css,html}\"", + "lint:react": "cd projects/zeppelin-react && npm run lint", + "lint:fix:react": "cd projects/zeppelin-react && npm run lint:fix", "e2e": "playwright test", "e2e:fast": "playwright test --project=chromium", "e2e:ui": "playwright test --ui", From 1bcd87198e94c1d46384775d0f22de665ee6e4b6 Mon Sep 17 00:00:00 2001 From: Manhua Date: Wed, 3 Jun 2026 13:19:20 +0800 Subject: [PATCH 047/179] [ZEPPELIN-6419] Fix clone paragraph content loss caused by shortCircuit seq filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? **Problem** When cloning a paragraph in zeppelin-web-angular, the cloned paragraph only contains the interpreter binding (e.g., %mysql) but not the actual editor content (e.g., select 1 a, 2 a). The old zeppelin-web handles this correctly. **Root Cause Analysis** The backend copyParagraph is a two-step operation: ``` 1. insertParagraph() → broadcasts PARAGRAPH_ADDED (empty new paragraph, text="%mysql\n") 2. updateParagraph() → broadcasts PARAGRAPH (full text="%mysql\nselect 1 a, 2 a") ``` Step 2's PARAGRAPH response gets silently discarded by the frontend shortCircuit mechanism in message.ts. The original filter logic compares the currently-sent message sequence number against the received response's sequence number: ```ts // OLD logic — overly aggressive if (this.lastMsgIdSeqSent > msgIdSeqReceived) { // "message is already updated by shortcircuit" → discard! return false; } ``` The problem: between sending COPY_PARAGRAPH (seq=49) and receiving its PARAGRAPH response, other unrelated messages like EDITOR_SETTING (seq=50) may be sent. This makes lastMsgIdSeqSent (50) > msgIdSeqReceived (49), causing the legitimate PARAGRAPH response for the cloned paragraph to be incorrectly filtered out. image ~~**Solution** Replace the implicit sequence-number comparison with an explicit tracking set (shortCircuitedParagraphMsgIds). Only messages that were explicitly passed to shortCircuit() get filtered — not all messages where lastMsgIdSeqSent > receivedSeq.~~ **Updated Solution** Dropping the PARAGRAPH msgId compare filter branch when received msg ### What type of PR is it? Bug Fix ### Todos * [ ] - Task ### What is the Jira issue? * Open an issue on Jira https://issues.apache.org/jira/browse/ZEPPELIN/ * Put link here, and add [ZEPPELIN-*Jira number*] in PR title, eg. [ZEPPELIN-533] ### How should this be tested? * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? * Is there breaking changes for older versions? * Does this needs documentation? Closes #5254 from kevinjmh/ZEPPELIN-6419. Signed-off-by: ChanHo Lee --- .../interfaces/message-paragraph.interface.ts | 4 ++-- .../projects/zeppelin-sdk/src/message.ts | 22 +------------------ 2 files changed, 3 insertions(+), 23 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts index 689104668db..2ea3916ea1e 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-paragraph.interface.ts @@ -77,10 +77,10 @@ export interface ParagraphConfig { } export interface ParagraphResults { + [index: number]: Record; + code?: string; msg?: ParagraphIResultsMsgItem[]; - - [index: number]: Record; } export enum DatasetType { diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts index 4f8c5e625ba..42821062eb3 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts @@ -52,6 +52,7 @@ export class Message { private wsUrl?: string; private ticket?: Ticket; private uniqueClientId = Math.random().toString(36).substring(2, 7); + // TODO: Clean up this variable with `msgId` in server-side. See ZEPPELIN-6419, ZEPPELIN-4985 private lastMsgIdSeqSent = 0; private readonly normalCloseCode = 1000; @@ -174,27 +175,6 @@ export class Message { receive(op: K): Observable[K]> { return this.received$.pipe( filter(message => message.op === op), - filter(message => { - if (!message.msgId) { - // when msgId is not specified, it is not response to client request. - // always process them - return true; - } - const uniqueClientId = message.msgId.split('-')[0]; - const msgIdSeqReceived = parseInt(message.msgId.split('-')[1], 10); - const isResponseForRequestFromThisClient = uniqueClientId === this.uniqueClientId; - - if (message.op === OP.PARAGRAPH) { - if (isResponseForRequestFromThisClient && this.lastMsgIdSeqSent > msgIdSeqReceived) { - console.log('PARAPGRAPH is already updated by shortcircuit'); - return false; - } else { - return true; - } - } else { - return true; - } - }), map(message => message.data) ) as Observable[K]>; } From ef090724d1e29e0d599fed41d3bad4769668f92f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Wed, 3 Jun 2026 15:48:22 +0900 Subject: [PATCH 048/179] [ZEPPELIN-6425] Migrate zeppelin-react ESLint config to v9 flat format ### What is this PR for? This regression surfaced after ZEPPELIN-6421 (zeppelin-react lint integration) and ZEPPELIN-6424 (Angular 13 to 21 upgrade) merged in close succession. Each PR passed CI in isolation, but together they broke `npm run lint:react`: - ZEPPELIN-6421 added `projects/zeppelin-react/package.json` scripts that use the ESLint 8 `--ext .ts,.tsx` flag and rely on `projects/zeppelin-react/.eslintrc.json`. - ZEPPELIN-6424 bumped the root install to ESLint 9, which removed `--ext` and dropped `.eslintrc.*` support entirely in favor of flat config (`eslint.config.{js,mjs,cjs}`). The two changes never collided in their own PR CIs because each was tested against a master that didn't yet contain the other. Once both landed, master's `frontend / run-playwright-e2e-tests (auth, 3.9)` and `(anonymous, 3.9)` started failing at the `npm lint` step before Playwright ran. ### What type of PR is it? Bug Fix ### Todos ### What is the Jira issue? ZEPPELIN-6425 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5263 from voidmatcha/fix/zeppelin-react-eslint-config. Signed-off-by: ChanHo Lee --- .../projects/zeppelin-react/.eslintrc.json | 53 -- .../projects/zeppelin-react/README.md | 2 +- .../projects/zeppelin-react/eslint.config.js | 85 ++ .../projects/zeppelin-react/package-lock.json | 801 ++++++++---------- .../projects/zeppelin-react/package.json | 11 +- .../result-item/result-item.component.html | 28 +- .../app/share/header/header.component.html | 4 +- 7 files changed, 478 insertions(+), 506 deletions(-) delete mode 100644 zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json create mode 100644 zeppelin-web-angular/projects/zeppelin-react/eslint.config.js diff --git a/zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json b/zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json deleted file mode 100644 index 8be6028ca02..00000000000 --- a/zeppelin-web-angular/projects/zeppelin-react/.eslintrc.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "root": true, - "env": { - "browser": true, - "es2021": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "ecmaVersion": "latest", - "sourceType": "module", - "project": true - }, - "plugins": ["@typescript-eslint", "react", "react-hooks"], - "settings": { - "react": { - "version": "detect" - } - }, - "rules": { - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-unused-vars": [ - "error", - { - "argsIgnorePattern": "^_", - "varsIgnorePattern": "^_" - } - ], - "@typescript-eslint/no-for-in-array": "error", - "@typescript-eslint/no-this-alias": "error", - "no-duplicate-imports": "error", - "no-invalid-this": "error", - "no-irregular-whitespace": "error", - "no-param-reassign": "error", - "no-redeclare": "error", - "no-sparse-arrays": "error", - "no-template-curly-in-string": "error", - "prefer-object-spread": "error", - "prefer-template": "error", - "yoda": "error", - "react-hooks/exhaustive-deps": "error" - }, - "ignorePatterns": ["dist", "node_modules", "webpack.config.js"] -} diff --git a/zeppelin-web-angular/projects/zeppelin-react/README.md b/zeppelin-web-angular/projects/zeppelin-react/README.md index e3acdb68b2f..58f2d8a2d4f 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/README.md +++ b/zeppelin-web-angular/projects/zeppelin-react/README.md @@ -58,7 +58,7 @@ From `projects/zeppelin-react/`, run `npm run build`. Output goes to `dist/`. In ## Linting -From `projects/zeppelin-react/`, run `npm run lint` to check, `npm run lint:fix` to auto-fix. See `.eslintrc.json` for rules. +From `projects/zeppelin-react/`, run `npm run lint` to check, `npm run lint:fix` to auto-fix. See `eslint.config.js` for rules. ## Project structure diff --git a/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js b/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js new file mode 100644 index 00000000000..b981e30ca16 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js @@ -0,0 +1,85 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// ESLint 9 flat config for the zeppelin-react sub-app (migrated from the +// `.eslintrc.json` that worked under ESLint 8). The Angular 21 upgrade +// (ZEPPELIN-6424) bumped the root install to ESLint 9, which dropped +// `.eslintrc.*` support entirely; this file is a 1:1 port of the legacy rule +// set so the React sources are still linted by `npm run lint:react`. +// +// The root `zeppelin-web-angular/eslint.config.js` ignores +// `projects/zeppelin-react/**`, so this config owns linting inside this +// directory exclusively. + +const js = require('@eslint/js'); +const globals = require('globals'); +const tseslint = require('typescript-eslint'); +const react = require('eslint-plugin-react'); +const reactHooks = require('eslint-plugin-react-hooks'); + +module.exports = tseslint.config( + { + // == legacy `ignorePatterns` + ignores: ['dist/**', 'node_modules/**', 'webpack.config.js'] + }, + { + files: ['src/**/*.{ts,tsx}'], + // == legacy `extends`: eslint:recommended + @typescript-eslint/recommended + extends: [js.configs.recommended, ...tseslint.configs.recommended], + languageOptions: { + // == legacy `parserOptions` + parserOptions: { + ecmaFeatures: { jsx: true }, + ecmaVersion: 'latest', + sourceType: 'module', + project: true, + tsconfigRootDir: __dirname + }, + // == legacy `env: { browser: true, es2021: true }` + globals: { + ...globals.browser, + ...globals.es2021 + } + }, + plugins: { + react, + 'react-hooks': reactHooks + }, + settings: { + react: { version: 'detect' } + }, + rules: { + // == legacy `plugin:react/recommended` + `plugin:react/jsx-runtime` + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + // == legacy `plugin:react-hooks/recommended` + ...reactHooks.configs.recommended.rules, + + // == legacy custom `rules` (1:1 port from .eslintrc.json) + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], + '@typescript-eslint/no-for-in-array': 'error', + '@typescript-eslint/no-this-alias': 'error', + 'no-duplicate-imports': 'error', + 'no-invalid-this': 'error', + 'no-irregular-whitespace': 'error', + 'no-param-reassign': 'error', + 'no-redeclare': 'error', + 'no-sparse-arrays': 'error', + 'no-template-curly-in-string': 'error', + 'prefer-object-spread': 'error', + 'prefer-template': 'error', + yoda: 'error', + 'react-hooks/exhaustive-deps': 'error' + } + } +); diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index 598ac2b7bb6..f0f3439bab6 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -19,6 +19,7 @@ "xlsx-js-style": "1.2.0" }, "devDependencies": { + "@eslint/js": "^9.28.0", "@types/file-saver": "2.0.7", "@types/node": "18.19.64", "@types/react": "18.3.26", @@ -26,13 +27,15 @@ "@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/parser": "^8.56.1", "css-loader": "6.8.0", - "eslint": "^8.57.1", + "eslint": "^9.28.0", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-hooks": "^5.1.0", + "globals": "^15.14.0", "html-webpack-plugin": "5.5.0", "style-loader": "3.3.0", "ts-loader": "9.4.0", "typescript": "4.9.5", + "typescript-eslint": "^8.33.1", "webpack": "5.105.4", "webpack-cli": "5.1.4", "webpack-dev-server": "5.2.4" @@ -215,25 +218,91 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -257,6 +326,19 @@ } } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -275,55 +357,79 @@ "license": "MIT" }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "ms": "^2.1.3" + "@humanfs/types": "^0.15.0" }, "engines": { - "node": ">=6.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", @@ -339,13 +445,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", @@ -853,44 +965,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@peculiar/asn1-cms": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", @@ -1476,20 +1550,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", + "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/type-utils": "8.60.1", + "@typescript-eslint/utils": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1499,22 +1573,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", + "@typescript-eslint/parser": "^8.60.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", + "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", "debug": "^4.4.3" }, "engines": { @@ -1526,7 +1600,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser/node_modules/debug": { @@ -1555,14 +1629,14 @@ "license": "MIT" }, "node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", + "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", + "@typescript-eslint/tsconfig-utils": "^8.60.1", + "@typescript-eslint/types": "^8.60.1", "debug": "^4.4.3" }, "engines": { @@ -1573,7 +1647,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/project-service/node_modules/debug": { @@ -1602,14 +1676,14 @@ "license": "MIT" }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", + "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1620,9 +1694,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", + "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", "dev": true, "license": "MIT", "engines": { @@ -1633,21 +1707,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", + "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1", "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1658,7 +1732,7 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils/node_modules/debug": { @@ -1687,9 +1761,9 @@ "license": "MIT" }, "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", + "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", "dev": true, "license": "MIT", "engines": { @@ -1701,21 +1775,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", + "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", + "@typescript-eslint/project-service": "8.60.1", + "@typescript-eslint/tsconfig-utils": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/visitor-keys": "8.60.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" + "ts-api-utils": "^2.5.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1725,7 +1799,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { @@ -1739,9 +1813,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -1770,13 +1844,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -1793,16 +1867,16 @@ "license": "MIT" }, "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", + "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" + "@typescript-eslint/scope-manager": "8.60.1", + "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1813,17 +1887,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", + "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -1847,13 +1921,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -2150,9 +2217,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3763,60 +3830,63 @@ "license": "MIT" }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-react": { @@ -3853,16 +3923,16 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", "dev": true, "license": "MIT", "engines": { "node": ">=10" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react/node_modules/estraverse": { @@ -3987,19 +4057,6 @@ } } }, - "node_modules/eslint/node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -4014,9 +4071,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4024,7 +4081,20 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -4149,18 +4219,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -4363,16 +4446,6 @@ "node": ">= 4.9.1" } }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -4393,16 +4466,16 @@ "license": "MIT" }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/file-saver": { @@ -4468,18 +4541,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -4555,13 +4627,6 @@ "node": ">= 0.6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4685,28 +4750,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -4745,16 +4788,13 @@ "license": "BSD-2-Clause" }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4797,13 +4837,6 @@ "dev": true, "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -5212,18 +5245,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -5574,16 +5595,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -5832,10 +5843,20 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -6420,16 +6441,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, "node_modules/open": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", @@ -6597,16 +6608,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -6934,27 +6935,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7811,34 +7791,6 @@ "node": ">= 4" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -7852,30 +7804,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -8858,13 +8786,6 @@ "source-map": "^0.6.0" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/thingies": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", @@ -8899,14 +8820,14 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -8993,9 +8914,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -9111,19 +9032,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -9230,6 +9138,30 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-eslint": { + "version": "8.60.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.60.1.tgz", + "integrity": "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.60.1", + "@typescript-eslint/parser": "8.60.1", + "@typescript-eslint/typescript-estree": "8.60.1", + "@typescript-eslint/utils": "8.60.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/uc.micro": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", @@ -9823,13 +9755,6 @@ "node": ">=0.10.0" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json index 7621820adaa..ecc1b361da9 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -8,8 +8,8 @@ "start": "webpack serve --config webpack.config.js --mode development", "build": "webpack --config webpack.config.js --mode production", "dev": "webpack serve --config webpack.config.js --mode development", - "lint": "eslint src --ext .ts,.tsx", - "lint:fix": "eslint src --ext .ts,.tsx --fix" + "lint": "eslint 'src/**/*.{ts,tsx}'", + "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix" }, "dependencies": { "@ant-design/icons": "5.4.0", @@ -23,6 +23,7 @@ "xlsx-js-style": "1.2.0" }, "devDependencies": { + "@eslint/js": "^9.28.0", "@types/file-saver": "2.0.7", "@types/node": "18.19.64", "@types/react": "18.3.26", @@ -30,13 +31,15 @@ "@typescript-eslint/eslint-plugin": "^8.56.1", "@typescript-eslint/parser": "^8.56.1", "css-loader": "6.8.0", - "eslint": "^8.57.1", + "eslint": "^9.28.0", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-hooks": "^5.1.0", + "globals": "^15.14.0", "html-webpack-plugin": "5.5.0", "style-loader": "3.3.0", "ts-loader": "9.4.0", "typescript": "4.9.5", + "typescript-eslint": "^8.33.1", "webpack": "5.105.4", "webpack-cli": "5.1.4", "webpack-dev-server": "5.2.4" diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html index 5e393de9129..53d8c61812e 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.html @@ -13,14 +13,24 @@
      {{ displayName }} - {{ interpreter }} + @if (interpreter) { + {{ interpreter }} + }
      -
      -
      -
      
      -  
      -
      -
      {{ outputText }}
      -
      -
      Tables: {{ tablesText }}
      + @if (titleHtml) { +
      + } + @if (codeHtml) { +
      +
      
      +    
      + } + @if (outputText) { +
      +
      {{ outputText }}
      +
      + } + @if (tablesText) { +
      Tables: {{ tablesText }}
      + }
      diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html index 57bffcdae24..a2b378870d4 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.html +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -94,7 +94,9 @@ /> - + @for (item of searchHistory; track item) { + + }
    From 0539c8a386c198985bd69acefbe8208bcfa12412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Wed, 3 Jun 2026 19:55:46 +0900 Subject: [PATCH 049/179] [ZEPPELIN-6422] Stabilize flaky Playwright E2E tests ### What is this PR for? Three races caused flaky `frontend / run-playwright-e2e-tests`: 1. Per-test login raced on the shared session cookie under parallel workers -> moved to a single `setup` project + `storageState`. 2. `locator.fill` on Ant modal inputs landed before Angular bound the form-control -> new `BasePage.fillAndVerifyInput()` retries via `expect.toPass` until the input value sticks. 3. Modal/dropdown/theme/logout transitions had no explicit wait -> targeted waits added at each boundary. Inline comments on the diff for the non-obvious bits. ### What type of PR is it? Bug Fix ### Todos ### What is the Jira issue? ZEPPELIN-6422 ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5262 from voidmatcha/fix/e2e-flaky-final. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/.gitignore | 1 + zeppelin-web-angular/e2e/global.setup.ts | 45 +++ zeppelin-web-angular/e2e/models/base-page.ts | 22 +- .../e2e/models/dark-mode-page.ts | 5 + .../e2e/models/folder-rename-page.ts | 40 ++- .../e2e/models/folder-rename-page.util.ts | 2 +- zeppelin-web-angular/e2e/models/home-page.ts | 5 +- .../e2e/models/node-list-page.ts | 9 +- .../e2e/models/note-create-modal.ts | 3 +- .../e2e/models/note-import-modal.ts | 4 +- .../e2e/models/note-rename-page.ts | 2 +- .../e2e/models/notebook-repos-page.ts | 9 +- .../e2e/models/notebook.util.ts | 6 +- zeppelin-web-angular/e2e/tests/app.spec.ts | 71 ++-- .../e2e/tests/home/home-page-elements.spec.ts | 3 +- .../home/home-page-external-links.spec.ts | 3 +- .../e2e/tests/home/home-page-layout.spec.ts | 3 +- .../home/home-page-note-operations.spec.ts | 31 +- .../home/home-page-notebook-actions.spec.ts | 7 +- .../e2e/tests/login/login.spec.ts | 17 +- .../action-bar-functionality.spec.ts | 14 +- .../notebook-keyboard-shortcuts.spec.ts | 9 +- .../notebook/main/notebook-container.spec.ts | 11 +- .../notebook/main/notebook-navigation.spec.ts | 3 +- .../published/published-paragraph.spec.ts | 8 +- .../sidebar/sidebar-functionality.spec.ts | 11 +- .../about-zeppelin-modal.spec.ts | 3 +- .../share/folder-rename/folder-rename.spec.ts | 35 +- .../share/header/header-navigation.spec.ts | 21 +- .../tests/share/header/header-search.spec.ts | 9 +- .../node-list/node-list-functionality.spec.ts | 27 +- .../note-create/note-create-modal.spec.ts | 11 +- .../note-import/note-import-modal.spec.ts | 3 +- .../share/note-rename/note-rename.spec.ts | 17 +- .../e2e/tests/share/note-toc/note-toc.spec.ts | 14 +- .../e2e/tests/theme/dark-mode.spec.ts | 15 +- .../notebook-repo-item-display.spec.ts | 3 +- .../notebook-repo-item-edit.spec.ts | 3 +- ...notebook-repo-item-form-validation.spec.ts | 3 +- .../notebook-repo-item-settings.spec.ts | 3 +- .../notebook-repo-item-workflow.spec.ts | 3 +- .../notebook-repos-page-structure.spec.ts | 3 +- .../workspace/user-menu-navigation.spec.ts | 3 +- .../tests/workspace/workspace-main.spec.ts | 3 +- zeppelin-web-angular/e2e/utils.ts | 325 +++++++++++------- zeppelin-web-angular/playwright.config.js | 44 ++- .../app/share/header/header.component.html | 1 + .../app/share/header/header.component.less | 11 + 48 files changed, 560 insertions(+), 344 deletions(-) create mode 100644 zeppelin-web-angular/e2e/global.setup.ts diff --git a/zeppelin-web-angular/.gitignore b/zeppelin-web-angular/.gitignore index f285d87e9b1..42b640c2fdd 100644 --- a/zeppelin-web-angular/.gitignore +++ b/zeppelin-web-angular/.gitignore @@ -48,6 +48,7 @@ Thumbs.db /playwright-coverage/ /test-results/ /playwright/.cache/ +/playwright/.auth/ # .env diff --git a/zeppelin-web-angular/e2e/global.setup.ts b/zeppelin-web-angular/e2e/global.setup.ts new file mode 100644 index 00000000000..234d0dbea14 --- /dev/null +++ b/zeppelin-web-angular/e2e/global.setup.ts @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import { test as setup, expect } from '@playwright/test'; +import { LoginTestUtil } from './models/login-page.util'; +import { performLoginIfRequired, waitForZeppelinReady } from './utils'; + +// Resolved against the Playwright project rootDir (zeppelin-web-angular/). +// Must match the `storageState` value declared for browser projects in playwright.config.js. +export const STORAGE_STATE = path.join('playwright', '.auth', 'user.json'); + +setup('authenticate', async ({ page }) => { + fs.mkdirSync(path.dirname(STORAGE_STATE), { recursive: true }); + + const isShiroEnabled = await LoginTestUtil.isShiroEnabled(); + if (!isShiroEnabled) { + // Auth variant disabled — write an empty storage state so dependent projects load, + // then exit. This keeps the setup-project pattern uniform across CI matrix variants. + await page.context().storageState({ path: STORAGE_STATE }); + return; + } + + await page.goto('/'); + await waitForZeppelinReady(page); + + await performLoginIfRequired(page); + + // Verify we are authenticated. Don't rely on performLoginIfRequired's return value — + // it returns false both for "no work to do" and "login attempt failed". + await expect(page.locator('zeppelin-login')).toBeHidden({ timeout: 30000 }); + await expect(page.getByRole('heading', { name: 'Welcome to Zeppelin!' })).toBeVisible({ timeout: 30000 }); + + await page.context().storageState({ path: STORAGE_STATE }); +}); diff --git a/zeppelin-web-angular/e2e/models/base-page.ts b/zeppelin-web-angular/e2e/models/base-page.ts index aa37f1a1384..403be0f7807 100644 --- a/zeppelin-web-angular/e2e/models/base-page.ts +++ b/zeppelin-web-angular/e2e/models/base-page.ts @@ -104,10 +104,22 @@ export class BasePage { await expect(locator).toBeVisible({ timeout }); await expect(locator).toBeEnabled({ timeout: 5000 }); - // Click first so Angular's form control is focused and its initial setValue cycle - // has completed before we overwrite it. Then fill() atomically sets the value. - await locator.click(); - await locator.fill(value); - await expect(locator).toHaveValue(value, { timeout: 10000 }); + // Ant-modal autofocus + Angular form initialization race: any of fill / type / + // pressSequentially can land BEFORE the form-control's initial value sync, + // after which Angular silently resets the input back to the model's initial + // value (placeholder). ng-dirty is set but the visible value is wrong. + await expect(async () => { + await locator.click(); + await locator.fill(value); + await locator.evaluate((el: HTMLInputElement) => { + el.dispatchEvent(new Event('input', { bubbles: true })); + el.dispatchEvent(new Event('change', { bubbles: true })); + }); + // Verify the value stuck — if Angular reset it, this throws and toPass retries. + const actual = await locator.inputValue(); + if (actual !== value) { + throw new Error(`fillAndVerifyInput retry: expected "${value}" got "${actual}"`); + } + }).toPass({ timeout: 15000, intervals: [200, 500, 1000, 2000] }); } } diff --git a/zeppelin-web-angular/e2e/models/dark-mode-page.ts b/zeppelin-web-angular/e2e/models/dark-mode-page.ts index 98f77c89335..bedea19f575 100644 --- a/zeppelin-web-angular/e2e/models/dark-mode-page.ts +++ b/zeppelin-web-angular/e2e/models/dark-mode-page.ts @@ -40,6 +40,11 @@ export class DarkModePage extends BasePage { } async assertSystemTheme() { + // After page reload, Angular re-bootstraps and reads theme from localStorage. The + // toggle-button icon refresh races against that bootstrap window. Wait for the + // root element's data-theme attribute to be set first — that guarantees Angular's + // theme-init has completed — then assert the icon. + await expect(this.rootElement).toHaveAttribute('data-theme', /light|dark/, { timeout: 15000 }); await expect(this.themeToggleButton).toHaveText('smart_toy', { timeout: 60000 }); } diff --git a/zeppelin-web-angular/e2e/models/folder-rename-page.ts b/zeppelin-web-angular/e2e/models/folder-rename-page.ts index 58f9327c6f3..93f49d30beb 100644 --- a/zeppelin-web-angular/e2e/models/folder-rename-page.ts +++ b/zeppelin-web-angular/e2e/models/folder-rename-page.ts @@ -31,23 +31,12 @@ export class FolderRenamePage extends BasePage { this.deleteConfirmation = page.locator('.ant-popover').filter({ hasText: 'This folder will be moved to trash.' }); } - private getFolderNode(folderName: string): Locator { - return this.page - .locator('.folder') - .filter({ - has: this.page.locator('a.name', { - hasText: new RegExp(`^\\s*${folderName}\\s*$`, 'i') - }) - }) - .first(); - } - async hoverOverFolder(folderName: string): Promise { await this.page.waitForSelector('zeppelin-node-list', { state: 'visible' }); - const folderNode = this.getFolderNode(folderName); // Hover a.name (not .folder) — CSS :hover on .operation is triggered by the text link, same as clickRenameMenuItem() - const nameLink = folderNode.locator('a.name'); - await nameLink.scrollIntoViewIfNeeded(); + const nameLink = this.getFolderNameLink(folderName); + await expect(nameLink).toBeVisible({ timeout: 60000 }); + await nameLink.scrollIntoViewIfNeeded({ timeout: 10000 }); await nameLink.hover({ force: true }); // JUSTIFIED: .operation buttons are CSS-:hover-revealed; force required to trigger the hover event on the text link that activates the context menu } @@ -63,9 +52,10 @@ export class FolderRenamePage extends BasePage { async clickRenameMenuItem(folderName: string): Promise { const folderNode = this.getFolderNode(folderName); - const nameLink = folderNode.locator('a.name'); + const nameLink = this.getFolderNameLink(folderName); - await nameLink.scrollIntoViewIfNeeded(); + await expect(nameLink).toBeVisible({ timeout: 60000 }); + await nameLink.scrollIntoViewIfNeeded({ timeout: 10000 }); await nameLink.hover({ force: true }); // JUSTIFIED: .operation buttons are CSS-:hover-revealed; force required to trigger the hover event on the text link that activates the context menu const renameIcon = folderNode.locator('.operation a[nztooltiptitle="Rename folder"]'); @@ -77,12 +67,11 @@ export class FolderRenamePage extends BasePage { } async enterNewName(name: string): Promise { - await this.renameInput.fill(name); + await this.fillAndVerifyInput(this.renameInput, name); } async clearNewName(): Promise { - await this.renameInput.clear(); - await expect(this.renameInput).toHaveValue(''); + await this.fillAndVerifyInput(this.renameInput, ''); } async clickConfirm(): Promise { @@ -97,4 +86,17 @@ export class FolderRenamePage extends BasePage { async clickCancel(): Promise { await this.cancelButton.click(); } + + private getFolderNameLink(folderName: string): Locator { + return this.page.getByTestId(`folder-${folderName}`).first(); + } + + private getFolderNode(folderName: string): Locator { + return this.page + .locator('.node') + .filter({ + has: this.getFolderNameLink(folderName) + }) + .first(); + } } diff --git a/zeppelin-web-angular/e2e/models/folder-rename-page.util.ts b/zeppelin-web-angular/e2e/models/folder-rename-page.util.ts index f1e32b1ded3..c248e3e376b 100644 --- a/zeppelin-web-angular/e2e/models/folder-rename-page.util.ts +++ b/zeppelin-web-angular/e2e/models/folder-rename-page.util.ts @@ -31,7 +31,7 @@ export class FolderRenamePageUtil { return this.folderRenamePage.page .locator('.node') .filter({ - has: this.folderRenamePage.page.locator('.folder .name', { hasText: folderName }) + has: this.folderRenamePage.page.getByTestId(`folder-${folderName}`) }) .first(); } diff --git a/zeppelin-web-angular/e2e/models/home-page.ts b/zeppelin-web-angular/e2e/models/home-page.ts index 3222fc3964a..412642df440 100644 --- a/zeppelin-web-angular/e2e/models/home-page.ts +++ b/zeppelin-web-angular/e2e/models/home-page.ts @@ -122,8 +122,9 @@ export class HomePage extends BasePage { await expect(this.createNoteButton).toBeEnabled({ timeout: 5000 }); await this.createNoteButton.click({ timeout: 15000 }); // Wait for navigation to the notebook page — confirms the note was created server-side. - // waitForPageLoad() (domcontentloaded) fires instantly on SPA routing and does not guarantee this. - await this.page.waitForURL(/\/notebook\//, { timeout: 45000 }); + // This is an Angular hash-route transition, so polling the URL is more reliable than + // waitForURL()'s default "load" wait, which can hang on same-document SPA navigation. + await expect(this.page).toHaveURL(/\/notebook\//, { timeout: 45000 }); } async clickImportNote(): Promise { diff --git a/zeppelin-web-angular/e2e/models/node-list-page.ts b/zeppelin-web-angular/e2e/models/node-list-page.ts index 9c81bda02f4..88fa2721cd0 100644 --- a/zeppelin-web-angular/e2e/models/node-list-page.ts +++ b/zeppelin-web-angular/e2e/models/node-list-page.ts @@ -41,15 +41,12 @@ export class NodeListPage extends BasePage { await this.createNewNoteButton.click(); } - private getNoteByName(noteName: string): Locator { - return this.page.locator('nz-tree-node').filter({ hasText: noteName }).first(); + noteLinkByName(noteName: string): Locator { + return this.nodeListContainer.getByRole('link', { name: noteName, exact: true }); } async clickNote(noteName: string): Promise { - const note = this.getNoteByName(noteName); - // Target the specific link that navigates to the notebook (has href with "#/notebook/") - const noteLink = note.locator('a[href*="#/notebook/"]'); - await noteLink.click(); + await this.noteLinkByName(noteName).click(); } async getAllVisibleNoteNames(): Promise { diff --git a/zeppelin-web-angular/e2e/models/note-create-modal.ts b/zeppelin-web-angular/e2e/models/note-create-modal.ts index a00ef19219f..b39d62d85b2 100644 --- a/zeppelin-web-angular/e2e/models/note-create-modal.ts +++ b/zeppelin-web-angular/e2e/models/note-create-modal.ts @@ -40,8 +40,7 @@ export class NoteCreateModal extends BasePage { } async setNoteName(name: string): Promise { - await this.noteNameInput.clear(); - await this.noteNameInput.fill(name); + await this.fillAndVerifyInput(this.noteNameInput, name); } async clickCreate(): Promise { diff --git a/zeppelin-web-angular/e2e/models/note-import-modal.ts b/zeppelin-web-angular/e2e/models/note-import-modal.ts index e4634f94bc8..92bfe0e8a01 100644 --- a/zeppelin-web-angular/e2e/models/note-import-modal.ts +++ b/zeppelin-web-angular/e2e/models/note-import-modal.ts @@ -48,7 +48,7 @@ export class NoteImportModal extends BasePage { } async setImportAsName(name: string): Promise { - await this.importAsInput.fill(name); + await this.fillAndVerifyInput(this.importAsInput, name); } async getImportAsName(): Promise { @@ -60,7 +60,7 @@ export class NoteImportModal extends BasePage { } async setImportUrl(url: string): Promise { - await this.urlInput.fill(url); + await this.fillAndVerifyInput(this.urlInput, url); } async clickImportNote(): Promise { diff --git a/zeppelin-web-angular/e2e/models/note-rename-page.ts b/zeppelin-web-angular/e2e/models/note-rename-page.ts index 932babc4092..9999bfcab9f 100644 --- a/zeppelin-web-angular/e2e/models/note-rename-page.ts +++ b/zeppelin-web-angular/e2e/models/note-rename-page.ts @@ -31,7 +31,7 @@ export class NoteRenamePage extends BasePage { async enterTitle(title: string): Promise { await this.ensureEditMode(); - await this.noteTitleInput.fill(title, { timeout: 15000 }); + await this.fillAndVerifyInput(this.noteTitleInput, title); } async clearTitle(): Promise { diff --git a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts index 66234f5b61c..76cbf00f7bc 100644 --- a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts @@ -58,21 +58,26 @@ export class NotebookRepoItemPage extends BasePage { async clickEdit(): Promise { await this.editButton.click({ timeout: 15000 }); + // Wait for Angular to swap to edit mode before returning. Without this, + // a follow-up assertion like `expect(editButton).not.toBeVisible()` races + // against the re-render and intermittently sees the button still present. + await this.saveButton.waitFor({ state: 'visible', timeout: 10000 }); } async clickSave(): Promise { await this.saveButton.click({ timeout: 15000 }); + await this.editButton.waitFor({ state: 'visible', timeout: 10000 }); } async clickCancel(): Promise { await this.cancelButton.click({ timeout: 15000 }); + await this.editButton.waitFor({ state: 'visible', timeout: 10000 }); } async fillSettingInput(settingName: string, value: string): Promise { const row = this.repositoryCard.locator('tbody tr').filter({ hasText: settingName }); const input = row.locator('input[nz-input]'); - await input.clear(); - await input.fill(value); + await this.fillAndVerifyInput(input, value); } async getSettingInputValue(settingName: string): Promise { diff --git a/zeppelin-web-angular/e2e/models/notebook.util.ts b/zeppelin-web-angular/e2e/models/notebook.util.ts index 98ee1d9648d..1070618264f 100644 --- a/zeppelin-web-angular/e2e/models/notebook.util.ts +++ b/zeppelin-web-angular/e2e/models/notebook.util.ts @@ -11,7 +11,7 @@ */ import { expect, Page } from '@playwright/test'; -import { performLoginIfRequired, waitForZeppelinReady } from '../utils'; +import { waitForZeppelinReady } from '../utils'; import { BasePage } from './base-page'; import { HomePage } from './home-page'; @@ -26,9 +26,7 @@ export class NotebookUtil extends BasePage { async createNotebook(notebookName: string): Promise { await this.homePage.navigateToHome(); - // Perform login if required - await performLoginIfRequired(this.page); - + // Auth is handled by the `setup` Playwright project + storageState; no per-call login here. // Wait for Zeppelin to be fully ready await waitForZeppelinReady(this.page); diff --git a/zeppelin-web-angular/e2e/tests/app.spec.ts b/zeppelin-web-angular/e2e/tests/app.spec.ts index d637896e0b2..759fde133a2 100644 --- a/zeppelin-web-angular/e2e/tests/app.spec.ts +++ b/zeppelin-web-angular/e2e/tests/app.spec.ts @@ -12,7 +12,9 @@ import { expect, test } from '@playwright/test'; import { BasePage } from '../models/base-page'; -import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES, performLoginIfRequired } from '../utils'; +import { LoginPage } from '../models/login-page'; +import { LoginTestUtil, TestCredentials } from '../models/login-page.util'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../utils'; test.describe('Zeppelin App Component', () => { addPageAnnotationBeforeEach(PAGES.APP); @@ -23,7 +25,6 @@ test.describe('Zeppelin App Component', () => { await page.goto('/', { waitUntil: 'load' }); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test('should have correct component selector and structure', async ({ page }) => { @@ -85,7 +86,7 @@ test.describe('Zeppelin App Component', () => { await expect(loadingSpinner).toBeHidden(); }); - test('should show logout spinner when logging out', async ({ page }) => { + test('should show logout spinner when logging out', async ({ page, browser, baseURL }) => { await waitForZeppelinReady(page); // Only test logout flow for authenticated (non-anonymous) users — skip before any assertions @@ -94,27 +95,52 @@ test.describe('Zeppelin App Component', () => { const statusText = await statusElement.textContent(); test.skip(statusText?.includes('anonymous') ?? false, 'Logout spinner only applies to authenticated users'); - const logoutSpinner = page.locator('zeppelin-spin').filter({ hasText: 'Logging out' }); - - // Initially logout spinner should be hidden - await expect(logoutSpinner).toBeHidden(); - - await statusElement.click(); - const logoutButton = page.getByRole('link', { name: 'Logout' }); - - // If the dropdown has no Logout link, auth is not configured — skip gracefully - const logoutCount = await logoutButton.count(); - test.skip(logoutCount === 0, 'Logout option not available — auth not configured in this environment'); - - await logoutButton.click(); - - await expect(logoutSpinner).toBeVisible(); - await expect(logoutSpinner).toContainText('Logging out ...'); + const credentials = await LoginTestUtil.getTestCredentials(); + const logoutUser = getIsolatedLogoutUser(credentials); + test.skip(!logoutUser, 'No non-shared logout test user available'); + + // The default auth storage state is shared by the whole parallel suite. Logging + // out from that shared user invalidates the server-side Shiro session for many + // still-running tests, so exercise logout from a throwaway user/session instead. + const context = await browser.newContext({ + baseURL: baseURL ?? 'http://localhost:4200', + storageState: { cookies: [], origins: [] } + }); + + try { + const logoutPage = await context.newPage(); + const loginPage = new LoginPage(logoutPage); + await loginPage.navigate(); + await loginPage.login(logoutUser!.username, logoutUser!.password); + await logoutPage.waitForURL('/#/', { timeout: 30000 }); + await waitForZeppelinReady(logoutPage); + + const isolatedStatusElement = logoutPage.locator('.status'); + const logoutSpinner = logoutPage.locator('zeppelin-spin').filter({ hasText: 'Logging out' }); + + await expect(logoutSpinner).toBeHidden(); + + await isolatedStatusElement.click(); + const logoutButton = logoutPage.getByRole('link', { name: 'Logout' }); + + // If the dropdown has no Logout link, auth is not configured — skip gracefully + const logoutCount = await logoutButton.count(); + test.skip(logoutCount === 0, 'Logout option not available — auth not configured in this environment'); + + await logoutButton.click(); + + // `toBeVisible` can resolve briefly before the spinner mounts then misses the + // narrow visibility window. `toHaveCount(1)` polls the DOM for the spinner's + // presence which is more tolerant of the transient mount. + await expect(logoutSpinner).toHaveCount(1, { timeout: 10000 }); + await expect(logoutSpinner).toContainText('Logging out ...'); + } finally { + await context.close(); + } }); test('should maintain component integrity during navigation', async ({ page }) => { await waitForZeppelinReady(page); - await performLoginIfRequired(page); // Navigate to different pages and ensure component remains intact const testPaths = ['/#/notebook', '/#/jobmanager', '/#/configuration']; @@ -132,3 +158,8 @@ test.describe('Zeppelin App Component', () => { await waitForZeppelinReady(page); }); }); + +const getIsolatedLogoutUser = (credentials: Record): TestCredentials | undefined => + Object.values(credentials).find( + credential => credential.username && credential.password && credential.username !== 'user1' + ); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts index cac761ae85b..66a7e9bd529 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-elements.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Home Page - Core Elements', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); @@ -23,7 +23,6 @@ test.describe('Home Page - Core Elements', () => { homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test.describe('Welcome Section', () => { diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts index 97a250d6abe..09cf4ea563c 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Home Page - External Links', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); @@ -23,7 +23,6 @@ test.describe('Home Page - External Links', () => { homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test.describe('Documentation Link', () => { diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts index 5a12f6ea4e0..ef3cc36511f 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-layout.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Home Page - Layout and Grid', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); @@ -23,7 +23,6 @@ test.describe('Home Page - Layout and Grid', () => { homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test.describe('Responsive Grid Layout', () => { diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts index 66be0f6f4de..280ab64a341 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts @@ -12,24 +12,30 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; +import { addPageAnnotationBeforeEach, createTestNotebookWithName, waitForZeppelinReady, PAGES } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); test.describe('Home Page Note Operations', () => { + // JUSTIFIED: homePage and testNoteName are describe-scoped; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + let homePage: HomePage; let testNoteName: string; test.beforeEach(async ({ page }) => { homePage = new HomePage(page); - testNoteName = `_e2e_ops_test_${Date.now()}`; - await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); - // Create a test note so all operation tests have a real target - await homePage.createNote(testNoteName); + // Create the operation target through the REST API so setup is not coupled to + // the UI create-note modal, which this suite exercises separately below. + const testNote = await createTestNotebookWithName(page, { + folderPath: null, + namePrefix: '_e2e_ops_test' + }); + testNoteName = testNote.notebookName; + await page.goto('/#/'); await waitForZeppelinReady(page); @@ -161,7 +167,18 @@ test.describe('Home Page Note Operations', () => { const maxLengthAttr = await notebookNameInput.getAttribute('maxlength'); const longName = `_e2e_ml_${'a'.repeat(300)}`; - await notebookNameInput.fill(longName); + await expect(async () => { + await notebookNameInput.click(); + await notebookNameInput.fill(longName); + await notebookNameInput.evaluate((el: HTMLInputElement) => { + el.dispatchEvent(new Event('input', { bubbles: true })); + el.dispatchEvent(new Event('change', { bubbles: true })); + }); + const value = await notebookNameInput.inputValue(); + if (value.length === 0 || value === 'Untitled Note 1') { + throw new Error(`note name fill retry: got "${value}"`); + } + }).toPass({ timeout: 15000, intervals: [200, 500, 1000, 2000] }); const actualValue = await notebookNameInput.inputValue(); // Must have content — input did not silently reject the fill diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts index c14a5474e2c..a92326f32e1 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { HomePage } from '../../models/home-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); @@ -23,7 +23,6 @@ test.describe('Home Page Notebook Actions', () => { homePage = new HomePage(page); await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test.describe('Given notebook list is displayed', () => { @@ -54,7 +53,7 @@ test.describe('Home Page Notebook Actions', () => { // When: User types special characters that could break regex or URL encoding for (const specialInput of ['[test]', '*.note', '/folder/sub', 'a?b=c']) { - await homePage.nodeList.filterInput.fill(specialInput); + await homePage.fillAndVerifyInput(homePage.nodeList.filterInput, specialInput); // Then: The page must still render without crashing — no blank screen, input remains editable. // Note: nz-tree may be hidden when the filter returns 0 results; that is valid behavior. await expect(page.locator('zeppelin-node-list')).toBeVisible(); @@ -64,7 +63,7 @@ test.describe('Home Page Notebook Actions', () => { } // Clean up: clear the filter so other tests start fresh - await homePage.nodeList.filterInput.fill(''); + await homePage.nodeList.filterInput.clear(); }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/login/login.spec.ts b/zeppelin-web-angular/e2e/tests/login/login.spec.ts index cd9786d82f8..e7d07c649e5 100644 --- a/zeppelin-web-angular/e2e/tests/login/login.spec.ts +++ b/zeppelin-web-angular/e2e/tests/login/login.spec.ts @@ -12,19 +12,30 @@ import { expect, test } from '@playwright/test'; import { LoginPage } from '../../models/login-page'; -import { LoginTestUtil } from '../../models/login-page.util'; +import { LoginTestUtil, TestCredentials } from '../../models/login-page.util'; import { addPageAnnotationBeforeEach, PAGES } from '../../utils'; test.describe('Login Page', () => { + test.use({ storageState: { cookies: [], origins: [] } }); + addPageAnnotationBeforeEach(PAGES.PAGES.LOGIN); let loginPage: LoginPage; - let testCredentials: Record; + let testCredentials: Record; - test.beforeAll(async () => { + test.beforeAll(async ({ request }) => { const isShiroEnabled = await LoginTestUtil.isShiroEnabled(); if (!isShiroEnabled) { test.skip(true, 'Skipping all login tests - shiro.ini not found'); } + + const ticketResponse = await request.get('/api/security/ticket', { failOnStatusCode: false }); + if (ticketResponse.ok()) { + const ticket = await ticketResponse.json(); + if (ticket?.body?.principal === 'anonymous') { + test.skip(true, 'Skipping all login tests - Zeppelin server is running in anonymous mode'); + } + } + testCredentials = await LoginTestUtil.getTestCredentials(); }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts index 4d012b93c41..358e77c65dc 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts @@ -14,13 +14,16 @@ import { expect, test } from '@playwright/test'; import { NotebookActionBarPage } from '../../../models/notebook-action-bar-page'; import { addPageAnnotationBeforeEach, - performLoginIfRequired, waitForZeppelinReady, PAGES, - createTestNotebook + createTestNotebook, + navigateToNotebookWithFallback } from '../../../utils'; test.describe('Notebook Action Bar Functionality', () => { + // JUSTIFIED: page objects and notebook ids are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_ACTION_BAR); let actionBarPage: NotebookActionBarPage; @@ -29,13 +32,11 @@ test.describe('Notebook Action Bar Functionality', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); testNotebook = await createTestNotebook(page); actionBarPage = new NotebookActionBarPage(page); - await page.goto(`/#/notebook/${testNotebook.noteId}`); - await page.waitForLoadState('networkidle'); + await navigateToNotebookWithFallback(page, testNotebook.noteId); }); test('should display and allow title editing with tooltip', async ({ page }) => { @@ -45,8 +46,7 @@ test.describe('Notebook Action Bar Functionality', () => { await actionBarPage.titleEditor.click(); const titleInputField = actionBarPage.titleEditor.locator('input'); - await expect(titleInputField).toBeVisible(); - await titleInputField.fill(notebookName); + await actionBarPage.fillAndVerifyInput(titleInputField, notebookName); await page.keyboard.press('Enter'); await expect(actionBarPage.titleEditor).toHaveText(notebookName, { timeout: 10000 }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts index e482464364e..b0818c9f02b 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts @@ -14,7 +14,6 @@ import { expect, test } from '@playwright/test'; import { NotebookKeyboardPage } from 'e2e/models/notebook-keyboard-page'; import { addPageAnnotationBeforeEach, - performLoginIfRequired, waitForNotebookLinks, waitForZeppelinReady, PAGES, @@ -43,7 +42,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); await waitForNotebookLinks(page); // Handle the welcome modal if it appears @@ -1004,7 +1002,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%md\n# Test paragraph'); // Remove focus by clicking on empty area - await keyboardPage.page.click('body'); + await keyboardPage.page.locator('body').click(); await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM const initialCount = await keyboardPage.getParagraphCount(); @@ -1026,13 +1024,14 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { test('should handle rapid keyboard operations without instability', async () => { await keyboardPage.tryFocusCodeEditor(); - await keyboardPage.setCodeEditorContent('%python\nprint("test")'); + await keyboardPage.setCodeEditorContent('%md\nrapid keyboard test'); // Rapid Shift+Enter operations for (let i = 0; i < 3; i++) { await keyboardPage.pressRunParagraph(); + await keyboardPage.waitForParagraphExecution(0, 60000); // JUSTIFIED: single-paragraph test notebook; first() is deterministic - await expect(keyboardPage.paragraphResult.first()).toBeVisible({ timeout: 15000 }); + await expect(keyboardPage.paragraphResult.first()).toBeVisible({ timeout: 60000 }); await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: brief gap between rapid sequential runs to prevent WebSocket message overlap } diff --git a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts index d66df7fa5f3..03b956e77d6 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts @@ -14,13 +14,16 @@ import { expect, test } from '@playwright/test'; import { NotebookPage } from '../../../models/notebook-page'; import { addPageAnnotationBeforeEach, - performLoginIfRequired, waitForZeppelinReady, PAGES, - createTestNotebook + createTestNotebook, + navigateToNotebookWithFallback } from '../../../utils'; test.describe('Notebook Container Component', () => { + // JUSTIFIED: page objects and notebook ids are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); let notebookPage: NotebookPage; @@ -29,13 +32,11 @@ test.describe('Notebook Container Component', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); testNotebook = await createTestNotebook(page); notebookPage = new NotebookPage(page); - await page.goto(`/#/notebook/${testNotebook.noteId}`); - await page.waitForLoadState('networkidle'); + await navigateToNotebookWithFallback(page, testNotebook.noteId); }); test('should display notebook container with proper structure', async () => { diff --git a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts index db259de8340..877a191569a 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-navigation.spec.ts @@ -13,7 +13,7 @@ import { expect, Page, test } from '@playwright/test'; import { HeaderPage } from '../../../models/header-page'; import { HomePage } from '../../../models/home-page'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; const noteIdFromUrl = (url: string): string => { const match = url.match(/\/notebook\/([^/?]+)/); @@ -37,7 +37,6 @@ test.describe('Notebook Navigation', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); // Regression: ZEPPELIN-6387 moved the note fetch onto the WebSocket connectedStatus$ diff --git a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts index 475da43f3ba..099212243d3 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/published/published-paragraph.spec.ts @@ -15,7 +15,6 @@ import { PublishedParagraphPage } from 'e2e/models/published-paragraph-page'; import { PublishedParagraphTestUtil } from '../../../models/published-paragraph-page.util'; import { addPageAnnotationBeforeEach, - performLoginIfRequired, waitForNotebookLinks, waitForZeppelinReady, PAGES, @@ -23,6 +22,9 @@ import { } from '../../../utils'; test.describe('Published Paragraph', () => { + // JUSTIFIED: page objects and notebook ids are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + addPageAnnotationBeforeEach(PAGES.WORKSPACE.PUBLISHED_PARAGRAPH); let publishedParagraphPage: PublishedParagraphPage; @@ -33,7 +35,6 @@ test.describe('Published Paragraph', () => { publishedParagraphPage = new PublishedParagraphPage(page); await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); await waitForNotebookLinks(page); if ((await publishedParagraphPage.cancelButton.count()) > 0) { @@ -91,8 +92,7 @@ test.describe('Published Paragraph', () => { test('should enter published paragraph by clicking link', async ({ page }) => { const { noteId, paragraphId } = testNotebook; - await page.goto(`/#/notebook/${noteId}`); - await page.waitForLoadState('networkidle'); + await publishedParagraphPage.navigateToNotebook(noteId); // JUSTIFIED: createTestNotebook creates a single paragraph; first() is deterministic const paragraphElement = page.locator('zeppelin-notebook-paragraph').first(); diff --git a/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts index 1cc2b2b2604..996ac0d24ca 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts @@ -14,13 +14,16 @@ import { expect, test } from '@playwright/test'; import { NotebookSidebarPage } from '../../../models/notebook-sidebar-page'; import { addPageAnnotationBeforeEach, - performLoginIfRequired, waitForZeppelinReady, PAGES, - createTestNotebook + createTestNotebook, + navigateToNotebookWithFallback } from '../../../utils'; test.describe('Notebook Sidebar Functionality', () => { + // JUSTIFIED: page objects and notebook ids are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_SIDEBAR); let sidebar: NotebookSidebarPage; @@ -29,13 +32,11 @@ test.describe('Notebook Sidebar Functionality', () => { test.beforeEach(async ({ page }) => { await page.goto('/', { waitUntil: 'load', timeout: 60000 }); await waitForZeppelinReady(page); - await performLoginIfRequired(page); sidebar = new NotebookSidebarPage(page); testNotebook = await createTestNotebook(page); - await page.goto(`/#/notebook/${testNotebook.noteId}`); - await page.waitForLoadState('networkidle'); + await navigateToNotebookWithFallback(page, testNotebook.noteId); }); test('should display navigation buttons', async ({ page }) => { diff --git a/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts index 1f2d6fed08c..c162293d48f 100644 --- a/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/about-zeppelin/about-zeppelin-modal.spec.ts @@ -13,7 +13,7 @@ import { test, expect } from '@playwright/test'; import { HeaderPage } from '../../../models/header-page'; import { AboutZeppelinModal } from '../../../models/about-zeppelin-modal'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; test.describe('About Zeppelin Modal', () => { let headerPage: HeaderPage; @@ -27,7 +27,6 @@ test.describe('About Zeppelin Modal', () => { await page.goto('/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); await headerPage.clickUserDropdown(); await headerPage.clickAboutZeppelin(); diff --git a/zeppelin-web-angular/e2e/tests/share/folder-rename/folder-rename.spec.ts b/zeppelin-web-angular/e2e/tests/share/folder-rename/folder-rename.spec.ts index a364a20bb50..1bbc8d090d3 100644 --- a/zeppelin-web-angular/e2e/tests/share/folder-rename/folder-rename.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/folder-rename/folder-rename.spec.ts @@ -10,16 +10,16 @@ * limitations under the License. */ -import { test, expect } from '@playwright/test'; +import { test, expect, Page } from '@playwright/test'; import { FolderRenamePage } from '../../../models/folder-rename-page'; import { FolderRenamePageUtil } from '../../../models/folder-rename-page.util'; -import { - addPageAnnotationBeforeEach, - PAGES, - performLoginIfRequired, - waitForZeppelinReady, - createTestNotebook -} from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady, createTestNotebook } from '../../../utils'; + +const refreshHomeAndWaitForFolder = async (page: Page, folderName: string): Promise => { + await page.reload({ waitUntil: 'domcontentloaded' }); + await waitForZeppelinReady(page); + await expect(page.getByTestId(`folder-${folderName}`)).toBeVisible({ timeout: 60000 }); +}; // JUSTIFIED: rename/delete ops mutate shared state; parallel runs cause folder-not-found races test.describe.serial('Folder Rename', () => { @@ -35,19 +35,18 @@ test.describe.serial('Folder Rename', () => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); // Create a test notebook with folder structure testFolderName = `TestFolder_${Date.now()}`; await createTestNotebook(page, testFolderName); - await page.goto('/#/'); + await refreshHomeAndWaitForFolder(page, testFolderName); }); test('Given folder exists in notebook list, When hovering over folder, Then context menu should appear with Rename option', async () => { await folderRenamePage.hoverOverFolder(testFolderName); const folderNode = folderRenamePage.page .locator('.node') - .filter({ has: folderRenamePage.page.locator('.folder .name', { hasText: testFolderName }) }) + .filter({ has: folderRenamePage.page.getByTestId(`folder-${testFolderName}`) }) // JUSTIFIED: filter already narrows to target folder; first() handles nested .node structure .first(); const renameButton = folderNode.locator('.folder .operation a[nz-tooltip][nztooltiptitle="Rename folder"]'); @@ -79,13 +78,13 @@ test.describe.serial('Folder Rename', () => { await folderRenamePage.clickConfirm(); await expect(folderRenamePage.renameModal).not.toBeVisible({ timeout: 10000 }); - await expect(page.locator('.folder .name', { hasText: testFolderName })).not.toBeVisible({ timeout: 10000 }); + await expect(page.getByTestId(`folder-${testFolderName}`)).not.toBeVisible({ timeout: 10000 }); await page.reload(); await page.waitForLoadState('domcontentloaded', { timeout: 15000 }); const baseNewName = renamedFolderName.split('/').pop() ?? renamedFolderName; - await expect(page.locator('.folder .name', { hasText: baseNewName })).toBeVisible({ timeout: 30000 }); + await expect(page.getByTestId(`folder-${baseNewName}`)).toBeVisible({ timeout: 30000 }); }); test('Given rename modal is open, When submitting empty name, Then empty name should not be allowed', async () => { @@ -97,7 +96,7 @@ test.describe.serial('Folder Rename', () => { await folderRenamePage.clickCancel(); await expect(folderRenamePage.renameModal).not.toBeVisible({ timeout: 5000 }); - await expect(folderRenamePage.page.locator('.folder .name', { hasText: testFolderName })).toBeVisible({ + await expect(folderRenamePage.page.getByTestId(`folder-${testFolderName}`)).toBeVisible({ timeout: 5000 }); }); @@ -106,7 +105,7 @@ test.describe.serial('Folder Rename', () => { await folderRenamePage.hoverOverFolder(testFolderName); const folderNode = folderRenamePage.page .locator('.node') - .filter({ has: folderRenamePage.page.locator('.folder .name', { hasText: testFolderName }) }) + .filter({ has: folderRenamePage.page.getByTestId(`folder-${testFolderName}`) }) // JUSTIFIED: filter already narrows to target folder; first() handles nested .node structure .first(); await expect(folderNode.locator('.folder .operation a[nztooltiptitle*="Move folder to Trash"]')).toBeVisible(); @@ -129,7 +128,7 @@ test.describe.serial('Folder Rename', () => { // Create a second folder to use as a name collision target const existingFolderName = `ExistingFolder_${Date.now()}`; await createTestNotebook(page, existingFolderName); - await page.goto('/#/'); // Refresh to see the new folder + await refreshHomeAndWaitForFolder(page, existingFolderName); // Attempt to rename the first folder to the name of the second folder await folderRenamePage.hoverOverFolder(testFolderName); @@ -139,8 +138,8 @@ test.describe.serial('Folder Rename', () => { await folderRenamePage.clickConfirm(); // Wait for the source folder to disappear (as it's merged into target) - await expect(page.locator('.folder .name', { hasText: testFolderName })).toHaveCount(0, { timeout: 10000 }); + await expect(page.getByTestId(`folder-${testFolderName}`)).toHaveCount(0, { timeout: 10000 }); // Wait for the target folder to remain visible - await expect(page.locator('.folder .name', { hasText: existingFolderName })).toBeVisible({ timeout: 10000 }); + await expect(page.getByTestId(`folder-${existingFolderName}`)).toBeVisible({ timeout: 10000 }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts index aae38d544a1..a37d7c41713 100644 --- a/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/header/header-navigation.spec.ts @@ -13,7 +13,7 @@ import { test, expect } from '@playwright/test'; import { HeaderPage } from '../../../models/header-page'; import { NodeListPage } from '../../../models/node-list-page'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; test.describe('Header Navigation', () => { let headerPage: HeaderPage; @@ -25,7 +25,6 @@ test.describe('Header Navigation', () => { await page.goto('/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test('Given user is on any page, When viewing the header, Then all header elements should be visible', async () => { @@ -42,16 +41,14 @@ test.describe('Header Navigation', () => { page }) => { await headerPage.clickBrandLogo(); - await page.waitForURL(/\/(#\/)?$/); - expect(page.url()).toMatch(/\/(#\/)?$/); + await expect(page).toHaveURL(/\/(#\/)?$/); }); test('Given user is on home page, When clicking the Job menu item, Then user should navigate to Job Manager page', async ({ page }) => { await headerPage.clickJobMenu(); - await page.waitForURL(/jobmanager/); - expect(page.url()).toContain('jobmanager'); + await expect(page).toHaveURL(/jobmanager/); }); test('Given user is on home page, When clicking the Notebook dropdown, Then dropdown with node list should open', async ({ @@ -89,8 +86,7 @@ test.describe('Header Navigation', () => { }) => { await headerPage.clickUserDropdown(); await headerPage.clickInterpreter(); - await page.waitForURL(/interpreter/); - expect(page.url()).toContain('interpreter'); + await expect(page).toHaveURL(/interpreter/); }); test('Given user opens user dropdown, When clicking Notebook Repos menu item, Then user should navigate to Notebook Repos page', async ({ @@ -98,8 +94,7 @@ test.describe('Header Navigation', () => { }) => { await headerPage.clickUserDropdown(); await headerPage.clickNotebookRepos(); - await page.waitForURL(/notebook-repos/); - expect(page.url()).toContain('notebook-repos'); + await expect(page).toHaveURL(/notebook-repos/); }); test('Given user opens user dropdown, When clicking Credential menu item, Then user should navigate to Credential page', async ({ @@ -107,8 +102,7 @@ test.describe('Header Navigation', () => { }) => { await headerPage.clickUserDropdown(); await headerPage.clickCredential(); - await page.waitForURL(/credential/); - expect(page.url()).toContain('credential'); + await expect(page).toHaveURL(/credential/); }); test('Given user opens user dropdown, When clicking Configuration menu item, Then user should navigate to Configuration page', async ({ @@ -116,7 +110,6 @@ test.describe('Header Navigation', () => { }) => { await headerPage.clickUserDropdown(); await headerPage.clickConfiguration(); - await page.waitForURL(/configuration/); - expect(page.url()).toContain('configuration'); + await expect(page).toHaveURL(/configuration/); }); }); diff --git a/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts b/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts index f6960142a41..17f0c4bfc2d 100644 --- a/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/header/header-search.spec.ts @@ -12,7 +12,7 @@ import { test, expect } from '@playwright/test'; import { HeaderPage } from '../../../models/header-page'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; test.describe('Header Search Functionality', () => { let headerPage: HeaderPage; @@ -24,7 +24,6 @@ test.describe('Header Search Functionality', () => { await page.goto('/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test('Given user is on home page, When entering search query and pressing Enter, Then user should navigate to search results page', async ({ @@ -32,9 +31,9 @@ test.describe('Header Search Functionality', () => { }) => { const searchQuery = 'test'; await headerPage.searchNote(searchQuery); - await page.waitForURL(/search/); - expect(page.url()).toContain('search'); - expect(page.url()).toContain(searchQuery); + await expect(page).toHaveURL(/search/); + // searchQuery is alphanumeric test data ('test'); safe for new RegExp without escaping. + await expect(page).toHaveURL(new RegExp(searchQuery)); }); test('Given user is on home page, When viewing search input, Then search input should be visible and accessible', async () => { diff --git a/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts index 2ef30aa82f1..0bef3a74bb1 100644 --- a/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/node-list/node-list-functionality.spec.ts @@ -13,9 +13,12 @@ import { test, expect } from '@playwright/test'; import { HomePage } from '../../../models/home-page'; import { NodeListPage } from '../../../models/node-list-page'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; test.describe('Node List Functionality', () => { + // JUSTIFIED: page objects are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + let nodeListPage: NodeListPage; addPageAnnotationBeforeEach(PAGES.SHARE.NODE_LIST); @@ -25,7 +28,6 @@ test.describe('Node List Functionality', () => { await page.goto('/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); test('Given user is on home page, When viewing node list, Then node list should display tree structure', async () => { @@ -81,22 +83,17 @@ test.describe('Node List Functionality', () => { page }) => { const homePage = new HomePage(page); + const noteName = `_e2e_nav_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; - await expect(nodeListPage.treeView).toBeVisible(); - let notes = await nodeListPage.getAllVisibleNoteNames(); - - if (notes.length === 0) { - // Seed a note so the test always runs — critical navigation path must not be skipped - await homePage.createNote(`_e2e_nav_${Date.now()}`); - await page.goto('/'); - await waitForZeppelinReady(page); - notes = await nodeListPage.getAllVisibleNoteNames(); - } + // Seed a unique note so the click target is deterministic even when other + // parallel specs leave many notes/folders in the shared test workspace. + await homePage.createNote(noteName); + await page.goto('/'); + await waitForZeppelinReady(page); - const noteName = notes[0].trim(); + await expect(nodeListPage.noteLinkByName(noteName)).toBeVisible({ timeout: 15000 }); await nodeListPage.clickNote(noteName); - await page.waitForURL(/notebook\//); - expect(page.url()).toContain('notebook/'); + await expect(page).toHaveURL(/notebook\//, { timeout: 45000 }); }); test('Given user clicks Create New Note button, When modal opens, Then note create modal should be displayed', async ({ diff --git a/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts index dbc27205b3e..239f8740733 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-create/note-create-modal.spec.ts @@ -13,7 +13,7 @@ import { test, expect } from '@playwright/test'; import { HomePage } from '../../../models/home-page'; import { NoteCreateModal } from '../../../models/note-create-modal'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; test.describe('Note Create Modal', () => { let homePage: HomePage; @@ -27,7 +27,6 @@ test.describe('Note Create Modal', () => { await page.goto('/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); await homePage.clickCreateNewNote(); await page.waitForSelector('input[name="noteName"]'); @@ -39,7 +38,7 @@ test.describe('Note Create Modal', () => { await expect(noteCreateModal.createButton).toBeVisible(); await expect(noteCreateModal.interpreterDropdown).toBeVisible(); await expect(noteCreateModal.folderInfoAlert).toBeVisible(); - expect(await noteCreateModal.folderInfoAlert.textContent()).toContain('/'); + await expect(noteCreateModal.folderInfoAlert).toContainText('/'); }); test('Given Create Note modal is open, When checking default note name, Then auto-generated name should follow pattern', async () => { @@ -57,8 +56,7 @@ test.describe('Note Create Modal', () => { // Wait for modal to disappear await expect(noteCreateModal.modal).not.toBeVisible(); - await page.waitForURL(/notebook\//); - expect(page.url()).toContain('notebook/'); + await expect(page).toHaveURL(/notebook\//); // Verify the note was created with the correct name const notebookTitle = page.locator('[data-testid="notebook-title"]'); @@ -85,8 +83,7 @@ test.describe('Note Create Modal', () => { // Wait for modal to disappear await expect(noteCreateModal.modal).not.toBeVisible(); - await page.waitForURL(/notebook\//); - expect(page.url()).toContain('notebook/'); + await expect(page).toHaveURL(/notebook\//); // Verify the note was created with the correct name (without folder path) const notebookTitle = page.locator('[data-testid="notebook-title"]'); diff --git a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts index 2100d56a394..9fe75cbae34 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts @@ -13,7 +13,7 @@ import { test, expect } from '@playwright/test'; import { HomePage } from '../../../models/home-page'; import { NoteImportModal } from '../../../models/note-import-modal'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../../utils'; test.describe('Note Import Modal', () => { let homePage: HomePage; @@ -27,7 +27,6 @@ test.describe('Note Import Modal', () => { await page.goto('/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); await homePage.clickImportNote(); await page.waitForSelector('input[name="noteImportName"]'); diff --git a/zeppelin-web-angular/e2e/tests/share/note-rename/note-rename.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-rename/note-rename.spec.ts index a5a6f1c13f8..34bdac8a178 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-rename/note-rename.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-rename/note-rename.spec.ts @@ -15,13 +15,16 @@ import { NoteRenamePage } from '../../../models/note-rename-page'; import { NoteRenamePageUtil } from '../../../models/note-rename-page.util'; import { addPageAnnotationBeforeEach, + createTestNotebook, + navigateToNotebookWithFallback, PAGES, - performLoginIfRequired, - waitForZeppelinReady, - createTestNotebook + waitForZeppelinReady } from '../../../utils'; test.describe('Note Rename', () => { + // JUSTIFIED: page objects and notebook ids are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + let noteRenamePage: NoteRenamePage; let noteRenameUtil: NoteRenamePageUtil; let testNotebook: { noteId: string; paragraphId: string }; @@ -34,14 +37,14 @@ test.describe('Note Rename', () => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); // Create a test notebook for each test testNotebook = await createTestNotebook(page); - // Navigate to the test notebook - await page.goto(`/#/notebook/${testNotebook.noteId}`); - await page.waitForLoadState('networkidle'); + // Navigate to the test notebook and wait for the notebook component to bind + // to backend data. Hash-route navigation can leave the home shell visible + // for a short time in auth mode, which makes the title locator race. + await navigateToNotebookWithFallback(page, testNotebook.noteId); }); test('Given notebook page is loaded, When checking note title, Then title should be displayed', async () => { diff --git a/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts index 6b6527842e7..355bb287708 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts @@ -13,15 +13,12 @@ import { test, expect } from '@playwright/test'; import { NoteTocPage } from '../../../models/note-toc-page'; import { NoteTocPageUtil } from '../../../models/note-toc-page.util'; -import { - addPageAnnotationBeforeEach, - PAGES, - performLoginIfRequired, - waitForZeppelinReady, - createTestNotebook -} from '../../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady, createTestNotebook } from '../../../utils'; test.describe('Note Table of Contents', () => { + // JUSTIFIED: page objects and notebook ids are stored in describe scope; fullyParallel can overwrite them. + test.describe.configure({ mode: 'default' }); + let noteTocPage: NoteTocPage; let noteTocUtil: NoteTocPageUtil; let testNotebook: { noteId: string; paragraphId: string }; @@ -34,7 +31,6 @@ test.describe('Note Table of Contents', () => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); testNotebook = await createTestNotebook(page); @@ -56,7 +52,7 @@ test.describe('Note Table of Contents', () => { test('Given TOC panel is open, When checking panel title, Then title should display "Table of Contents"', async () => { await noteTocUtil.verifyTocPanelOpens(); await expect(noteTocPage.tocTitle).toBeVisible(); - expect(await noteTocPage.tocTitle.textContent()).toBe('Table of Contents'); + await expect(noteTocPage.tocTitle).toHaveText('Table of Contents'); }); test('Given TOC panel is open with no headings, When checking content, Then empty message should be displayed', async () => { diff --git a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts index 13b03fbdd37..49bbdf92cb6 100644 --- a/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts +++ b/zeppelin-web-angular/e2e/tests/theme/dark-mode.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { DarkModePage } from '../../models/dark-mode-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../utils'; test.describe('Dark Mode Theme Switching', () => { addPageAnnotationBeforeEach(PAGES.SHARE.THEME_TOGGLE); @@ -28,7 +28,6 @@ test.describe('Dark Mode Theme Switching', () => { await waitForZeppelinReady(page); // Handle authentication if shiro.ini exists - await performLoginIfRequired(page); // Ensure a clean localStorage for each test await darkModePage.clearLocalStorage(); @@ -100,8 +99,8 @@ test.describe('Dark Mode Theme Switching', () => { await waitForZeppelinReady(page); // When no explicit theme is set, it defaults to 'system' mode // Even in system mode with light preference, the icon should be robot - await expect(darkModePage.rootElement).toHaveClass(/light/); - await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'light'); + await expect(darkModePage.rootElement).toHaveClass(/light/, { timeout: 15000 }); + await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'light', { timeout: 15000 }); await darkModePage.assertSystemTheme(); // Should show robot icon }); @@ -125,8 +124,8 @@ test.describe('Dark Mode Theme Switching', () => { await page.emulateMedia({ colorScheme: 'light' }); await page.goto('/'); await waitForZeppelinReady(page); - await expect(darkModePage.rootElement).toHaveClass(/light/); - await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'light'); + await expect(darkModePage.rootElement).toHaveClass(/light/, { timeout: 15000 }); + await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'light', { timeout: 15000 }); await darkModePage.assertSystemTheme(); // Robot icon for system theme }); @@ -135,8 +134,8 @@ test.describe('Dark Mode Theme Switching', () => { await page.emulateMedia({ colorScheme: 'dark' }); await page.goto('/'); await waitForZeppelinReady(page); - await expect(darkModePage.rootElement).toHaveClass(/dark/); - await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'dark'); + await expect(darkModePage.rootElement).toHaveClass(/dark/, { timeout: 15000 }); + await expect(darkModePage.rootElement).toHaveAttribute('data-theme', 'dark', { timeout: 15000 }); await darkModePage.assertSystemTheme(); // Robot icon for system theme }); }); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts index 1796e1578a5..3cdc499f682 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-display.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Display Mode', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS_ITEM); @@ -24,7 +24,6 @@ test.describe('Notebook Repository Item - Display Mode', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); await notebookReposPage.navigate(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts index 5fd6af53b94..d941829bc0f 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-edit.spec.ts @@ -13,7 +13,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; import { NotebookRepoItemUtil } from '../../../models/notebook-repo-item.util'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Edit Mode', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS_ITEM); @@ -26,7 +26,6 @@ test.describe('Notebook Repository Item - Edit Mode', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); await notebookReposPage.navigate(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts index e4fc940322f..29cbd419cb2 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-form-validation.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Form Validation', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS_ITEM); @@ -24,7 +24,6 @@ test.describe('Notebook Repository Item - Form Validation', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); await notebookReposPage.navigate(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts index db65b97063d..e8f6f30695c 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-settings.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Settings', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS_ITEM); @@ -24,7 +24,6 @@ test.describe('Notebook Repository Item - Settings', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); await notebookReposPage.navigate(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts index 0fd368e4933..f39f2773036 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repo-item-workflow.spec.ts @@ -13,7 +13,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage, NotebookRepoItemPage } from '../../../models/notebook-repos-page'; import { NotebookRepoItemUtil } from '../../../models/notebook-repo-item.util'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Item - Edit Workflow', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS_ITEM); @@ -26,7 +26,6 @@ test.describe('Notebook Repository Item - Edit Workflow', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); await notebookReposPage.navigate(); diff --git a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts index 39cccf2c581..40c3fa7ae3c 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/notebook-repos/notebook-repos-page-structure.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { NotebookReposPage } from '../../../models/notebook-repos-page'; -import { addPageAnnotationBeforeEach, performLoginIfRequired, waitForZeppelinReady, PAGES } from '../../../utils'; +import { addPageAnnotationBeforeEach, waitForZeppelinReady, PAGES } from '../../../utils'; test.describe('Notebook Repository Page - Structure', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK_REPOS); @@ -22,7 +22,6 @@ test.describe('Notebook Repository Page - Structure', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); notebookReposPage = new NotebookReposPage(page); await notebookReposPage.navigate(); }); diff --git a/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts index 55adf20cf30..c4ee882cf17 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { HeaderPage } from '../../models/header-page'; -import { performLoginIfRequired, waitForZeppelinReady } from '../../utils'; +import { waitForZeppelinReady } from '../../utils'; /** * Regression guard for the header user-menu navigation. @@ -41,7 +41,6 @@ test.describe('Header user menu - full-row navigation', () => { header = new HeaderPage(page); await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); }); for (const item of MENU_ITEMS) { diff --git a/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts index 106345fd2e9..86095206d79 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/workspace-main.spec.ts @@ -12,7 +12,7 @@ import { expect, test } from '@playwright/test'; import { BasePage } from 'e2e/models/base-page'; -import { addPageAnnotationBeforeEach, PAGES, performLoginIfRequired, waitForZeppelinReady } from '../../utils'; +import { addPageAnnotationBeforeEach, PAGES, waitForZeppelinReady } from '../../utils'; addPageAnnotationBeforeEach(PAGES.WORKSPACE.MAIN); @@ -22,7 +22,6 @@ test.describe('Workspace Main Component', () => { test.beforeEach(async ({ page }) => { await page.goto('/#/'); await waitForZeppelinReady(page); - await performLoginIfRequired(page); basePage = new BasePage(page); }); diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index 18a66a0ee6d..b8be01c99a4 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -10,14 +10,13 @@ * limitations under the License. */ -import { test, Page, TestInfo } from '@playwright/test'; +import { test, expect, Page, TestInfo } from '@playwright/test'; import { LoginTestUtil } from './models/login-page.util'; import { E2E_TEST_FOLDER } from './models/base-page'; -import { NotebookUtil } from './models/notebook.util'; +import { LoginPage } from './models/login-page'; export const NOTEBOOK_PATTERNS = { URL_REGEX: /\/notebook\/[^\/\?]+/, - URL_EXTRACT_NOTEBOOK_ID_REGEX: /\/notebook\/([^\/\?]+)/, LINK_SELECTOR: 'a[href*="/notebook/"]' } as const; @@ -161,7 +160,91 @@ export const getBasicPageMetadata = async ( path: getCurrentPath(page) }); -import { LoginPage } from './models/login-page'; +interface WaitForZeppelinReadyOptions { + allowLoginPage?: boolean; +} + +const isLoginPageVisible = async (page: Page): Promise => + page + .locator('zeppelin-login') + .isVisible() + .catch(() => false); + +const waitForLoginPageReady = async (page: Page): Promise => { + await page.waitForFunction( + // JUSTIFIED: multi-condition AND — Angular presence + login element OR across three selectors; can't express as single locator wait + () => { + const hasAngular = document.querySelector('[ng-version]') !== null; + const hasLoginElements = + document.querySelector('zeppelin-login') !== null || + document.querySelector('input[placeholder*="User"], input[placeholder*="user"], input[type="text"]') !== null; + return hasAngular && hasLoginElements; + }, + { timeout: 30000 } + ); +}; + +const waitForWorkspaceOrLogin = async (page: Page): Promise<'workspace' | 'login' | undefined> => + new Promise(resolve => { + let pending = 3; + let resolved = false; + + const finish = (state?: 'workspace' | 'login') => { + if (resolved) { + return; + } + if (state) { + resolved = true; + resolve(state); + return; + } + pending -= 1; + if (pending === 0) { + resolved = true; + resolve(undefined); + } + }; + + page + .locator('zeppelin-workspace') + .waitFor({ state: 'attached', timeout: 45000 }) + .then(() => finish('workspace')) + .catch(() => finish()); + page + .locator('zeppelin-login') + .waitFor({ state: 'visible', timeout: 45000 }) + .then(() => finish('login')) + .catch(() => finish()); + page + .waitForURL(url => url.toString().includes('#/login'), { timeout: 45000 }) + .then(() => finish('login')) + .catch(() => finish()); + }); + +const handleLoginPageIfNeeded = async (page: Page, options: WaitForZeppelinReadyOptions): Promise => { + const isOnLoginPage = page.url().includes('#/login') || (await isLoginPageVisible(page)); + if (!isOnLoginPage) { + return false; + } + + await waitForLoginPageReady(page); + + if (options.allowLoginPage) { + return true; + } + + if (await LoginTestUtil.isShiroEnabled()) { + const loggedIn = await performLoginIfRequired(page); + if (loggedIn) { + return true; + } + + throw new Error('Authentication is required, but the test page remained on the login screen'); + } + + return true; +}; + export const performLoginIfRequired = async (page: Page): Promise => { const isShiroEnabled = await LoginTestUtil.isShiroEnabled(); if (!isShiroEnabled) { @@ -169,9 +252,7 @@ export const performLoginIfRequired = async (page: Page): Promise => { } const credentials = await LoginTestUtil.getTestCredentials(); - const validUsers = Object.values(credentials).filter( - cred => cred.username && cred.password && cred.username !== 'INVALID_USER' && cred.username !== 'EMPTY_CREDENTIALS' - ); + const validUsers = Object.values(credentials).filter(cred => cred.username && cred.password); if (validUsers.length === 0) { return false; @@ -205,31 +286,12 @@ export const performLoginIfRequired = async (page: Page): Promise => { return false; }; -export const waitForZeppelinReady = async (page: Page): Promise => { +export const waitForZeppelinReady = async (page: Page, options: WaitForZeppelinReadyOptions = {}): Promise => { try { // Enhanced wait for network idle with longer timeout for CI environments await page.waitForLoadState('domcontentloaded', { timeout: 45000 }); - // Check if we're on login page and authentication is required - const isOnLoginPage = page.url().includes('#/login'); - if (isOnLoginPage) { - console.log('On login page - checking if authentication is enabled'); - - // If we're on login page, this is expected when authentication is required - // Just wait for login elements to be ready instead of waiting for app content - await page.waitForFunction( - // JUSTIFIED: multi-condition AND — Angular presence + login element OR across three selectors; can't express as single locator wait - () => { - const hasAngular = document.querySelector('[ng-version]') !== null; - const hasLoginElements = - document.querySelector('zeppelin-login') !== null || - document.querySelector('input[placeholder*="User"], input[placeholder*="user"], input[type="text"]') !== - null; - return hasAngular && hasLoginElements; - }, - { timeout: 30000 } - ); - console.log('Login page is ready'); + if (await handleLoginPageIfNeeded(page, options)) { return; } @@ -259,8 +321,10 @@ export const waitForZeppelinReady = async (page: Page): Promise => { { timeout: 90000 } ); - // Additional stability check - wait for DOM to be stable - await page.waitForLoadState('domcontentloaded'); + const settledState = await waitForWorkspaceOrLogin(page); + if (settledState === 'login' || (await handleLoginPageIfNeeded(page, options))) { + return; + } } catch (error) { throw new Error(`Zeppelin loading failed: ${String(error)}`); } @@ -278,6 +342,21 @@ export const waitForNotebookLinks = async (page: Page, timeout: number = 30000) await locator.first().waitFor({ state: 'visible', timeout }); }; +const waitForNotebookParagraphVisible = async (page: Page, noteId: string): Promise => { + const waitOnce = async () => { + await page.waitForURL(new RegExp(`/notebook/${noteId}`), { timeout: 15000 }); + await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 'visible', timeout: 30000 }); + }; + + try { + await waitOnce(); + } catch { + await page.reload({ waitUntil: 'domcontentloaded', timeout: 30000 }); + await waitForZeppelinReady(page); + await waitOnce(); + } +}; + export const navigateToNotebookWithFallback = async ( page: Page, noteId: string, @@ -290,8 +369,6 @@ export const navigateToNotebookWithFallback = async ( await page.goto(`/#/notebook/${noteId}`, { waitUntil: 'networkidle', timeout: 30000 }); navigationSuccessful = true; } catch (error) { - console.log('Direct navigation failed, trying fallback strategies...'); - // Strategy 2: Wait for loading completion and check URL await page.waitForFunction( () => { @@ -327,121 +404,125 @@ export const navigateToNotebookWithFallback = async ( throw new Error(`Failed to navigate to notebook ${noteId}`); } - // Wait for notebook to be ready + // Wait for notebook to be ready. Hash navigation can occasionally reach the + // target URL before the notebook component has subscribed to the backend data; + // a single reload keeps the same route while forcing Angular to fetch the note. await waitForZeppelinReady(page); + await waitForNotebookParagraphVisible(page, noteId); }; -const extractNoteIdFromUrl = async (page: Page): Promise => { - const url = page.url(); - const match = url.match(NOTEBOOK_PATTERNS.URL_EXTRACT_NOTEBOOK_ID_REGEX); - return match ? match[1] : null; -}; +interface ZeppelinJsonResponse { + status: string; + message?: string; + body: T; +} -const waitForNotebookNavigation = async (page: Page): Promise => { - await page.waitForURL(NOTEBOOK_PATTERNS.URL_REGEX, { timeout: 30000 }); - return await extractNoteIdFromUrl(page); -}; +interface InterpreterSettingSummary { + name?: string; +} -const navigateViaHomePageFallback = async (page: Page, baseNotebookName: string): Promise => { - await page.goto('/#/'); - await page.waitForLoadState('networkidle', { timeout: 15000 }); - await page.waitForSelector('zeppelin-node-list', { timeout: 15000 }); +interface NoteSummary { + paragraphs?: Array<{ id?: string }>; +} - await page.locator(NOTEBOOK_PATTERNS.LINK_SELECTOR).first().waitFor({ state: 'attached', timeout: 15000 }); - await page.waitForLoadState('domcontentloaded', { timeout: 15000 }); +const getDefaultInterpreterGroup = async (page: Page): Promise => { + const response = await page.request.get('/api/interpreter/setting', { failOnStatusCode: false }); + if (!response.ok()) { + return undefined; + } - const notebookLink = page.locator(NOTEBOOK_PATTERNS.LINK_SELECTOR).filter({ hasText: baseNotebookName }); + const json = (await response.json()) as ZeppelinJsonResponse; + return json.body?.find(setting => !!setting.name)?.name; +}; - const browserName = page.context().browser()?.browserType().name(); - if (browserName === 'firefox') { - await page.waitForSelector(`${NOTEBOOK_PATTERNS.LINK_SELECTOR}:has-text("${baseNotebookName}")`, { - state: 'visible', - timeout: 90000 - }); - } else { - await notebookLink.waitFor({ state: 'visible', timeout: 60000 }); +const createNotebookViaRest = async ( + page: Page, + notebookName: string +): Promise<{ noteId: string; paragraphId: string }> => { + const defaultInterpreterGroup = await getDefaultInterpreterGroup(page); + const payload: Record = { + notePath: notebookName, + addingEmptyParagraph: true + }; + + if (defaultInterpreterGroup) { + payload.defaultInterpreterGroup = defaultInterpreterGroup; } - await notebookLink.click({ timeout: 15000 }); - await page.waitForURL(NOTEBOOK_PATTERNS.URL_REGEX, { timeout: 20000 }); + const createResponse = await page.request.post('/api/notebook', { + data: payload, + failOnStatusCode: false + }); + if (!createResponse.ok()) { + throw new Error(`Create notebook REST request failed: ${createResponse.status()} ${await createResponse.text()}`); + } - const noteId = await extractNoteIdFromUrl(page); + const createJson = (await createResponse.json()) as ZeppelinJsonResponse; + const noteId = createJson.body; if (!noteId) { - throw new Error('Failed to extract notebook ID after home page navigation'); + throw new Error(`Create notebook REST response did not include note id: ${JSON.stringify(createJson)}`); } - return noteId; -}; - -const extractFirstParagraphId = async (page: Page): Promise => { - await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 'visible', timeout: 20000 }); + let noteJson!: ZeppelinJsonResponse; + await expect(async () => { + const response = await page.request.get(`/api/notebook/${noteId}`, { failOnStatusCode: false }); + if (!response.ok()) { + throw new Error(`Fetch notebook REST request failed: ${response.status()} ${await response.text()}`); + } + noteJson = (await response.json()) as ZeppelinJsonResponse; + }).toPass({ timeout: 7500, intervals: [500, 1000, 1500, 2000, 2500] }); - const paragraphContainer = page.locator('zeppelin-notebook-paragraph').first(); - const dropdownTrigger = paragraphContainer.locator('a[nz-dropdown]'); - await dropdownTrigger.click(); + const paragraphId = noteJson.body?.paragraphs?.[0]?.id; + if (!paragraphId || !paragraphId.startsWith('paragraph_')) { + throw new Error(`Create notebook REST response did not include paragraph id: ${JSON.stringify(noteJson.body)}`); + } - const paragraphLink = page.locator('li.paragraph-id a').first(); - await paragraphLink.waitFor({ state: 'attached', timeout: 15000 }); + return { noteId, paragraphId }; +}; - const paragraphId = await paragraphLink.textContent(); +interface CreateTestNotebookWithNameOptions { + folderPath?: string | null; + namePrefix?: string; +} - // Close the dropdown before returning — leaving it open leaks state into subsequent tests - await page.keyboard.press('Escape'); +export const createTestNotebookWithName = async ( + page: Page, + options: CreateTestNotebookWithNameOptions = {} +): Promise<{ noteId: string; paragraphId: string; notebookName: string; notebookPath: string }> => { + const isRetryableError = (message: string): boolean => + /REST request failed: (404|409|500)\b/.test(message) || message.includes('Fetch notebook REST request failed'); + + const tryCreate = async () => { + const prefix = options.namePrefix ?? 'TestNotebook'; + const notebookName = `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`; + const notebookPath = + options.folderPath === null ? notebookName : `${options.folderPath || E2E_TEST_FOLDER}/${notebookName}`; + const { noteId, paragraphId } = await createNotebookViaRest(page, notebookPath); + await page.goto('/#/'); + await waitForZeppelinReady(page); + return { noteId, paragraphId, notebookName, notebookPath }; + }; - if (!paragraphId || !paragraphId.startsWith('paragraph_')) { - throw new Error(`Invalid paragraph ID found: ${paragraphId}`); + for (let attempt = 1; attempt <= 3; attempt++) { + try { + return await tryCreate(); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + if (attempt === 3 || !isRetryableError(message)) { + throw new Error(`Failed to create test notebook: ${message}. Current URL: ${page.url()}`); + } + await page.waitForTimeout(1000 * attempt); + } } - return paragraphId; + // Unreachable: loop returns on success or throws on final attempt. + throw new Error('createTestNotebookWithName: exhausted retries without resolution'); }; export const createTestNotebook = async ( page: Page, folderPath?: string ): Promise<{ noteId: string; paragraphId: string }> => { - const notebookUtil = new NotebookUtil(page); - const baseNotebookName = `TestNotebook_${Date.now()}`; - const notebookName = folderPath ? `${folderPath}/${baseNotebookName}` : `${E2E_TEST_FOLDER}/${baseNotebookName}`; - - try { - // Create notebook - await notebookUtil.createNotebook(notebookName); - - let noteId: string | null = null; - - // Try direct navigation first - noteId = await waitForNotebookNavigation(page); - - if (!noteId) { - console.log('Direct navigation failed, trying fallback strategies...'); - - // Check if we're already on a notebook page - noteId = await extractNoteIdFromUrl(page); - - if (noteId) { - // Use existing fallback navigation - await navigateToNotebookWithFallback(page, noteId, notebookName); - } else { - // Navigate via home page as last resort - noteId = await navigateViaHomePageFallback(page, baseNotebookName); - } - } - - if (!noteId) { - throw new Error(`Failed to extract notebook ID from URL: ${page.url()}`); - } - - // Extract paragraph ID - const paragraphId = await extractFirstParagraphId(page); - - // Navigate back to home - await page.goto('/#/'); - await waitForZeppelinReady(page); - - return { noteId, paragraphId }; - } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error); - const currentUrl = page.url(); - throw new Error(`Failed to create test notebook: ${errorMessage}. Current URL: ${currentUrl}`); - } + const { noteId, paragraphId } = await createTestNotebookWithName(page, { folderPath }); + return { noteId, paragraphId }; }; diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index 06e92703854..bc1bd46ebd5 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -20,7 +20,7 @@ module.exports = defineConfig({ fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 1, - workers: process.env.CI ? 2 : 5, + workers: 5, timeout: 300000, expect: { timeout: 60000 @@ -43,17 +43,39 @@ module.exports = defineConfig({ navigationTimeout: 180000 }, projects: [ + // Auth setup runs once and writes playwright/.auth/user.json, which the browser + // projects consume via storageState — replaces the per-test login that raced + // under parallel workers. + { + name: 'setup', + testMatch: /global\.setup\.ts/ + }, { name: 'chromium', - use: { ...devices['Desktop Chrome'], permissions: ['clipboard-read', 'clipboard-write'] } + use: { + ...devices['Desktop Chrome'], + permissions: ['clipboard-read', 'clipboard-write'], + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] }, { name: 'Google Chrome', - use: { ...devices['Desktop Chrome'], channel: 'chrome', permissions: ['clipboard-read', 'clipboard-write'] } + use: { + ...devices['Desktop Chrome'], + channel: 'chrome', + permissions: ['clipboard-read', 'clipboard-write'], + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] }, { name: 'firefox', - use: { ...devices['Desktop Firefox'] } + use: { + ...devices['Desktop Firefox'], + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] }, { name: 'webkit', @@ -61,12 +83,20 @@ module.exports = defineConfig({ ...devices['Desktop Safari'], launchOptions: { slowMo: 200 - } - } + }, + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] }, { name: 'Microsoft Edge', - use: { ...devices['Desktop Edge'], channel: 'msedge', permissions: ['clipboard-read', 'clipboard-write'] } + use: { + ...devices['Desktop Edge'], + channel: 'msedge', + permissions: ['clipboard-read', 'clipboard-write'], + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] } ], webServer: process.env.CI diff --git a/zeppelin-web-angular/src/app/share/header/header.component.html b/zeppelin-web-angular/src/app/share/header/header.component.html index a2b378870d4..bb0c706bc4f 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.html +++ b/zeppelin-web-angular/src/app/share/header/header.component.html @@ -25,6 +25,7 @@ class="node-list-trigger" [nzDropdownMenu]="list" [nzTrigger]="'click'" + nzOverlayClassName="zeppelin-notebook-dropdown" [(nzVisible)]="noteListVisible" > Notebook diff --git a/zeppelin-web-angular/src/app/share/header/header.component.less b/zeppelin-web-angular/src/app/share/header/header.component.less index 116d84034f0..faec20b3674 100644 --- a/zeppelin-web-angular/src/app/share/header/header.component.less +++ b/zeppelin-web-angular/src/app/share/header/header.component.less @@ -140,3 +140,14 @@ } } } + +// Cap the dropdown so workspaces with many notes don't overflow the viewport. +// ::ng-deep escapes view encapsulation since the overlay renders in a body-level CDK overlay. +// Scoped via nzOverlayClassName so no other dropdown is affected. +::ng-deep .zeppelin-notebook-dropdown { + zeppelin-node-list { + display: block; + max-height: calc(100vh - 100px); + overflow-y: auto; + } +} From 15966b53d8a96a00fc6f4752516b6edd037b8c1a Mon Sep 17 00:00:00 2001 From: Kalyan Date: Wed, 3 Jun 2026 07:46:00 -0700 Subject: [PATCH 050/179] [ZEPPELIN-4407] Add copy to clipboard (TSV/CSV) for table results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What is this PR for? I've seen users downloading CSV and opening in spreadsheet viewer and copying the text. Adding way to copy CSV/TSV directly. This is orginally implemented by amakaur #3496 but it was closed due to lack of tests. I'm picking it up now. ### Changes **Angular UI (`zeppelin-web-angular`)** - `result.component` — paragraph toolbar dropdown: renamed existing items to "Download as CSV/TSV", added divider, then "Copy as TSV" and "Copy as CSV" - `table-visualization.component` — inner table Export menu: added "Copy all data as TSV/CSV" and "Copy visible data as TSV/CSV" (mirrors the existing "Export visible" scope) **Classic AngularJS UI (`zeppelin-web`)** - `result-chart-selector.html` — same dropdown restructure: Download / divider / Copy - `result.controller.js` — new `$scope.copyToClipboard(delimiter)` function ### Behaviour - Header row (column names) is always included in the copied text - Cell values containing the delimiter, double-quotes, or newlines are RFC 4180 quoted - Uses `navigator.clipboard.writeText` with a `document.execCommand('copy')` fallback for older browsers ## What type of PR is it? Feature ## What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-4407 ## How should this be tested? 1. Run a paragraph that outputs a TABLE (e.g. `%sh printf "col1\tcol2\na\t1\nb\t2\n"`) 2. Click the **▾** next to the download button in the paragraph toolbar 3. Verify the menu shows: **Download as CSV**, **Download as TSV**, *(divider)*, **Copy as TSV**, **Copy as CSV** 4. Click **Copy as TSV** → paste into a spreadsheet app or text editor — expect headers + rows, tab-delimited 5. Click **Copy as CSV** → paste → expect headers + rows, comma-delimited 6. Test with a cell value containing a comma, e.g. `"hello, world"` → the CSV copy should quote it correctly ## Tests - **Classic UI (Karma/Jasmine):** `zeppelin-web/src/app/notebook/paragraph/result/result.controller.test.js` — 4 new specs covering TSV copy, CSV copy, delimiter quoting, and double-quote escaping - **Angular UI (Playwright E2E):** `zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts` — 3 new specs (skipped on CI, require a live interpreter) ## Questions - Does the license file need update? No - Is there a breaking change for older versions? No — existing Download as CSV/TSV behaviour is unchanged - Does this need documentation? No ## screenshots image image Closes #5261 from kkalyan/master. Signed-off-by: ChanHo Lee --- .../paragraph/copy-to-clipboard.spec.ts | 145 ++++++++++++++++ .../share/result/result.component.html | 7 +- .../share/result/result.component.ts | 35 ++++ .../table/table-visualization.component.html | 13 ++ .../table/table-visualization.component.ts | 32 ++++ .../result/result-chart-selector.html | 9 +- .../paragraph/result/result.controller.js | 44 +++++ .../result/result.controller.test.js | 163 ++++++++++++++++++ 8 files changed, 443 insertions(+), 5 deletions(-) create mode 100644 zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts diff --git a/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts new file mode 100644 index 00000000000..dc13297dd46 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts @@ -0,0 +1,145 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, test } from '@playwright/test'; +import { NotebookParagraphPage } from 'e2e/models/notebook-paragraph-page'; +import { NotebookKeyboardPage } from 'e2e/models/notebook-keyboard-page'; +import { + addPageAnnotationBeforeEach, + performLoginIfRequired, + waitForZeppelinReady, + PAGES, + createTestNotebook +} from '../../../utils'; + +test.describe('Copy table result to clipboard', () => { + addPageAnnotationBeforeEach(PAGES.SHARE.SHARE_RESULT); + + let paragraphPage: NotebookParagraphPage; + let testNotebook: { noteId: string; paragraphId: string }; + + test.beforeEach(async ({ page, context }, testInfo) => { + testInfo.skip(!!process.env.CI, 'Requires a running shell interpreter — skipped on CI'); + // Grant clipboard permissions so navigator.clipboard.writeText works in tests + await context.grantPermissions(['clipboard-read', 'clipboard-write']); + + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + + testNotebook = await createTestNotebook(page); + paragraphPage = new NotebookParagraphPage(page); + + await page.goto(`/#/notebook/${testNotebook.noteId}`); + await page.waitForLoadState('networkidle'); + + // Type a paragraph that outputs a TABLE result using the %sh interpreter + await paragraphPage.doubleClickToEdit(); + await expect(paragraphPage.codeEditor).toBeVisible(); + + const codeEditor = paragraphPage.codeEditor.locator('textarea, .monaco-editor .input-area').first(); + await expect(codeEditor).toBeAttached({ timeout: 10000 }); + await codeEditor.focus(); + + const keyboard = new NotebookKeyboardPage(page); + await keyboard.pressSelectAll(); + await page.keyboard.type('%sh\nprintf "name\\tcount\\na\\t12\\nb\\t24\\n"'); + + await paragraphPage.runParagraph(); + await expect(paragraphPage.resultDisplay).toBeVisible({ timeout: 30000 }); + }); + + test('export dropdown should contain Copy as TSV and Copy as CSV options', async ({ page }) => { + // Open the export dropdown (down-arrow button next to the download icon) + const exportDropdownTrigger = page + .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') + .first(); + await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); + await exportDropdownTrigger.click(); + + const menu = page.locator('.ant-dropdown-menu'); + await expect(menu).toBeVisible({ timeout: 5000 }); + + await expect(menu.locator('li:has-text("Download as CSV")')).toBeVisible(); + await expect(menu.locator('li:has-text("Download as TSV")')).toBeVisible(); + await expect(menu.locator('li:has-text("Copy as TSV")')).toBeVisible(); + await expect(menu.locator('li:has-text("Copy as CSV")')).toBeVisible(); + }); + + test('Copy as TSV should write tab-delimited data with headers to clipboard', async ({ page }) => { + const exportDropdownTrigger = page + .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') + .first(); + await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); + await exportDropdownTrigger.click(); + + const menu = page.locator('.ant-dropdown-menu'); + await expect(menu).toBeVisible({ timeout: 5000 }); + await menu.locator('li:has-text("Copy as TSV")').click(); + + // Read back what was written to the clipboard + const clipboardText = await page.evaluate(() => navigator.clipboard.readText()); + const lines = clipboardText.split('\n').filter(l => l.trim().length > 0); + + // First line must be the header row + expect(lines[0]).toBe('name\tcount'); + // Data rows follow + expect(lines[1]).toBe('a\t12'); + expect(lines[2]).toBe('b\t24'); + }); + + test('Copy as CSV should write comma-delimited data with headers to clipboard', async ({ page }) => { + const exportDropdownTrigger = page + .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') + .first(); + await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); + await exportDropdownTrigger.click(); + + const menu = page.locator('.ant-dropdown-menu'); + await expect(menu).toBeVisible({ timeout: 5000 }); + await menu.locator('li:has-text("Copy as CSV")').click(); + + const clipboardText = await page.evaluate(() => navigator.clipboard.readText()); + const lines = clipboardText.split('\n').filter(l => l.trim().length > 0); + + expect(lines[0]).toBe('name,count'); + expect(lines[1]).toBe('a,12'); + expect(lines[2]).toBe('b,24'); + }); + + test('Copy as CSV should quote cell values that contain double quotes', async ({ page }) => { + // Re-run the paragraph with a value containing a double quote + const codeEditor = page.locator('.monaco-editor .input-area, textarea').first(); + await codeEditor.focus(); + const keyboard = new NotebookKeyboardPage(page); + await keyboard.pressSelectAll(); + await page.keyboard.type('%sh\nprintf "col1\\tcol2\\nsay \\"hi\\"\\t1\\n"'); + await new NotebookParagraphPage(page).runParagraph(); + await page.waitForLoadState('networkidle'); + + const exportDropdownTrigger = page + .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') + .first(); + await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); + await exportDropdownTrigger.click(); + + const menu = page.locator('.ant-dropdown-menu'); + await expect(menu).toBeVisible({ timeout: 5000 }); + await menu.locator('li:has-text("Copy as CSV")').click(); + + const clipboardText = await page.evaluate(() => navigator.clipboard.readText()); + const lines = clipboardText.split('\n').filter(l => l.trim().length > 0); + + // 'say "hi"' contains double quotes — must be RFC 4180 quoted in CSV output + expect(lines[1]).toBe('"say ""hi""",1'); + }); +}); diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html index ce70756b3ec..878bd2efdc4 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.html @@ -42,8 +42,11 @@
      -
    • CSV
    • -
    • TSV
    • +
    • Download as CSV
    • +
    • Download as TSV
    • +
    • +
    • Copy as TSV
    • +
    • Copy as CSV
    diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts index 04b994911b6..85f9715c7f2 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts @@ -271,6 +271,41 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, } } + copyToClipboard(type: 'tsv' | 'csv'): void { + if (!this.tableData || !this.tableData.rows) { + return; + } + const delimiter = type === 'tsv' ? '\t' : ','; + const { columns, rows } = this.tableData; + const escape = (value: unknown): string => { + const str = String(value ?? ''); + return str.includes(delimiter) || str.includes('"') || str.includes('\n') ? `"${str.replace(/"/g, '""')}"` : str; + }; + const lines = [ + columns.map(escape).join(delimiter), + ...rows.map(row => columns.map(col => escape(row[col])).join(delimiter)) + ]; + const text = lines.join('\n'); + // TODO: Refactor the duplicated copy-to-clipboard logics + const fallbackCopy = () => { + const el = document.createElement('textarea'); + el.value = text; + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + }; + // navigator.clipboard is undefined in non-secure contexts (e.g. plain HTTP), + // where writeText would throw synchronously before the catch could run. + if (navigator.clipboard) { + navigator.clipboard.writeText(text).catch(fallbackCopy); + } else { + fallbackCopy(); + } + } + switchMode(mode: VisualizationMode) { if (!this.config) { throw new Error('config is not defined'); diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html index 7ea134b803c..f5213cc831c 100644 --- a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.html @@ -28,6 +28,19 @@
  • Export visible data as excel
  • +
  • +
  • + Copy all data as TSV +
  • +
  • + Copy all data as CSV +
  • +
  • + Copy visible data as TSV +
  • +
  • + Copy visible data as CSV +
  • { + const str = String(value ?? ''); + return str.includes(delimiter) || str.includes('"') || str.includes('\n') ? `"${str.replace(/"/g, '""')}"` : str; + }; + const lines = [ + this.columns.map(escape).join(delimiter), + ...sourceRows.map(row => this.columns.map(col => escape(row[col])).join(delimiter)) + ]; + const text = lines.join('\n'); + // TODO: Refactor the duplicated copy-to-clipboard logics + const fallbackCopy = () => { + const el = document.createElement('textarea'); + el.value = text; + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + }; + // navigator.clipboard is undefined in non-secure contexts (e.g. plain HTTP), + // where writeText would throw synchronously before the catch could run. + if (navigator.clipboard) { + navigator.clipboard.writeText(text).catch(fallbackCopy); + } else { + fallbackCopy(); + } + } + onChangeType(type: ColType, col: string) { this.getColOptionOrThrow(col).type = type; this.filterRows(); diff --git a/zeppelin-web/src/app/notebook/paragraph/result/result-chart-selector.html b/zeppelin-web/src/app/notebook/paragraph/result/result-chart-selector.html index 6b34977f8f9..1e78a6e3ee4 100644 --- a/zeppelin-web/src/app/notebook/paragraph/result/result-chart-selector.html +++ b/zeppelin-web/src/app/notebook/paragraph/result/result-chart-selector.html @@ -87,9 +87,12 @@ Toggle Dropdown -
    diff --git a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js index d55c51e025f..bd850d0ba31 100644 --- a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js +++ b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.js @@ -914,6 +914,50 @@ function ResultCtrl($scope, $rootScope, $route, $window, $routeParams, $location saveAsService.saveAs(dsv, exportedFileName, extension); }; + $scope.copyToClipboard = function(delimiter) { + const escape = function(value) { + let stringValue = (value === null || value === undefined) ? '' : String(value); + let hasDelimiter = stringValue.indexOf(delimiter) > -1; + let hasQuote = stringValue.indexOf('"') > -1; + let hasNewline = stringValue.indexOf('\n') > -1; + if (hasDelimiter || hasQuote || hasNewline) { + return '"' + stringValue.replaceAll('"', '""') + '"'; + } + return stringValue; + }; + let headerParts = []; + for (let titleIndex in tableData.columns) { + if (tableData.columns.hasOwnProperty(titleIndex)) { + headerParts.push(escape(tableData.columns[titleIndex].name)); + } + } + let text = headerParts.join(delimiter) + '\n'; + for (let r in tableData.rows) { + if (tableData.rows.hasOwnProperty(r)) { + let row = tableData.rows[r]; + let dsvRow = ''; + for (let index in row) { + if (row.hasOwnProperty(index)) { + dsvRow += escape(row[index]) + delimiter; + } + } + text += dsvRow.substring(0, dsvRow.length - 1) + '\n'; + } + } + if (navigator.clipboard) { + navigator.clipboard.writeText(text); + } else { + let el = document.createElement('textarea'); + el.value = text; + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + } + }; + $scope.getBase64ImageSrc = function(base64Data) { return 'data:image/png;base64,' + base64Data; }; diff --git a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.test.js b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.test.js index c299973cc83..0086ad80d1e 100644 --- a/zeppelin-web/src/app/notebook/paragraph/result/result.controller.test.js +++ b/zeppelin-web/src/app/notebook/paragraph/result/result.controller.test.js @@ -38,4 +38,167 @@ describe('Controller: ResultCtrl', function() { expect(scope).toBeDefined(); expect(controller).toBeDefined(); }); + + describe('copyToClipboard', function() { + let tableResultMock; + let tableConfigMock; + let tableParagraphMock; + let clipboardText; + + beforeEach(inject(function($controller, $rootScope) { + tableResultMock = { + type: 'TABLE', + data: 'name\tcount\na\t12\nb\t24\n', + }; + tableConfigMock = { + graph: { + mode: 'table', + height: 300, + optionOpen: false, + setting: {}, + }, + }; + tableParagraphMock = { + id: 'p2', + results: { + msg: [tableResultMock], + }, + }; + + scope = $rootScope.$new(); + scope.$parent = $rootScope.$new(true, $rootScope); + scope.$parent.paragraph = tableParagraphMock; + + controller = $controller('ResultCtrl', { + $scope: scope, + $route: route, + }); + + scope.init(tableResultMock, tableConfigMock, tableParagraphMock, 0); + + clipboardText = null; + spyOn(navigator.clipboard, 'writeText').and.callFake(function(text) { + clipboardText = text; + return Promise.resolve(); + }); + })); + + it('should copy TSV with header row to clipboard', function(done) { + scope.copyToClipboard('\t'); + setTimeout(function() { + expect(navigator.clipboard.writeText).toHaveBeenCalled(); + let lines = clipboardText.split('\n').filter(function(l) { + return l.length > 0; + }); + expect(lines[0]).toBe('name\tcount'); + expect(lines[1]).toBe('a\t12'); + expect(lines[2]).toBe('b\t24'); + done(); + }, 0); + }); + + it('should copy CSV with header row to clipboard', function(done) { + scope.copyToClipboard(','); + setTimeout(function() { + expect(navigator.clipboard.writeText).toHaveBeenCalled(); + let lines = clipboardText.split('\n').filter(function(l) { + return l.length > 0; + }); + expect(lines[0]).toBe('name,count'); + expect(lines[1]).toBe('a,12'); + done(); + }, 0); + }); + + it('should quote cell values that contain the delimiter', function(done) { + let specialResultMock = { + type: 'TABLE', + data: 'col1\tcol2\nhello,world\t42\n', + }; + let specialParagraphMock = { + id: 'p3', + results: { + msg: [specialResultMock], + }, + }; + + inject(function($controller, $rootScope) { + let specialScope = $rootScope.$new(); + specialScope.$parent = $rootScope.$new(true, $rootScope); + specialScope.$parent.paragraph = specialParagraphMock; + $controller('ResultCtrl', {$scope: specialScope, $route: route}); + specialScope.init(specialResultMock, tableConfigMock, specialParagraphMock, 0); + + specialScope.copyToClipboard(','); + setTimeout(function() { + let lines = clipboardText.split('\n').filter(function(l) { + return l.length > 0; + }); + // "hello,world" contains comma — must be quoted for CSV + expect(lines[1]).toBe('"hello,world",42'); + done(); + }, 0); + }); + }); + + it('should quote cell values that contain double quotes', function(done) { + let quoteResultMock = { + type: 'TABLE', + data: 'col1\tcol2\nsay "hi"\t1\n', + }; + let quoteParagraphMock = { + id: 'p4', + results: { + msg: [quoteResultMock], + }, + }; + + inject(function($controller, $rootScope) { + let quoteScope = $rootScope.$new(); + quoteScope.$parent = $rootScope.$new(true, $rootScope); + quoteScope.$parent.paragraph = quoteParagraphMock; + $controller('ResultCtrl', {$scope: quoteScope, $route: route}); + quoteScope.init(quoteResultMock, tableConfigMock, quoteParagraphMock, 0); + + quoteScope.copyToClipboard('\t'); + setTimeout(function() { + let lines = clipboardText.split('\n').filter(function(l) { + return l.length > 0; + }); + expect(lines[1]).toBe('"say ""hi"""\t1'); + done(); + }, 0); + }); + }); + + it('should quote header values that contain double quotes', function(done) { + let headerQuoteResultMock = { + type: 'TABLE', + data: 'col "A"\tcol2\nval1\t1\n', + }; + let headerQuoteParagraphMock = { + id: 'p5', + results: { + msg: [headerQuoteResultMock], + }, + }; + + inject(function($controller, $rootScope) { + let headerScope = $rootScope.$new(); + headerScope.$parent = $rootScope.$new(true, $rootScope); + headerScope.$parent.paragraph = headerQuoteParagraphMock; + $controller('ResultCtrl', {$scope: headerScope, $route: route}); + headerScope.init(headerQuoteResultMock, tableConfigMock, headerQuoteParagraphMock, 0); + + headerScope.copyToClipboard('\t'); + setTimeout(function() { + let lines = clipboardText.split('\n').filter(function(l) { + return l.length > 0; + }); + expect(lines[0]).toBe('"col ""A"""\tcol2'); + done(); + }, 0); + }); + }); + }); }); From 6c13c8edafa9d5b9a747aadc50fb909b0e3268b6 Mon Sep 17 00:00:00 2001 From: hojeong park Date: Sun, 7 Jun 2026 14:50:50 +0900 Subject: [PATCH 051/179] [ZEPPELIN-6424] Align web-angular README Node.js prerequisite ### What is this PR for? Updates the `zeppelin-web-angular` README Node.js prerequisite from v16 to `22.21.1`. This matches the version pinned in `zeppelin-web-angular/.nvmrc` and `zeppelin-web-angular/pom.xml`. ### What type of PR is it? Documentation ### Todos * [x] Update the `zeppelin-web-angular` Node.js prerequisite ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6424 ### How should this be tested? Documentation-only change. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? Yes Closes #5269 from parkhojeong/docs/web-angular-node-prerequisite. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-web-angular/README.md b/zeppelin-web-angular/README.md index af2e65425ff..9084494005d 100644 --- a/zeppelin-web-angular/README.md +++ b/zeppelin-web-angular/README.md @@ -23,7 +23,7 @@ Zeppelin notebooks front-end built with Angular. ### Prerequisites -- [Node.js](https://nodejs.org) v16 or use [creationix/nvm](https://github.com/creationix/nvm). +- [Node.js](https://nodejs.org) 22.21.1 or use [creationix/nvm](https://github.com/creationix/nvm). - NPM package manager (which is installed with Node.js by default). - [Angular CLI](https://angular.io/cli) version 8.3.0 or later. From e1712ecee5f170ec375b3b4945e061bd2ca73a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Tue, 9 Jun 2026 00:27:12 +0900 Subject: [PATCH 052/179] [ZEPPELIN-6429] Focus paragraph editor on clone/insert in New UI ### What is this PR for? After cloning or inserting a paragraph in the New UI, the cursor stays on the wrapper element instead of the editor, so you have to click before typing. This focuses the new paragraph's editor one tick after `PARAGRAPH_ADDED`, gated to clone/insert initiated by this client so auto-append on run and other clients' inserts don't steal focus. It also skips dirty-marking on programmatic editor `setValue` (`isFlush`) so the cloned content isn't discarded. (The clone *content* loss itself is handled separately in https://github.com/apache/zeppelin/pull/5254#pullrequestreview-4415596876; this covers the *cursor* part.) ### What type of PR is it? Bug Fix ### Todos ### What is the Jira issue? ZEPPELIN-6429 ### How should this be tested? ### Screenshots (if appropriate) https://github.com/user-attachments/assets/2dca9137-3eb3-49c3-bff8-da3429613025 ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5267 from voidmatcha/fix/clone-paragraph-cursor-focus-master. Signed-off-by: ChanHo Lee --- .../zeppelin/socket/NotebookServer.java | 13 +++--- .../interfaces/message-notebook.interface.ts | 1 + .../workspace/notebook/notebook.component.ts | 11 +++++ .../code-editor/code-editor.component.ts | 11 +++-- .../src/app/services/message.service.ts | 40 +++++++++++++++++-- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 20343d8a0a5..090272ce5d9 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -692,16 +692,17 @@ private void broadcastParagraphs(Map userParagraphMap, Paragr inlineBroadcastParagraphs(userParagraphMap, msgId); } - private void inlineBroadcastNewParagraph(Note note, Paragraph para) { + private void inlineBroadcastNewParagraph(Note note, Paragraph para, String msgId) { LOGGER.info("Broadcasting paragraph on run call instead of note."); int paraIndex = note.getParagraphs().indexOf(para); - Message message = new Message(OP.PARAGRAPH_ADDED).put("paragraph", para).put("index", paraIndex); + Message message = + new Message(OP.PARAGRAPH_ADDED).withMsgId(msgId).put("paragraph", para).put("index", paraIndex); connectionManager.broadcast(note.getId(), message); } - private void broadcastNewParagraph(Note note, Paragraph para) { - inlineBroadcastNewParagraph(note, para); + private void broadcastNewParagraph(Note note, Paragraph para, String msgId) { + inlineBroadcastNewParagraph(note, para, msgId); } private void inlineBroadcastNoteList() { @@ -1451,7 +1452,7 @@ private String insertParagraph(NotebookSocket conn, @Override public void onSuccess(Paragraph p, ServiceContext context) throws IOException { super.onSuccess(p, context); - broadcastNewParagraph(p.getNote(), p); + broadcastNewParagraph(p.getNote(), p, fromMessage.msgId); } }); @@ -1555,7 +1556,7 @@ public void onSuccess(Paragraph p, ServiceContext context) StringUtils.isEmpty(p.getScriptText())) && isTheLastParagraph) { Paragraph newPara = p.getNote().addNewParagraph(p.getAuthenticationInfo()); - broadcastNewParagraph(p.getNote(), newPara); + broadcastNewParagraph(p.getNote(), newPara, fromMessage.msgId); } } }); diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts index 986aed0b910..665e8dfd71f 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-notebook.interface.ts @@ -167,6 +167,7 @@ export interface ImportNoteReceived { export interface ParagraphAdded { index: number; + msgId?: string; paragraph: ParagraphItem; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 6905a5fc4e5..1cb8d2b288b 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -157,6 +157,17 @@ export class NotebookComponent extends MessageListenersManager implements OnInit definedNote.paragraphs[paragraphIndex].focus = true; this.cdr.markForCheck(); + + // Focus the editor only for a clone/insert initiated by this client (not auto-append on run or remote inserts). + // Defer a tick so the new paragraph's editor child exists, since `focus = true` alone misses it. + if (this.messageService.consumeLocalAddFocusMsgId(data.msgId)) { + const addedId = data.paragraph.id; + setTimeout(() => { + const added = this.listOfNotebookParagraphComponent?.find(e => e.paragraph.id === addedId); + added?.focusEditor(); + added?.notebookParagraphCodeEditorComponent?.setRestorePosition(); + }); + } } @MessageListener(OP.SAVE_NOTE_FORMS) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index c212de77cf7..093a34e11cc 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -94,19 +94,24 @@ export class NotebookParagraphCodeEditorComponent this.position = e.position; }); }), - editor.onDidChangeModelContent(() => { + editor.onDidChangeModelContent(e => { this.ngZone.run(() => { const model = editor.getModel(); if (!model) { throw new Error('Model content changed but model not found.'); } this.text = model.getValue(); - this.textChanged.emit(this.text); - this.setParagraphMode(true); this.autoAdjustEditorHeight(); setTimeout(() => { this.autoAdjustEditorHeight(); }); + this.setParagraphMode(true); + // A flush is a programmatic setValue (editor init, remote content update, patch), not a user edit. + // Such changes must not mark the paragraph dirty. + if (e.isFlush) { + return; + } + this.textChanged.emit(this.text); }); }) ); diff --git a/zeppelin-web-angular/src/app/services/message.service.ts b/zeppelin-web-angular/src/app/services/message.service.ts index 8949e5e1c79..9b86a7d42d6 100644 --- a/zeppelin-web-angular/src/app/services/message.service.ts +++ b/zeppelin-web-angular/src/app/services/message.service.ts @@ -12,6 +12,7 @@ import { Inject, Injectable, OnDestroy, Optional } from '@angular/core'; import { Observable } from 'rxjs'; +import { take } from 'rxjs/operators'; import { MessageInterceptor, MESSAGE_INTERCEPTOR } from '@zeppelin/interfaces'; import { @@ -22,6 +23,7 @@ import { MessageSendDataTypeMap, Note, NoteConfig, + OP, ParagraphConfig, ParagraphParams, PersonalizedMode, @@ -38,6 +40,8 @@ import { TicketService } from './ticket.service'; providedIn: 'root' }) export class MessageService extends Message implements OnDestroy { + private readonly localAddFocusMsgIds = new Set(); + constructor( private baseUrlService: BaseUrlService, private ticketService: TicketService, @@ -47,7 +51,11 @@ export class MessageService extends Message implements OnDestroy { } interceptReceived(data: WebSocketMessage): WebSocketMessage { - return this.messageInterceptor ? this.messageInterceptor.received(data) : super.interceptReceived(data); + const received = this.messageInterceptor ? this.messageInterceptor.received(data) : super.interceptReceived(data); + if (received.op === OP.PARAGRAPH_ADDED && received.data && received.msgId) { + (received.data as MessageReceiveDataTypeMap[OP.PARAGRAPH_ADDED]).msgId = received.msgId; + } + return received; } bootstrap(): void { @@ -78,6 +86,30 @@ export class MessageService extends Message implements OnDestroy { return super.receive(op); } + consumeLocalAddFocusMsgId(msgId: string | undefined): boolean { + if (!msgId) { + return false; + } + return this.localAddFocusMsgIds.delete(msgId); + } + + private captureLocalAddFocusMsgId(sendMessage: () => void): void { + const subscription = super + .sent() + .pipe(take(1)) + .subscribe(message => { + if (message.msgId) { + this.localAddFocusMsgIds.add(message.msgId); + } + }); + try { + sendMessage(); + } catch (error) { + subscription.unsubscribe(); + throw error; + } + } + opened(): Observable { return super.opened(); } @@ -167,7 +199,7 @@ export class MessageService extends Message implements OnDestroy { } insertParagraph(newIndex: number): void { - super.insertParagraph(newIndex); + this.captureLocalAddFocusMsgId(() => super.insertParagraph(newIndex)); } copyParagraph( @@ -177,7 +209,9 @@ export class MessageService extends Message implements OnDestroy { paragraphConfig: ParagraphConfig, paragraphParams: ParagraphParams ): void { - super.copyParagraph(newIndex, paragraphTitle, paragraphData, paragraphConfig, paragraphParams); + this.captureLocalAddFocusMsgId(() => + super.copyParagraph(newIndex, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) + ); } angularObjectUpdate( From 78255fd960234022e4f6149239c43ae963cffa9e Mon Sep 17 00:00:00 2001 From: Jarek Potiuk Date: Fri, 12 Jun 2026 03:38:47 +0200 Subject: [PATCH 053/179] Add security threat model and wire AGENTS.md -> SECURITY.md -> THREAT_MODEL.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **This is a v0 draft proposal for the Zeppelin PMC to review — please correct, reject, or discuss as needed.** The maintainer is the decision-maker; nothing here is a requirement. The threat model does not need to be "finished" for anything downstream — it just makes automated security review (and triage of inbound reports) far less noisy. **Context.** The ASF Security team is preparing the project for an automated agentic security scan we're piloting. Those scans run against a threat model that tells the scanner what's in scope, what's by-design, and what counts as a real finding — without one, the output buries maintainers in noise. This PR proposes the discoverable model plus the wiring the scanner needs. **What's in this PR:** - **`THREAT_MODEL.md`** (new) — a v0 security threat model written from Zeppelin's public docs + codebase, following the [threat-model-producer rubric](https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573). Every claim carries a provenance tag: *(documented)* (from your docs/site) or *(inferred)* (our guess from code/docs, for you to confirm / correct / strike). Draft confidence ~18 documented / 24 inferred. - **`SECURITY.md`** (was an empty file) — disclosure pointer + link to the threat model. - **`AGENTS.md`** — a `## Security` section so the `AGENTS.md → SECURITY.md → THREAT_MODEL.md` chain resolves for automated tooling. The existing developer guidance is unchanged. **The framing to sanity-check first:** Apache Zeppelin runs user notebook code by design, so RBAC (Shiro + notebook ACL + URL ACL + impersonation) is the boundary, **not a sandbox** — a `%sh` command from a run-capable user is the product working, not RCE. The model treats interpreter execution as in-scope only when it crosses an authn/authz or tenant boundary. **What we'd need from the PMC:** 1. **§14 wave 1 (the important one):** rule on the insecure defaults — is anonymous-by-default / public-notebooks / impersonation-off the *supported production posture* (a report against it is `VALID`), or a dev-convenience operators are expected to change (`OUT-OF-MODEL: non-default-build`)? This reshapes the whole model. 2. Walk the §14 questions (waves 1–3) — a one-line confirm / correct / strike per question is enough; each *(inferred)* tag becomes *(maintainer)* as you answer. If you'd rather own the drafting yourselves, close the PR and we'll wait — entirely your call. Closes #5268 from potiuk/asf-security/threat-model-2026-06-05. Signed-off-by: Jongyoul Lee --- AGENTS.md | 13 ++ SECURITY.md | 44 ++++++ THREAT_MODEL.md | 383 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 440 insertions(+) create mode 100644 SECURITY.md create mode 100644 THREAT_MODEL.md diff --git a/AGENTS.md b/AGENTS.md index ff974bed7e7..a9a559817e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -558,3 +558,16 @@ Key conventions: - **Testing**: JUnit 5 (Jupiter) + Mockito (Java; a small number of legacy JUnit 4 tests still exist), Playwright (frontend E2E) - **Logging**: SLF4J + Log4j2 - **License**: Apache License 2.0 — all new files need the ASF header + +## Security + +Security model: [SECURITY.md](./SECURITY.md), which links to the project's +threat model at [THREAT_MODEL.md](./THREAT_MODEL.md). + +Agents that scan this repository should consult `THREAT_MODEL.md` for the +project's in-scope / out-of-scope declarations, the security properties it +provides and disclaims, the configuration knobs whose defaults change the +security envelope, and the known non-findings (recurring false positives) +before reporting issues. In particular, Apache Zeppelin executes user-supplied +notebook code through its interpreters by design — that is the product's +function, not a vulnerability; see `THREAT_MODEL.md` §3, §9, and §11a. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..b4d40854d0a --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,44 @@ + + +# Security Policy + +## Reporting a Vulnerability + +Please report suspected security vulnerabilities in Apache Zeppelin privately +to the Apache Security Team at , following the ASF process +at . Do not open public GitHub issues or pull +requests for security reports. + +## Threat Model + +Apache Zeppelin's security threat model — what is in and out of scope, the +security properties the project provides and disclaims, the adversary model, +the configuration knobs whose defaults change the security envelope, and how +findings are triaged — is documented in [THREAT_MODEL.md](./THREAT_MODEL.md). + +Note that Apache Zeppelin executes user-supplied notebook code through its +interpreters by design; that capability is the product's primary function, and +the threat model is about *who may reach it and with what isolation*. See +`THREAT_MODEL.md` §3, §9, and §11a. + +## Operational Security Setup + +Operator-facing security configuration — authentication via Apache Shiro, +notebook authorization, interpreter user impersonation, and HTTPS / HTTP +security headers — is documented on the project website: + diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md new file mode 100644 index 00000000000..285a7b3cb4c --- /dev/null +++ b/THREAT_MODEL.md @@ -0,0 +1,383 @@ + + +# Apache Zeppelin — Security Threat Model + +## §1 Header + +- **Project:** Apache Zeppelin +- **Modeled against:** `master` HEAD as of 2026-06-05 (latest released docs line). +- **Authors:** ASF Security team (v0 draft, generated via the + `threat-model-producer` rubric), for the Apache Zeppelin PMC to review. +- **Status:** **DRAFT v0 — draft-first, not yet maintainer-ratified.** Most + claims are *(inferred)* from public documentation and the codebase and + must be confirmed; see §14. +- **Version binding:** this model is versioned with the project. A report + against Zeppelin release *N* is triaged against the model as it stood at *N*. +- **Reporting cross-reference:** findings that violate a §8 property should be + reported privately per the project's disclosure channel + (`security@apache.org`); findings that fall under §3 or §9 are closed citing + this document. +- **Provenance legend:** *(documented)* = stated in Zeppelin's own docs/site; + *(maintainer)* = confirmed by a Zeppelin PMC member; *(inferred)* = reasoned + from code/docs/domain knowledge, not yet confirmed (each has a §14 question). +- **Draft confidence:** ~18 documented / 0 maintainer / ~24 inferred. + +**What Zeppelin is.** Apache Zeppelin is a web-based, multi-user notebook +server for interactive data analytics. Users open notebooks in a browser and +run "paragraphs" of code against pluggable *interpreters* (Spark, Flink, +Python, JDBC, shell, etc.); the Zeppelin server launches and talks to +interpreter processes over a Thrift IPC channel and returns results to the +browser over a websocket. **Executing user-supplied code on the server is the +product's primary function, not a vulnerability** — the security model is +about *who is allowed to reach that capability and with what isolation*, not +about preventing code execution. + +## §2 Scope and intended use + +- **Primary intended use** *(inferred)*: an operator-deployed, multi-tenant + analytics notebook server, run inside an organization's trusted network and + fronted by authentication, where authorized analysts author and run + notebooks against backend compute (Spark/Flink/etc.). +- **Deployment shape** *(documented)*: a long-running JVM server + (`zeppelin-server`) plus one or more interpreter processes; reached via HTTP + + websocket, optionally behind a reverse proxy (NGINX). +- **Caller roles** (a network service, so the role splits): + - **client / notebook user** — untrusted until authenticated; once + authenticated, trusted only up to their notebook/role permissions. + - **operator / admin** — trusted for the instance; owns `shiro.ini`, + interpreter settings, `zeppelin-site.xml`, the host. + - **anonymous visitor** — present **by default** (see §5a); trusted at + whatever level the deployment's authorization grants anonymous, which by + default is full access. + +**Component-family table** *(inferred — confirm in §14)*: + +| Family | Entry point | Touches outside process? | In model? | +| --- | --- | --- | --- | +| Web/REST/websocket server | `org.apache.zeppelin.rest.*`, websocket | network | **yes** | +| AuthN/AuthZ (Shiro + notebook ACL + URL ACL) | `shiro.ini`, `NotebookAuthorization`, `SecurityRestApi` | filesystem (config) | **yes** | +| Interpreter launch + IPC | Thrift `RemoteInterpreterServer`, process launcher | child processes, network | **yes** (the launch/isolation boundary) | +| Interpreter-executed user code | `%spark`, `%sh`, `%python`, `%jdbc`, … | arbitrary (by design) | **boundary only** — the *code* is by-design; reaching/isolating it is in model | +| Credentials / datasource auth | `CredentialRestApi`, credential injection | filesystem, backends | **yes** | +| Notebook storage / repos | `NotebookRepo` (local FS, S3, Git, etc.) | filesystem / cloud | **yes** | +| Bundled interpreters / examples / web UI assets | `*-interpreter` modules, demos | varies | **per-interpreter** — confirm which are supported (§14) | + +## §3 Out of scope (explicit non-goals) + +- **Sandboxing the code a permitted user runs.** A user with run permission on + a notebook can execute arbitrary code (`%sh`, Spark driver code, etc.) by + design; Zeppelin does not attempt to confine what that code does on the host + or backend. *(inferred — §14)* +- **Defending a deployment that disables authentication and is exposed to an + untrusted network.** The docs direct operators to enable Shiro *or* deploy + only in a secured/trusted environment *(documented)*; an unauthenticated, + internet-exposed instance is an operator misconfiguration, not a Zeppelin + defect (pending the §5a/§14 ruling on whether anonymous is a supported + posture). +- **Security of third-party interpreter backends** (the Spark cluster, the + JDBC database, the host shell) — Zeppelin brokers access; it does not own + those systems' security. *(inferred)* +- **Bundled examples / demo notebooks / unsupported interpreters** — threat- + modeled separately if at all; integrators should not extend core guarantees + to them. *(inferred — §14: which interpreters are first-class?)* + +## §4 Trust boundaries and data flow + +The **primary trust boundary is the authentication + authorization layer** +(Shiro realm → notebook ACL → URL ACL), not the API surface itself. Data flow +and the trust transitions it crosses: + +1. Browser → **HTTP/websocket** → server: crosses the network boundary. + Untrusted until Shiro authenticates the session. *(documented)* +2. Authenticated session → **notebook operation** (read/write/run): crosses + the notebook-ACL boundary (owner/reader/writer/runner). *(documented)* +3. Run request → **interpreter process** over Thrift IPC: the server hands + user code to an interpreter. Whether this crosses an OS-user boundary + depends on **impersonation** (off by default → runs as the *server* OS + user). *(documented)* +4. Interpreter → backend (Spark/JDBC/FS/shell): leaves Zeppelin's boundary + entirely. *(inferred)* + +**Reachability preconditions per family** (the triager's first test): +- A finding in the web/REST/websocket family is in-model only if reachable by + a network client **before** the Shiro auth gate, or by an authenticated user + **beyond** their granted role/notebook permission. +- A finding in interpreter-launch/IPC is in-model only if it lets a user cross + a boundary the model claims (e.g., one tenant reaching another tenant's + interpreter/credentials, or escaping the impersonation user when impersonation + is on). +- A finding that is "authenticated run-capable user executes code / reads files + as the interpreter's OS user" is **out of model** (that is the granted + capability) unless it crosses into another tenant or the operator boundary. + +## §5 Assumptions about the environment + +- **Operator-controlled host and config** *(inferred)*: `shiro.ini`, + `zeppelin-site.xml`, credential stores, and the interpreter settings are + trusted inputs written by the operator, not attacker-controllable. +- **Network placement** *(documented)*: Zeppelin expects to sit in a secured/ + trusted network or behind an authenticating proxy; HTTPS is "highly + recommended" for the web/websocket channel. +- **Backend trust** *(inferred)*: the Spark/Flink/JDBC/SSH backends an + interpreter reaches are provisioned by the operator. +- **What the server does to its host** *(inferred — §14)*: launches child + interpreter processes; reads config + notebook storage; opens listening + sockets (HTTP/websocket, Thrift); with impersonation, performs SSH/`setuid`- + style user switching. It is *not* expected to run as root. + +## §5a Build-time and configuration variants (the security-envelope knobs) + +This is the heart of Zeppelin's model — several **defaults are the less-secure +value**, so the model is ambiguous until the PMC rules on each (see §14 wave 1): + +| Knob | Default | Effect on model | Maintainer stance | +| --- | --- | --- | --- | +| Shiro authentication (`conf/shiro.ini`) | **absent → anonymous** *(documented)* | No auth boundary at all; every §8 authn/authz property is void | **?** supported posture vs dev-only — §14.1 | +| `zeppelin.notebook.public` / `ZEPPELIN_NOTEBOOK_PUBLIC` | **`true` → new notes public** *(documented)* | Empty-ACL note is readable/runnable by any authenticated (or anonymous) user | **?** §14.2 | +| Interpreter user impersonation | **off → runs as server OS user** *(documented)* | Without it, every run-capable user's code shares the *server's* OS identity/privileges and filesystem | **?** §14.3 | +| Interpreter binding mode (shared / scoped / isolated) | **shared** *(inferred)* | Process-level separation between users/notes; "isolated" is a *stability/resource* boundary, **not** a security sandbox | **?** §14.4 | +| URL ACLs (`[urls]` in shiro.ini) gating `/interpreter`, `/credential`, `/configurations` | **not restricted unless operator adds them** *(documented)* | Sensitive admin endpoints open to any authenticated role absent explicit `[urls]` rules | **?** §14.5 | +| HTTPS / security headers (`http_security_headers`) | **off/plain unless configured** *(documented)* | Credentials + session over plaintext; missing CSP/XFO | operator responsibility (§10) | + +**Insecure-default ruling needed.** For each row whose default is the less- +secure value, the PMC must rule: is the default the *supported production +posture* (→ a report against it is `VALID`), or a *dev-convenience operators +must change* (→ `OUT-OF-MODEL: non-default-build`, and the requirement moves to +§10)? The public docs lean toward the latter ("strongly recommended… or only +deploy… in a secured and trusted environment"), but this needs an explicit PMC +call because it reshapes §8/§10/§11a/§13 at once. + +## §6 Assumptions about inputs + +Inputs and their trust (network-service shape — rows are endpoints/messages): + +| Surface | Input | Attacker-controllable? | Caller/operator must enforce | +| --- | --- | --- | --- | +| `POST` login / Shiro filter | credentials | **yes** (pre-auth) | strong realm config; lockout/rate-limit at proxy *(inferred)* | +| Websocket ops (run/edit/move paragraph) | notebook + paragraph payload | **yes** (authenticated user) | notebook ACL + run permission enforced server-side *(documented)* | +| `NotebookRestApi` / `InterpreterRestApi` | note id, interpreter settings | **yes** (authenticated user) | URL ACL + ownership checks *(inferred — §14.6)* | +| `CredentialRestApi` | per-user credentials | **yes** (authenticated user) | per-user credential isolation *(inferred — §14.7)* | +| Paragraph code body | arbitrary code | **yes — by design** | this is the granted capability, not validated input | +| `shiro.ini`, `zeppelin-site.xml`, interpreter JSON | config | **no — operator-trusted** | filesystem perms on config/secret files *(inferred)* | +| Notebook storage backend contents | persisted notes | **mostly trusted** (written via the app) | integrity of the repo (S3/Git/FS) *(inferred)* | + +Size/shape/rate: *(inferred — §14)* no documented limits on paragraph size, +result size, or websocket message rate; resource exhaustion via large +results / many interpreter launches is plausible and needs a §8 resource line. + +## §7 Adversary model + +**In scope:** +- **Unauthenticated network client** (when Shiro is enabled): tries to reach + any authenticated capability without valid credentials — bypass the login + filter, forge/steal a session, reach a websocket/REST op pre-auth. +- **Authenticated lower-privileged user**: a legitimate user trying to exceed + their grant — read/edit/run another user's note they lack ACL for, read + another user's credentials, reach admin endpoints (`/interpreter`, + `/credential`) their role shouldn't, or (impersonation on) break out of their + impersonation identity into another user's or the server's. + +**Capabilities:** can send arbitrary HTTP/websocket traffic; can author +arbitrary code in paragraphs they may run; cannot (assumed) read the operator's +config/secret files or the host outside what their interpreter identity grants. + +**Explicitly out of scope:** +- The **operator/admin** and anyone with write access to `shiro.ini` / + interpreter config / the host — they have already won. +- A user **executing code within their own granted run permission** — that is + the product working as designed, even though the code can be `%sh rm -rf`. +- Anyone reaching a **default anonymous** instance over an untrusted network — + out of model pending the §5a/§14 ruling. + +## §8 Security properties the project provides + +Each conditional on the relevant §5a knob being set securely. *(All +*(inferred)* pending §14 — Zeppelin documents the mechanisms but does not +publish them as committed "properties".)* + +1. **Authentication of the web/REST/websocket surface** *when Shiro is + configured*. Violation symptom: an unauthenticated client performs an + operation requiring a session. Severity: **critical**. *(inferred)* +2. **Authorization of notebook operations per the owner/reader/writer/runner + ACL** *when auth is on*. Violation symptom: a user reads/edits/runs a note + they lack permission for. Severity: **critical**. *(documented mechanism / + inferred as a committed property)* +3. **URL-level access control** for sensitive endpoints via `[urls]`. + Violation symptom: a non-admin reaches `/interpreter`, `/credential`, or + `/configurations` despite a restricting rule. Severity: **high**. + *(documented mechanism)* +4. **Per-user credential isolation** (one user cannot read another's injected + datasource credentials). Violation symptom: cross-user credential read. + Severity: **critical**. *(inferred — §14.7)* +5. **Impersonation confinement** *when enabled*: interpreter code runs as the + logged-in user, not the server user, and not as another user. Violation + symptom: code runs as a different identity than the session's. Severity: + **high**. *(documented mechanism / inferred property)* +6. **Resource/availability** *(inferred — §14)*: **needs a line.** Is an + unauthenticated request able to spawn interpreters / exhaust memory a bug? + Propose: pre-auth resource exhaustion is in-model; an authenticated user + running an expensive query is not. Confirm threshold in §14. + +## §9 Security properties the project does *not* provide + +- **No sandbox of permitted code.** A run-capable user's paragraph executes + with the full authority of the interpreter's OS identity (the *server* user + unless impersonation is on). "Zeppelin runs my shell command" is not a + vulnerability. *(inferred — §14.3)* +- **No protection in anonymous/default mode.** With no `shiro.ini`, there is no + authn/authz boundary; everything in §8 is void. *(documented)* +- **No transport security by default.** Plaintext HTTP/websocket unless the + operator configures TLS; credentials transit in the clear otherwise. + *(documented)* + +**False-friend properties (call out explicitly):** +- **Interpreter "isolated" binding mode is not a security sandbox.** It gives + each user/note a separate interpreter *process* for stability and resource + separation; it does **not** confine what the code in that process can do to + the host or to shared backends, and absent impersonation all those processes + still run as the **same server OS user**. *(inferred — §14.4)* +- **Notebook permissions are an application-layer ACL, not OS isolation.** A + user denied *read* on a note in the UI may still reach data through an + interpreter they *can* run if backends aren't separately access-controlled. + *(inferred — §14)* + +**Well-known attack classes left to the operator/integrator:** SSRF from +interpreter code reaching internal services; secrets-in-notebooks; XSS/CSRF on +the notebook web UI (mitigated only if `http_security_headers` + CSRF defenses +are enabled — confirm coverage in §14); websocket cross-origin. One line each; +the point is to put integrators on notice. + +## §10 Downstream / operator responsibilities + +For Zeppelin the "user" is the **operator** deploying it: +- **Enable Shiro authentication** (or keep Zeppelin strictly inside a trusted, + network-isolated perimeter). *(documented)* +- **Add `[urls]` rules** restricting `/interpreter`, `/credential`, + `/configurations` (and other admin paths) to admin roles. *(documented)* +- **Set `zeppelin.notebook.public=false`** if notebooks should default to + private. *(documented)* +- **Enable interpreter impersonation** for genuine multi-tenant isolation; do + not rely on binding mode alone. *(documented)* +- **Terminate TLS** and enable `http_security_headers`. *(documented)* +- **Protect `shiro.ini`, credential stores, and notebook storage** with host + filesystem permissions; do not run the server as root. *(inferred)* +- **Treat backends (Spark/JDBC/SSH) as reachable by any run-capable user** and + access-control them independently. *(inferred)* + +## §11 Known misuse patterns + +- Exposing a **default (anonymous) Zeppelin to the public internet** — turns + the by-design code-execution surface into unauthenticated RCE-equivalent. +- Relying on **notebook ACLs while interpreters run shared/as-server-user**, so + a run-capable user reaches data the ACL meant to hide. +- Treating **"isolated" binding as a security boundary** between tenants. +- Storing **long-lived secrets in notebook source** instead of the credential + store, then sharing the note. +- Leaving **`/interpreter` and `/credential` reachable** by all authenticated + users (no `[urls]` rules). + +## §11a Known non-findings (recurring false positives) + +The highest-leverage section for keeping scan output signal-heavy: + +- **"`%sh` / interpreter executes arbitrary shell or driver code → RCE."** + By design for a run-capable user; `OUT-OF-MODEL` / `BY-DESIGN` unless it + crosses a tenant or the operator boundary. (§3, §9) *(inferred — §14.3)* +- **"Interpreter process runs as the Zeppelin server OS user / can read server + files."** Documented default behavior without impersonation; operator config, + not a defect. (§5a, §10) *(documented)* +- **"Anonymous user can do X"** reported against a deployment with **no + `shiro.ini`.** Out of model — auth is operator-enabled. (§5a, §9) + *(documented)* +- **"No TLS / credentials in plaintext"** against a deployment the operator did + not configure for HTTPS. Operator responsibility. (§10) *(documented)* +- **Static-analysis "command injection / code execution" hits on the + interpreter execution path.** That path *is* the feature; in-model only if it + bypasses the authn/authz gate. (§4 reachability test) *(inferred)* + +## §12 Conditions that would change this model + +- A new network surface or REST/websocket endpoint; a new first-class + interpreter; a change of any §5a default (e.g., shipping `shiro.ini` enabled, + or `notebook.public=false` by default); adding a built-in sandbox for + interpreter code; a new notebook-storage backend with different trust. +- **A report that cannot be routed to one §13 disposition** is itself evidence + the model is incomplete — revise §8/§9 rather than make an ad-hoc call. + +## §13 Triage dispositions + +| Disposition | Meaning | Licensed by | +| --- | --- | --- | +| `VALID` | Bypasses the authn/authz gate, or lets a user exceed their notebook/role grant, or crosses a tenant/credential/impersonation boundary, with auth configured. | §8, §6, §7 | +| `VALID-HARDENING` | No §8 property broken, but the API makes a §11 misuse too easy; hardened at maintainer discretion. | §11 | +| `OUT-OF-MODEL: trusted-input` | Requires control of operator config (`shiro.ini`, interpreter JSON, host). | §6 | +| `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator/admin privilege, or is a run-capable user executing code within their grant. | §7 | +| `OUT-OF-MODEL: non-default-build` | Only manifests under an insecure §5a default the PMC rules dev-only (e.g., anonymous mode, public notebooks, no impersonation). | §5a | +| `BY-DESIGN: property-disclaimed` | Concerns interpreter code execution or a property §9 disclaims. | §9 | +| `KNOWN-NON-FINDING` | Matches a §11a pattern. | §11a | +| `MODEL-GAP` | Cannot be routed above → revise the model. | §12 | + +## §14 Open questions for the maintainers + +Grouped in waves; each states a **proposed answer** to confirm/correct/strike. +Every *(inferred)* tag above maps to one of these. + +**Wave 1 — scope & the insecure defaults (these reshape everything):** +1. **Anonymous default.** Proposed: anonymous/no-`shiro.ini` is a *dev- + convenience*; the supported production posture requires Shiro **or** a + trusted isolated network. So reports against an internet-exposed anonymous + instance are `OUT-OF-MODEL: non-default-build`. Correct? (→ §5a, §3, §11a) +2. **`notebook.public=true` default.** Proposed: public-by-default is intended + convenience; operators needing isolation set it false. A "any user can read + an empty-ACL note" report is by-design, not a bug. Correct? (→ §5a, §2) +3. **Impersonation off by default.** Proposed: without impersonation, all + interpreter code legitimately runs as the **server** OS user; this is the + documented default and not a vulnerability; multi-tenant OS isolation + requires enabling impersonation. Correct? (→ §3, §5a, §9, §11a) +4. **Binding mode as boundary.** Proposed: shared/scoped/isolated are + stability/resource controls, **not** security sandboxes; we should state + that explicitly in §9. Agree? Which is the default? (→ §5a, §9) + +**Wave 2 — properties & enforcement:** +5. **URL ACL default.** Are `/interpreter`, `/credential`, `/configurations` + open to any authenticated role unless `[urls]` restricts them, or is there a + built-in admin gate? (→ §5a, §8) +6. **Server-side ACL enforcement.** Are notebook ACLs + role checks enforced on + the **server** for every websocket/REST op (not just hidden in the UI)? Any + ops that check only client-side? (→ §6, §8) +7. **Credential isolation.** Does the credential store guarantee one user + cannot read another user's injected credentials, including via a shared + interpreter process? (→ §8, §9) + +**Wave 3 — surfaces & limits:** +8. **First-class interpreters.** Which interpreters/modules are supported for + security purposes vs. community/unsupported (→ §2/§3 carve-out)? +9. **Resource limits.** Any limits on paragraph/result size, websocket rate, or + concurrent interpreter launches? Where's the line between in-model pre-auth + exhaustion and by-design expensive queries? (→ §6, §8) +10. **Web-UI hardening.** Does enabling `http_security_headers` give CSRF + XSS + + clickjacking coverage, or are those partly the operator's job? (→ §9) +11. **Coexistence.** This is a new `THREAT_MODEL.md`; `SECURITY.md` (currently a + stub) should point at it as canonical, and the website security pages stay + the operator how-to. Agree? (→ meta) + +## §15 Machine-readable companion + +Deferred for v0; a `threat-model.yaml` sidecar (entry points → trust, §5a +defaults, §8 properties, §11a suppressions, §13 labels) can be generated once +the prose is ratified. From 0c25a6ee09cd43f3b4b1de1218b4e43bd8434b86 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Wed, 17 Jun 2026 00:48:44 +0900 Subject: [PATCH 054/179] [ZEPPELIN-6426] Remove redundant eslint-disable comments in zeppelin-web-angular ### What is this PR for? zeppelin-web-angular has several eslint-disable comments that no longer suppress any violation under the current ESLint configuration (e.g. no-invalid-this, id-blacklist, no-eval, jsdoc/no-types, typescript-eslint/naming-convention, angular-eslint/component-class-suffix). These unused directives are misleading and add noise, so this PR removes them. No functional change. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6426 ### How should this be tested? * Run `npm run lint` in zeppelin-web-angular and confirm it still passes. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5264 from tbonelee/fix-lint. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/eslint.config.js | 7 +++++++ .../projects/zeppelin-react/eslint.config.js | 8 ++++++++ .../src/interfaces/message-common.interface.ts | 1 - .../src/interfaces/message-operator.interface.ts | 1 - .../src/g2-visualization-component-base.ts | 1 - .../zeppelin-visualization/src/table-transformation.ts | 1 - zeppelin-web-angular/src/app/app-http.interceptor.ts | 1 - .../src/app/core/destroy-hook/destroy-hook.component.ts | 1 - .../src/app/core/message-listener/message-listener.ts | 7 +------ zeppelin-web-angular/src/app/languages/scala.ts | 1 - .../app/pages/workspace/share/result/result.component.ts | 1 - zeppelin-web-angular/src/app/services/helium.service.ts | 1 - 12 files changed, 16 insertions(+), 15 deletions(-) diff --git a/zeppelin-web-angular/eslint.config.js b/zeppelin-web-angular/eslint.config.js index 86f78bb57c1..69bc491e056 100644 --- a/zeppelin-web-angular/eslint.config.js +++ b/zeppelin-web-angular/eslint.config.js @@ -25,6 +25,13 @@ module.exports = tseslint.config( // Build output, vendored binaries and the React sub-app are never linted. ignores: ['dist/**', 'target/**', '.angular/**', 'coverage/**', 'node/**', 'projects/zeppelin-react/**'] }, + { + // Fail (not just warn) on eslint-disable directives that no longer suppress + // anything. The flat-config default is 'warn', and `ng lint` exits 0 on + // warnings, so stale directives would otherwise accumulate unnoticed -- + // promoting to 'error' keeps the ZEPPELIN-6426 cleanup enforced. + linterOptions: { reportUnusedDisableDirectives: 'error' } + }, { files: ['**/*.ts'], // == legacy `plugin:@angular-eslint/recommended` (sets the TS parser and diff --git a/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js b/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js index b981e30ca16..4cc363261d9 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js +++ b/zeppelin-web-angular/projects/zeppelin-react/eslint.config.js @@ -31,6 +31,14 @@ module.exports = tseslint.config( // == legacy `ignorePatterns` ignores: ['dist/**', 'node_modules/**', 'webpack.config.js'] }, + { + // Fail (not just warn) on eslint-disable directives that no longer suppress + // anything. The flat-config default is 'warn', and `npm run lint:react` + // (plain `eslint`, no --max-warnings) exits 0 on warnings, so stale + // directives would otherwise accumulate unnoticed -- mirrors the root + // zeppelin-web-angular config (ZEPPELIN-6426). + linterOptions: { reportUnusedDisableDirectives: 'error' } + }, { files: ['src/**/*.{ts,tsx}'], // == legacy `extends`: eslint:recommended + @typescript-eslint/recommended diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts index 2ebbe71f526..dfbaf4bf189 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ /* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts index c1a0c969524..1f8036b3931 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-operator.interface.ts @@ -10,7 +10,6 @@ * limitations under the License. */ -/* eslint-disable jsdoc/no-types */ /** * Representation of event type. */ diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts index 3a1f3da43c2..cc6e01173f0 100644 --- a/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/g2-visualization-component-base.ts @@ -21,7 +21,6 @@ import { Visualization } from './visualization'; template: '', standalone: false }) -// eslint-disable-next-line @angular-eslint/component-class-suffix export abstract class G2VisualizationComponentBase implements OnDestroy { abstract container: ElementRef; chart?: G2.Chart | null; diff --git a/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts index fcaf559cb56..aa671fcd735 100644 --- a/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts +++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/table-transformation.ts @@ -14,7 +14,6 @@ import { GraphConfig } from '@zeppelin/sdk'; import { TableData } from './table-data'; import { Transformation } from './transformation'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any export class TableTransformation extends Transformation { constructor(config: GraphConfig) { super(config); diff --git a/zeppelin-web-angular/src/app/app-http.interceptor.ts b/zeppelin-web-angular/src/app/app-http.interceptor.ts index db003370f90..e3e4f26a4f0 100644 --- a/zeppelin-web-angular/src/app/app-http.interceptor.ts +++ b/zeppelin-web-angular/src/app/app-http.interceptor.ts @@ -28,7 +28,6 @@ export class AppHttpInterceptor implements HttpInterceptor { intercept(httpRequest: HttpRequest, next: HttpHandler): Observable> { let httpRequestUpdated = httpRequest.clone({ withCredentials: true }); if (environment.production) { - // eslint-disable-next-line @typescript-eslint/naming-convention httpRequestUpdated = httpRequest.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); } return next.handle(httpRequestUpdated).pipe( diff --git a/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts index 97d15b2d7e0..12e7374e9b3 100644 --- a/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts +++ b/zeppelin-web-angular/src/app/core/destroy-hook/destroy-hook.component.ts @@ -17,7 +17,6 @@ import { Subject } from 'rxjs'; template: '', standalone: false }) -// eslint-disable-next-line @angular-eslint/component-class-suffix export class DestroyHookComponent implements OnDestroy { readonly destroy$ = new Subject(); diff --git a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts index 12897460aef..6487124ecc7 100644 --- a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts +++ b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts @@ -19,7 +19,6 @@ import { Message, MessageReceiveDataTypeMap, ReceiveArgumentsType } from '@zeppe template: '', standalone: false }) -// eslint-disable-next-line @angular-eslint/component-class-suffix export class MessageListenersManager implements OnDestroy { __zeppelinMessageListeners__?: Array<() => void>; __zeppelinMessageListeners$__: Subscriber | null = new Subscriber(); @@ -43,18 +42,14 @@ export function MessageListener(op: K ) { const oldValue = descriptor.value as ReceiveArgumentsType; - // eslint-disable-next-line no-invalid-this const fn = function (this: MessageListenersManager) { - // eslint-disable-next-line no-invalid-this if (!this.__zeppelinMessageListeners$__) { throw new Error('__zeppelinMessageListeners$__ is not defined'); } - // eslint-disable-next-line no-invalid-this + this.__zeppelinMessageListeners$__.add( - // eslint-disable-next-line no-invalid-this this.messageService.receive(op).subscribe(data => { // @ts-ignore - // eslint-disable-next-line no-invalid-this oldValue.apply(this, [data]); }) ); diff --git a/zeppelin-web-angular/src/app/languages/scala.ts b/zeppelin-web-angular/src/app/languages/scala.ts index 4b8c821055e..4930eb05c92 100644 --- a/zeppelin-web-angular/src/app/languages/scala.ts +++ b/zeppelin-web-angular/src/app/languages/scala.ts @@ -232,7 +232,6 @@ export const language = { [/[\/*]/, 'comment.doc'] ], - // eslint-disable-next-line id-blacklist string: [ [/[^\\"]+/, 'string'], [/@escapes/, 'string.escape'], diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts index 85f9715c7f2..1b2ef5c9f38 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts @@ -596,7 +596,6 @@ export class NotebookParagraphResultComponent implements OnInit, AfterViewInit, this.destroy$.complete(); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any private commitClassicVizConfigChange(configForMode: GraphConfig, mode: string) { if (this.isPending) { return; diff --git a/zeppelin-web-angular/src/app/services/helium.service.ts b/zeppelin-web-angular/src/app/services/helium.service.ts index 84fe126e2f0..f120bc120da 100644 --- a/zeppelin-web-angular/src/app/services/helium.service.ts +++ b/zeppelin-web-angular/src/app/services/helium.service.ts @@ -91,7 +91,6 @@ export class HeliumService extends BaseRest { // eslint-disable-next-line @typescript-eslint/no-explicit-any (window as any)._heliumBundles = [] as HeliumBundle[]; availableBundles.forEach(bundle => { - // eslint-disable-next-line no-eval eval(bundle); }); From 3d92e924f2a4cc1926d544e885da6167c1dcbf9a Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Wed, 17 Jun 2026 00:52:20 +0900 Subject: [PATCH 055/179] [ZEPPELIN-6427] Convert interpreter setting form to typed reactive forms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Numeric interpreter properties edited in the Angular UI are sent as JSON numbers, which Gson deserializes as `Double` (`60000` → `"60000.0"`), breaking `Long`/`Integer` parsing in interpreters such as JDBC (ZEPPELIN-6395). The server-side workaround from ZEPPELIN-6131 only covers the update path, not create. This PR fixes it on the client by converting `InterpreterItemComponent` from `UntypedFormBuilder` to typed reactive forms: - Non-checkbox values are sent as strings (like the classic UI); checkbox values stay real booleans, and `"true"`/`"false"` strings from corrupted data are normalized back on save. - New request DTOs mirror the fields `InterpreterOption.java` actually reads; the UI-only `session`/`process` fields (dead since ZEPPELIN-1210) are no longer sent. - Fixes wrong `Properties.value`/`type` interface types; response option fields that Gson omits when null are now optional. Alternative to #5147, which stringifies checkbox booleans too — persisting `"false"` makes an unchecked checkbox render as checked on reload. Credit to kevinjmh for the original diagnosis. ### What type of PR is it? Improvement ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6427 (fixes ZEPPELIN-6395) ### How should this be tested? No unit test infra exists in `zeppelin-web-angular` (Playwright e2e only), so verified by `ng build` (strict, 0 errors), lint/prettier, and manually: numeric property saves as `"60000"` in `interpreter.json` (create and update), JDBC paragraph runs without `NumberFormatException`, unchecked checkbox stays unchecked after reload, and a regression pass over create/edit/cancel, property and dependency CRUD, and interpreter binding mode options. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5265 from tbonelee/ZEPPELIN-6427-typed-interpreter-forms. Signed-off-by: ChanHo Lee --- .../src/app/interfaces/interpreter.ts | 54 ++- .../interpreter/interpreter.component.ts | 11 +- .../interpreter/item/item.component.html | 3 +- .../interpreter/item/item.component.ts | 313 +++++++++++------- .../src/app/services/interpreter.service.ts | 15 +- 5 files changed, 254 insertions(+), 142 deletions(-) diff --git a/zeppelin-web-angular/src/app/interfaces/interpreter.ts b/zeppelin-web-angular/src/app/interfaces/interpreter.ts index 76a6e00ad0a..4b289987bae 100644 --- a/zeppelin-web-angular/src/app/interfaces/interpreter.ts +++ b/zeppelin-web-angular/src/app/interfaces/interpreter.ts @@ -65,13 +65,52 @@ interface SnapshotPolicy { interface Properties { [key: string]: { name: string; - value: boolean; - type: string; - defaultValue?: string; + // The server serializes every property value as a string or boolean. + // `type: 'number'` props are still sent as quoted strings (e.g. "1000") — + // the type is only a UI hint, not the JSON type. null is never sent either: + // Gson omits null values, so an unset value arrives as undefined (key absent). + value: string | boolean; + type: InterpreterPropertyTypes; + defaultValue?: string | boolean; description?: string; }; } +export interface InterpreterPropertyValue { + name: string; + value: string | boolean; + type: InterpreterPropertyTypes; +} + +/** + * Request shape for creating/updating an interpreter setting. + * Mirrors the fields the server actually reads (InterpreterOption.java) — + * UI-only state such as `session`/`process` must not be sent. + */ +export interface InterpreterSettingOption { + isExistingProcess: boolean; + isUserImpersonate: boolean; + owners: string[]; + perNote: string; + perUser: string; + /** null is accepted by the server and kept as the default -1 (unset) */ + port: number | null; + host: string; + remote: boolean; + setPermission: boolean; +} + +export interface InterpreterSettingRequest { + name: string; + group: string; + option: InterpreterSettingOption; + properties: Record; + dependencies: Array<{ + groupArtifactVersion: string; + exclusions: string[]; + }>; +} + interface InterpreterGroupItem { name: string; class: string; @@ -91,14 +130,19 @@ interface DependenciesItem { exclusions: string[]; } +/** + * Response shape of InterpreterOption.java serialized by Gson. + * Primitive boolean/int fields are always present; String/List fields + * are omitted when null (e.g. fresh option templates from GET /interpreter). + */ interface Option { remote: boolean; port: number; isExistingProcess: boolean; setPermission: boolean; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - owners: any[]; isUserImpersonate: boolean; + host?: string; + owners?: string[]; perNote?: string; perUser?: string; } diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts index 1c6a7a3e861..0c31e2a752c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/interpreter.component.ts @@ -17,7 +17,12 @@ import { debounceTime } from 'rxjs/operators'; import { NzMessageService } from 'ng-zorro-antd/message'; import { NzModalService } from 'ng-zorro-antd/modal'; -import { Interpreter, InterpreterPropertyTypes, InterpreterRepository } from '@zeppelin/interfaces'; +import { + Interpreter, + InterpreterPropertyTypes, + InterpreterRepository, + InterpreterSettingRequest +} from '@zeppelin/interfaces'; import { InterpreterService } from '@zeppelin/services'; import { InterpreterCreateRepositoryModalComponent } from './create-repository-modal/create-repository-modal.component'; @@ -75,7 +80,7 @@ export class InterpreterComponent implements OnInit, OnDestroy { }); } - addInterpreterSetting(data: Interpreter): void { + addInterpreterSetting(data: InterpreterSettingRequest): void { this.interpreterService.addInterpreterSetting(data).subscribe(res => { this.interpreterSettings.push(res); this.showCreateSetting = false; @@ -84,7 +89,7 @@ export class InterpreterComponent implements OnInit, OnDestroy { }); } - updateInterpreter(data: Interpreter): void { + updateInterpreter(data: InterpreterSettingRequest): void { this.interpreterService.updateInterpreter(data).subscribe(res => { const current = this.interpreterSettings.find(e => e.name === res.name); if (current) { diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html index 5d8b81b914a..f38c9363426 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.html @@ -257,6 +257,7 @@

    Option

    Properties ****** } @case ('url') { - + {{ control.get('value')?.value || '' }} } diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts index 15e10e7e12d..06634bff485 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/item/item.component.ts @@ -11,22 +11,58 @@ */ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnDestroy, OnInit } from '@angular/core'; -import { - AbstractControl, - UntypedFormArray, - UntypedFormBuilder, - UntypedFormGroup, - ValidationErrors, - Validators, - ValidatorFn -} from '@angular/forms'; +import { AbstractControl, FormArray, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms'; import { DestroyHookComponent } from '@zeppelin/core'; -import { Interpreter } from '@zeppelin/interfaces'; +import { + Interpreter, + InterpreterPropertyTypes, + InterpreterPropertyValue, + InterpreterSettingRequest +} from '@zeppelin/interfaces'; import { InterpreterService, SecurityService, TicketService } from '@zeppelin/services'; import { BehaviorSubject, Observable } from 'rxjs'; import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators'; import { InterpreterComponent } from '../interpreter.component'; +type PropertyValue = string | number | boolean | null; + +interface PropertyFormGroup { + key: FormControl; + value: FormControl; + description: FormControl; + type: FormControl; +} + +interface DependencyFormGroup { + groupArtifactVersion: FormControl; + exclusions: FormControl; +} + +interface OptionFormGroup { + isExistingProcess: FormControl; + isUserImpersonate: FormControl; + owners: FormControl; + perNote: FormControl; + perUser: FormControl; + port: FormControl; + host: FormControl; + remote: FormControl; + setPermission: FormControl; + // TODO: `session`/`process` are write-only leftovers from the pre-0.7 boolean isolation + // model, superseded by the perNote/perUser modes in ZEPPELIN-1210. They are never read + // by the template, never sent to the server, and should be removed in a follow-up. + session: FormControl; + process: FormControl; +} + +interface InterpreterFormGroup { + name: FormControl; + group: FormControl; + option: FormGroup; + properties: FormArray>; + dependencies: FormArray>; +} + @Component({ selector: 'zeppelin-interpreter-item', templateUrl: './item.component.html', @@ -38,12 +74,12 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On @Input() mode: 'create' | 'view' | 'edit' = 'view'; @Input() interpreter?: Interpreter; - formGroup!: UntypedFormGroup; - optionFormGroup!: UntypedFormGroup; - editingPropertiesFormGroup?: UntypedFormGroup; - editingDependenceFormGroup?: UntypedFormGroup; - propertiesFormArray!: UntypedFormArray; - dependenciesFormArray!: UntypedFormArray; + formGroup!: FormGroup; + optionFormGroup!: FormGroup; + editingPropertiesFormGroup?: FormGroup; + editingDependenceFormGroup?: FormGroup; + propertiesFormArray!: FormArray>; + dependenciesFormArray!: FormArray>; userList$?: Observable; userSearchChange$: BehaviorSubject | null = new BehaviorSubject(''); runningOptionMap = { @@ -86,31 +122,41 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On this.addProperties(); this.addDependence(); const formData = this.formGroup.getRawValue(); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const properties: Record = {}; - - formData.properties - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .sort((e: any) => e.key) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .forEach((e: any) => { - const { key, value, type } = e; - properties[key] = { - value, - type, - name: key - }; - }); - formData.properties = properties; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - formData.dependencies.forEach((e: any) => { - e.exclusions = e.exclusions.split(',').filter((s: string) => s !== ''); + const properties: Record = {}; + + formData.properties.forEach(({ key, value, type }) => { + properties[key] = { + // Numeric inputs hold JS numbers, which Gson would deserialize as Double + // (e.g. 60000 -> "60000.0") and break Long/Integer parsing (ZEPPELIN-6395), + // so send them as strings. Checkboxes stay real booleans, as in the classic UI. + value: type === 'checkbox' ? value === true || value === 'true' : String(value ?? ''), + type, + name: key + }; }); + // session/process are UI-only state derived from perNote/perUser; + // the server-side InterpreterOption has no such fields, so they are not sent. + const { isExistingProcess, isUserImpersonate, owners, perNote, perUser, port, host, remote, setPermission } = + formData.option; + const setting: InterpreterSettingRequest = { + name: formData.name, + group: formData.group, + option: { isExistingProcess, isUserImpersonate, owners, perNote, perUser, port, host, remote, setPermission }, + properties, + dependencies: formData.dependencies.map(({ groupArtifactVersion, exclusions }) => ({ + groupArtifactVersion, + exclusions: exclusions + .split(',') + .map(s => s.trim()) + .filter(s => s !== '') + })) + }; + if (this.mode === 'create') { - this.parent.addInterpreterSetting(formData); + this.parent.addInterpreterSetting(setting); } else { - this.parent.updateInterpreter(formData); + this.parent.updateInterpreter(setting); this.mode = 'view'; } } @@ -146,11 +192,11 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On this.cdr.markForCheck(); } - onTypeChange(type: string) { + onTypeChange(type: InterpreterPropertyTypes) { if (!this.editingPropertiesFormGroup) { throw new Error("'editingPropertiesFormGroup' is not defined. Please check if it is initialized properly."); } - let valueSet: string | boolean | number; + let valueSet: PropertyValue; switch (type) { case 'number': valueSet = 0; @@ -161,7 +207,7 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On default: valueSet = ''; } - this.editingPropertiesFormGroup.get('value')!.setValue(valueSet); + this.editingPropertiesFormGroup.controls.value.setValue(valueSet); } addDependence(): void { @@ -172,17 +218,12 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On if (this.editingDependenceFormGroup.valid) { const data = this.editingDependenceFormGroup.getRawValue(); const current = this.dependenciesFormArray.controls.find( - control => control.get('groupArtifactVersion')!.value === data.groupArtifactVersion + control => control.controls.groupArtifactVersion.value === data.groupArtifactVersion ); if (current) { - current.get('exclusions')!.setValue(data.exclusions); + current.controls.exclusions.setValue(data.exclusions); } else { - this.dependenciesFormArray.push( - this.formBuilder.group({ - groupArtifactVersion: [data.groupArtifactVersion, [Validators.required]], - exclusions: data.exclusions - }) - ); + this.dependenciesFormArray.push(this.createDependencyFormGroup(data)); } this.editingDependenceFormGroup.reset({ exclusions: '', @@ -199,19 +240,12 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On if (this.editingPropertiesFormGroup.valid) { const data = this.editingPropertiesFormGroup.getRawValue(); - const current = this.propertiesFormArray.controls.find(control => control.get('key')!.value === data.key); + const current = this.propertiesFormArray.controls.find(control => control.controls.key.value === data.key); if (current) { - current.get('value')!.setValue(data.value); - current.get('type')!.setValue(data.type); + current.controls.value.setValue(data.value); + current.controls.type.setValue(data.type); } else { - this.propertiesFormArray.push( - this.formBuilder.group({ - key: [data.key, [Validators.required]], - value: data.value || '', - description: null, - type: data.type - }) - ); + this.propertiesFormArray.push(this.createPropertyFormGroup({ ...data, value: data.value ?? '' })); } this.editingPropertiesFormGroup.reset({ key: '', @@ -225,8 +259,8 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On setInterpreterRunningOption(perNote: string, perUser: string) { const { sharedModeName, globallyModeName, perNoteModeName, perUserModeName } = this.runningOptionMap; - this.optionFormGroup.get('perNote')!.setValue(perNote); - this.optionFormGroup.get('perUser')!.setValue(perUser); + this.optionFormGroup.controls.perNote.setValue(perNote); + this.optionFormGroup.controls.perUser.setValue(perUser); // Globally == shared_perNote + shared_perUser if (perNote === sharedModeName && perUser === sharedModeName) { @@ -252,34 +286,34 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On } } - this.optionFormGroup.get('perNote')!.setValue(sharedModeName); - this.optionFormGroup.get('perUser')!.setValue(sharedModeName); + this.optionFormGroup.controls.perNote.setValue(sharedModeName); + this.optionFormGroup.controls.perUser.setValue(sharedModeName); this.interpreterRunningOption = globallyModeName; } setPerNoteOrUserOption(type: 'perNote' | 'perUser', value: string) { - this.optionFormGroup.get(type)!.setValue(value); + this.optionFormGroup.controls[type].setValue(value); switch (value) { case this.sessionOptionMap.isolated: - this.optionFormGroup.get('session')!.setValue(false); - this.optionFormGroup.get('process')!.setValue(true); + this.optionFormGroup.controls.session.setValue(false); + this.optionFormGroup.controls.process.setValue(true); break; case this.sessionOptionMap.scoped: - this.optionFormGroup.get('session')!.setValue(true); - this.optionFormGroup.get('process')!.setValue(false); + this.optionFormGroup.controls.session.setValue(true); + this.optionFormGroup.controls.process.setValue(false); break; case this.sessionOptionMap.shared: - this.optionFormGroup.get('session')!.setValue(false); - this.optionFormGroup.get('process')!.setValue(false); + this.optionFormGroup.controls.session.setValue(false); + this.optionFormGroup.controls.process.setValue(false); break; } } - nameValidator(control: AbstractControl): ValidationErrors | null { + nameValidator(control: AbstractControl): ValidationErrors | null { if (this.mode !== 'create') { return null; } - const name = (control.value as string).trim(); + const name = control.value.trim(); const exist = this.parent.interpreterSettings.find(e => e.name === name); if (exist) { return { exist: true, message: `Name '${name}' already exists` }; @@ -291,25 +325,24 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On buildForm(): void { let name = ''; let group = ''; - this.optionFormGroup = this.formBuilder.group({ - isExistingProcess: false, - isUserImpersonate: false, - owners: [[]], - perNote: '', - perUser: '', - port: [ - null, - [Validators.pattern('^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$')] - ], - host: '', - remote: true, - setPermission: false, - session: false, - process: false + this.optionFormGroup = new FormGroup({ + isExistingProcess: new FormControl(false, { nonNullable: true }), + isUserImpersonate: new FormControl(false, { nonNullable: true }), + owners: new FormControl([], { nonNullable: true }), + perNote: new FormControl('', { nonNullable: true }), + perUser: new FormControl('', { nonNullable: true }), + port: new FormControl(null, [ + Validators.pattern('^()([1-9]|[1-5]?[0-9]{2,4}|6[1-4][0-9]{3}|65[1-4][0-9]{2}|655[1-2][0-9]|6553[1-5])$') + ]), + host: new FormControl('', { nonNullable: true }), + remote: new FormControl(true, { nonNullable: true }), + setPermission: new FormControl(false, { nonNullable: true }), + session: new FormControl(false, { nonNullable: true }), + process: new FormControl(false, { nonNullable: true }) }); - this.propertiesFormArray = this.formBuilder.array([]); - this.dependenciesFormArray = this.formBuilder.array([]); + this.propertiesFormArray = new FormArray>([]); + this.dependenciesFormArray = new FormArray>([]); if (this.mode === 'view' && this.interpreter) { name = this.interpreter.name; @@ -324,18 +357,18 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On // set dependencies fields this.interpreter.dependencies.forEach(e => { const exclusions = Array.isArray(e.exclusions) ? e.exclusions : []; - this.dependenciesFormArray!.push( - this.formBuilder.group({ - exclusions: [exclusions.join(',')], - groupArtifactVersion: [e.groupArtifactVersion, [Validators.required]] + this.dependenciesFormArray.push( + this.createDependencyFormGroup({ + exclusions: exclusions.join(','), + groupArtifactVersion: e.groupArtifactVersion }) ); }); // set properties fields Object.entries(this.interpreter.properties).forEach(([key, item]) => { - this.propertiesFormArray!.push( - this.formBuilder.group({ + this.propertiesFormArray.push( + this.createPropertyFormGroup({ key, value: item.value, description: null, @@ -345,9 +378,12 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On }); } - this.formGroup = this.formBuilder.group({ - name: [name, [Validators.required, (c: Parameters[0]) => this.nameValidator(c)]], - group: [group, [Validators.required]], + this.formGroup = new FormGroup({ + name: new FormControl(name, { + nonNullable: true, + validators: [Validators.required, control => this.nameValidator(control)] + }), + group: new FormControl(group, { nonNullable: true, validators: [Validators.required] }), option: this.optionFormGroup, properties: this.propertiesFormArray, dependencies: this.dependenciesFormArray @@ -368,43 +404,40 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On }) ); - this.editingPropertiesFormGroup = this.formBuilder.group({ - key: ['', [Validators.required]], + this.editingPropertiesFormGroup = this.createPropertyFormGroup({ + key: '', value: '', description: null, type: 'string' }); - this.editingDependenceFormGroup = this.formBuilder.group({ - groupArtifactVersion: ['', [Validators.required]], - exclusions: [''] + this.editingDependenceFormGroup = this.createDependencyFormGroup({ + groupArtifactVersion: '', + exclusions: '' }); if (this.mode === 'create') { - this.formGroup - .get('group')! - .valueChanges.pipe(takeUntil(this.destroy$)) - .subscribe(value => { - // remove all controls - while (this.propertiesFormArray!.length) { - this.propertiesFormArray!.removeAt(0); - } - - const interpreters = this.parent.availableInterpreters.filter(e => e.group === value); - interpreters.forEach(interpreter => { - Object.entries(interpreter.properties).forEach(([key, item]) => { - this.propertiesFormArray!.push( - this.formBuilder.group({ - key: [key, [Validators.required]], - value: item.defaultValue, - description: item.description, - type: item.type - }) - ); - }); + this.formGroup.controls.group.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => { + // remove all controls + while (this.propertiesFormArray.length) { + this.propertiesFormArray.removeAt(0); + } + + const interpreters = this.parent.availableInterpreters.filter(e => e.group === value); + interpreters.forEach(interpreter => { + Object.entries(interpreter.properties).forEach(([key, item]) => { + this.propertiesFormArray.push( + this.createPropertyFormGroup({ + key, + value: item.defaultValue ?? '', + description: item.description ?? null, + type: item.type + }) + ); }); - this.cdr.markForCheck(); }); + this.cdr.markForCheck(); + }); } } @@ -413,7 +446,6 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On public ticketService: TicketService, private securityService: SecurityService, private interpreterService: InterpreterService, - private formBuilder: UntypedFormBuilder, private cdr: ChangeDetectorRef ) { super(); @@ -421,7 +453,7 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On ngOnInit() { this.buildForm(); - const option = this.optionFormGroup!.getRawValue(); + const option = this.optionFormGroup.getRawValue(); this.setInterpreterRunningOption(option.perNote, option.perUser); if (this.mode !== 'view') { @@ -437,4 +469,31 @@ export class InterpreterItemComponent extends DestroyHookComponent implements On this.userSearchChange$ = null; super.ngOnDestroy(); } + + private createPropertyFormGroup(property: { + key: string; + value: PropertyValue; + description: string | null; + type: InterpreterPropertyTypes; + }): FormGroup { + return new FormGroup({ + key: new FormControl(property.key, { nonNullable: true, validators: [Validators.required] }), + value: new FormControl(property.value), + description: new FormControl(property.description), + type: new FormControl(property.type, { nonNullable: true }) + }); + } + + private createDependencyFormGroup(dependency: { + groupArtifactVersion: string; + exclusions: string; + }): FormGroup { + return new FormGroup({ + groupArtifactVersion: new FormControl(dependency.groupArtifactVersion, { + nonNullable: true, + validators: [Validators.required] + }), + exclusions: new FormControl(dependency.exclusions, { nonNullable: true }) + }); + } } diff --git a/zeppelin-web-angular/src/app/services/interpreter.service.ts b/zeppelin-web-angular/src/app/services/interpreter.service.ts index e0f60bf8361..0deef5b7e5b 100644 --- a/zeppelin-web-angular/src/app/services/interpreter.service.ts +++ b/zeppelin-web-angular/src/app/services/interpreter.service.ts @@ -18,7 +18,8 @@ import { Interpreter, InterpreterMap, InterpreterPropertyTypes, - InterpreterRepository + InterpreterRepository, + InterpreterSettingRequest } from '@zeppelin/interfaces'; import { InterpreterItem } from '@zeppelin/sdk'; @@ -60,13 +61,15 @@ export class InterpreterService extends BaseRest { return this.http.get(this.restUrl`/interpreter/property/types`); } - addInterpreterSetting(interpreter: Interpreter) { - return this.http.post(this.restUrl`/interpreter/setting`, interpreter); + addInterpreterSetting(setting: InterpreterSettingRequest) { + return this.http.post(this.restUrl`/interpreter/setting`, setting); } - updateInterpreter(interpreter: Interpreter) { - const { option, properties, dependencies } = interpreter; - return this.http.put(this.restUrl`/interpreter/setting/${interpreter.name}`, { + updateInterpreter(setting: InterpreterSettingRequest) { + // PUT only accepts option/properties/dependencies; name is used as the path id + // and group is immutable after creation (see UpdateInterpreterSettingRequest.java). + const { option, properties, dependencies } = setting; + return this.http.put(this.restUrl`/interpreter/setting/${setting.name}`, { option, properties, dependencies From 52a638e5b99ac66cb08cb5f066f807383b37d268 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Wed, 17 Jun 2026 00:53:38 +0900 Subject: [PATCH 056/179] [ZEPPELIN-6428] Add reusable React mount infrastructure and migrate paragraph footer behind a flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? zeppelin-web-angular ships React islands via Webpack Module Federation (PublishedParagraph pilot). This PR promotes that ad-hoc integration into reusable mount infrastructure and migrates the notebook paragraph footer as its first consumer, behind a `?reactFooter=true` query-param gate. - `share/react-mount/`: `ReactMountDirective`, `ReactRemoteLoaderService`, and a `ReactMountHandle` contract (`mount(element, props)` returning `{ update, unmount }`) so prop changes update the React root in place instead of remounting. `remoteEntry.js` is loaded once per page (cached promise with failure eviction); each directive instance owns an isolated React root. - React `ParagraphFooter` component (zeppelin-react) matching the Angular footer's execution-time and elapsed-time behavior, wrapped in an error boundary. - Gate: `?reactFooter=true`. Without the flag, rendering is unchanged. With the flag, remote load/mount/update errors — and React render/lifecycle errors caught by the error boundary — fall back to the Angular footer for that paragraph only. - Playwright E2E (`react-footer.spec.ts`) and a vitest unit-test harness for zeppelin-react covering the error boundary and the mount contract. - Toolchain alignment for `projects/zeppelin-react`: typescript 4.9.5 → 5.9.3 (matching the Angular workspace), types/node 18 → 22 (matching the node 22 runtime), vitest 4.1.8 — the latter fixes the critical advisory GHSA-5xrq-8626-4rwp flagged by the npm-audit CI job. The existing PublishedParagraph pilot remains on its current loader; this PR only types its `container.get()` call. Migrating it to the new directive is a follow-up. ### What type of PR is it? Improvement ### Todos * [x] Mount infrastructure (`react-mount/`) * [x] React `ParagraphFooter` + error boundary * [x] `?reactFooter=true` gate with per-paragraph Angular fallback * [x] Playwright E2E (5 cases incl. load-failure fallback) * [x] vitest unit tests (error boundary spec, mount contract) * [x] zeppelin-react toolchain alignment (TS 5.9 / types/node 22 / vitest 4.1.8) ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6428 ### How should this be tested? Verified locally: * `npx playwright test --project=chromium react-footer` — 5/5 passed against a local Zeppelin server (0.13.0-SNAPSHOT), including the remote-load-failure fallback case. * `cd projects/zeppelin-react && npm test` — 13/13 vitest unit tests (error boundary behavior, `mount()` contract incl. update/unmount, outdated/elapsed formatting with a pinned clock). * `npm audit --audit-level=high` exits 0 in `projects/zeppelin-react` (same gate as the npm-audit CI job). One moderate uuid advisory remains via sockjs/webpack-dev-server with no compatible upstream fix; it does not trip the high-level gate. * `eslint`/`prettier` clean on changed files; `tsc --noEmit` clean (also covers what the `transpileOnly` webpack build skips). Manual: * Open a notebook with `?reactFooter=true` → footer renders from React (`data-testid="react-paragraph-footer"`), `remoteEntry.js` requested once. * Without the flag → the Angular footer renders as before. * Block `remoteEntry.js` in DevTools → the paragraph falls back to the Angular footer with a console diagnostic. Note on coverage: the React pieces are unit-tested via a new self-contained vitest setup in `projects/zeppelin-react` (vitest 4.1.8). The Angular-side pieces (`ReactMountDirective`, `ReactRemoteLoaderService`) are covered through E2E only, since zeppelin-web-angular has no unit-test harness (zero `.spec.ts` under `src/`, no test target in angular.json). Happy to add Angular unit tests if a harness lands or committers prefer a different approach. ### Screenshots (if appropriate) The React footer is intended to match the existing footer's rendering (same text and layout; styles ported to a scoped CSS class). ### Questions: * Does the license files need to update? Adds `date-fns` (MIT) to `projects/zeppelin-react`'s package.json and lockfile (the Angular app already depends on it), plus dev-only test dependencies (vitest, jsdom, Testing Library). The lockfile diff includes npm peer-flag normalization from `npm install`. * Is there breaking changes for older versions? No. The footer change is opt-in via query param; default rendering is unchanged. * Does this needs documentation? No user-facing docs; developer docs updated in `projects/zeppelin-react/README.md`. Closes #5266 from tbonelee/ZEPPELIN-6428-react-mount-infrastructure. Signed-off-by: ChanHo Lee --- .../notebook/paragraph/react-footer.spec.ts | 109 + .../projects/zeppelin-react/README.md | 65 +- .../projects/zeppelin-react/package-lock.json | 4014 ++++++++++++----- .../projects/zeppelin-react/package.json | 15 +- .../zeppelin-react/src/components/index.ts | 1 + .../components/paragraph/ParagraphFooter.css | 21 + .../paragraph/ParagraphFooter.spec.tsx | 119 + .../components/paragraph/ParagraphFooter.tsx | 110 + .../paragraph/ReactErrorBoundary.spec.tsx | 102 + .../paragraph/ReactErrorBoundary.tsx | 47 + .../src/components/paragraph/index.ts | 14 + .../projects/zeppelin-react/src/main.ts | 1 + .../projects/zeppelin-react/src/test-setup.ts | 22 + .../projects/zeppelin-react/vitest.config.ts | 21 + .../projects/zeppelin-react/webpack.config.js | 6 +- .../notebook/notebook.component.html | 1 + .../workspace/notebook/notebook.component.ts | 7 + .../paragraph/paragraph.component.html | 25 +- .../notebook/paragraph/paragraph.component.ts | 44 + .../paragraph/paragraph.component.ts | 4 +- .../src/app/share/public-api.ts | 1 + .../src/app/share/react-mount/index.ts | 13 + .../src/app/share/react-mount/public-api.ts | 15 + .../share/react-mount/react-mount-handle.ts | 44 + .../react-mount/react-mount.directive.ts | 149 + .../react-remote-loader.service.ts | 98 + .../src/app/share/share.module.ts | 4 +- 27 files changed, 3873 insertions(+), 1199 deletions(-) create mode 100644 zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.css create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.spec.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/index.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/test-setup.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/vitest.config.ts create mode 100644 zeppelin-web-angular/src/app/share/react-mount/index.ts create mode 100644 zeppelin-web-angular/src/app/share/react-mount/public-api.ts create mode 100644 zeppelin-web-angular/src/app/share/react-mount/react-mount-handle.ts create mode 100644 zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts create mode 100644 zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts diff --git a/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts new file mode 100644 index 00000000000..d76ff4438bd --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts @@ -0,0 +1,109 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, test } from '@playwright/test'; +import { + addPageAnnotationBeforeEach, + createTestNotebook, + PAGES, + performLoginIfRequired, + waitForNotebookLinks, + waitForZeppelinReady +} from '../../../utils'; + +test.describe('React Paragraph Footer', () => { + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); + + let testNotebook: { noteId: string; paragraphId: string }; + + test.beforeEach(async ({ page }) => { + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + await waitForNotebookLinks(page); + testNotebook = await createTestNotebook(page); + }); + + test('without reactFooter flag, Angular footer renders', async ({ page }) => { + const { noteId } = testNotebook; + + await page.goto(`/#/notebook/${noteId}`); + await waitForZeppelinReady(page); + + await expect(page.locator('[data-testid="angular-paragraph-footer"]').first()).toBeAttached({ timeout: 15000 }); + await expect(page.locator('[data-testid="react-paragraph-footer"]')).toHaveCount(0); + }); + + test('with reactFooter=true, React footer renders', async ({ page }) => { + const { noteId } = testNotebook; + + await page.goto(`/#/notebook/${noteId}?reactFooter=true`); + await waitForZeppelinReady(page); + + await expect(page.locator('[data-testid="react-paragraph-footer-content"]').first()).toBeAttached({ + timeout: 15000 + }); + await expect(page.locator('[data-testid="angular-paragraph-footer"]')).toHaveCount(0); + }); + + test('reactFooter=true preserves the paragraph query param', async ({ page }) => { + const { noteId, paragraphId } = testNotebook; + + await page.goto(`/#/notebook/${noteId}?paragraph=${paragraphId}&reactFooter=true`); + await waitForZeppelinReady(page); + + await expect(page).toHaveURL(/reactFooter=true/); + await expect(page).toHaveURL(new RegExp(`paragraph=${paragraphId}`)); + await expect(page.locator('[data-testid="react-paragraph-footer-content"]').first()).toBeAttached({ + timeout: 15000 + }); + }); + + test('when the remote fails to load, paragraphs fall back to the Angular footer', async ({ page }) => { + const { noteId } = testNotebook; + + // Simulate a dead remote: every remoteEntry.js request fails + await page.route('**/remoteEntry.js', route => route.abort()); + + await page.goto(`/#/notebook/${noteId}?reactFooter=true`); + await waitForZeppelinReady(page); + + // The loader rejection reaches each paragraph's onError, which flips + // reactFooterFailed and re-renders the Angular footer + await expect(page.locator('[data-testid="angular-paragraph-footer"]').first()).toBeAttached({ timeout: 15000 }); + await expect(page.locator('[data-testid="react-paragraph-footer"]')).toHaveCount(0); + }); + + test('navigating away during remoteEntry load does not throw', async ({ page }) => { + const { noteId } = testNotebook; + + // Delay remoteEntry.js to widen the destroy-while-loading window + await page.route('**/remoteEntry.js', async route => { + await new Promise(r => setTimeout(r, 1500)); + await route.continue(); + }); + + const consoleErrors: string[] = []; + page.on('pageerror', err => consoleErrors.push(err.message)); + + // Navigate away only once the request is in-flight, so destroy-while-loading is exercised. + const remoteRequested = page.waitForRequest('**/remoteEntry.js'); + await page.goto(`/#/notebook/${noteId}?reactFooter=true`); + await remoteRequested; + await page.goto('/#/'); + await waitForZeppelinReady(page); + + await page.waitForTimeout(2500); + + expect(consoleErrors).toEqual([]); + }); +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/README.md b/zeppelin-web-angular/projects/zeppelin-react/README.md index 58f2d8a2d4f..f452ee1455a 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/README.md +++ b/zeppelin-web-angular/projects/zeppelin-react/README.md @@ -16,6 +16,21 @@ React micro-frontend that runs alongside the Angular host via [Webpack Module Fe - Design Document: [Micro Frontend Migration (Angular to React) Proposal](https://cwiki.apache.org/confluence/display/ZEPPELIN/Micro+Frontend+Migration%28Angular+to+React%29+Proposal) +## React mount infrastructure (Angular side) + +The Angular host's `src/app/share/react-mount/` exports two pieces: + +- `ReactRemoteLoaderService` — loads `remoteEntry.js` once per page, + caches per-module promises, evicts on error. +- `ReactMountDirective` — owns the host element, mounts outside the + Angular zone, forwards `[reactProps]` changes through + `handle.update(...)`, and unmounts on destroy. Re-checks `destroyed` + after the async load so a navigation during load does not leak a mount. + +Both are exported from `ShareModule`. Any notebook or interpreter +template can use the directive without additional wiring. The selector +is kebab-case (`zeppelin-react-mount`) per project ESLint convention. + ## Migration roadmap | Phase | Scope | Status | @@ -78,23 +93,51 @@ src/ ## Adding a new React module -1. Create a component (e.g. `src/pages/ExampleFeature.tsx`). -2. Export a `mount(element, props)` function that creates a React root and renders the component. -3. Register in `webpack.config.js` under `exposes`: +The Angular host loads each exposed module through the +`ReactMountDirective` (see `src/app/share/react-mount/`). The contract: + +```ts +export interface ReactMountHandle { + update: (props: Props & { onError?: (e: unknown) => void }) => void; + unmount: () => void; +} + +export function mount(element: HTMLElement, props: Props): ReactMountHandle; +``` + +1. Create a component (e.g. `src/components//ExampleFeature.tsx`). +2. Wrap its render tree in ``. +3. Export a `mount(element, props)` function that: + - Creates a single `Root` via `createRoot(element)`. + - Calls `root.render()` on initial mount AND on + every `update(newProps)` call. React's reconciler preserves state. + - Returns `{ update, unmount }`. `unmount` calls `root.unmount()`. +4. Register in `webpack.config.js` under `exposes`: ```js exposes: { './PublishedParagraph': './src/pages/PublishedParagraph', - './ExampleFeature': './src/pages/ExampleFeature' + './ParagraphFooter': './src/components/paragraph/ParagraphFooter', + './ExampleFeature': './src/components//ExampleFeature' } ``` -4. Re-export from `main.ts`: +5. Re-export from `main.ts`: ```ts - export { ExampleFeature, mount as mountExampleFeature } from './pages/ExampleFeature'; + export { + ExampleFeature, + mount as mountExampleFeature + } from './components//ExampleFeature'; ``` -5. Load from Angular (same pattern as `paragraph.component.ts`): - ```ts - const factory = await container.get('./ExampleFeature'); - const { mount } = factory(); - mount(hostElement, props); +6. Use from Angular by adding the directive to your template: + ```html +
    ``` + `exampleFeatureProps` should be a getter on the host component (not + an inline object literal) so identity is stable when nothing changed. + +The legacy `./PublishedParagraph` module returns a bare unmount fn from +`mount`. The directive tolerates that shape, but new modules should use +the handle contract. diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index f0f3439bab6..354bdcc974a 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -13,6 +13,7 @@ "ansi-to-react": "6.2.6", "antd": "5.21.0", "chart.js": "^4.5.1", + "date-fns": "^3.6.0", "file-saver": "2.0.5", "react": "18.3.1", "react-dom": "18.3.1", @@ -20,8 +21,10 @@ }, "devDependencies": { "@eslint/js": "^9.28.0", + "@testing-library/dom": "10.4.1", + "@testing-library/react": "16.3.2", "@types/file-saver": "2.0.7", - "@types/node": "18.19.64", + "@types/node": "22.19.19", "@types/react": "18.3.26", "@types/react-dom": "18.3.7", "@typescript-eslint/eslint-plugin": "^8.56.1", @@ -32,10 +35,12 @@ "eslint-plugin-react-hooks": "^5.1.0", "globals": "^15.14.0", "html-webpack-plugin": "5.5.0", + "jsdom": "29.1.1", "style-loader": "3.3.0", - "ts-loader": "9.4.0", - "typescript": "4.9.5", + "ts-loader": "9.5.7", + "typescript": "5.9.3", "typescript-eslint": "^8.33.1", + "vitest": "4.1.8", "webpack": "5.105.4", "webpack-cli": "5.1.4", "webpack-dev-server": "5.2.4" @@ -149,15 +154,244 @@ "react": ">=16.9.0" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.1.tgz", + "integrity": "sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", + "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@ctrl/tinycolor": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", @@ -177,6 +411,40 @@ "node": ">=10.0.0" } }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", @@ -233,30 +501,36 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/config-array/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@eslint/config-array/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@eslint/config-array/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, "node_modules/@eslint/config-helpers": { "version": "0.4.2", @@ -308,22 +582,22 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/@eslint/eslintrc/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/@eslint/eslintrc/node_modules/globals": { @@ -349,12 +623,18 @@ "node": ">= 4" } }, - "node_modules/@eslint/eslintrc/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT" + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, "node_modules/@eslint/js": { "version": "9.39.4", @@ -393,6 +673,24 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@humanfs/core": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", @@ -561,14 +859,14 @@ } }, "node_modules/@jsonjoy.com/fs-core": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.56.11.tgz", - "integrity": "sha512-wThHjzUp01ImIjfCwhs+UnFkeGPFAymwLEkOtenHewaKe2pTP12p6r1UuwikA9NEvNf9Vlck92r8fb8n/MWM5w==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.6.tgz", + "integrity": "sha512-uI++Wx6VkBJqVmkb4ZeExwAVpZiA2Do5NrEtXoDk0Pdvce3ytFXJoviT1sLOj16+qDIMnD5nWPfOhVpnDmRJKg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.56.11", - "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/fs-node-builtins": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.57.6", "thingies": "^2.5.0" }, "engines": { @@ -583,15 +881,15 @@ } }, "node_modules/@jsonjoy.com/fs-fsa": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.56.11.tgz", - "integrity": "sha512-ZYlF3XbMayyp97xEN8ZvYutU99PCHjM64mMZvnCseXkCJXJDVLAwlF8Q/7q/xiWQRsv3pQBj1WXHd9eEyYcaCQ==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.6.tgz", + "integrity": "sha512-pKkw/yC5CzSZKhIIUIsH1przOa+K5jGmZIg1sWaSF24JojyrUFbjcQv7QrcGAudriei6HQ6R0BFj+V8NbQinJw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-core": "4.56.11", - "@jsonjoy.com/fs-node-builtins": "4.56.11", - "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/fs-core": "4.57.6", + "@jsonjoy.com/fs-node-builtins": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.57.6", "thingies": "^2.5.0" }, "engines": { @@ -606,17 +904,17 @@ } }, "node_modules/@jsonjoy.com/fs-node": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.56.11.tgz", - "integrity": "sha512-D65YrnP6wRuZyEWoSFnBJSr5zARVpVBGctnhie4rCsMuGXNzX7IHKaOt85/Aj7SSoG1N2+/xlNjWmkLvZ2H3Tg==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.6.tgz", + "integrity": "sha512-Kbn1jdkvDN4F2+BhoB6mMu7NCbhP0bgA5NcI1aJj/Q5UcU+I1JLLW+dEQean33iV4tXv35AzBVKPICnDltBpxw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-core": "4.56.11", - "@jsonjoy.com/fs-node-builtins": "4.56.11", - "@jsonjoy.com/fs-node-utils": "4.56.11", - "@jsonjoy.com/fs-print": "4.56.11", - "@jsonjoy.com/fs-snapshot": "4.56.11", + "@jsonjoy.com/fs-core": "4.57.6", + "@jsonjoy.com/fs-node-builtins": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.57.6", + "@jsonjoy.com/fs-print": "4.57.6", + "@jsonjoy.com/fs-snapshot": "4.57.6", "glob-to-regex.js": "^1.0.0", "thingies": "^2.5.0" }, @@ -632,9 +930,9 @@ } }, "node_modules/@jsonjoy.com/fs-node-builtins": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.56.11.tgz", - "integrity": "sha512-CNmt3a0zMCIhniFLXtzPWuUxXFU+U+2VyQiIrgt/rRVeEJNrMQUABaRbVxR0Ouw1LyR9RjaEkPM6nYpED+y43A==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.6.tgz", + "integrity": "sha512-V4DgEFT3Cg5S9fCMOZSCVdTxdJWWLBO0WnAazV7hnCM96u5zXHyW/ubDAfcSVwqjkMJ50W1Y44IXtxRoIwaCVg==", "dev": true, "license": "Apache-2.0", "engines": { @@ -649,15 +947,15 @@ } }, "node_modules/@jsonjoy.com/fs-node-to-fsa": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.56.11.tgz", - "integrity": "sha512-5OzGdvJDgZVo+xXWEYo72u81zpOWlxlbG4d4nL+hSiW+LKlua/dldNgPrpWxtvhgyntmdFQad2UTxFyGjJAGhA==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.6.tgz", + "integrity": "sha512-+JptNw3iifihxH2rEXrninDzX4FFVW8JD/wPR8GbJPAeL9CQUSblrlumOPB5gZuS7tYRX+PJPLtT7XzKoRhv/Q==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-fsa": "4.56.11", - "@jsonjoy.com/fs-node-builtins": "4.56.11", - "@jsonjoy.com/fs-node-utils": "4.56.11" + "@jsonjoy.com/fs-fsa": "4.57.6", + "@jsonjoy.com/fs-node-builtins": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.57.6" }, "engines": { "node": ">=10.0" @@ -671,13 +969,13 @@ } }, "node_modules/@jsonjoy.com/fs-node-utils": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.56.11.tgz", - "integrity": "sha512-JADOZFDA3wRfsuxkT0+MYc4F9hJO2PYDaY66kRTG6NqGX3+bqmKu66YFYAbII/tEmQWPZeHoClUB23rtQM9UPg==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.6.tgz", + "integrity": "sha512-foyUrfS7WmYEUzqYXSNxmJBcSj04TABrkpFabwO9SCDCpVCfJ+qG+2sk5FjfiflG2n0SDFZDCJ6vYlJAEpxJFg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.56.11" + "@jsonjoy.com/fs-node-builtins": "4.57.6" }, "engines": { "node": ">=10.0" @@ -691,13 +989,13 @@ } }, "node_modules/@jsonjoy.com/fs-print": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.56.11.tgz", - "integrity": "sha512-rnaKRgCRIn8JGTjxhS0JPE38YM3Pj/H7SW4/tglhIPbfKEkky7dpPayNKV2qy25SZSL15oFVgH/62dMZ/z7cyA==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.6.tgz", + "integrity": "sha512-96eAn4Dudtt67LTeuU47yUD+pg9/G/oKpI10zei9ljk3X3WK4lYKc+n3cpaPCAbKPzoyfxl0mXm8f8Y7BOSFXw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.57.6", "tree-dump": "^1.1.0" }, "engines": { @@ -712,14 +1010,14 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.56.11.tgz", - "integrity": "sha512-IIldPX+cIRQuUol9fQzSS3hqyECxVpYMJQMqdU3dCKZFRzEl1rkIkw4P6y7Oh493sI7YdxZlKr/yWdzEWZ1wGQ==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.6.tgz", + "integrity": "sha512-V57CMzbOgTzUWGOWQ8GzHQdpJP6JnrYVNCtTBNxVYEnlVRvo4uEJqHhtAT8vhDFrIuJOXLrTL1Fki4h5oI7xxg==", "dev": true, "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/buffers": "^17.65.0", - "@jsonjoy.com/fs-node-utils": "4.56.11", + "@jsonjoy.com/fs-node-utils": "4.57.6", "@jsonjoy.com/json-pack": "^17.65.0", "@jsonjoy.com/util": "^17.65.0" }, @@ -952,155 +1250,194 @@ "dev": true, "license": "MIT" }, - "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 16" + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" }, "funding": { - "url": "https://paulmillr.com/funding/" + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@peculiar/asn1-cms": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", - "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", - "dev": true, + "node_modules/@noble/hashes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", + "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", + "extraneous": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.133.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", + "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.7.0.tgz", + "integrity": "sha512-hew63shtzzvBcSHbhm+cyAmKe6AIfinT9hzEqSPjDC6opTTMKmTkQ0gHuN2KsWlvqiKw1S/fS94fhag/FJkioQ==", + "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-csr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", - "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.7.0.tgz", + "integrity": "sha512-VVsAyGqErT9D1SY4aEqozThXMVI+ssVRiv2DDeYuvpBKLIgZ3hYs3Ay3u/VSoKq6ESFi9cf6rf3IOOzfwh7oMA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", - "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.7.0.tgz", + "integrity": "sha512-n7KEs/Q/wrB415cxy4fHOBhegp4NdJ15fkJPwcB/3/8iNBQC2L/N7SChJPKDJPZGYH0jD4Tg4/0vnHmwghnbKw==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pfx": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", - "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.7.0.tgz", + "integrity": "sha512-V/nrlQVmhg7lYAsM7E13UDL5erAwFv6kCIVFqNaMIHSVi7dngcT839JkRTkQBqznMG98l2XjxYk74ZztAohZzA==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-rsa": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-rsa": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", - "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.7.0.tgz", + "integrity": "sha512-9GTl1nE8Mx1kTZ+7QyYatDyKsm34QcWRBFkY1iPvWC3X4Dona5s/tlLiQsx5WzVdZqiMBZNYT0buyw4/vbhnjw==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", - "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.7.0.tgz", + "integrity": "sha512-Bh7m+OuIaSEllPQcSd9OSp93F4ROWH7sbITWV8MI+8dwsjE5111/87VxiWVvYFKyww3vp39geLv9ENqhwWHcew==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pfx": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", + "@peculiar/asn1-cms": "^2.7.0", + "@peculiar/asn1-pfx": "^2.7.0", + "@peculiar/asn1-pkcs8": "^2.7.0", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", + "@peculiar/asn1-x509-attr": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", - "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.7.0.tgz", + "integrity": "sha512-/qvENQrXyTZURjMqSeofHul0JJt2sNSzSwk36pl2olkHbaioMQgrASDZAlHXl0xUlnVbHj0uGgOrBMTb5x2aJQ==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", - "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.7.0.tgz", + "integrity": "sha512-W8ZfWzLmQnrcky+eh3tni4IozMdqBDiHWU0N+vve/UGjMaUs8c0L7A2oEdkBXS8rTpWDpK/aoI3DG/L/hxmxPg==", "dev": true, "license": "MIT", "dependencies": { + "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", - "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.7.0.tgz", + "integrity": "sha512-mUn9RRrkGDnG4ALfunDmzyRW5dg+sWCj/pfnCCqEHYbkGxEpvUt6iVJv8Yw1cyp6SWZ26ZE5oSmI5SqEaen15g==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", - "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.7.0.tgz", + "integrity": "sha512-NS8e7SOgXipkzUPLF/sce7ukpMpWjhxYsH0n6Y+bHYo4TTxOb95Zv7hqwSuL212mj5YxovjdOKQOgH1As3E94w==", "dev": true, "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-schema": "^2.7.0", + "@peculiar/asn1-x509": "^2.7.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, + "node_modules/@peculiar/utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz", + "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, "node_modules/@peculiar/x509": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", @@ -1125,9 +1462,9 @@ } }, "node_modules/@rc-component/async-validator": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz", - "integrity": "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.1.0.tgz", + "integrity": "sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.24.4" @@ -1167,9 +1504,9 @@ } }, "node_modules/@rc-component/mini-decimal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz", - "integrity": "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.3.tgz", + "integrity": "sha512-bk/FJ09fLf+NLODMAFll6CfYrHPBioTedhW6lxDBuuWucJEqFUd4l/D/5JgIi3dina6sYahB8iuPAZTNz2pMxw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.0" @@ -1252,9 +1589,9 @@ } }, "node_modules/@rc-component/trigger": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.3.0.tgz", - "integrity": "sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.3.1.tgz", + "integrity": "sha512-ORENF39PeXTzM+gQEshuk460Z8N4+6DkjpxlpE7Q3gYy1iBpLrx0FOJz3h62ryrJZ/3zCAUIkT1Pb/8hHWpb3A==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.2", @@ -1272,6 +1609,361 @@ "react-dom": ">=16.9.0" } }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.3.tgz", + "integrity": "sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.3.tgz", + "integrity": "sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.3.tgz", + "integrity": "sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.3.tgz", + "integrity": "sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.3.tgz", + "integrity": "sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.3.tgz", + "integrity": "sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.3.tgz", + "integrity": "sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.3.tgz", + "integrity": "sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.3.tgz", + "integrity": "sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.3.tgz", + "integrity": "sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.3.tgz", + "integrity": "sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.3.tgz", + "integrity": "sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.3.tgz", + "integrity": "sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.3.tgz", + "integrity": "sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.3.tgz", + "integrity": "sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/body-parser": { "version": "1.19.6", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", @@ -1293,6 +1985,17 @@ "@types/node": "*" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -1314,6 +2017,13 @@ "@types/node": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -1337,9 +2047,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, @@ -1357,22 +2067,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/express/node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", "dev": true, "license": "MIT", "dependencies": { @@ -1428,13 +2125,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "18.19.64", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", - "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/@types/prop-types": { @@ -1445,9 +2142,9 @@ "license": "MIT" }, "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", "dev": true, "license": "MIT" }, @@ -1603,31 +2300,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-eslint/project-service": { "version": "8.60.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", @@ -1650,31 +2322,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/project-service/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/project-service/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.60.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", @@ -1735,31 +2382,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-eslint/types": { "version": "8.60.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", @@ -1802,70 +2424,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@typescript-eslint/utils": { "version": "8.60.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", @@ -1921,6 +2479,119 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vitest/expect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.8", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -2208,10 +2879,17 @@ } }, "node_modules/adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", + "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", "license": "Apache-2.0", + "dependencies": { + "exit-on-epipe": "~1.0.1", + "printj": "~1.1.0" + }, + "bin": { + "adler32": "bin/adler32.njs" + }, "engines": { "node": ">=0.8" } @@ -2252,9 +2930,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -2294,6 +2972,32 @@ "ansi-html": "bin/ansi-html" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/ansi-to-react": { "version": "6.2.6", "resolved": "https://registry.npmjs.org/ansi-to-react/-/ansi-to-react-6.2.6.tgz", @@ -2404,6 +3108,19 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2411,6 +3128,16 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -2563,20 +3290,30 @@ } }, "node_modules/asn1js": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", - "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz", + "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", + "pvutils": "^1.1.5", "tslib": "^2.8.1" }, "engines": { "node": ">=12.0.0" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -2604,16 +3341,19 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", - "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2630,6 +3370,16 @@ "dev": true, "license": "MIT" }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -2668,10 +3418,27 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/bonjour-service": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", - "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", + "integrity": "sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==", "dev": true, "license": "MIT", "dependencies": { @@ -2687,14 +3454,16 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/braces": { @@ -2711,9 +3480,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -2731,11 +3500,11 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -2788,15 +3557,15 @@ } }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -2859,9 +3628,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001777", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", - "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", "dev": true, "funding": [ { @@ -2892,6 +3661,42 @@ "node": ">=0.8" } }, + "node_modules/cfb/node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/chart.js": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", @@ -2929,6 +3734,19 @@ "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -2973,6 +3791,28 @@ "node": ">=6" } }, + "node_modules/codepage": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", + "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==", + "license": "Apache-2.0", + "dependencies": { + "commander": "~2.14.1", + "exit-on-epipe": "~1.0.1" + }, + "bin": { + "codepage": "bin/codepage.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/codepage/node_modules/commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", + "license": "MIT" + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3042,6 +3882,23 @@ "node": ">= 0.8.0" } }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/compute-scroll-into-view": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", @@ -3088,6 +3945,13 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/cookie": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", @@ -3192,6 +4056,20 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", @@ -3219,11 +4097,25 @@ } }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -3278,22 +4170,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/dayjs": { - "version": "1.11.18", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", - "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", "license": "MIT" }, "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3390,6 +4307,16 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -3401,6 +4328,16 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -3434,6 +4371,13 @@ "node": ">=0.10.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, "node_modules/dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -3459,6 +4403,16 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -3537,9 +4491,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.307", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", - "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "version": "1.5.366", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.366.tgz", + "integrity": "sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg==", "dev": true, "license": "ISC" }, @@ -3554,33 +4508,36 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" } }, "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/envinfo": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.19.0.tgz", - "integrity": "sha512-DoSM9VyG6O3vqBf+p3Gjgr/Q52HYBBtO3v+4koAxt1MnWr+zEnxE+nke/yXS4lt2P4SYCHQ4V3f1i88LQVOpAw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", "dev": true, "license": "MIT", "bin": { @@ -3591,9 +4548,9 @@ } }, "node_modules/es-abstract": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz", - "integrity": "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", "dev": true, "license": "MIT", "dependencies": { @@ -3659,38 +4616,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-abstract/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract/node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -3712,16 +4637,16 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.2.tgz", - "integrity": "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "define-properties": "^1.2.1", - "es-abstract": "^1.24.1", + "es-abstract": "^1.24.2", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", @@ -3733,23 +4658,23 @@ "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", - "safe-array-concat": "^1.1.3" + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -3829,6 +4754,19 @@ "dev": true, "license": "MIT" }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint": { "version": "9.39.4", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", @@ -3935,287 +4873,129 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, - "node_modules/eslint-plugin-react/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint-plugin-react/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", - "integrity": "sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==", + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "*" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, "engines": { - "node": ">= 4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/eslint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" - }, + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 4" } }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, "node_modules/espree": { @@ -4262,16 +5042,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4285,7 +5055,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -4295,14 +5065,14 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" } }, "node_modules/esutils": { @@ -4351,6 +5121,16 @@ "node": ">=0.8" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/express": { "version": "4.22.2", "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", @@ -4398,6 +5178,23 @@ "url": "https://opencollective.com/express" } }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4459,6 +5256,24 @@ "node": ">=0.8.0" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/fflate": { "version": "0.3.11", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.3.11.tgz", @@ -4516,18 +5331,38 @@ "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat": { @@ -4751,16 +5586,16 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/glob-to-regex.js": { @@ -4926,9 +5761,9 @@ } }, "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, "license": "MIT", "dependencies": { @@ -5001,6 +5836,19 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -5067,6 +5915,16 @@ "entities": "^2.0.0" } }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -5205,16 +6063,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", @@ -5278,9 +6126,9 @@ } }, "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", "dev": true, "license": "MIT", "engines": { @@ -5385,13 +6233,13 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -5556,9 +6404,9 @@ } }, "node_modules/is-network-error": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.1.tgz", - "integrity": "sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.3.2.tgz", + "integrity": "sha512-PhBY86zaxNZUuWP6h13Vu5oFe0XY6/UlKzQnYFELzGVHygP3MxmvTfYSG7GN3aIab/iWudSMgjSnG9Dq+nHrgA==", "dev": true, "license": "MIT", "engines": { @@ -5621,6 +6469,32 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -5865,6 +6739,47 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -5939,14 +6854,14 @@ } }, "node_modules/launch-editor": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", - "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", "dev": true, "license": "MIT", "dependencies": { "picocolors": "^1.1.1", - "shell-quote": "^1.8.3" + "shell-quote": "^1.8.4" } }, "node_modules/levn": { @@ -5963,6 +6878,279 @@ "node": ">= 0.8.0" } }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/linkify-it": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", @@ -5973,9 +7161,9 @@ } }, "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", "dev": true, "license": "MIT", "engines": { @@ -5987,16 +7175,19 @@ } }, "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -6035,6 +7226,36 @@ "tslib": "^2.0.3" } }, + "node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6045,6 +7266,13 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6056,20 +7284,20 @@ } }, "node_modules/memfs": { - "version": "4.56.11", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.56.11.tgz", - "integrity": "sha512-/GodtwVeKVIHZKLUSr2ZdOxKBC5hHki4JNCU22DoCGPEHr5o2PD5U721zvESKyWwCfTfavFl9WZYgA13OAYK0g==", + "version": "4.57.6", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.6.tgz", + "integrity": "sha512-WQK+DGjKCnPdpSyJUXphz+COF2uEhhsxQ3VIWBSbzpbbXuch3h4FePMqXrXGdLjsTgo4JFzBFsP6AWd9pVazGw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-core": "4.56.11", - "@jsonjoy.com/fs-fsa": "4.56.11", - "@jsonjoy.com/fs-node": "4.56.11", - "@jsonjoy.com/fs-node-builtins": "4.56.11", - "@jsonjoy.com/fs-node-to-fsa": "4.56.11", - "@jsonjoy.com/fs-node-utils": "4.56.11", - "@jsonjoy.com/fs-print": "4.56.11", - "@jsonjoy.com/fs-snapshot": "4.56.11", + "@jsonjoy.com/fs-core": "4.57.6", + "@jsonjoy.com/fs-fsa": "4.57.6", + "@jsonjoy.com/fs-node": "4.57.6", + "@jsonjoy.com/fs-node-builtins": "4.57.6", + "@jsonjoy.com/fs-node-to-fsa": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.57.6", + "@jsonjoy.com/fs-print": "4.57.6", + "@jsonjoy.com/fs-snapshot": "4.57.6", "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", @@ -6126,6 +7354,19 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -6170,22 +7411,25 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -6204,9 +7448,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -6287,11 +7531,14 @@ } }, "node_modules/node-releases": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", - "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/normalize-path": { "version": "3.0.0", @@ -6326,6 +7573,19 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -6418,6 +7678,17 @@ "dev": true, "license": "MIT" }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -6497,32 +7768,35 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-retry": { @@ -6577,6 +7851,19 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6632,6 +7919,13 @@ "dev": true, "license": "MIT" }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6640,13 +7934,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -6665,10 +7959,66 @@ "node": ">=8" } }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/pkijs": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.3.3.tgz", - "integrity": "sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.4.0.tgz", + "integrity": "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6683,6 +8033,19 @@ "node": ">=16.0.0" } }, + "node_modules/pkijs/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -6694,9 +8057,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -6714,7 +8077,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -6786,9 +8149,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -6827,6 +8190,34 @@ "renderkid": "^3.0.0" } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/printj": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/printj/-/printj-1.1.2.tgz", @@ -7548,6 +8939,12 @@ "react-dom": ">=16.9.0" } }, + "node_modules/rc-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, "node_modules/rc-virtual-list": { "version": "3.19.2", "resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.19.2.tgz", @@ -7593,9 +8990,10 @@ } }, "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, "license": "MIT" }, "node_modules/readable-stream": { @@ -7626,6 +9024,19 @@ "node": ">=8.10.0" } }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -7639,6 +9050,28 @@ "node": ">= 10.13.0" } }, + "node_modules/rechoir/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", @@ -7738,13 +9171,16 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.1", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -7771,7 +9207,7 @@ "node": ">=8" } }, - "node_modules/resolve-from": { + "node_modules/resolve-cwd/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", @@ -7781,6 +9217,16 @@ "node": ">=8" } }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -7791,6 +9237,40 @@ "node": ">= 4" } }, + "node_modules/rolldown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", + "integrity": "sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.133.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.3", + "@rolldown/binding-darwin-arm64": "1.0.3", + "@rolldown/binding-darwin-x64": "1.0.3", + "@rolldown/binding-freebsd-x64": "1.0.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.3", + "@rolldown/binding-linux-arm64-gnu": "1.0.3", + "@rolldown/binding-linux-arm64-musl": "1.0.3", + "@rolldown/binding-linux-ppc64-gnu": "1.0.3", + "@rolldown/binding-linux-s390x-gnu": "1.0.3", + "@rolldown/binding-linux-x64-gnu": "1.0.3", + "@rolldown/binding-linux-x64-musl": "1.0.3", + "@rolldown/binding-openharmony-arm64": "1.0.3", + "@rolldown/binding-wasm32-wasi": "1.0.3", + "@rolldown/binding-win32-arm64-msvc": "1.0.3", + "@rolldown/binding-win32-x64-msvc": "1.0.3" + } + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -7805,15 +9285,15 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, @@ -7880,25 +9360,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-regex-test/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -7906,6 +9367,19 @@ "dev": true, "license": "MIT" }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", @@ -7936,9 +9410,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -8003,9 +9477,9 @@ } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", "dev": true, "license": "ISC", "bin": { @@ -8040,30 +9514,54 @@ "node": ">= 0.8.0" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, "node_modules/serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", "dev": true, "license": "MIT", "dependencies": { - "accepts": "~1.3.4", + "accepts": "~1.3.8", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" }, "engines": { "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" } }, "node_modules/serve-index/node_modules/depd": { @@ -8077,34 +9575,28 @@ } }, "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", "dev": true, "license": "MIT", "dependencies": { "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.6" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "ISC" + "license": "MIT" }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", @@ -8225,9 +9717,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "dev": true, "license": "MIT", "engines": { @@ -8245,27 +9737,10 @@ "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -8274,12 +9749,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel-list/node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, "engines": { "node": ">= 0.4" }, @@ -8306,19 +9785,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel-map/node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/side-channel-weakmap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", @@ -8339,31 +9805,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel-weakmap/node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel/node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "ISC" }, "node_modules/sockjs": { "version": "0.3.24", @@ -8397,6 +9844,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -8429,56 +9887,6 @@ "wbuf": "^1.7.3" } }, - "node_modules/spdy-transport/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy-transport/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/spdy/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/spdy/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", @@ -8491,6 +9899,13 @@ "node": ">=0.8" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -8501,6 +9916,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -8642,16 +10064,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -8683,11 +10095,24 @@ } }, "node_modules/stylis": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", - "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", "license": "MIT" }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -8701,10 +10126,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "dev": true, "license": "MIT", "engines": { @@ -8716,9 +10148,9 @@ } }, "node_modules/terser": { - "version": "5.44.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", - "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -8735,9 +10167,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.17", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.17.tgz", - "integrity": "sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8757,12 +10189,39 @@ "webpack": "^5.1.0" }, "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, "@swc/core": { "optional": true }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, "esbuild": { "optional": true }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, "uglify-js": { "optional": true } @@ -8775,21 +10234,10 @@ "dev": true, "license": "MIT" }, - "node_modules/terser/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/thingies": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.5.0.tgz", - "integrity": "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/thingies/-/thingies-2.6.0.tgz", + "integrity": "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==", "dev": true, "license": "MIT", "engines": { @@ -8819,6 +10267,23 @@ "dev": true, "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -8836,37 +10301,36 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "node": ">=14.0.0" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "node_modules/tldts": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.2.tgz", + "integrity": "sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "tldts-core": "^7.4.2" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "bin": { + "tldts": "bin/cli.js" } }, + "node_modules/tldts-core": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.2.tgz", + "integrity": "sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==", + "dev": true, + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8896,6 +10360,32 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/tree-dump": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", @@ -8924,72 +10414,37 @@ }, "peerDependencies": { "typescript": ">=4.8.4" - } - }, - "node_modules/ts-loader": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.0.tgz", - "integrity": "sha512-0G3UMhk1bjgsgiwF4rnZRAeTi69j9XMDtmDDMghGSqlWESIAS3LFgJe//GYfE4vcjbyzuURLB9Us2RZIWp2clQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ts-loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + } + }, + "node_modules/ts-loader": { + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.7.tgz", + "integrity": "sha512-/ZNrKgA3K3PtpMYOC71EeMWIloGw3IYEa5/t1cyz2r5/PyUwTXGzYJvcD3kfUvmhlfpz1rhV8B2O6IVTQ0avsg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" }, "engines": { - "node": ">=10" + "node": ">=12.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" } }, - "node_modules/ts-loader/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=8" + "node": ">= 12" } }, "node_modules/tslib": { @@ -9104,18 +10559,18 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" + "call-bind": "^1.0.9", + "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" }, "engines": { "node": ">= 0.4" @@ -9125,9 +10580,9 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -9135,7 +10590,7 @@ "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/typescript-eslint": { @@ -9187,10 +10642,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.0.tgz", + "integrity": "sha512-+t2Z/GwkZQDtu00813aP66ygViGtPHKhhoFZpQKpKrE+9jIgES+Zw+mFNaDWOVRKiuJjuqKHzD3B1sfGg8+ZOQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, @@ -9273,6 +10738,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, "license": "MIT", "bin": { @@ -9289,6 +10755,187 @@ "node": ">= 0.8" } }, + "node_modules/vite": { + "version": "8.0.16", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.16.tgz", + "integrity": "sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.15", + "rolldown": "1.0.3", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.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 + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/watchpack": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", @@ -9313,6 +10960,16 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, "node_modules/webpack": { "version": "5.105.4", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", @@ -9533,19 +11190,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/@types/express-serve-static-core": { - "version": "4.19.8", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", - "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, "node_modules/webpack-merge": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", @@ -9562,15 +11206,39 @@ } }, "node_modules/webpack-sources": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", - "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -9596,6 +11264,31 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9660,25 +11353,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-builtin-type/node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-collection": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", @@ -9699,14 +11373,14 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.21.tgz", + "integrity": "sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", @@ -9720,6 +11394,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -9756,9 +11447,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { @@ -9817,48 +11508,27 @@ "node": ">=0.8" } }, - "node_modules/xlsx-js-style/node_modules/adler-32": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.2.0.tgz", - "integrity": "sha512-/vUqU/UY4MVeFsg+SsK6c+/05RZXIHZMGJA+PX5JyWI0ZRcBpupnRuPLU/NXXoFwMYCPCoxIfElM2eS+DUXCqQ==", - "license": "Apache-2.0", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.1.0" - }, - "bin": { - "adler32": "bin/adler32.njs" - }, - "engines": { - "node": ">=0.8" - } + "node_modules/xlsx-js-style/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "license": "MIT" }, - "node_modules/xlsx-js-style/node_modules/codepage": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.14.0.tgz", - "integrity": "sha512-iz3zJLhlrg37/gYRWgEPkaFTtzmnEv1h+r7NgZum2lFElYQPi0/5bnmuDfODHxfp0INEfnRqyfyeIJDbb7ahRw==", + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, "license": "Apache-2.0", - "dependencies": { - "commander": "~2.14.1", - "exit-on-epipe": "~1.0.1" - }, - "bin": { - "codepage": "bin/codepage.njs" - }, "engines": { - "node": ">=0.8" + "node": ">=18" } }, - "node_modules/xlsx-js-style/node_modules/codepage/node_modules/commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", - "license": "MIT" - }, - "node_modules/xlsx-js-style/node_modules/commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, "license": "MIT" }, "node_modules/yocto-queue": { diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json index ecc1b361da9..cf1e807d581 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -9,7 +9,9 @@ "build": "webpack --config webpack.config.js --mode production", "dev": "webpack serve --config webpack.config.js --mode development", "lint": "eslint 'src/**/*.{ts,tsx}'", - "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix" + "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix", + "test": "vitest run", + "test:watch": "vitest" }, "dependencies": { "@ant-design/icons": "5.4.0", @@ -17,6 +19,7 @@ "ansi-to-react": "6.2.6", "antd": "5.21.0", "chart.js": "^4.5.1", + "date-fns": "^3.6.0", "file-saver": "2.0.5", "react": "18.3.1", "react-dom": "18.3.1", @@ -24,8 +27,10 @@ }, "devDependencies": { "@eslint/js": "^9.28.0", + "@testing-library/dom": "10.4.1", + "@testing-library/react": "16.3.2", "@types/file-saver": "2.0.7", - "@types/node": "18.19.64", + "@types/node": "22.19.19", "@types/react": "18.3.26", "@types/react-dom": "18.3.7", "@typescript-eslint/eslint-plugin": "^8.56.1", @@ -36,10 +41,12 @@ "eslint-plugin-react-hooks": "^5.1.0", "globals": "^15.14.0", "html-webpack-plugin": "5.5.0", + "jsdom": "29.1.1", "style-loader": "3.3.0", - "ts-loader": "9.4.0", - "typescript": "4.9.5", + "ts-loader": "9.5.7", + "typescript": "5.9.3", "typescript-eslint": "^8.33.1", + "vitest": "4.1.8", "webpack": "5.105.4", "webpack-cli": "5.1.4", "webpack-dev-server": "5.2.4" diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts index a9beee6fe3a..b27f8b46604 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/index.ts @@ -13,3 +13,4 @@ export * from './renderers'; export * from './visualizations'; export * from './common'; +export * from './paragraph'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.css b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.css new file mode 100644 index 00000000000..52b8f842bb9 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.css @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.zeppelin-react-paragraph-footer { + color: rgba(0, 0, 0, 0.45); + font-size: 12px; + margin-top: 12px; +} + +html.dark .zeppelin-react-paragraph-footer { + color: rgba(255, 255, 255, 0.65); +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx new file mode 100644 index 00000000000..69d1476b4f6 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx @@ -0,0 +1,119 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { act } from 'react'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { mount, ParagraphFooterMountHandle, ParagraphFooterProps } from './ParagraphFooter'; + +const baseProps: ParagraphFooterProps = { + dateStarted: '2026-06-03T10:00:00.000Z', + dateFinished: '2026-06-03T10:00:05.000Z', + dateUpdated: '2026-06-03T09:59:00.000Z', + showExecutionTime: true, + showElapsedTime: false, + user: 'alice' +}; + +describe('ParagraphFooter mount contract', () => { + let host: HTMLElement | null = null; + let handle: ParagraphFooterMountHandle | null = null; + + const mountFooter = (props: ParagraphFooterProps): void => { + host = document.createElement('div'); + document.body.appendChild(host); + act(() => { + handle = mount(host as HTMLElement, props); + }); + }; + + afterEach(() => { + if (handle) { + const h = handle; + act(() => h.unmount()); + handle = null; + } + host?.remove(); + host = null; + }); + + it('throws when no element is given', () => { + expect(() => mount(null as unknown as HTMLElement, baseProps)).toThrow('Mount element is required'); + }); + + it('returns an update/unmount handle and renders the execution time', () => { + mountFooter(baseProps); + + expect(typeof handle!.update).toBe('function'); + expect(typeof handle!.unmount).toBe('function'); + + const executionTime = host!.querySelector('.execution-time'); + expect(executionTime).not.toBeNull(); + expect(executionTime!.textContent).toContain('Took 5 seconds. Last updated by alice at'); + expect(host!.querySelector('.elapsed-time')).toBeNull(); + }); + + it('falls back to "anonymous" when no user is given', () => { + mountFooter({ ...baseProps, user: undefined }); + + expect(host!.querySelector('.execution-time')!.textContent).toContain('Last updated by anonymous at'); + }); + + it('appends (outdated) when the paragraph changed after the run started', () => { + mountFooter({ ...baseProps, dateUpdated: '2026-06-03T10:00:01.000Z' }); + + expect(host!.querySelector('.execution-time')!.textContent).toMatch(/\(outdated\)$/); + }); + + it('renders bare "outdated" when the duration is invalid but the paragraph is stale', () => { + mountFooter({ + ...baseProps, + dateFinished: '2026-06-03T09:00:00.000Z', // finished before started + dateUpdated: '2026-06-03T10:00:01.000Z' + }); + + expect(host!.querySelector('.execution-time')!.textContent).toBe('outdated'); + }); + + it('renders the elapsed time since dateStarted while running', () => { + // Fake only Date so React's scheduler timers keep working + vi.useFakeTimers({ toFake: ['Date'], now: new Date('2026-06-03T10:05:00.000Z') }); + try { + mountFooter({ ...baseProps, showExecutionTime: false, showElapsedTime: true }); + + expect(host!.querySelector('.execution-time')).toBeNull(); + expect(host!.querySelector('.elapsed-time')!.textContent).toBe('Started 5 minutes ago.'); + } finally { + vi.useRealTimers(); + } + }); + + it('update() re-renders in place with new props', () => { + mountFooter(baseProps); + expect(host!.querySelector('.execution-time')).not.toBeNull(); + + const h = handle!; + act(() => h.update({ ...baseProps, showExecutionTime: false })); + + expect(host!.querySelector('.execution-time')).toBeNull(); + expect(host!.querySelector('[data-testid="react-paragraph-footer-content"]')).not.toBeNull(); + }); + + it('unmount() empties the host element', () => { + mountFooter(baseProps); + const h = handle!; + handle = null; + + act(() => h.unmount()); + + expect(host!.innerHTML).toBe(''); + }); +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx new file mode 100644 index 00000000000..d73f881653b --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx @@ -0,0 +1,110 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createRoot, Root } from 'react-dom/client'; +import { format, formatDistanceStrict, formatDistanceToNow } from 'date-fns'; +import { ReactErrorBoundary } from './ReactErrorBoundary'; +import './ParagraphFooter.css'; + +export interface ParagraphFooterProps { + dateStarted?: string; + dateFinished?: string; + dateUpdated?: string; + showExecutionTime?: boolean; + showElapsedTime?: boolean; + user?: string; + onError?: (error: unknown) => void; +} + +const isOutdated = (dateUpdated?: string, dateStarted?: string): boolean => { + return ( + dateUpdated !== undefined && + dateStarted !== undefined && + Date.parse(dateUpdated) > Date.parse(dateStarted) + ); +}; + +const computeExecutionTime = (props: ParagraphFooterProps): string => { + const { dateStarted, dateFinished, user, dateUpdated } = props; + if (dateFinished === undefined || dateStarted === undefined) { + return ''; + } + const timeMs = Date.parse(dateFinished) - Date.parse(dateStarted); + if (isNaN(timeMs) || timeMs < 0) { + return isOutdated(dateUpdated, dateStarted) ? 'outdated' : ''; + } + + const durationFormat = formatDistanceStrict( + new Date(dateStarted), + new Date(dateFinished) + ); + const endFormat = format(new Date(dateFinished), 'MMMM dd yyyy, h:mm:ss a'); + const userLabel = user === undefined || user === null ? 'anonymous' : user; + let desc = `Took ${durationFormat}. Last updated by ${userLabel} at ${endFormat}.`; + if (isOutdated(dateUpdated, dateStarted)) { + desc += ' (outdated)'; + } + return desc; +}; + +const computeElapsedTime = (dateStarted?: string): string => { + const base = dateStarted ? new Date(dateStarted) : new Date(); + return `Started ${formatDistanceToNow(base)} ago.`; +}; + +export const ParagraphFooter = (props: ParagraphFooterProps) => { + const { showExecutionTime, showElapsedTime } = props; + const executionTime = computeExecutionTime(props); + const elapsedTime = computeElapsedTime(props.dateStarted); + + return ( +
    + {showExecutionTime &&
    {executionTime}
    } + {showElapsedTime &&
    {elapsedTime}
    } +
    + ); +}; + +export interface ParagraphFooterMountHandle { + update: (props: ParagraphFooterProps) => void; + unmount: () => void; +} + +export const mount = ( + element: HTMLElement, + initialProps: ParagraphFooterProps +): ParagraphFooterMountHandle => { + if (!element) { + throw new Error('Mount element is required'); + } + + const root: Root = createRoot(element); + + const renderWith = (props: ParagraphFooterProps) => { + root.render( + + + + ); + }; + + renderWith(initialProps); + + return { + update: (newProps: ParagraphFooterProps) => { + renderWith(newProps); + }, + unmount: () => { + root.unmount(); + } + }; +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.spec.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.spec.tsx new file mode 100644 index 00000000000..cf2b155072e --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.spec.tsx @@ -0,0 +1,102 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { render } from '@testing-library/react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { ReactErrorBoundary } from './ReactErrorBoundary'; + +const Bomb = (): never => { + throw new Error('boom'); +}; + +describe('ReactErrorBoundary', () => { + beforeEach(() => { + // React logs caught boundary errors via console.error in development; + // silence it so test output stays readable. + vi.spyOn(console, 'error').mockImplementation(() => undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('renders children when nothing throws', () => { + const onError = vi.fn(); + const { container } = render( + +
    ok
    +
    + ); + + expect(container.querySelector('[data-testid="child"]')).not.toBeNull(); + expect(onError).not.toHaveBeenCalled(); + }); + + it('renders nothing and reports the error once when a child throws during render', () => { + const onError = vi.fn(); + const { container } = render( + + + + ); + + expect(container.innerHTML).toBe(''); + expect(onError).toHaveBeenCalledTimes(1); + expect(onError).toHaveBeenCalledWith(expect.objectContaining({ message: 'boom' })); + }); + + it('swallows errors thrown by the onError callback itself', () => { + const onError = vi.fn(() => { + throw new Error('callback exploded'); + }); + + expect(() => + render( + + + + ) + ).not.toThrow(); + expect(onError).toHaveBeenCalledTimes(1); + }); + + it('does not crash when no onError is provided', () => { + expect(() => + render( + + + + ) + ).not.toThrow(); + }); + + it('does not recover after an error: healthy re-renders still produce nothing', () => { + const onError = vi.fn(); + const { container, rerender } = render( + + + + ); + expect(container.innerHTML).toBe(''); + + rerender( + +
    ok
    +
    + ); + + // hasError never resets; recovery requires unmount + remount, + // which is exactly what the Angular host does via the fallback branch. + expect(container.innerHTML).toBe(''); + expect(onError).toHaveBeenCalledTimes(1); + }); +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.tsx new file mode 100644 index 00000000000..f0d6157e0fb --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ReactErrorBoundary.tsx @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, ErrorInfo, ReactNode } from 'react'; + +interface Props { + onError?: (error: unknown) => void; + children: ReactNode; +} + +interface State { + hasError: boolean; +} + +export class ReactErrorBoundary extends Component { + state: State = { hasError: false }; + + static getDerivedStateFromError(): State { + return { hasError: true }; + } + + componentDidCatch(error: Error, _info: ErrorInfo): void { + if (typeof this.props.onError === 'function') { + try { + this.props.onError(error); + } catch { + /* swallow */ + } + } + } + + render(): ReactNode { + if (this.state.hasError) { + return null; + } + return this.props.children; + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/index.ts new file mode 100644 index 00000000000..80c0ecafbb3 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/index.ts @@ -0,0 +1,14 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './ParagraphFooter'; +export * from './ReactErrorBoundary'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/main.ts b/zeppelin-web-angular/projects/zeppelin-react/src/main.ts index 190f1978160..cf8e866a318 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/main.ts +++ b/zeppelin-web-angular/projects/zeppelin-react/src/main.ts @@ -11,3 +11,4 @@ */ export { PublishedParagraph, mount } from './pages/PublishedParagraph'; +export { ParagraphFooter, mount as mountParagraphFooter } from './components/paragraph/ParagraphFooter'; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/test-setup.ts b/zeppelin-web-angular/projects/zeppelin-react/src/test-setup.ts new file mode 100644 index 00000000000..43cdd4dba51 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/test-setup.ts @@ -0,0 +1,22 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { cleanup } from '@testing-library/react'; +import { afterEach } from 'vitest'; + +// Tests drive React roots directly (the Module Federation mount contract), +// so opt into act()-aware scheduling globally. +(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true; + +// Vitest globals are disabled, so Testing Library cannot self-register its +// auto-cleanup hook; without this, rendered DOM leaks between tests. +afterEach(cleanup); diff --git a/zeppelin-web-angular/projects/zeppelin-react/vitest.config.ts b/zeppelin-web-angular/projects/zeppelin-react/vitest.config.ts new file mode 100644 index 00000000000..8fde66b75c1 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/vitest.config.ts @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + include: ['src/**/*.spec.{ts,tsx}'], + setupFiles: ['./src/test-setup.ts'] + } +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js b/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js index 4facdadc09b..aef55f29ace 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js +++ b/zeppelin-web-angular/projects/zeppelin-react/webpack.config.js @@ -69,7 +69,8 @@ module.exports = (_env, argv) => { name: 'reactApp', filename: 'remoteEntry.js', exposes: { - './PublishedParagraph': './src/pages/PublishedParagraph' + './PublishedParagraph': './src/pages/PublishedParagraph', + './ParagraphFooter': './src/components/paragraph/ParagraphFooter' }, shared: { react: { @@ -101,7 +102,8 @@ module.exports = (_env, argv) => { version: '1.0.0', baseUrl: isProduction ? '/assets/react/' : 'http://localhost:3001/', exposes: { - './PublishedParagraph': './PublishedParagraph.tsx' + './PublishedParagraph': './PublishedParagraph.tsx', + './ParagraphFooter': './ParagraphFooter.tsx' } }; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html index 20a45920771..6dc08633df8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.html @@ -100,6 +100,7 @@ [revisionView]="revisionView" [first]="first" [last]="last" + [useReactFooter]="useReactFooter" [attr.data-testid]="p.id" (selectAtIndex)="onSelectAtIndex($event)" (selected)="onParagraphSelect($event)" diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 1cb8d2b288b..d76bca003e4 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -78,6 +78,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit sidebarWidth = 370; sidebarAnimationFrame = -1; isSidebarOpen = false; + useReactFooter = false; @MessageListener(OP.NOTE) getNote(data: MessageReceiveDataTypeMap[OP.NOTE]) { @@ -441,6 +442,12 @@ export class NotebookComponent extends MessageListenersManager implements OnInit this.onParagraphScrolled(id); this.onParagraphSearch(params.get('term') || ''); }); + this.activatedRoute.queryParamMap + .pipe(startWith(this.activatedRoute.snapshot.queryParamMap), takeUntil(this.destroy$)) + .subscribe(data => { + this.useReactFooter = data.get('reactFooter') === 'true'; + this.cdr.markForCheck(); + }); this.activatedRoute.params.pipe(takeUntil(this.destroy$), distinctUntilKeyChanged('noteId')).subscribe(() => { this.noteVarShareService.clear(); }); diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html index 579546a02f9..d509136f18c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.html @@ -114,14 +114,23 @@ > } } - + @if (shouldUseReactFooter) { +
    + } @else { + + }
    @if (!viewOnly && !revisionView && last && looknfeel !== 'report') { , b: Record): boolean => { + const aKeys = Object.keys(a); + const bKeys = Object.keys(b); + return aKeys.length === bKeys.length && aKeys.every(key => Object.is(a[key], b[key])); +}; + @Component({ selector: 'zeppelin-notebook-paragraph', templateUrl: './paragraph.component.html', @@ -94,6 +100,44 @@ export class NotebookParagraphComponent @Input() collaborativeMode = false; @Input() first!: boolean; @Input() interpreterBindings: InterpreterBindingItem[] = []; + @Input() useReactFooter = false; + reactFooterFailed = false; + + get shouldUseReactFooter(): boolean { + return this.useReactFooter && !this.reactFooterFailed; + } + + readonly onReactFooterError = (error: unknown): void => { + console.error('React footer error', error); + this.reactFooterFailed = true; + this.cdr.markForCheck(); + }; + + private lastReactFooterProps: Record | null = null; + + // Memoized so the template binding keeps a stable object identity when + // nothing changed; otherwise every change-detection pass would hand + // ReactMountDirective a fresh object and trigger handle.update(). + get reactFooterProps(): Record { + const next: Record = !this.paragraph + ? { onError: this.onReactFooterError } + : { + dateStarted: this.paragraph.dateStarted, + dateFinished: this.paragraph.dateFinished, + dateUpdated: this.paragraph.dateUpdated, + showExecutionTime: !this.paragraph.config.tableHide && !this.viewOnly, + showElapsedTime: this.paragraph.status === 'RUNNING', + user: this.paragraph.user, + onError: this.onReactFooterError + }; + const prev = this.lastReactFooterProps; + if (prev !== null && shallowEquals(prev, next)) { + return prev; + } + this.lastReactFooterProps = next; + return next; + } + @Output() readonly saveNoteTimer = new EventEmitter(); @Output() readonly triggerSaveParagraph = new EventEmitter(); @Output() readonly selected = new EventEmitter(); diff --git a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts index 1f6e7f73997..8429e895e24 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts @@ -228,7 +228,9 @@ export class PublishedParagraphComponent extends ParagraphBase implements Publis throw new Error('window.reactApp not available'); } - const factory = await container.get('./PublishedParagraph'); + const factory = await container.get<{ mount: (el: HTMLElement, props: unknown) => () => void }>( + './PublishedParagraph' + ); const { mount } = factory(); if (!mount || typeof mount !== 'function') { diff --git a/zeppelin-web-angular/src/app/share/public-api.ts b/zeppelin-web-angular/src/app/share/public-api.ts index 312df06dbde..07192569474 100644 --- a/zeppelin-web-angular/src/app/share/public-api.ts +++ b/zeppelin-web-angular/src/app/share/public-api.ts @@ -16,6 +16,7 @@ export * from './note-create'; export * from './note-import'; export * from './note-rename'; export * from './pipes'; +export * from './react-mount'; export * from './resize-handle'; export * from './share.module'; export * from './shortcut'; diff --git a/zeppelin-web-angular/src/app/share/react-mount/index.ts b/zeppelin-web-angular/src/app/share/react-mount/index.ts new file mode 100644 index 00000000000..49e47404422 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/react-mount/index.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './public-api'; diff --git a/zeppelin-web-angular/src/app/share/react-mount/public-api.ts b/zeppelin-web-angular/src/app/share/react-mount/public-api.ts new file mode 100644 index 00000000000..43a3bfccf88 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/react-mount/public-api.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './react-mount-handle'; +export * from './react-mount.directive'; +export * from './react-remote-loader.service'; diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-mount-handle.ts b/zeppelin-web-angular/src/app/share/react-mount/react-mount-handle.ts new file mode 100644 index 00000000000..aefeb58fe31 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/react-mount/react-mount-handle.ts @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type ReactProps = Record; + +export interface ReactHostCallbacks { + onError?: (error: unknown) => void; +} + +export interface ReactMountHandle { + update: (props: ReactProps & ReactHostCallbacks) => void; + unmount: () => void; +} + +export type ReactMountFn = (element: HTMLElement, props: ReactProps & ReactHostCallbacks) => ReactMountHandle; + +/** + * Shape of a Module Federation exposed module: a factory returning an + * object whose `mount` is the entry point. + */ +export interface ReactExposedModule { + mount: ReactMountFn; +} + +/** + * Legacy shape (used by ./PublishedParagraph until its follow-up + * refactor): mount returns a bare unmount function. + */ +export type LegacyMountFn = (element: HTMLElement, props: ReactProps) => () => void; + +export interface LegacyExposedModule { + mount: LegacyMountFn; +} + +export type AnyExposedModule = ReactExposedModule | LegacyExposedModule; diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts new file mode 100644 index 00000000000..c93c168001b --- /dev/null +++ b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts @@ -0,0 +1,149 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Directive, ElementRef, Input, NgZone, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; +import { ReactRemoteLoaderService } from './react-remote-loader.service'; +import { + AnyExposedModule, + ReactExposedModule, + ReactHostCallbacks, + ReactMountHandle, + ReactProps +} from './react-mount-handle'; + +const isLegacyModule = (mod: AnyExposedModule, handleOrUnmount: unknown): handleOrUnmount is () => void => { + void mod; + return typeof handleOrUnmount === 'function'; +}; + +const wrapLegacyHandle = (unmount: () => void): ReactMountHandle => ({ + update: () => { + /* legacy modules don't support updates; no-op */ + }, + unmount +}); + +@Directive({ + selector: '[zeppelin-react-mount]', + standalone: false +}) +export class ReactMountDirective implements OnChanges, OnDestroy { + @Input('zeppelin-react-mount') module!: string; + @Input() reactProps: ReactProps & ReactHostCallbacks = {}; + + private latestProps: ReactProps & ReactHostCallbacks = {}; + private destroyed = false; + private loading = false; + private handle: ReactMountHandle | null = null; + private mountedModule: string | null = null; + + constructor( + private readonly host: ElementRef, + private readonly ngZone: NgZone, + private readonly loader: ReactRemoteLoaderService + ) {} + + ngOnChanges(changes: SimpleChanges): void { + this.latestProps = this.reactProps ?? {}; + + if (changes.module && !changes.module.firstChange && this.mountedModule) { + // Module swap after first mount is unsupported. Report via onError + // and otherwise leave the existing handle in place. + this.reportError( + new Error( + `ReactMountDirective: module input changed after mount ` + + `(from "${this.mountedModule}" to "${this.module}") — unsupported` + ) + ); + return; + } + + if (this.handle) { + this.ngZone.runOutsideAngular(() => { + try { + this.handle!.update(this.latestProps); + } catch (err) { + this.reportError(err); + } + }); + return; + } + + if (!this.loading && !this.destroyed && this.module) { + void this.startLoad(); + } + } + + ngOnDestroy(): void { + this.destroyed = true; + if (this.handle) { + try { + this.handle.unmount(); + } catch (err) { + this.reportError(err); + } + this.handle = null; + } + } + + private async startLoad(): Promise { + this.loading = true; + const moduleKey = this.module; + try { + const mod = await this.loader.loadModule(moduleKey); + if (this.destroyed) { + return; + } + this.ngZone.runOutsideAngular(() => { + try { + const returned = (mod as ReactExposedModule).mount(this.host.nativeElement, this.latestProps); + if (isLegacyModule(mod, returned)) { + this.handle = wrapLegacyHandle(returned as unknown as () => void); + } else { + this.handle = returned as ReactMountHandle; + } + this.mountedModule = moduleKey; + } catch (err) { + this.handle = null; + this.reportError(err); + } + }); + } catch (err) { + // Mirror the success-path guard: don't report a load that failed after destroy. + if (!this.destroyed) { + this.reportError(err); + } + } finally { + this.loading = false; + } + } + + private reportError(error: unknown): void { + const onError = this.latestProps.onError; + if (typeof onError === 'function') { + // Re-enter the Angular zone so onError handlers can safely mutate + // host state and trigger change detection. React lifecycle callbacks + // (e.g. error boundaries) run outside the zone because we mounted + // there; calling back into the host without ngZone.run would leave + // markForCheck() with nothing to flush. + this.ngZone.run(() => { + try { + onError(error); + } catch { + /* swallow callback errors; they shouldn't loop */ + } + }); + } else { + console.error('[ReactMountDirective]', error); + } + } +} diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts b/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts new file mode 100644 index 00000000000..75e8a2fd4de --- /dev/null +++ b/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts @@ -0,0 +1,98 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { environment } from '../../../environments/environment'; +import { AnyExposedModule } from './react-mount-handle'; + +interface RemoteContainer { + get(key: string): Promise<() => T>; + init?: (shareScope: unknown) => Promise; +} + +declare global { + interface Window { + reactApp?: RemoteContainer; + } +} + +@Injectable({ providedIn: 'root' }) +export class ReactRemoteLoaderService { + private containerPromise: Promise | null = null; + private readonly modulePromises = new Map>(); + + loadContainer(): Promise { + if (this.containerPromise) { + return this.containerPromise; + } + + this.containerPromise = new Promise((resolve, reject) => { + if (window.reactApp) { + resolve(window.reactApp); + return; + } + + const script = document.createElement('script'); + script.src = environment.reactRemoteEntryUrl; + script.async = true; + + // Remove the tag on *any* failure (network error or loaded-but-unregistered): + // containerPromise resets on rejection, so each retry would otherwise leak a tag. + const fail = (message: string) => { + script.remove(); + reject(new Error(message)); + }; + + script.onload = () => { + if (!window.reactApp) { + fail('window.reactApp not registered after script load'); + return; + } + resolve(window.reactApp); + }; + script.onerror = () => fail(`Failed to load React remote at ${script.src}`); + document.head.appendChild(script); + }); + + // Clear the container promise AND drain module cache on failure so a + // future caller can retry. A stale failed container would otherwise + // poison every module fetch. + this.containerPromise.catch(() => { + this.containerPromise = null; + this.modulePromises.clear(); + }); + + return this.containerPromise; + } + + loadModule(exposedKey: string): Promise { + const cached = this.modulePromises.get(exposedKey); + if (cached) { + return cached as Promise; + } + + const promise = (async () => { + const container = await this.loadContainer(); + const factory = await container.get(exposedKey); + return factory(); + })(); + + this.modulePromises.set(exposedKey, promise); + + // Evict failed module promise so the next caller can retry. + promise.catch(() => { + this.modulePromises.delete(exposedKey); + }); + + return promise; + } +} diff --git a/zeppelin-web-angular/src/app/share/share.module.ts b/zeppelin-web-angular/src/app/share/share.module.ts index 247850864ca..89326234a5b 100644 --- a/zeppelin-web-angular/src/app/share/share.module.ts +++ b/zeppelin-web-angular/src/app/share/share.module.ts @@ -49,6 +49,7 @@ import { NoteTocComponent } from './note-toc/note-toc.component'; import { PageHeaderComponent } from './page-header/page-header.component'; import { HumanizeBytesPipe } from './pipes'; import { ResizeHandleComponent } from './resize-handle'; +import { ReactMountDirective } from './react-mount'; import { RunScriptsDirective } from './run-scripts/run-scripts.directive'; import { ShortcutComponent } from './shortcut/shortcut.component'; import { SpinComponent } from './spin/spin.component'; @@ -69,7 +70,8 @@ const EXPORT_LIST = [ PageHeaderComponent, SpinComponent, ThemeToggleComponent, - ResizeHandleComponent + ResizeHandleComponent, + ReactMountDirective ]; const PIPES = [HumanizeBytesPipe]; From b3870e95bb5d9dfbd83bd3f4682602614ccbde54 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Wed, 1 Jul 2026 23:36:50 +0900 Subject: [PATCH 057/179] [MINOR] Record PMC answers to the security THREAT_MODEL.md open questions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #5268, which added the security `THREAT_MODEL.md` as a v0 draft for the PMC to review. This folds the Apache Zeppelin PMC review answers into the document so it reflects maintainer positions rather than the draft `(inferred)` guesses: - Records the PMC answer for each open question in §14 (waves 1–3) inline. - Re-tags the corresponding `(inferred)` claims as `(maintainer)` across §2/§3/§5a/§6/§8/§9/§11a. - §5a: records the insecure-default ruling — anonymous-by-default, public notebooks, impersonation-off, and the shared binding mode are dev-conveniences / by-design, so reports against them are `OUT-OF-MODEL: non-default-build`. - §8: confirms authentication, notebook authorization (server-side), URL ACL (operator-configured), credential isolation, and impersonation confinement as committed properties; clarifies that resource/availability is not a committed property today (treated as `VALID-HARDENING`). - Keeps the core framing: RBAC is the trust boundary, not a sandbox. Documentation only; no code changes. Closes #5275 from jongyoul/threat-model-maintainer-answers. Signed-off-by: Jongyoul Lee --- THREAT_MODEL.md | 133 +++++++++++++++++++++++++++++------------------- 1 file changed, 80 insertions(+), 53 deletions(-) diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md index 285a7b3cb4c..93a7389d1b9 100644 --- a/THREAT_MODEL.md +++ b/THREAT_MODEL.md @@ -23,9 +23,10 @@ limitations under the License. - **Modeled against:** `master` HEAD as of 2026-06-05 (latest released docs line). - **Authors:** ASF Security team (v0 draft, generated via the `threat-model-producer` rubric), for the Apache Zeppelin PMC to review. -- **Status:** **DRAFT v0 — draft-first, not yet maintainer-ratified.** Most - claims are *(inferred)* from public documentation and the codebase and - must be confirmed; see §14. +- **Status:** **v0 — PMC-reviewed.** The Apache Zeppelin PMC has reviewed the + framing (confirmed) and answered the §14 questions; the answers are recorded + inline in §14 and folded into the sections below, with confirmed claims + re-tagged *(maintainer)*. - **Version binding:** this model is versioned with the project. A report against Zeppelin release *N* is triaged against the model as it stood at *N*. - **Reporting cross-reference:** findings that violate a §8 property should be @@ -35,7 +36,9 @@ limitations under the License. - **Provenance legend:** *(documented)* = stated in Zeppelin's own docs/site; *(maintainer)* = confirmed by a Zeppelin PMC member; *(inferred)* = reasoned from code/docs/domain knowledge, not yet confirmed (each has a §14 question). -- **Draft confidence:** ~18 documented / 0 maintainer / ~24 inferred. +- **Confidence:** ~18 documented; the §14 answers fold the bulk of the former + *(inferred)* claims to *(maintainer)*; a few loose environmental assumptions + remain *(inferred)*. **What Zeppelin is.** Apache Zeppelin is a web-based, multi-user notebook server for interactive data analytics. Users open notebooks in a browser and @@ -65,7 +68,7 @@ about preventing code execution. whatever level the deployment's authorization grants anonymous, which by default is full access. -**Component-family table** *(inferred — confirm in §14)*: +**Component-family table** *(maintainer — §14.8)*: | Family | Entry point | Touches outside process? | In model? | | --- | --- | --- | --- | @@ -75,14 +78,14 @@ about preventing code execution. | Interpreter-executed user code | `%spark`, `%sh`, `%python`, `%jdbc`, … | arbitrary (by design) | **boundary only** — the *code* is by-design; reaching/isolating it is in model | | Credentials / datasource auth | `CredentialRestApi`, credential injection | filesystem, backends | **yes** | | Notebook storage / repos | `NotebookRepo` (local FS, S3, Git, etc.) | filesystem / cloud | **yes** | -| Bundled interpreters / examples / web UI assets | `*-interpreter` modules, demos | varies | **per-interpreter** — confirm which are supported (§14) | +| Bundled interpreters / examples / web UI assets | `*-interpreter` modules, demos | varies | **all bundled interpreters first-class** for security purposes (§14.8); demo/example notebooks are a separate category | ## §3 Out of scope (explicit non-goals) - **Sandboxing the code a permitted user runs.** A user with run permission on a notebook can execute arbitrary code (`%sh`, Spark driver code, etc.) by design; Zeppelin does not attempt to confine what that code does on the host - or backend. *(inferred — §14)* + or backend. *(maintainer — §14.3)* - **Defending a deployment that disables authentication and is exposed to an untrusted network.** The docs direct operators to enable Shiro *or* deploy only in a secured/trusted environment *(documented)*; an unauthenticated, @@ -92,9 +95,10 @@ about preventing code execution. - **Security of third-party interpreter backends** (the Spark cluster, the JDBC database, the host shell) — Zeppelin brokers access; it does not own those systems' security. *(inferred)* -- **Bundled examples / demo notebooks / unsupported interpreters** — threat- - modeled separately if at all; integrators should not extend core guarantees - to them. *(inferred — §14: which interpreters are first-class?)* +- **Bundled demo / example notebooks** — a separate category from the + interpreters, threat-modeled separately if at all; integrators should not + extend core guarantees to them. (All bundled *interpreters* are first-class; + see §2 and §14.8.) *(maintainer — §14.8)* ## §4 Trust boundaries and data flow @@ -147,20 +151,20 @@ value**, so the model is ambiguous until the PMC rules on each (see §14 wave 1) | Knob | Default | Effect on model | Maintainer stance | | --- | --- | --- | --- | -| Shiro authentication (`conf/shiro.ini`) | **absent → anonymous** *(documented)* | No auth boundary at all; every §8 authn/authz property is void | **?** supported posture vs dev-only — §14.1 | -| `zeppelin.notebook.public` / `ZEPPELIN_NOTEBOOK_PUBLIC` | **`true` → new notes public** *(documented)* | Empty-ACL note is readable/runnable by any authenticated (or anonymous) user | **?** §14.2 | -| Interpreter user impersonation | **off → runs as server OS user** *(documented)* | Without it, every run-capable user's code shares the *server's* OS identity/privileges and filesystem | **?** §14.3 | -| Interpreter binding mode (shared / scoped / isolated) | **shared** *(inferred)* | Process-level separation between users/notes; "isolated" is a *stability/resource* boundary, **not** a security sandbox | **?** §14.4 | -| URL ACLs (`[urls]` in shiro.ini) gating `/interpreter`, `/credential`, `/configurations` | **not restricted unless operator adds them** *(documented)* | Sensitive admin endpoints open to any authenticated role absent explicit `[urls]` rules | **?** §14.5 | -| HTTPS / security headers (`http_security_headers`) | **off/plain unless configured** *(documented)* | Credentials + session over plaintext; missing CSP/XFO | operator responsibility (§10) | - -**Insecure-default ruling needed.** For each row whose default is the less- -secure value, the PMC must rule: is the default the *supported production -posture* (→ a report against it is `VALID`), or a *dev-convenience operators -must change* (→ `OUT-OF-MODEL: non-default-build`, and the requirement moves to -§10)? The public docs lean toward the latter ("strongly recommended… or only -deploy… in a secured and trusted environment"), but this needs an explicit PMC -call because it reshapes §8/§10/§11a/§13 at once. +| Shiro authentication (`conf/shiro.ini`) | **absent → anonymous** *(documented)* | No auth boundary at all; every §8 authn/authz property is void | **dev-convenience** *(maintainer — §14.1)*: anonymous is *not* the supported posture; reports against an exposed anonymous instance are `OUT-OF-MODEL: non-default-build` | +| `zeppelin.notebook.public` / `ZEPPELIN_NOTEBOOK_PUBLIC` | **`true` → new notes public** *(documented)* | Empty-ACL note is readable/runnable by any authenticated (or anonymous) user | **by-design** *(maintainer — §14.2)*: public-by-default is intended; an empty-ACL note being readable/runnable is not a bug | +| Interpreter user impersonation | **off → runs as server OS user** *(documented)* | Without it, every run-capable user's code shares the *server's* OS identity/privileges and filesystem | **by-design** *(maintainer — §14.3)*: running as the server OS user is the documented default; OS isolation requires enabling impersonation | +| Interpreter binding mode (shared / scoped / isolated) | **shared** *(maintainer — §14.4)* | Process-level separation between users/notes; "isolated" is a *stability/resource* boundary, **not** a security sandbox | **maintainer — §14.4**: default is `shared`; no binding mode is a security sandbox | +| URL ACLs (`[urls]` in shiro.ini) gating `/interpreter`, `/credential`, `/configurations` | **not restricted unless operator adds them** *(documented)* | Sensitive admin endpoints open to any authenticated role absent explicit `[urls]` rules | **maintainer — §14.5**: no built-in admin gate; protection relies entirely on `shiro.ini [urls]` | +| HTTPS / security headers (`http_security_headers`) | **off/plain unless configured** *(documented)* | Credentials + session over plaintext; missing CSP/XFO | operator responsibility (§10); no CSP and Origin-based CSRF only — `VALID-HARDENING` *(maintainer — §14.10)* | + +**Insecure-default ruling (recorded).** The PMC has ruled that every insecure +§5a default above is a *dev-convenience / by-design* choice, not the supported +production posture: Zeppelin's stance is "open by default, secure by +configuration" (enable Shiro, or deploy only in a secured/trusted network). A +report that only manifests under one of these defaults is therefore +`OUT-OF-MODEL: non-default-build` (or `BY-DESIGN`), with the requirement living +in §10. See §14 wave 1 for the per-knob answers. ## §6 Assumptions about inputs @@ -170,15 +174,15 @@ Inputs and their trust (network-service shape — rows are endpoints/messages): | --- | --- | --- | --- | | `POST` login / Shiro filter | credentials | **yes** (pre-auth) | strong realm config; lockout/rate-limit at proxy *(inferred)* | | Websocket ops (run/edit/move paragraph) | notebook + paragraph payload | **yes** (authenticated user) | notebook ACL + run permission enforced server-side *(documented)* | -| `NotebookRestApi` / `InterpreterRestApi` | note id, interpreter settings | **yes** (authenticated user) | URL ACL + ownership checks *(inferred — §14.6)* | -| `CredentialRestApi` | per-user credentials | **yes** (authenticated user) | per-user credential isolation *(inferred — §14.7)* | +| `NotebookRestApi` / `InterpreterRestApi` | note id, interpreter settings | **yes** (authenticated user) | URL ACL + ownership checks, enforced server-side *(maintainer — §14.6)* | +| `CredentialRestApi` | per-user credentials | **yes** (authenticated user) | per-user credential isolation *(maintainer — §14.7)* | | Paragraph code body | arbitrary code | **yes — by design** | this is the granted capability, not validated input | | `shiro.ini`, `zeppelin-site.xml`, interpreter JSON | config | **no — operator-trusted** | filesystem perms on config/secret files *(inferred)* | | Notebook storage backend contents | persisted notes | **mostly trusted** (written via the app) | integrity of the repo (S3/Git/FS) *(inferred)* | -Size/shape/rate: *(inferred — §14)* no documented limits on paragraph size, -result size, or websocket message rate; resource exhaustion via large -results / many interpreter launches is plausible and needs a §8 resource line. +Size/shape/rate: *(maintainer — §14.9)* there is no rate limit and no +concurrent-interpreter-launch cap today; the PMC treats this as +`VALID-HARDENING` and welcomes the scan surfacing concrete limits. ## §7 Adversary model @@ -206,32 +210,35 @@ config/secret files or the host outside what their interpreter identity grants. ## §8 Security properties the project provides -Each conditional on the relevant §5a knob being set securely. *(All -*(inferred)* pending §14 — Zeppelin documents the mechanisms but does not -publish them as committed "properties".)* +Each conditional on the relevant §5a knob being set securely. The PMC has +confirmed properties 1–5 below as committed properties (§14.5–§14.7), now +tagged *(maintainer)*; property 6 (resource/availability) is **not** a committed +property today (§14.9). 1. **Authentication of the web/REST/websocket surface** *when Shiro is configured*. Violation symptom: an unauthenticated client performs an - operation requiring a session. Severity: **critical**. *(inferred)* + operation requiring a session. Severity: **critical**. *(maintainer — + §14.6)* 2. **Authorization of notebook operations per the owner/reader/writer/runner ACL** *when auth is on*. Violation symptom: a user reads/edits/runs a note - they lack permission for. Severity: **critical**. *(documented mechanism / - inferred as a committed property)* + they lack permission for. Severity: **critical**. *(maintainer — §14.6: + enforced server-side for every websocket/REST op, not client-side only)* 3. **URL-level access control** for sensitive endpoints via `[urls]`. Violation symptom: a non-admin reaches `/interpreter`, `/credential`, or `/configurations` despite a restricting rule. Severity: **high**. - *(documented mechanism)* + *(documented mechanism; maintainer — §14.5: no built-in admin gate, so this + property holds only when the operator adds `[urls]` rules)* 4. **Per-user credential isolation** (one user cannot read another's injected datasource credentials). Violation symptom: cross-user credential read. - Severity: **critical**. *(inferred — §14.7)* + Severity: **critical**. *(maintainer — §14.7)* 5. **Impersonation confinement** *when enabled*: interpreter code runs as the logged-in user, not the server user, and not as another user. Violation symptom: code runs as a different identity than the session's. Severity: - **high**. *(documented mechanism / inferred property)* -6. **Resource/availability** *(inferred — §14)*: **needs a line.** Is an - unauthenticated request able to spawn interpreters / exhaust memory a bug? - Propose: pre-auth resource exhaustion is in-model; an authenticated user - running an expensive query is not. Confirm threshold in §14. + **high**. *(maintainer — §14.3)* +6. **Resource/availability** — **not a committed property today** *(maintainer — + §14.9)*. There is no rate limit or concurrent-launch cap. The PMC treats + hardening here as `VALID-HARDENING` and welcomes concrete recommendations + from the scan rather than suppressing them. ## §9 Security properties the project does *not* provide @@ -250,17 +257,18 @@ publish them as committed "properties".)* each user/note a separate interpreter *process* for stability and resource separation; it does **not** confine what the code in that process can do to the host or to shared backends, and absent impersonation all those processes - still run as the **same server OS user**. *(inferred — §14.4)* + still run as the **same server OS user**. *(maintainer — §14.4)* - **Notebook permissions are an application-layer ACL, not OS isolation.** A user denied *read* on a note in the UI may still reach data through an interpreter they *can* run if backends aren't separately access-controlled. - *(inferred — §14)* + *(maintainer)* **Well-known attack classes left to the operator/integrator:** SSRF from interpreter code reaching internal services; secrets-in-notebooks; XSS/CSRF on -the notebook web UI (mitigated only if `http_security_headers` + CSRF defenses -are enabled — confirm coverage in §14); websocket cross-origin. One line each; -the point is to put integrators on notice. +the notebook web UI — *(maintainer — §14.10)* there is **no Content-Security- +Policy** and CSRF protection is **Origin-header-based only**, so strengthening +these (CSP, stronger CSRF) is welcome `VALID-HARDENING`; websocket cross-origin. +The point is to put integrators on notice. ## §10 Downstream / operator responsibilities @@ -297,18 +305,18 @@ The highest-leverage section for keeping scan output signal-heavy: - **"`%sh` / interpreter executes arbitrary shell or driver code → RCE."** By design for a run-capable user; `OUT-OF-MODEL` / `BY-DESIGN` unless it - crosses a tenant or the operator boundary. (§3, §9) *(inferred — §14.3)* + crosses a tenant or the operator boundary. (§3, §9) *(maintainer — §14.3)* - **"Interpreter process runs as the Zeppelin server OS user / can read server files."** Documented default behavior without impersonation; operator config, - not a defect. (§5a, §10) *(documented)* + not a defect. (§5a, §10) *(documented; maintainer — §14.3)* - **"Anonymous user can do X"** reported against a deployment with **no `shiro.ini`.** Out of model — auth is operator-enabled. (§5a, §9) - *(documented)* + *(maintainer — §14.1)* - **"No TLS / credentials in plaintext"** against a deployment the operator did not configure for HTTPS. Operator responsibility. (§10) *(documented)* - **Static-analysis "command injection / code execution" hits on the interpreter execution path.** That path *is* the feature; in-model only if it - bypasses the authn/authz gate. (§4 reachability test) *(inferred)* + bypasses the authn/authz gate. (§4 reachability test) *(maintainer)* ## §12 Conditions that would change this model @@ -334,47 +342,66 @@ The highest-leverage section for keeping scan output signal-heavy: ## §14 Open questions for the maintainers -Grouped in waves; each states a **proposed answer** to confirm/correct/strike. -Every *(inferred)* tag above maps to one of these. +Grouped in waves; each states the **proposed answer** followed by the **PMC +answer** (recorded by the Apache Zeppelin PMC, 2026-06-11). The core framing — +RBAC (Shiro + notebook ACL + URL ACL + impersonation) is the trust boundary, +not a sandbox, and a `%sh` from a run-capable user is the product working, not +RCE — was confirmed by the PMC and is kept. **Wave 1 — scope & the insecure defaults (these reshape everything):** 1. **Anonymous default.** Proposed: anonymous/no-`shiro.ini` is a *dev- convenience*; the supported production posture requires Shiro **or** a trusted isolated network. So reports against an internet-exposed anonymous instance are `OUT-OF-MODEL: non-default-build`. Correct? (→ §5a, §3, §11a) + **→ PMC: confirmed.** 2. **`notebook.public=true` default.** Proposed: public-by-default is intended convenience; operators needing isolation set it false. A "any user can read an empty-ACL note" report is by-design, not a bug. Correct? (→ §5a, §2) + **→ PMC: confirmed — by-design.** 3. **Impersonation off by default.** Proposed: without impersonation, all interpreter code legitimately runs as the **server** OS user; this is the documented default and not a vulnerability; multi-tenant OS isolation requires enabling impersonation. Correct? (→ §3, §5a, §9, §11a) + **→ PMC: confirmed.** 4. **Binding mode as boundary.** Proposed: shared/scoped/isolated are stability/resource controls, **not** security sandboxes; we should state that explicitly in §9. Agree? Which is the default? (→ §5a, §9) + **→ PMC: agreed — the default is `shared`, and no binding mode is a security + sandbox.** **Wave 2 — properties & enforcement:** 5. **URL ACL default.** Are `/interpreter`, `/credential`, `/configurations` open to any authenticated role unless `[urls]` restricts them, or is there a built-in admin gate? (→ §5a, §8) + **→ PMC: no built-in admin gate — it relies on `shiro.ini [urls]`.** 6. **Server-side ACL enforcement.** Are notebook ACLs + role checks enforced on the **server** for every websocket/REST op (not just hidden in the UI)? Any ops that check only client-side? (→ §6, §8) + **→ PMC: enforced server-side; there are no client-side-only checks.** 7. **Credential isolation.** Does the credential store guarantee one user cannot read another user's injected credentials, including via a shared interpreter process? (→ §8, §9) + **→ PMC: yes — per-user credentials are isolated.** **Wave 3 — surfaces & limits:** 8. **First-class interpreters.** Which interpreters/modules are supported for security purposes vs. community/unsupported (→ §2/§3 carve-out)? + **→ PMC: all bundled interpreters are supported for security purposes + (first-class).** 9. **Resource limits.** Any limits on paragraph/result size, websocket rate, or concurrent interpreter launches? Where's the line between in-model pre-auth exhaustion and by-design expensive queries? (→ §6, §8) + **→ PMC: `VALID-HARDENING` — please surface. No rate limit or + concurrent-launch cap today; this is an area we would like the scan to flag + and recommend improvements for.** 10. **Web-UI hardening.** Does enabling `http_security_headers` give CSRF + XSS + clickjacking coverage, or are those partly the operator's job? (→ §9) + **→ PMC: `VALID-HARDENING` — please surface. No CSP, and CSRF is + Origin-based only; concrete improvements from the scan are welcome.** 11. **Coexistence.** This is a new `THREAT_MODEL.md`; `SECURITY.md` (currently a stub) should point at it as canonical, and the website security pages stay the operator how-to. Agree? (→ meta) + **→ PMC: agreed.** ## §15 Machine-readable companion From 963a5183603a41209a66642e7bb1a2658f941bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Tue, 7 Jul 2026 01:23:35 +0900 Subject: [PATCH 058/179] [MINOR] Bump zeppelin-react linkify-it and undici to clear high npm-audit advisories ### What is this PR for? `npm audit --audit-level=high` fails on master, so every frontend PR's npm-audit job goes red. Two high-severity advisories in zeppelin-react's dependency tree: - **linkify-it** 3.0.3 (via ansi-to-react): GHSA-22p9-wv53-3rq4. Constrained to `^5.0.2`. - **undici** 7.27.0 (via jsdom): GHSA-vmh5-mc38-953g and related. Constrained to `^7.28.0`, which stays within jsdom's `^7.25.0` and lets in-range security patches flow. Both use `overrides`. `npm audit fix --force` was avoided because it downgrades ansi-to-react. The linkify-it 3 to 5 bump needs no source changes. No project code imports linkify-it, and its only consumer (ansi-to-react) calls `.tlds()`, `.pretest()`, and `.match()`, which are unchanged from v3 through v5. The override deliberately crosses ansi-to-react's declared `^3.0.3` range, and can be revisited if ansi-to-react is updated. ### What type of PR is it? Improvement ### What is the Jira issue? N/A ### How should this be tested? * `cd zeppelin-web-angular/projects/zeppelin-react && npm ci && npm audit --audit-level=high` exits 0. * `npm run lint`, `npm test` (vitest), and `npm run build` pass. * ansi-to-react still renders URLs as links with linkify-it 5. ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No. * Does this needs documentation? No. Closes #5278 from voidmatcha/react-npm-audit-high. Signed-off-by: ChanHo Lee --- .../projects/zeppelin-react/package-lock.json | 43 +++++++++---------- .../projects/zeppelin-react/package.json | 3 ++ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index 354bdcc974a..e8b9719d447 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -1269,19 +1269,6 @@ "@emnapi/runtime": "^1.7.1" } }, - "node_modules/@noble/hashes": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.2.0.tgz", - "integrity": "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==", - "extraneous": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@oxc-project/types": { "version": "0.133.0", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.133.0.tgz", @@ -7152,12 +7139,22 @@ } }, "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "node_modules/loader-runner": { @@ -10618,9 +10615,9 @@ } }, "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "license": "MIT" }, "node_modules/unbox-primitive": { @@ -10643,9 +10640,9 @@ } }, "node_modules/undici": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.0.tgz", - "integrity": "sha512-+t2Z/GwkZQDtu00813aP66ygViGtPHKhhoFZpQKpKrE+9jIgES+Zw+mFNaDWOVRKiuJjuqKHzD3B1sfGg8+ZOQ==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", "dev": true, "license": "MIT", "engines": { diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json index cf1e807d581..a17a90e6b6c 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -50,5 +50,8 @@ "webpack": "5.105.4", "webpack-cli": "5.1.4", "webpack-dev-server": "5.2.4" + }, + "overrides": { + "linkify-it": "^5.0.2" } } From 0f0a2d59b2c65be61cbd30ebdf53f89531b96ab6 Mon Sep 17 00:00:00 2001 From: Cheng Pan Date: Tue, 7 Jul 2026 10:19:32 +0800 Subject: [PATCH 059/179] [ZEPPELIN-6430] Remove SparkR and R interpreter ### What is this PR for? SparkR has been officially deprecated since Spark 4.0, and plans to be removed in Spark 5.0 (early 2027), it also lacks maintenance and user cases in Zeppelin. https://lists.apache.org/thread/qjgsgxklvpvyvbzsx1qr8o533j4zjlm5 ### What type of PR is it? Breaking change. ### What is the Jira issue? ZEPPELIN-6430 ### How should this be tested? Pass GHA ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? Yes. * Does this needs documentation? Yes. Assisted-by: GLM 5.2 Closes #5271 from pan3793/ZEPPELIN-6430. Signed-off-by: Cheng Pan --- .github/dependabot.yml | 11 - .github/workflows/core.yml | 72 +- .github/workflows/frontend.yml | 11 +- AGENTS.md | 3 +- .../themes/zeppelin/_navigation.html | 2 - .../zeppelin/img/docs-img/ir_kernel.png | Bin 206755 -> 0 bytes docs/index.md | 1 - docs/interpreter/jupyter.md | 22 - docs/interpreter/livy.md | 13 +- docs/interpreter/r.md | 417 ------- docs/interpreter/spark.md | 79 +- docs/quickstart/install.md | 1 - docs/quickstart/r_with_zeppelin.md | 42 - docs/quickstart/spark_with_zeppelin.md | 4 +- docs/setup/basics/how_to_build.md | 1 - docs/setup/deployment/virtual_machine.md | 8 +- .../interpreter/interpreter_binding_mode.md | 2 +- docs/usage/interpreter/overview.md | 2 +- docs/usage/zeppelin_sdk/session_api.md | 4 - k8s/zeppelin-server.yaml | 2 +- .../zeppelin/livy/LivySparkRInterpreter.java | 48 - .../main/resources/interpreter-setting.json | 22 - .../zeppelin/livy/LivyInterpreterIT.java | 113 +- .../R Tutorial/1. R Basics_2BWJFTXKJ.zpln | 902 -------------- .../R Tutorial/2. Shiny App_2EZ66TM57.zpln | 219 ---- ...3. R Conda Env in Yarn Mode_2GB9HRSH9.zpln | 401 ------- ... Spark Delta Lake Tutorial_2F8VDBMMT.zpln} | 0 .../5. SparkR Basics_2BWJFTXKM.zpln | 1063 ----------------- ...ark Conda Env in Yarn Mode_2GE79Y5FV.zpln} | 0 .../6. SparkR Shiny App_2F1CHQ4TT.zpln | 274 ----- pom.xml | 1 - rlang/pom.xml | 246 ---- .../org/apache/zeppelin/r/IRInterpreter.java | 218 ---- .../org/apache/zeppelin/r/RInterpreter.java | 196 --- .../apache/zeppelin/r/RZeppelinContext.java | 49 - .../apache/zeppelin/r/ShinyInterpreter.java | 154 --- .../org/apache/zeppelin/r/SparkRBackend.java | 85 -- .../org/apache/zeppelin/r/SparkRUtils.java | 51 - .../java/org/apache/zeppelin/r/ZeppelinR.java | 407 ------- .../apache/zeppelin/r/ZeppelinRDisplay.java | 147 --- rlang/src/main/resources/R/zeppelin_isparkr.R | 134 --- rlang/src/main/resources/R/zeppelin_sparkr.R | 170 --- .../main/resources/interpreter-setting.json | 94 -- .../apache/zeppelin/r/IRInterpreterTest.java | 91 -- .../apache/zeppelin/r/RInterpreterTest.java | 147 --- .../zeppelin/r/ShinyInterpreterTest.java | 253 ---- rlang/src/test/resources/invalid_ui.R | 1 - rlang/src/test/resources/log4j.properties | 27 - rlang/src/test/resources/server.R | 23 - rlang/src/test/resources/ui.R | 35 - .../docker/zeppelin-interpreter/Dockerfile | 8 +- ...v_python_3_with_R.yml => env_python_3.yml} | 13 +- scripts/docker/zeppelin/bin/Dockerfile | 10 +- ...v_python_3_with_R.yml => env_python_3.yml} | 11 +- scripts/vagrant/zeppelin-dev/README.md | 17 +- .../vagrant/zeppelin-dev/ansible-roles.yml | 1 - .../zeppelin-dev/roles/r/defaults/main.yml | 24 - .../zeppelin-dev/roles/r/tasks/main.yml | 50 - .../vagrant/zeppelin-dev/show-instructions.sh | 2 +- spark/README.md | 2 +- spark/interpreter/pom.xml | 66 +- .../zeppelin/spark/SparkIRInterpreter.java | 101 -- .../zeppelin/spark/SparkRInterpreter.java | 144 --- .../zeppelin/spark/SparkShinyInterpreter.java | 43 - .../zeppelin/spark/ZeppelinRContext.java | 69 -- .../main/resources/interpreter-setting.json | 74 -- .../spark/SparkIRInterpreterTest.java | 144 --- .../zeppelin/spark/SparkRInterpreterTest.java | 185 --- .../spark/SparkShinyInterpreterTest.java | 127 -- .../src/test/resources/spark_server.R | 23 - .../interpreter/src/test/resources/spark_ui.R | 35 - spark/pom.xml | 5 +- spark/scala-2.12/pom.xml | 2 +- .../zeppelin/spark/SparkZeppelinContext.scala | 3 +- spark/scala-2.13/pom.xml | 2 +- .../zeppelin/spark/SparkZeppelinContext.scala | 3 +- ...thon_3.7_with_R.yml => env_python_3.7.yml} | 13 +- ...thon_3.9_with_R.yml => env_python_3.8.yml} | 13 +- ...thon_3.8_with_R.yml => env_python_3.9.yml} | 13 +- testing/env_python_3.yml | 23 +- .../env_python_3_with_R_and_tensorflow.yml | 39 - ...R.yml => env_python_3_with_tensorflow.yml} | 14 +- .../client/examples/SparkExample.java | 4 - .../integration/SparkIntegrationTest.java | 26 - .../integration/ZSessionIntegrationTest.java | 17 - .../integration/ZeppelinSparkClusterTest.java | 86 +- .../interpreter/util/ProcessLauncher.java | 1 - .../zeppelin/jupyter/JupyterKernelClient.java | 41 - .../apache/zeppelin/jupyter/IRKernelTest.java | 167 --- .../launcher/SparkInterpreterLauncher.java | 29 - .../apache/zeppelin/notebook/Paragraph.java | 2 +- .../SparkInterpreterLauncherTest.java | 17 +- .../apache/zeppelin/test/DownloadUtils.java | 2 +- .../interfaces/message-common.interface.ts | 10 +- 94 files changed, 107 insertions(+), 7842 deletions(-) delete mode 100644 docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png delete mode 100644 docs/interpreter/r.md delete mode 100644 docs/quickstart/r_with_zeppelin.md delete mode 100644 livy/src/main/java/org/apache/zeppelin/livy/LivySparkRInterpreter.java delete mode 100644 notebook/R Tutorial/1. R Basics_2BWJFTXKJ.zpln delete mode 100644 notebook/R Tutorial/2. Shiny App_2EZ66TM57.zpln delete mode 100644 notebook/R Tutorial/3. R Conda Env in Yarn Mode_2GB9HRSH9.zpln rename notebook/Spark Tutorial/{7. Spark Delta Lake Tutorial_2F8VDBMMT.zpln => 5. Spark Delta Lake Tutorial_2F8VDBMMT.zpln} (100%) delete mode 100644 notebook/Spark Tutorial/5. SparkR Basics_2BWJFTXKM.zpln rename notebook/Spark Tutorial/{8. PySpark Conda Env in Yarn Mode_2GE79Y5FV.zpln => 6. PySpark Conda Env in Yarn Mode_2GE79Y5FV.zpln} (100%) delete mode 100644 notebook/Spark Tutorial/6. SparkR Shiny App_2F1CHQ4TT.zpln delete mode 100644 rlang/pom.xml delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/RInterpreter.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/RZeppelinContext.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/SparkRBackend.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/SparkRUtils.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/ZeppelinR.java delete mode 100644 rlang/src/main/java/org/apache/zeppelin/r/ZeppelinRDisplay.java delete mode 100644 rlang/src/main/resources/R/zeppelin_isparkr.R delete mode 100644 rlang/src/main/resources/R/zeppelin_sparkr.R delete mode 100644 rlang/src/main/resources/interpreter-setting.json delete mode 100644 rlang/src/test/java/org/apache/zeppelin/r/IRInterpreterTest.java delete mode 100644 rlang/src/test/java/org/apache/zeppelin/r/RInterpreterTest.java delete mode 100644 rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java delete mode 100644 rlang/src/test/resources/invalid_ui.R delete mode 100644 rlang/src/test/resources/log4j.properties delete mode 100644 rlang/src/test/resources/server.R delete mode 100644 rlang/src/test/resources/ui.R rename scripts/docker/zeppelin-interpreter/{env_python_3_with_R.yml => env_python_3.yml} (69%) rename scripts/docker/zeppelin/bin/{env_python_3_with_R.yml => env_python_3.yml} (68%) delete mode 100644 scripts/vagrant/zeppelin-dev/roles/r/defaults/main.yml delete mode 100644 scripts/vagrant/zeppelin-dev/roles/r/tasks/main.yml delete mode 100644 spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java delete mode 100644 spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java delete mode 100644 spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java delete mode 100644 spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java delete mode 100644 spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkIRInterpreterTest.java delete mode 100644 spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java delete mode 100644 spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java delete mode 100644 spark/interpreter/src/test/resources/spark_server.R delete mode 100644 spark/interpreter/src/test/resources/spark_ui.R rename testing/{env_python_3.7_with_R.yml => env_python_3.7.yml} (68%) rename testing/{env_python_3.9_with_R.yml => env_python_3.8.yml} (69%) rename testing/{env_python_3.8_with_R.yml => env_python_3.9.yml} (69%) delete mode 100644 testing/env_python_3_with_R_and_tensorflow.yml rename testing/{env_python_3_with_R.yml => env_python_3_with_tensorflow.yml} (70%) delete mode 100644 zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IRKernelTest.java diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0a475fa0e09..849706ab659 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -100,17 +100,6 @@ updates: patterns: - "*" - - package-ecosystem: "maven" - directory: "/rlang" - schedule: - interval: "weekly" - open-pull-requests-limit: 0 - groups: - rlang-security-updates: - applies-to: security-updates - patterns: - - "*" - - package-ecosystem: "maven" directory: "/shell" schedule: diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index c7b8f11b9e4..28b8777261d 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -67,25 +67,24 @@ jobs: run: ./mvnw install -Pbuild-distr -DskipTests -pl zeppelin-server,zeppelin-web,spark-submit,spark/scala-2.12,spark/scala-2.13,markdown,angular,shell -am -Pweb-classic -Phelium-dev -Pexamples ${MAVEN_ARGS} - name: install and test plugins run: ./mvnw package -pl zeppelin-plugins -amd ${MAVEN_ARGS} - - name: Setup conda environment with python 3.9 and R + - name: Setup conda environment with python 3.9 uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R - environment-file: testing/env_python_3.9_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_3.9.yml python-version: 3.9 channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter + - name: Show conda environment run: | - R -e "IRkernel::installspec()" conda list conda info - name: run tests # skip spark test because we would run them in other CI run: ./mvnw verify -Pusing-packaged-distr -pl zeppelin-server,zeppelin-web,spark-submit,spark/scala-2.12,spark/scala-2.13,markdown,angular,shell -am -Pweb-classic -Phelium-dev -Pexamples -Dtests.to.exclude=**/org/apache/zeppelin/spark/* -DfailIfNoTests=false - # test interpreter modules except spark, flink, python, rlang, jupyter + # test interpreter modules except spark, flink, python, jupyter interpreter-test-non-core: runs-on: ubuntu-24.04 strategy: @@ -117,11 +116,11 @@ jobs: ${{ runner.os }}-zeppelin- - name: install environment run: ./mvnw install -DskipTests -am -pl ${INTERPRETERS} ${MAVEN_ARGS} - - name: Setup conda environment with python 3.9 and R + - name: Setup conda environment with python 3.9 uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R_and_tensorflow - environment-file: testing/env_python_3_with_R_and_tensorflow.yml + activate-environment: python_3_with_tensorflow + environment-file: testing/env_python_3_with_tensorflow.yml python-version: 3.9 channels: conda-forge,defaults channel-priority: strict @@ -130,8 +129,8 @@ jobs: - name: verify interpreter run: ./mvnw verify -am -pl ${INTERPRETERS} ${MAVEN_ARGS} - # test interpreter modules for jupyter, python, rlang - interpreter-test-jupyter-python-rlang: + # test interpreter modules for jupyter, python + interpreter-test-jupyter-python: runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -159,25 +158,22 @@ jobs: key: ${{ runner.os }}-zeppelin-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-zeppelin- - - name: Setup conda environment with python ${{ matrix.python }} and R + - name: Setup conda environment with python ${{ matrix.python }} uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R - environment-file: testing/env_python_${{ matrix.python }}_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_${{ matrix.python }}.yml python-version: ${{ matrix.python }} channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter - run: | - R -e "IRkernel::installspec()" - name: install environment run: | - ./mvnw install -DskipTests -pl python,rlang,zeppelin-jupyter-interpreter -am ${MAVEN_ARGS} + ./mvnw install -DskipTests -pl python,zeppelin-jupyter-interpreter -am ${MAVEN_ARGS} - name: run tests with ${{ matrix.python }} run: | - ./mvnw test -pl python,rlang,zeppelin-jupyter-interpreter -DfailIfNoTests=false ${MAVEN_ARGS} + ./mvnw test -pl python,zeppelin-jupyter-interpreter -DfailIfNoTests=false ${MAVEN_ARGS} # zeppelin integration test except Spark & Flink zeppelin-integration-test: @@ -214,19 +210,16 @@ jobs: run: | ./mvnw install -DskipTests -Pintegration -pl zeppelin-interpreter-integration,zeppelin-web,spark-submit,spark/scala-2.12,spark/scala-2.13,markdown,flink-cmd,flink/flink-scala-2.12,jdbc,shell -am -Pweb-classic -Pflink-1.20 ${MAVEN_ARGS} ./mvnw package -pl zeppelin-plugins -amd -DskipTests ${MAVEN_ARGS} - - name: Setup conda environment with python 3.9 and R + - name: Setup conda environment with python 3.9 uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R - environment-file: testing/env_python_3_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_3.yml python-version: 3.9 channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter - run: | - R -e "IRkernel::installspec()" - name: run tests run: ./mvnw test -pl zeppelin-interpreter-integration -Pintegration -DfailIfNoTests=false -Dtest=ZeppelinClientIntegrationTest,ZeppelinClientWithAuthIntegrationTest,ZSessionIntegrationTest,ShellIntegrationTest,JdbcIntegrationTest - name: Print zeppelin logs @@ -270,7 +263,7 @@ jobs: run: | ./mvnw install -DskipTests -am -pl flink/flink-scala-2.12,flink-cmd,zeppelin-interpreter-integration -Pflink-${{ matrix.flink-profile }} -Pintegration ${MAVEN_ARGS} ./mvnw clean package -pl zeppelin-plugins -amd -DskipTests ${MAVEN_ARGS} - - name: Setup conda environment with python ${{ matrix.python }} and R + - name: Setup conda environment with python ${{ matrix.python }} uses: conda-incubator/setup-miniconda@v3 with: activate-environment: python_3_with_flink @@ -318,19 +311,16 @@ jobs: run: | ./mvnw install -DskipTests -pl zeppelin-interpreter-integration,zeppelin-web,spark-submit,spark/scala-2.12,spark/scala-2.13,markdown -am -Pweb-classic -Pintegration ${MAVEN_ARGS} ./mvnw clean package -pl zeppelin-plugins -amd -DskipTests ${MAVEN_ARGS} - - name: Setup conda environment with python 3.9 and R + - name: Setup conda environment with python 3.9 uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R - environment-file: testing/env_python_3_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_3.yml python-version: 3.9 channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter - run: | - R -e "IRkernel::installspec()" - name: run tests run: ./mvnw test -pl zeppelin-interpreter-integration -Pintegration -Dtest=SparkSubmitIntegrationTest,ZeppelinSparkClusterTest32,SparkIntegrationTest32,ZeppelinSparkClusterTest33,SparkIntegrationTest33 -DfailIfNoTests=false ${MAVEN_ARGS} @@ -365,19 +355,16 @@ jobs: ${{ runner.os }}-zeppelin- - name: install environment run: ./mvnw install -DskipTests -pl spark-submit,spark/scala-2.12,spark/scala-2.13 -am ${MAVEN_ARGS} - - name: Setup conda environment with python ${{ matrix.python }} and R + - name: Setup conda environment with python ${{ matrix.python }} uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R - environment-file: testing/env_python_${{ matrix.python }}_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_${{ matrix.python }}.yml python-version: ${{ matrix.python }} channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter - run: | - R -e "IRkernel::installspec()" - name: run spark-3.3 tests with scala-2.12 and python-${{ matrix.python }} if: ${{ matrix.java == 11 }} run: | @@ -434,19 +421,16 @@ jobs: ./mvnw install -DskipTests -pl livy -am ${MAVEN_ARGS} ./testing/downloadSpark.sh "3.2.4" "3.2" ./testing/downloadLivy.sh "0.8.0-incubating" "2.12" - - name: Setup conda environment with python 3.9 and R + - name: Setup conda environment with python 3.9 uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_39_with_R - environment-file: testing/env_python_3.9_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_3.9.yml python-version: 3.9 channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter - run: | - R -e "IRkernel::installspec()" - name: run tests run: | export SPARK_HOME=$PWD/spark-3.2.4-bin-hadoop3.2 diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 8f6bc4880ed..68ce1c63a66 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -122,7 +122,7 @@ jobs: channels: conda-forge,defaults channel-priority: strict - name: Install application - run: ./mvnw clean install -DskipTests -am -pl python,rlang,zeppelin-jupyter-interpreter,zeppelin-web-angular ${MAVEN_ARGS} + run: ./mvnw clean install -DskipTests -am -pl python,zeppelin-jupyter-interpreter,zeppelin-web-angular ${MAVEN_ARGS} - name: Setup Zeppelin Server (Shiro.ini) run: | export ZEPPELIN_CONF_DIR=./conf @@ -184,19 +184,16 @@ jobs: key: ${{ runner.os }}-zeppelin-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-zeppelin- - - name: Setup conda environment with python 3.9 and R + - name: Setup conda environment with python 3.9 uses: conda-incubator/setup-miniconda@v3 with: - activate-environment: python_3_with_R - environment-file: testing/env_python_3_with_R.yml + activate-environment: python_3 + environment-file: testing/env_python_3.yml python-version: 3.9 channels: conda-forge,defaults channel-priority: strict auto-activate: false use-mamba: true - - name: Make IRkernel available to Jupyter - run: | - R -e "IRkernel::installspec()" - name: Install Environment run: | ./mvnw clean install -DskipTests -am -pl zeppelin-integration -Pweb-classic -Pintegration -Pspark-scala-2.12 -Pspark-3.5 -Pweb-dist ${MAVEN_ARGS} diff --git a/AGENTS.md b/AGENTS.md index a9a559817e8..6cced4fb2d4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -80,7 +80,7 @@ zeppelin-interpreter → zeppelin-interpreter-shaded → zeppelin-server All interpreter modules build after `zeppelin-interpreter-shaded`. A second shading chain exists for Jupyter: ``` -zeppelin-jupyter-interpreter → zeppelin-jupyter-interpreter-shaded → python, rlang +zeppelin-jupyter-interpreter → zeppelin-jupyter-interpreter-shaded → python ``` ## Module Architecture @@ -163,7 +163,6 @@ Each interpreter is an independent Maven module inheriting from `zeppelin-interp | `bigquery/` | Google BigQuery | | `cassandra/` | Apache Cassandra CQL | | `hbase/` | Apache HBase | -| `rlang/` | R language | | `livy/` | Apache Livy (remote Spark) | | `sparql/` | SPARQL queries | | `influxdb/` | InfluxDB | diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html index a82c1c36824..cc2d63ebb5f 100644 --- a/docs/_includes/themes/zeppelin/_navigation.html +++ b/docs/_includes/themes/zeppelin/_navigation.html @@ -37,7 +37,6 @@
  • Flink with Zeppelin
  • SQL with Zeppelin
  • Python with Zeppelin
  • -
  • R with Zeppelin
  • @@ -137,7 +136,6 @@
  • Flink
  • JDBC
  • Python
  • -
  • R
  • BigQuery
  • Cassandra
  • diff --git a/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png b/docs/assets/themes/zeppelin/img/docs-img/ir_kernel.png deleted file mode 100644 index a1bf5ec188cfa9da0b8794c03b3ec75643df6f0c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206755 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� 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 BL6!gj diff --git a/docs/index.md b/docs/index.md index 7f9f8ada490..0e471f4faf0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -153,7 +153,6 @@ limitations under the License. * [Neo4j](./interpreter/neo4j.html) * [Postgresql, HAWQ](./interpreter/postgresql.html) * [Python](./interpreter/python.html) - * [R](./interpreter/r.html) * [Shell](./interpreter/shell.html) * [Spark](./interpreter/spark.html) * [Sparql](./interpreter/sparql.html) diff --git a/docs/interpreter/jupyter.md b/docs/interpreter/jupyter.md index 89586e6bf00..f4e0343c809 100644 --- a/docs/interpreter/jupyter.md +++ b/docs/interpreter/jupyter.md @@ -64,28 +64,6 @@ plt.plot([1, 2, 3]) -## Jupyter R kernel - -In order to use [IRKernel](https://github.com/IRkernel/IRkernel), you need to first install `IRkernel` package in R. - -```r -install.packages('IRkernel') -IRkernel::installspec() # to register the kernel in the current R installation -``` - -Then you can run r code in Jupyter interpreter like following. - -```r -%jupyter(kernel=ir) - -library(ggplot2) -ggplot(mpg, aes(x = displ, y = hwy)) + - geom_point() -``` - - - - ## Jupyter Julia kernel In order to use Julia in Zeppelin, you first need to install [IJulia](https://github.com/JuliaLang/IJulia.jl) first diff --git a/docs/interpreter/livy.md b/docs/interpreter/livy.md index 8b0024fab64..d6ba00864db 100644 --- a/docs/interpreter/livy.md +++ b/docs/interpreter/livy.md @@ -220,17 +220,6 @@ sc.version print "1" ``` -**sparkR** - -```r -%livy.sparkr -hello <- function( name ) { - sprintf( "Hello, %s", name ); -} - -hello("livy") -``` - ## Impersonation When Zeppelin server is running with authentication enabled, then this interpreter utilizes Livy’s user impersonation feature @@ -249,7 +238,7 @@ And creating dynamic format programmatically is not feasible in livy interpreter ## Shared SparkContext Starting from livy 0.5 which is supported by Zeppelin 0.8.0, SparkContext is shared between scala, python, r and sql. -That means you can query the table via `%livy.sql` when this table is registered in `%livy.spark`, `%livy.pyspark`, `$livy.sparkr`. +That means you can query the table via `%livy.sql` when this table is registered in `%livy.spark`, `%livy.pyspark`. ## FAQ diff --git a/docs/interpreter/r.md b/docs/interpreter/r.md deleted file mode 100644 index 221f34e14e1..00000000000 --- a/docs/interpreter/r.md +++ /dev/null @@ -1,417 +0,0 @@ ---- -layout: page -title: "R Interpreter for Apache Zeppelin" -description: "R is a free software environment for statistical computing and graphics." -group: interpreter ---- - -{% include JB/setup %} - -# R Interpreter for Apache Zeppelin - -
    - -## Overview - -[R](https://www.r-project.org) is a free software environment for statistical computing and graphics. - -To run R code and visualize plots in Apache Zeppelin, you will need R on your zeppelin server node (or your dev laptop). - -+ For Centos: `yum install R R-devel libcurl-devel openssl-devel` -+ For Ubuntu: `apt-get install r-base` - -Validate your installation with a simple R command: - -``` -R -e "print(1+1)" -``` - -To enjoy plots, install additional libraries with: - -+ devtools with - - ```bash - R -e "install.packages('devtools', repos = 'http://cran.us.r-project.org')" - ``` - -+ knitr with - - ```bash - R -e "install.packages('knitr', repos = 'http://cran.us.r-project.org')" - ``` - -+ ggplot2 with - - ```bash - R -e "install.packages('ggplot2', repos = 'http://cran.us.r-project.org')" - ``` - -+ Other visualization libraries: - - ```bash - R -e "install.packages(c('devtools','mplot', 'googleVis'), repos = 'http://cran.us.r-project.org'); - require(devtools); install_github('ramnathv/rCharts')" - ``` - -We recommend you to also install the following optional R libraries for happy data analytics: - -+ glmnet -+ pROC -+ data.table -+ caret -+ sqldf -+ wordcloud - -## Supported Interpreters - -Zeppelin supports R language in 3 interpreters - - - - - - - - - - - - - - - - - - - - - - -
    NameClassDescription
    %r.rRInterpreterVanilla r interpreter, with least dependencies, only R environment and knitr are required. - It is always recommended to use the fully qualified interpreter name %r.r, because %r is ambiguous, - it could mean %spark.r when current note's default interpreter is %spark and %r.r when the default interpreter is %r
    %r.irIRInterpreterProvide more fancy R runtime via [IRKernel](https://github.com/IRkernel/IRkernel), almost the same experience like using R in Jupyter. It requires more things, but is the recommended interpreter for using R in Zeppelin.
    %r.shinyShinyInterpreterRun Shiny app in Zeppelin
    - -If you want to use R with Spark, it is almost the same via `%spark.r`, `%spark.ir` & `%spark.shiny` . You can refer Spark interpreter docs for more details. - -## Configuration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    PropertyDefaultDescription
    zeppelin.R.cmdRPath of the installed R binary. You should set this property explicitly if R is not in your $PATH(example: /usr/bin/R). -
    zeppelin.R.knitrtrueWhether to use knitr or not. It is recommended to install [knitr](https://yihui.org/knitr/)
    zeppelin.R.image.width100%Image width of R plotting
    zeppelin.R.shiny.iframe_width100%IFrame width of Shiny App
    zeppelin.R.shiny.iframe_height500pxIFrame height of Shiny App
    zeppelin.R.shiny.portRange:Shiny app would launch a web app at some port, this property is to specify the portRange via format 'start':'end', e.g. '5000:5001'. By default it is ':' which means any port.
    zeppelin.R.maxResult1000Max number of dataframe rows to display when using z.show
    - -## Play R in Zeppelin docker - -For beginner, we would suggest you to play R in Zeppelin docker first. In the Zeppelin docker image, we have already installed R and lots of useful R libraries including IRKernel's prerequisites, so `%r.ir` is available. - -Without any extra configuration, you can run most of tutorial notes under folder `R Tutorial` directly. - -``` -docker run -u $(id -u) -p 8080:8080 -p:6789:6789 --rm --name zeppelin apache/zeppelin:0.10.0 -``` - -After running the above command, you can open `http://localhost:8080` to play R in Zeppelin. -The port `6789` exposed in the above command is for R shiny app. You need to make the following 2 interpreter properties to enable shiny app accessible as iframe in Zeppelin docker container. - -* `zeppelin.R.shiny.portRange` to be `6789:6789` -* Set `ZEPPELIN_LOCAL_IP` to be `0.0.0.0` - - - - - -## Interpreter binding mode - -The default [interpreter binding mode](../usage/interpreter/interpreter_binding_mode.html) is `globally shared`. That means all notes share the same R interpreter. -So we would recommend you to ues `isolated per note` which means each note has own R interpreter without affecting each other. But it may run out of your machine resource if too many R -interpreters are created. You can [run R in yarn mode](../interpreter/r.html#run-r-in-yarn-cluster) to avoid this problem. - -## How to use R Interpreter - -There are two different implementations of R interpreters: `%r.r` and `%r.ir`. - -* Vanilla R Interpreter(`%r.r`) behaves like an ordinary REPL and use SparkR to communicate between R process and JVM process. It requires `knitr` to be installed. -* IRKernel R Interpreter(`%r.ir`) behaves like using IRKernel in Jupyter notebook. It is based on [jupyter interpreter](jupyter.html). Besides jupyter interpreter's prerequisites, [IRkernel](https://github.com/IRkernel/IRkernel) needs to be installed as well. - -Take a look at the tutorial note `R Tutorial/1. R Basics` for how to write R code in Zeppelin. - -### R basic expressions - -R basic expressions are supported in both `%r.r` and `%r.ir`. - - - -### R base plotting - -R base plotting is supported in both `%r.r` and `%r.ir`. - - - -### Other plotting - -Besides R base plotting, you can use other visualization libraries in both `%r.r` and `%r.ir`, e.g. `ggplot` and `googleVis` - - - - - -### z.show - -`z.show()` is only available in `%r.ir` to visualize R dataframe, e.g. - - - -By default, `z.show` would only display 1000 rows, you can specify the maxRows via `z.show(df, maxRows=2000)` - -## Make Shiny App in Zeppelin - -[Shiny](https://shiny.rstudio.com/tutorial/) is an R package that makes it easy to build interactive web applications (apps) straight from R. -`%r.shiny` is used for developing R shiny app in Zeppelin notebook. It only works when IRKernel Interpreter(`%r.ir`) is enabled. -For developing one Shiny App in Zeppelin, you need to write at least 3 paragraphs (server type paragraph, ui type paragraph and run type paragraph) - -* Server type R shiny paragraph - -```r - -%r.shiny(type=server) - -# Define server logic to summarize and view selected dataset ---- -server <- function(input, output) { - - # Return the requested dataset ---- - datasetInput <- reactive({ - switch(input$dataset, - "rock" = rock, - "pressure" = pressure, - "cars" = cars) - }) - - # Generate a summary of the dataset ---- - output$summary <- renderPrint({ - dataset <- datasetInput() - summary(dataset) - }) - - # Show the first "n" observations ---- - output$view <- renderTable({ - head(datasetInput(), n = input$obs) - }) -} -``` - -* UI type R shiny paragraph - -```r -%r.shiny(type=ui) - -# Define UI for dataset viewer app ---- -ui <- fluidPage( - - # App title ---- - titlePanel("Shiny Text"), - - # Sidebar layout with a input and output definitions ---- - sidebarLayout( - - # Sidebar panel for inputs ---- - sidebarPanel( - - # Input: Selector for choosing dataset ---- - selectInput(inputId = "dataset", - label = "Choose a dataset:", - choices = c("rock", "pressure", "cars")), - - # Input: Numeric entry for number of obs to view ---- - numericInput(inputId = "obs", - label = "Number of observations to view:", - value = 10) - ), - - # Main panel for displaying outputs ---- - mainPanel( - - # Output: Verbatim text for data summary ---- - verbatimTextOutput("summary"), - - # Output: HTML table with requested number of observations ---- - tableOutput("view") - - ) - ) -) -``` - -* Run type R shiny paragraph - -```r - -%r.shiny(type=run) - -``` - -After executing the run type R shiny paragraph, the shiny app will be launched and embedded as iframe in paragraph. -Take a look at the tutorial note `R Tutorial/2. Shiny App` for how to develop R shiny app. - - - -### Run multiple shiny apps - -If you want to run multiple shiny apps, you can specify `app` in paragraph local property to differentiate different shiny apps. - -e.g. - -```r -%r.shiny(type=ui, app=app_1) -``` - -```r -%r.shiny(type=server, app=app_1) -``` - -```r -%r.shiny(type=run, app=app_1) -``` - -## Run R in yarn cluster - -Zeppelin support to [run interpreter in yarn cluster](../quickstart/yarn.html). But there's one critical problem to run R in yarn cluster: how to manage the R environment in yarn container. -Because yarn cluster is a distributed cluster which is composed of many nodes, and your R interpreter can start in any node. -It is not practical to manage R environment in each node. - -So in order to run R in yarn cluster, we would suggest you to use conda to manage your R environment, and Zeppelin can ship your -R conda environment to yarn container, so that each R interpreter can have its own R environment without affecting each other. - -To be noticed, you can only run IRKernel interpreter(`%r.ir`) in yarn cluster. So make sure you include at least the following prerequisites in the below conda env: - -* python -* jupyter -* grpcio -* protobuf -* r-base -* r-essentials -* r-irkernel - -`python`, `jupyter`, `grpcio` and `protobuf` are required for [jupyter interpreter](../interpreter/jupyter.html), because IRKernel interpreter is based on [jupyter interpreter](../interpreter/jupyter.html). Others are for R runtime. - -Following are instructions of how to run R in yarn cluster. You can find all the code in the tutorial note `R Tutorial/3. R Conda Env in Yarn Mode`. - - -### Step 1 - -We would suggest you to use conda pack to create archive of conda environment. - -Here's one example of yaml file which is used to generate a conda environment with R and some useful R libraries. - -* Create a yaml file for conda environment, write the following content into file `r_env.yml` - -```text -name: r_env -channels: - - conda-forge - - defaults -dependencies: - - python=3.9 - - jupyter - - grpcio - - protobuf - - r-base=3 - - r-essentials - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis -``` - -* Create conda environment via this yaml file using either `conda` or `mamba` - -```bash - -conda env create -f r_env.yml -``` - -```bash - -mamba env create -f r_env.yml -``` - - -* Pack the conda environment using `conda` - -```bash - -conda pack -n r_env -``` - -### Step 2 - -Specify the following properties to enable yarn mode for R interpreter via [inline configuration](../usage/interpreter/overview.html#inline-generic-configuration) - -``` -%r.conf - -zeppelin.interpreter.launcher yarn -zeppelin.yarn.dist.archives hdfs:///tmp/r_env.tar.gz#environment -zeppelin.interpreter.conda.env.name environment -``` - -`zeppelin.yarn.dist.archives` is the R conda environment tar file which is created in step 1. This tar will be shipped to yarn container and untar in the working directory of yarn container. -`hdfs:///tmp/r_env.tar.gz` is the R conda archive file you created in step 2. `environment` in `hdfs:///tmp/r_env.tar.gz#environment` is the folder name after untar. -This folder name should be the same as `zeppelin.interpreter.conda.env.name`. - -### Step 3 - -Now you can use run R interpreter in yarn container and also use any R libraries you specify in step 1. diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md index 680ca054b3b..2b31a055cc5 100644 --- a/docs/interpreter/spark.md +++ b/docs/interpreter/spark.md @@ -49,21 +49,6 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist IPySparkInterpreter Provides a IPython environment - - %spark.r - SparkRInterpreter - Provides an vanilla R environment with SparkR support - - - %spark.ir - SparkIRInterpreter - Provides an R environment with SparkR support based on Jupyter IRKernel - - - %spark.shiny - SparkShinyInterpreter - Used to create R shiny app with SparkR support - %spark.sql SparkSQLInterpreter @@ -101,7 +86,7 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist Inline Visualization - You can visualize Spark Dataset/DataFrame vis Python/R's plotting libraries, and even you can make SparkR Shiny app in Zeppelin + You can visualize Spark Dataset/DataFrame vis Python's plotting libraries. @@ -119,8 +104,8 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist For beginner, we would suggest you to play Spark in Zeppelin docker. In the Zeppelin docker image, we have already installed -miniconda and lots of [useful python and R libraries](https://github.com/apache/zeppelin/blob/branch-0.10/scripts/docker/zeppelin/bin/env_python_3_with_R.yml) -including IPython and IRkernel prerequisites, so `%spark.pyspark` would use IPython and `%spark.ir` is enabled. +miniconda and lots of [useful python libraries](https://github.com/apache/zeppelin/blob/branch-0.10/scripts/docker/zeppelin/bin/env_python_3_with_R.yml) +including IPython prerequisites, so `%spark.pyspark` would use IPython. Without any extra configuration, you can run most of tutorial notes under folder `Spark Tutorial` directly. First you need to download Spark, because there's no Spark binary distribution shipped with Zeppelin. @@ -219,11 +204,6 @@ You can also set other Spark properties which are not listed in the table. For a false Whether use IPython when the ipython prerequisites are met in `%spark.pyspark` - - zeppelin.R.cmd - R - R binary executable path. - zeppelin.spark.concurrentSQL false @@ -388,7 +368,7 @@ You can also choose `scoped` mode. For `scoped` per note mode, Zeppelin creates SparkContext, SparkSession and ZeppelinContext are automatically created and exposed as variable names `sc`, `spark` and `z` respectively, in Scala, Python and R environments. -> Note that Scala/Python/R environment shares the same SparkContext, SQLContext, SparkSession and ZeppelinContext instance. +> Note that Scala/Python environment shares the same SparkContext, SQLContext, SparkSession and ZeppelinContext instance. ## Yarn Mode @@ -419,55 +399,6 @@ By default, Zeppelin would use IPython in `%spark.pyspark` when IPython is avail You can use `IPySpark` explicitly via `%spark.ipyspark`. IPySpark interpreter is almost the same as IPython interpreter except Spark interpreter inject SparkContext, SQLContext, SparkSession via variables `sc`, `sqlContext`, `spark`. For the IPython features, you can refer doc [Python Interpreter](python.html#ipython-interpreter-pythonipython-recommended) -## SparkR - -Zeppelin support SparkR via `%spark.r`, `%spark.ir` and `%spark.shiny`. Here's configuration for SparkR Interpreter. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Spark PropertyDefaultDescription
    zeppelin.R.cmdRR binary executable path.
    zeppelin.R.knitrtrueWhether use knitr or not. (It is recommended to install knitr and use it in Zeppelin)
    zeppelin.R.image.width100%R plotting image width.
    zeppelin.R.render.optionsout.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2R plotting options.
    zeppelin.R.shiny.iframe_width100%IFrame width of Shiny App
    zeppelin.R.shiny.iframe_height500pxIFrame height of Shiny App
    zeppelin.R.shiny.portRange:Shiny app would launch a web app at some port, this property is to specify the portRange via format ':', e.g. '5000:5001'. By default it is ':' which means any port
    - -Refer [R doc](r.html) for how to use R in Zeppelin. - ## SparkSql Spark sql interpreter share the same SparkContext/SparkSession with other Spark interpreters. That means any table registered in scala, python or r code can be accessed by Spark sql. @@ -502,7 +433,7 @@ But sql statements in different paragraphs can run concurrently by the following sql statement ``` -This pool feature is also available for all versions of scala Spark, PySpark. For SparkR, it is only available starting from 2.3.0. +This pool feature is also available for all versions of scala Spark, PySpark. ## Dependency Management diff --git a/docs/quickstart/install.md b/docs/quickstart/install.md index 0cbd3a66e84..0dbd4870e4d 100644 --- a/docs/quickstart/install.md +++ b/docs/quickstart/install.md @@ -170,7 +170,6 @@ Congratulations, you have successfully installed Apache Zeppelin! Here are a few * [Flink support in Zeppelin](./flink_with_zeppelin.html), to know more about deep integration with [Apache Flink](http://flink.apache.org/). * [SQL support in Zeppelin](./sql_with_zeppelin.html) for SQL support * [Python support in Zeppelin](./python_with_zeppelin.html), for Matplotlib, Pandas, Conda/Docker integration. - * [R support in Zeppelin](./r_with_zeppelin.html) * [All Available Interpreters](../#available-interpreters) #### Multi-user support ... diff --git a/docs/quickstart/r_with_zeppelin.md b/docs/quickstart/r_with_zeppelin.md deleted file mode 100644 index f9b9feb6596..00000000000 --- a/docs/quickstart/r_with_zeppelin.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -layout: page -title: "R with Zeppelin" -description: "" -group: quickstart ---- - -{% include JB/setup %} - -# R support in Zeppelin - -
    - -
    - -The following guides explain how to use Apache Zeppelin that enables you to write in R: - -- Supports [vanilla R](../interpreter/r.html#how-to-use-r-interpreter) and [IRkernel](../interpreter/r.html#how-to-use-r-interpreter) -- Visualize R dataframe via [ZeppelinContext](../interpreter/r.html#zshow) -- [Run R interpreter in yarn cluster](../interpreter/r.html#run-r-in-yarn-cluster) with customized conda R environment. -- [Make R Shiny App] (../interpreter/r.html#make-shiny-app-in-zeppelin) - -
    - -For the further information about R support in Zeppelin, please check - -- [R Interpreter](../interpreter/r.html) - - - diff --git a/docs/quickstart/spark_with_zeppelin.md b/docs/quickstart/spark_with_zeppelin.md index 7afa608e741..eeebea697f6 100644 --- a/docs/quickstart/spark_with_zeppelin.md +++ b/docs/quickstart/spark_with_zeppelin.md @@ -28,13 +28,13 @@ limitations under the License. For a brief overview of Apache Spark fundamentals with Apache Zeppelin, see the following guide: - **built-in** Apache Spark integration. -- With [Spark Scala](https://spark.apache.org/docs/latest/quick-start.html) [SparkSQL](http://spark.apache.org/sql/), [PySpark](https://spark.apache.org/docs/latest/api/python/), [SparkR](https://spark.apache.org/docs/latest/sparkr.html) +- With [Spark Scala](https://spark.apache.org/docs/latest/quick-start.html) [SparkSQL](http://spark.apache.org/sql/), [PySpark](https://spark.apache.org/docs/latest/api/python/). - Inject [SparkContext](https://spark.apache.org/docs/latest/api/java/org/apache/spark/SparkContext.html), [SQLContext](https://spark.apache.org/docs/latest/sql-programming-guide.html) and [SparkSession](https://spark.apache.org/docs/latest/sql-programming-guide.html) automatically - Canceling job and displaying its progress - Supports different modes: local, standalone, yarn(client & cluster), k8s - Dependency management - Supports [different context per user / note](../usage/interpreter/interpreter_binding_mode.html) -- Sharing variables among PySpark, SparkR and Spark through [ZeppelinContext](../interpreter/spark.html#zeppelincontext) +- Sharing variables among PySpark and Spark through [ZeppelinContext](../interpreter/spark.html#zeppelincontext) - [Livy Interpreter](../interpreter/livy.html)
    diff --git a/docs/setup/basics/how_to_build.md b/docs/setup/basics/how_to_build.md index acb37388d4c..0175fa96e09 100644 --- a/docs/setup/basics/how_to_build.md +++ b/docs/setup/basics/how_to_build.md @@ -159,7 +159,6 @@ Spark package ```bash spark.archive # default spark-${spark.version} spark.src.download.url # default http://d3kbcqa49mib13.cloudfront.net/${spark.archive}.tgz -spark.bin.download.url # default http://d3kbcqa49mib13.cloudfront.net/${spark.archive}-bin-without-hadoop.tgz ``` Py4J package diff --git a/docs/setup/deployment/virtual_machine.md b/docs/setup/deployment/virtual_machine.md index 4eb3ae92ce0..915ce89c798 100644 --- a/docs/setup/deployment/virtual_machine.md +++ b/docs/setup/deployment/virtual_machine.md @@ -29,7 +29,6 @@ Apache Zeppelin distribution includes a script directory `scripts/vagrant/zeppel This script creates a virtual machine that launches a repeatable, known set of core dependencies required for developing Zeppelin. It can also be used to run an existing Zeppelin build if you don't plan to build from source. For PySpark users, this script includes several helpful [Python Libraries](#python-extras). -For SparkR users, this script includes several helpful [R Libraries](#r-extras). ### Prerequisites @@ -103,7 +102,7 @@ The virtual machine consists of: ## How to build & run Zeppelin -This assumes you've already cloned the project either on the host machine in the zeppelin-dev directory (to be shared with the guest machine) or cloned directly into a directory while running inside the guest machine. The following build steps will also include Python and R support via PySpark and SparkR: +This assumes you've already cloned the project either on the host machine in the zeppelin-dev directory (to be shared with the guest machine) or cloned directly into a directory while running inside the guest machine. The following build steps will also include Python support via PySpark: ```bash cd /zeppelin @@ -182,8 +181,3 @@ plt.title('How fast do you want to go today?') show(plt) ``` - -### R Extras - -With zeppelin running, an R Tutorial notebook will be available. The R packages required to run the examples and graphs in this tutorial notebook were installed by this virtual machine. -The installed R Packages include: `knitr`, `devtools`, `repr`, `rCharts`, `ggplot2`, `googleVis`, `mplot`, `htmltools`, `base64enc`, `data.table`. diff --git a/docs/usage/interpreter/interpreter_binding_mode.md b/docs/usage/interpreter/interpreter_binding_mode.md index 44a7fcad3da..f54b4ea5ccf 100644 --- a/docs/usage/interpreter/interpreter_binding_mode.md +++ b/docs/usage/interpreter/interpreter_binding_mode.md @@ -88,7 +88,7 @@ In the case of the **per user** scope (available in a multi-user environment), Z Each Interpreter implementation may have different characteristics depending on the back end system that they integrate. And 3 interpreter modes can be used differently. Let’s take a look how Spark Interpreter implementation uses these 3 interpreter modes with **per note** scope, as an example. -Spark Interpreter implementation includes 4 different interpreters in the group: Spark, SparkSQL, Pyspark and SparkR. +Spark Interpreter implementation includes 3 different interpreters in the group: Spark, SparkSQL and PySpark. SparkInterpreter instance embeds Scala REPL for interactive Spark API execution.
    diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index 2ba9d8edb39..271103c4144 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -87,7 +87,7 @@ If the context parameter is null, then it is replaced by an empty string. The fo ## What are Interpreter Groups ? Every interpreter belongs to an **Interpreter Group**. Interpreter Groups are units of interpreters that run in one single JVM process and can be started/stopped together. -By default, every interpreter belongs to a separate group, but the group might contain more interpreters. For example, the Spark interpreter group includes Scala Spark, PySpark, IPySpark, SparkR and Spark SQL. +By default, every interpreter belongs to a separate group, but the group might contain more interpreters. For example, the Spark interpreter group includes Scala Spark, PySpark, IPySpark and Spark SQL. Technically, Zeppelin interpreters from the same group run within the same JVM. For more information about this, please consult [the documentation on writing interpreters](../development/writing_zeppelin_interpreter.html). diff --git a/docs/usage/zeppelin_sdk/session_api.md b/docs/usage/zeppelin_sdk/session_api.md index a8f809c3180..c32d3af412b 100644 --- a/docs/usage/zeppelin_sdk/session_api.md +++ b/docs/usage/zeppelin_sdk/session_api.md @@ -89,10 +89,6 @@ try { System.out.println("Matplotlib result, type: " + result.getResults().get(0).getType() + ", data: " + result.getResults().get(0).getData()); - // sparkr - result = session.execute("r", "df <- as.DataFrame(faithful)\nhead(df)"); - System.out.println("Sparkr dataframe: " + result.getResults().get(0).getData()); - // spark sql result = session.execute("sql", "select * from df"); System.out.println("Spark Sql dataframe: " + result.getResults().get(0).getData()); diff --git a/k8s/zeppelin-server.yaml b/k8s/zeppelin-server.yaml index 27cc087786e..65db35d1c99 100644 --- a/k8s/zeppelin-server.yaml +++ b/k8s/zeppelin-server.yaml @@ -28,7 +28,7 @@ data: # Default value is 'local.zeppelin-project.org' while it points 127.0.0.1 and `kubectl port-forward zeppelin-server` will give localhost to connects. # If you have your ingress controller configured to connect to `zeppelin-server` service and have a domain name for it (with wildcard subdomain point the same address), you can replace serviceDomain field with your own domain. SERVICE_DOMAIN: local.zeppelin-project.org:8080 - ZEPPELIN_K8S_SPARK_CONTAINER_IMAGE: spark:3.5.3 + ZEPPELIN_K8S_SPARK_CONTAINER_IMAGE: spark:3.5.8 ZEPPELIN_K8S_CONTAINER_IMAGE: zeppelin-interpreter:0.13.0-SNAPSHOT ZEPPELIN_HOME: /opt/zeppelin ZEPPELIN_SERVER_RPC_PORTRANGE: 12320:12320 diff --git a/livy/src/main/java/org/apache/zeppelin/livy/LivySparkRInterpreter.java b/livy/src/main/java/org/apache/zeppelin/livy/LivySparkRInterpreter.java deleted file mode 100644 index c2704371c64..00000000000 --- a/livy/src/main/java/org/apache/zeppelin/livy/LivySparkRInterpreter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.livy; - -import java.util.Properties; - - -/** - * Livy PySpark interpreter for Zeppelin. - */ -public class LivySparkRInterpreter extends BaseLivyInterpreter { - - public LivySparkRInterpreter(Properties property) { - super(property); - } - - @Override - public String getSessionKind() { - return "sparkr"; - } - - @Override - protected String extractAppId() throws LivyException { - //TODO(zjffdu) depends on SparkR - return null; - } - - @Override - protected String extractWebUIAddress() throws LivyException { - //TODO(zjffdu) depends on SparkR - return null; - } -} diff --git a/livy/src/main/resources/interpreter-setting.json b/livy/src/main/resources/interpreter-setting.json index f1278df465a..b56a3ea4fbf 100644 --- a/livy/src/main/resources/interpreter-setting.json +++ b/livy/src/main/resources/interpreter-setting.json @@ -229,28 +229,6 @@ "completionSupport": true } }, - { - "group": "livy", - "name": "sparkr", - "className": "org.apache.zeppelin.livy.LivySparkRInterpreter", - "properties": { - }, - "option": { - "remote": true, - "port": -1, - "perNote": "shared", - "perUser": "scoped", - "isExistingProcess": false, - "setPermission": false, - "users": [] - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - } - }, { "group": "livy", "name": "shared", diff --git a/livy/src/test/java/org/apache/zeppelin/livy/LivyInterpreterIT.java b/livy/src/test/java/org/apache/zeppelin/livy/LivyInterpreterIT.java index 8b9aa6a4e9b..2b20c2d6969 100644 --- a/livy/src/test/java/org/apache/zeppelin/livy/LivyInterpreterIT.java +++ b/livy/src/test/java/org/apache/zeppelin/livy/LivyInterpreterIT.java @@ -538,83 +538,6 @@ void testSparkInterpreterStringWithoutTruncation() } } - @Test - void testSparkRInterpreter() throws InterpreterException { - if (!checkPreCondition()) { - return; - } - - final LivySparkRInterpreter sparkRInterpreter = new LivySparkRInterpreter(properties); - sparkRInterpreter.setInterpreterGroup(mock(InterpreterGroup.class)); - - try { - sparkRInterpreter.getLivyVersion(); - } catch (APINotFoundException e) { - // don't run sparkR test for livy 0.2 as there's some issues for livy 0.2 - return; - } - AuthenticationInfo authInfo = new AuthenticationInfo("user1"); - MyInterpreterOutputListener outputListener = new MyInterpreterOutputListener(); - InterpreterOutput output = new InterpreterOutput(outputListener); - final InterpreterContext context = InterpreterContext.builder() - .setNoteId("noteId") - .setParagraphId("paragraphId") - .setAuthenticationInfo(authInfo) - .setInterpreterOut(output) - .build(); - sparkRInterpreter.open(); - - try { - // only test it in livy newer than 0.2.0 - boolean isSpark2 = isSpark2(sparkRInterpreter, context); - InterpreterResult result = null; - // test DataFrame api - if (isSpark2) { - result = sparkRInterpreter.interpret("df <- as.DataFrame(faithful)\nhead(df)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code(), result.toString()); - assertEquals(1, result.message().size()); - assertTrue(result.message().get(0).getData().contains("eruptions waiting")); - - // cancel - Thread cancelThread = new Thread() { - @Override - public void run() { - // invoke cancel after 1 millisecond to wait job starting - try { - Thread.sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - } - sparkRInterpreter.cancel(context); - } - }; - cancelThread.start(); - result = sparkRInterpreter.interpret("df <- as.DataFrame(faithful)\n" + - "df1 <- dapplyCollect(df, function(x) " + - "{ Sys.sleep(10); x <- cbind(x, x$waiting * 60) })", context); - assertEquals(InterpreterResult.Code.ERROR, result.code()); - String message = result.message().get(0).getData(); - // 2 possibilities, sometimes livy doesn't return the real cancel exception - assertTrue(message.contains("cancelled part of cancelled job group") || - message.contains("Job is cancelled")); - } else { - result = sparkRInterpreter.interpret("df <- createDataFrame(sqlContext, faithful)" + - "\nhead(df)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code(), result.toString()); - assertEquals(1, result.message().size()); - assertTrue(result.message().get(0).getData().contains("eruptions waiting")); - } - - // error - result = sparkRInterpreter.interpret("cat(a)", context); - assertEquals(InterpreterResult.Code.ERROR, result.code()); - assertEquals(InterpreterResult.Type.TEXT, result.message().get(0).getType()); - assertTrue(result.message().get(0).getData().contains("object 'a' not found")); - } finally { - sparkRInterpreter.close(); - } - } - @Test void testLivyParams() throws InterpreterException { if (!checkPreCondition()) { @@ -718,11 +641,6 @@ void testSharedInterpreter() throws InterpreterException { interpreterGroup.get("session_1").add(pysparkInterpreter); pysparkInterpreter.setInterpreterGroup(interpreterGroup); - LazyOpenInterpreter sparkRInterpreter = new LazyOpenInterpreter( - new LivySparkRInterpreter(properties)); - interpreterGroup.get("session_1").add(sparkRInterpreter); - sparkRInterpreter.setInterpreterGroup(interpreterGroup); - LazyOpenInterpreter sharedInterpreter = new LazyOpenInterpreter( new LivySharedInterpreter(properties)); interpreterGroup.get("session_1").add(sharedInterpreter); @@ -731,7 +649,6 @@ void testSharedInterpreter() throws InterpreterException { sparkInterpreter.open(); sqlInterpreter.open(); pysparkInterpreter.open(); - sparkRInterpreter.open(); try { AuthenticationInfo authInfo = new AuthenticationInfo("user1"); @@ -772,13 +689,6 @@ void testSharedInterpreter() throws InterpreterException { "+-----+-----+\n" + "|hello| 20|\n" + "+-----+-----+")); - - // access table from sparkr - result = sparkRInterpreter.interpret("head(sql(sqlContext, \"select * from df\"))", - context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code(), result.toString()); - assertEquals(1, result.message().size()); - assertTrue(result.message().get(0).getData().contains("col_1 col_2\n1 hello 20")); } else { result = sparkInterpreter.interpret( "val df=spark.createDataFrame(Seq((\"hello\",20))).toDF(\"col_1\", \"col_2\")\n" @@ -799,12 +709,6 @@ void testSharedInterpreter() throws InterpreterException { "+-----+-----+\n" + "|hello| 20|\n" + "+-----+-----+")); - - // access table from sparkr - result = sparkRInterpreter.interpret("head(sql(\"select * from df\"))", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code(), result.toString()); - assertEquals(1, result.message().size()); - assertTrue(result.message().get(0).getData().contains("col_1 col_2\n1 hello 20")); } // test plotting of python @@ -819,13 +723,6 @@ void testSharedInterpreter() throws InterpreterException { assertEquals(1, result.message().size()); assertEquals(InterpreterResult.Type.IMG, result.message().get(0).getType()); - // test plotting of R - result = sparkRInterpreter.interpret( - "hist(mtcars$mpg)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code(), result.toString()); - assertEquals(1, result.message().size()); - assertEquals(InterpreterResult.Type.IMG, result.message().get(0).getType()); - // test code completion List completionResult = sparkInterpreter .completion("df.sho", 6, context); @@ -839,14 +736,8 @@ void testSharedInterpreter() throws InterpreterException { } private boolean isSpark2(BaseLivyInterpreter interpreter, InterpreterContext context) { - if (interpreter instanceof LivySparkRInterpreter) { - InterpreterResult result = interpreter.interpret("sparkR.session()", context); - // SparkRInterpreter would always return SUCCESS, it is due to bug of LIVY-313 - return !result.message().get(0).getData().contains("Error"); - } else { - InterpreterResult result = interpreter.interpret("spark", context); - return result.code() == InterpreterResult.Code.SUCCESS; - } + InterpreterResult result = interpreter.interpret("spark", context); + return result.code() == InterpreterResult.Code.SUCCESS; } public static class MyInterpreterOutputListener implements InterpreterOutputListener { diff --git a/notebook/R Tutorial/1. R Basics_2BWJFTXKJ.zpln b/notebook/R Tutorial/1. R Basics_2BWJFTXKJ.zpln deleted file mode 100644 index 920c00f5747..00000000000 --- a/notebook/R Tutorial/1. R Basics_2BWJFTXKJ.zpln +++ /dev/null @@ -1,902 +0,0 @@ -{ - "paragraphs": [ - { - "title": "Overview", - "text": "%md\n\nThis tutorial note demonostrate how to use R in Zeppelin. There\u0027re 2 interpreters:\n* %r.r - Vanilla r interpreter, with least dependencies, only R environment installed is required\n* %r.ir (`recommended`) - Provide more fancy R runtime via [IRKernel](https://github.com/IRkernel/IRkernel), almost the same experience like using R in Jupyter.)\n\nThis tutorial is to show you how to use R language via `%r.ir`. \n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:23.771", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "markdown", - "editOnDblClick": true, - "completionKey": "TAB", - "completionSupport": false - }, - "editorMode": "ace/mode/markdown", - "title": true, - "editorHide": false, - "tableHide": false - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003cp\u003eThis tutorial note demonostrate how to use R in Zeppelin. There\u0026rsquo;re 2 interpreters:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e%r.r - Vanilla r interpreter, with least dependencies, only R environment installed is required\u003c/li\u003e\n\u003cli\u003e%r.ir (\u003ccode\u003erecommended\u003c/code\u003e) - Provide more fancy R runtime via \u003ca href\u003d\"https://github.com/IRkernel/IRkernel\"\u003eIRKernel\u003c/a\u003e, almost the same experience like using R in Jupyter.)\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThis tutorial is to show you how to use R language via \u003ccode\u003e%r.ir\u003c/code\u003e.\u003c/p\u003e\n\n\u003c/div\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580780002030_-2142389262", - "id": "paragraph_1580780002030_-2142389262", - "dateCreated": "2020-02-04 09:33:22.030", - "dateStarted": "2021-07-31 12:59:23.778", - "dateFinished": "2021-07-31 12:59:23.797", - "status": "FINISHED" - }, - { - "title": "Hello R", - "text": "%r.ir\nfoo \u003c- TRUE\nprint(foo)\nbare \u003c- c(1, 2.5, 4)\nprint(bare)\ndouble \u003c- 15.0\nprint(double)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:23.876", - "progress": 0, - "config": { - "colWidth": 12.0, - "editorMode": "ace/mode/r", - "enabled": true, - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 84.64583587646484, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "[1] TRUE\n[1] 1.0 2.5 4.0\n[1] 15\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1429882946244_-381648689", - "id": "20150424-154226_261270952", - "dateCreated": "2015-04-24 03:42:26.000", - "dateStarted": "2021-07-31 12:59:23.882", - "dateFinished": "2021-07-31 12:59:28.598", - "status": "FINISHED" - }, - { - "title": "Load R Librairies", - "text": "%r.ir\n\nlibrary(data.table)\ndt \u003c- data.table(1:3)\nprint(dt)\nfor (i in 1:5) {\n print(i*2)\n}\nprint(1:50)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:28.685", - "progress": 0, - "config": { - "colWidth": 12.0, - "editorMode": "ace/mode/r", - "enabled": true, - "title": false, - "results": [ - { - "graph": { - "mode": "table", - "height": 193.33334350585938, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nAttaching package: ‘data.table’\n\n\nThe following objects are masked from ‘package:SparkR’:\n\n between, cube, first, hour, last, like, minute, month, quarter,\n rollup, second, tables, year\n\n\n V1\n1: 1\n2: 2\n3: 3\n[1] 2\n[1] 4\n[1] 6\n[1] 8\n[1] 10\n [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25\n[26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1429882976611_1352445253", - "id": "20150424-154256_645296307", - "dateCreated": "2015-04-24 03:42:56.000", - "dateStarted": "2021-07-31 12:59:28.692", - "dateFinished": "2021-07-31 12:59:28.877", - "status": "FINISHED" - }, - { - "title": "Load Iris Dataset", - "text": "%r.ir\n\ncolnames(iris)\niris$Petal.Length\niris$Sepal.Length", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:28.891", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "editorMode": "ace/mode/r", - "title": false, - "results": [ - { - "graph": { - "mode": "table", - "height": 169.33334350585938, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cstyle\u003e\n.list-inline {list-style: none; margin:0; padding: 0}\n.list-inline\u003eli {display: inline-block}\n.list-inline\u003eli:not(:last-child)::after {content: \"\\00b7\"; padding: 0 .5ex}\n\u003c/style\u003e\n\u003col class\u003dlist-inline\u003e\u003cli\u003e\u0027Sepal.Length\u0027\u003c/li\u003e\u003cli\u003e\u0027Sepal.Width\u0027\u003c/li\u003e\u003cli\u003e\u0027Petal.Length\u0027\u003c/li\u003e\u003cli\u003e\u0027Petal.Width\u0027\u003c/li\u003e\u003cli\u003e\u0027Species\u0027\u003c/li\u003e\u003c/ol\u003e\n\n" - }, - { - "type": "HTML", - "data": "\u003cstyle\u003e\n.list-inline {list-style: none; margin:0; padding: 0}\n.list-inline\u003eli {display: inline-block}\n.list-inline\u003eli:not(:last-child)::after {content: \"\\00b7\"; padding: 0 .5ex}\n\u003c/style\u003e\n\u003col class\u003dlist-inline\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.7\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.1\u003c/li\u003e\u003cli\u003e1.2\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.7\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.7\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1\u003c/li\u003e\u003cli\u003e1.7\u003c/li\u003e\u003cli\u003e1.9\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.2\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.3\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.9\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.6\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e1.5\u003c/li\u003e\u003cli\u003e1.4\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e4\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e3.3\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e3.9\u003c/li\u003e\u003cli\u003e3.5\u003c/li\u003e\u003cli\u003e4.2\u003c/li\u003e\u003cli\u003e4\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e3.6\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e4.1\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e3.9\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e4\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e4.3\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e3.5\u003c/li\u003e\u003cli\u003e3.8\u003c/li\u003e\u003cli\u003e3.7\u003c/li\u003e\u003cli\u003e3.9\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e4.1\u003c/li\u003e\u003cli\u003e4\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e4\u003c/li\u003e\u003cli\u003e3.3\u003c/li\u003e\u003cli\u003e4.2\u003c/li\u003e\u003cli\u003e4.2\u003c/li\u003e\u003cli\u003e4.2\u003c/li\u003e\u003cli\u003e4.3\u003c/li\u003e\u003cli\u003e3\u003c/li\u003e\u003cli\u003e4.1\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.9\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6.6\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.3\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.3\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e6.9\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.9\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e5.2\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.2\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003c/ol\u003e\n\n" - }, - { - "type": "HTML", - "data": "\u003cstyle\u003e\n.list-inline {list-style: none; margin:0; padding: 0}\n.list-inline\u003eli {display: inline-block}\n.list-inline\u003eli:not(:last-child)::after {content: \"\\00b7\"; padding: 0 .5ex}\n\u003c/style\u003e\n\u003col class\u003dlist-inline\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e4.3\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.2\u003c/li\u003e\u003cli\u003e5.2\u003c/li\u003e\u003cli\u003e4.7\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e5.2\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e4.5\u003c/li\u003e\u003cli\u003e4.4\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e4.8\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e4.6\u003c/li\u003e\u003cli\u003e5.3\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e7\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e6.9\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e6.5\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e6.6\u003c/li\u003e\u003cli\u003e5.2\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.9\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6.2\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.9\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e6.6\u003c/li\u003e\u003cli\u003e6.8\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e5.4\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e5.5\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e5\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e6.2\u003c/li\u003e\u003cli\u003e5.1\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e7.1\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e6.5\u003c/li\u003e\u003cli\u003e7.6\u003c/li\u003e\u003cli\u003e4.9\u003c/li\u003e\u003cli\u003e7.3\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e7.2\u003c/li\u003e\u003cli\u003e6.5\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e6.8\u003c/li\u003e\u003cli\u003e5.7\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e6.5\u003c/li\u003e\u003cli\u003e7.7\u003c/li\u003e\u003cli\u003e7.7\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e6.9\u003c/li\u003e\u003cli\u003e5.6\u003c/li\u003e\u003cli\u003e7.7\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e7.2\u003c/li\u003e\u003cli\u003e6.2\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e7.2\u003c/li\u003e\u003cli\u003e7.4\u003c/li\u003e\u003cli\u003e7.9\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e6.1\u003c/li\u003e\u003cli\u003e7.7\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e6.4\u003c/li\u003e\u003cli\u003e6\u003c/li\u003e\u003cli\u003e6.9\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e6.9\u003c/li\u003e\u003cli\u003e5.8\u003c/li\u003e\u003cli\u003e6.8\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e6.7\u003c/li\u003e\u003cli\u003e6.3\u003c/li\u003e\u003cli\u003e6.5\u003c/li\u003e\u003cli\u003e6.2\u003c/li\u003e\u003cli\u003e5.9\u003c/li\u003e\u003c/ol\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455138077044_161383897", - "id": "20160210-220117_115873183", - "dateCreated": "2016-02-10 10:01:17.000", - "dateStarted": "2021-07-31 12:59:28.897", - "dateFinished": "2021-07-31 12:59:29.175", - "status": "FINISHED" - }, - { - "title": "TABLE Display", - "text": "%r.ir\n\ncat(\"%table name\\tsize\\nsmall\\t100\\nlarge\\t1000\")", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:29.197", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "title": false, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 408.6458435058594, - "optionOpen": false, - "keys": [ - { - "name": "name", - "index": 0.0, - "aggr": "sum" - } - ], - "values": [ - { - "name": "size", - "index": 1.0, - "aggr": "sum" - } - ], - "groups": [], - "scatter": { - "xAxis": { - "name": "name", - "index": 0.0, - "aggr": "sum" - }, - "yAxis": { - "name": "size", - "index": 1.0, - "aggr": "sum" - } - }, - "setting": { - "table": { - "tableGridState": {}, - "tableColumnTypeState": { - "names": { - "name": "string", - "size": "string" - }, - "updated": false - }, - "tableOptionSpecHash": "[{\"name\":\"useFilter\",\"valueType\":\"boolean\",\"defaultValue\":false,\"widget\":\"checkbox\",\"description\":\"Enable filter for columns\"},{\"name\":\"showPagination\",\"valueType\":\"boolean\",\"defaultValue\":false,\"widget\":\"checkbox\",\"description\":\"Enable pagination for better navigation\"},{\"name\":\"showAggregationFooter\",\"valueType\":\"boolean\",\"defaultValue\":false,\"widget\":\"checkbox\",\"description\":\"Enable a footer for displaying aggregated values\"}]", - "tableOptionValue": { - "useFilter": false, - "showPagination": false, - "showAggregationFooter": false - }, - "updated": false, - "initialized": false - } - }, - "commonSetting": {} - }, - "helium": {} - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TABLE", - "data": "name\tsize\nsmall\t100\nlarge\t1000" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1456216582752_6855525", - "id": "20160223-093622_330111284", - "dateCreated": "2016-02-23 09:36:22.000", - "dateStarted": "2021-07-31 12:59:29.202", - "dateFinished": "2021-07-31 12:59:29.260", - "status": "FINISHED" - }, - { - "title": "HTML Display", - "text": "%r.ir \n\ncat(\"%html \u003ch3\u003eHello HTML\u003c/h3\u003e\")\ncat(\"\u003cfont color\u003d\u0027blue\u0027\u003e\u003cspan class\u003d\u0027fa fa-bars\u0027\u003e Easy...\u003c/font\u003e\u003c/span\u003e\")\nfor (i in 1:10) {\n cat(paste0(\"\u003ch4\u003e\", i, \" * 2 \u003d \", i*2, \"\u003c/h4\u003e\"))\n}\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:29.301", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "editorMode": "ace/mode/r", - "title": false, - "results": [ - { - "graph": { - "mode": "table", - "height": 361.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003ch3\u003eHello HTML\u003c/h3\u003e\u003cfont color\u003d\u0027blue\u0027\u003e\u003cspan class\u003d\u0027fa fa-bars\u0027\u003e Easy...\u003c/font\u003e\u003c/span\u003e\u003ch4\u003e1 * 2 \u003d 2\u003c/h4\u003e\u003ch4\u003e2 * 2 \u003d 4\u003c/h4\u003e\u003ch4\u003e3 * 2 \u003d 6\u003c/h4\u003e\u003ch4\u003e4 * 2 \u003d 8\u003c/h4\u003e\u003ch4\u003e5 * 2 \u003d 10\u003c/h4\u003e\u003ch4\u003e6 * 2 \u003d 12\u003c/h4\u003e\u003ch4\u003e7 * 2 \u003d 14\u003c/h4\u003e\u003ch4\u003e8 * 2 \u003d 16\u003c/h4\u003e\u003ch4\u003e9 * 2 \u003d 18\u003c/h4\u003e\u003ch4\u003e10 * 2 \u003d 20\u003c/h4\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1456140102445_51059930", - "id": "20160222-122142_1323614681", - "dateCreated": "2016-02-22 12:21:42.000", - "dateStarted": "2021-07-31 12:59:29.307", - "dateFinished": "2021-07-31 12:59:29.369", - "status": "FINISHED" - }, - { - "title": "GoogleVis: Bar Chart", - "text": "%r.ir\n\nlibrary(googleVis)\ndf\u003ddata.frame(country\u003dc(\"US\", \"GB\", \"BR\"), \n val1\u003dc(10,13,14), \n val2\u003dc(23,12,32))\nBar \u003c- gvisBarChart(df)\nprint(Bar, tag \u003d \u0027chart\u0027)\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:29.407", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "results": { - "0": { - "graph": { - "mode": "table", - "height": 300.0, - "optionOpen": false - } - } - }, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "editorMode": "ace/mode/r", - "editorHide": false, - "tableHide": false, - "title": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nWelcome to googleVis version 0.6.10\n\nPlease read Google\u0027s Terms of Use\nbefore you start using the package:\nhttps://developers.google.com/terms/\n\nNote, the plot method of googleVis will by default use\nthe standard browser to display its output.\n\nSee the googleVis package vignettes for more details,\nor visit https://github.com/mages/googleVis.\n\nTo suppress this message use:\nsuppressPackageStartupMessages(library(googleVis))\n\n\n\n" - }, - { - "type": "HTML", - "data": "\u003c!-- BarChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\u003c!-- Sat Jul 31 12:59:29 2021 --\u003e\n\n\n\u003c!-- jsHeader --\u003e\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataBarChartID34f18480c5e () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"US\",\n10,\n23\n],\n[\n\"GB\",\n13,\n12\n],\n[\n\"BR\",\n14,\n32\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027country\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val1\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val2\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartBarChartID34f18480c5e() {\nvar data \u003d gvisDataBarChartID34f18480c5e();\nvar options \u003d {};\noptions[\"allowHtml\"] \u003d true;\n\n\n var chart \u003d new google.visualization.BarChart(\n document.getElementById(\u0027BarChartID34f18480c5e\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartBarChartID34f18480c5e);\n})();\nfunction displayChartBarChartID34f18480c5e() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\u003c!-- jsChart --\u003e \n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartBarChartID34f18480c5e\"\u003e\u003c/script\u003e\n \n\u003c!-- divChart --\u003e\n \n\u003cdiv id\u003d\"BarChartID34f18480c5e\" \n style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1485626417184_-1153542135", - "id": "20170129-030017_426747323", - "dateCreated": "2017-01-29 03:00:17.000", - "dateStarted": "2021-07-31 12:59:29.414", - "dateFinished": "2021-07-31 12:59:29.482", - "status": "FINISHED" - }, - { - "title": "GoogleVis: Candlestick Chart", - "text": "%r.ir\n\nlibrary(googleVis)\n\nCandle \u003c- gvisCandlestickChart(OpenClose, \n options\u003dlist(legend\u003d\u0027none\u0027))\n\nprint(Candle, tag \u003d \u0027chart\u0027)\n\n\n\n\n\n\n\n\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:29.514", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "results": { - "0": { - "graph": { - "mode": "table", - "height": 84.64583587646484, - "optionOpen": false - } - } - }, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "editorMode": "ace/mode/r", - "editorHide": false, - "tableHide": false, - "title": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003c!-- CandlestickChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\u003c!-- Sat Jul 31 12:59:29 2021 --\u003e\n\n\n\u003c!-- jsHeader --\u003e\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataCandlestickChartID34f1c7c0c2e () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"Mon\",\n20,\n28,\n38,\n45\n],\n[\n\"Tues\",\n31,\n38,\n55,\n66\n],\n[\n\"Wed\",\n50,\n55,\n77,\n80\n],\n[\n\"Thurs\",\n50,\n77,\n66,\n77\n],\n[\n\"Fri\",\n15,\n66,\n22,\n68\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027Weekday\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Low\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Open\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Close\u0027);\ndata.addColumn(\u0027number\u0027,\u0027High\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartCandlestickChartID34f1c7c0c2e() {\nvar data \u003d gvisDataCandlestickChartID34f1c7c0c2e();\nvar options \u003d {};\noptions[\"allowHtml\"] \u003d true;\noptions[\"legend\"] \u003d \"none\";\n\n\n var chart \u003d new google.visualization.CandlestickChart(\n document.getElementById(\u0027CandlestickChartID34f1c7c0c2e\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartCandlestickChartID34f1c7c0c2e);\n})();\nfunction displayChartCandlestickChartID34f1c7c0c2e() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\u003c!-- jsChart --\u003e \n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartCandlestickChartID34f1c7c0c2e\"\u003e\u003c/script\u003e\n \n\u003c!-- divChart --\u003e\n \n\u003cdiv id\u003d\"CandlestickChartID34f1c7c0c2e\" \n style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1485627113560_-130863711", - "id": "20170129-031153_758721410", - "dateCreated": "2017-01-29 03:11:53.000", - "dateStarted": "2021-07-31 12:59:29.518", - "dateFinished": "2021-07-31 12:59:29.579", - "status": "FINISHED" - }, - { - "title": "GoogleVis: Line chart", - "text": "%r.ir\n\nlibrary(googleVis)\ndf\u003ddata.frame(country\u003dc(\"US\", \"GB\", \"BR\"), \n val1\u003dc(10,13,14), \n val2\u003dc(23,12,32))\n\nLine \u003c- gvisLineChart(df)\n\nprint(Line, tag \u003d \u0027chart\u0027)\n\n\n\n\n\n\n\n\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:29.618", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 61.458335876464844, - "optionOpen": false - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "editorHide": false, - "tableHide": false, - "title": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003c!-- LineChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\u003c!-- Sat Jul 31 12:59:29 2021 --\u003e\n\n\n\u003c!-- jsHeader --\u003e\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataLineChartID34f1e8751b6 () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"US\",\n10,\n23\n],\n[\n\"GB\",\n13,\n12\n],\n[\n\"BR\",\n14,\n32\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027country\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val1\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val2\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartLineChartID34f1e8751b6() {\nvar data \u003d gvisDataLineChartID34f1e8751b6();\nvar options \u003d {};\noptions[\"allowHtml\"] \u003d true;\n\n\n var chart \u003d new google.visualization.LineChart(\n document.getElementById(\u0027LineChartID34f1e8751b6\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartLineChartID34f1e8751b6);\n})();\nfunction displayChartLineChartID34f1e8751b6() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\u003c!-- jsChart --\u003e \n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartLineChartID34f1e8751b6\"\u003e\u003c/script\u003e\n \n\u003c!-- divChart --\u003e\n \n\u003cdiv id\u003d\"LineChartID34f1e8751b6\" \n style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455138857313_92355963", - "id": "20160210-221417_1400405266", - "dateCreated": "2016-02-10 10:14:17.000", - "dateStarted": "2021-07-31 12:59:29.623", - "dateFinished": "2021-07-31 12:59:29.682", - "status": "FINISHED" - }, - { - "text": "%r.ir\n\npairs(iris)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:29.723", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 1857.0, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "title": false, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "IMG", - "data": "iVBORw0KGgoAAAANSUhEUgAAA0gAAANICAMAAADKOT/pAAADAFBMVEUAAAABAQECAgIDAwME\nBAQFBQUGBgYHBwcICAgJCQkKCgoLCwsMDAwNDQ0ODg4PDw8QEBARERESEhITExMUFBQVFRUW\nFhYXFxcYGBgZGRkaGhobGxscHBwdHR0eHh4fHx8gICAhISEiIiIjIyMkJCQlJSUmJiYnJyco\nKCgpKSkqKiorKyssLCwtLS0uLi4vLy8wMDAxMTEyMjIzMzM0NDQ1NTU2NjY3Nzc4ODg5OTk6\nOjo7Ozs8PDw9PT0+Pj4/Pz9AQEBBQUFCQkJDQ0NERERFRUVGRkZHR0dISEhJSUlKSkpLS0tM\nTExNTU1OTk5PT09QUFBRUVFSUlJTU1NUVFRVVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1e\nXl5fX19gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29w\ncHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGC\ngoKDg4OEhISFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OU\nlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJydnZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWm\npqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4\nuLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLDw8PExMTFxcXGxsbHx8fIyMjJycnK\nysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc\n3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u\n7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7////i\nsF19AAAACXBIWXMAABJ0AAASdAHeZh94AAAgAElEQVR4nOydBXgURxvH37XT3F3cjQgJEMEJ\nENw1uDsUKW4FijsULe5e3KVAi1Oc4lLkKw4t7iRE5pu5EHKX28tJNpek7P952Cy7M7Nzu/vb\n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\n143vRQp0iZQ0TASoeZYqYqSHpgJil2x0J68SaYDD/hf7HJLLkC9wAqj96FI135T38Ft7cu4i\ngZ58avH+ERefzuEO6a7JHPmDSImh5f55tliwO7Pdn1s5CTlnyTV8I1LAMBzX4v7druqHN+T9\nH9xua5MlT9E0yIhI24XLnp0LK5eBNnpHKgaQyIM4aTOqqbWBXleWS2yM7sQX6BJphtn258e8\nWprSGMfnkMgs23xGyKtEsqQK3FqrlBXtaMmN11xKwYNdZp8S3uPK3+k2cZKln/cWbUw5fP4g\n0iW+bl3XBpntvsYh4XMcLk3dQhLiE2YWJ/JcYtEFk+jodILTCqN7kxGR6tHCBHcyqjs/wzfp\nw6dEt8WxGrIpqVC+JuuF6nWhSyS/6eTPb9xH49vaAz/gR9hWYHpv8iqRYoCm4TiFUixymjrx\nyfnnklM8dtNT0WYLz74xFUw5fP4g0s9SquLMKJnZ7hP46O6WnTS/NEkTIr/rzl+zilnKG54G\nGREpYDaZJIn0uI4now/P+2rJddFoJj382JQylcnQJRKtMYgfwg29m2eIgUBfvqEF0djgQqMV\nJ7ulrOhTnjw8V9CF5N+/iclbOd5nfKp9d4yhsWBvVsBpck8r9jTl8PmDSPeBaji12ma2+07V\nc7KTmzZDw492Tw4feWi9Zr7LR/xmp1z7Snp58HhW3+AZEaklTYL/e0aFIJY4Pjl89KFl8uNm\nSTOqDgXevr1zzG9Z7EJq6BIpjN6t1bKsZnJOhXPQYd24UzKxCd3A+P3Rw2/zLpFWiQZvHyz6\n4vR1x6zexvnOUSm/Eyt5Lt5Qxf7flAVXzImY6/J+jZkQsd02NVClcXDMKvIHkXBH21mbmkkN\nj1VqEV+6xPK1ZV21w9UfHDmW5Yp8fOse1k2KkA3NP4sXy0Ws4+Gs9SYjIl2QtNw806ZrBnu/\nt+dYhnNNbmIRFBtQHYWRuetqcuOcX2etD6mgS6T9XM+tYxWTjW6JwIw3Now1Zded1pxAvTHP\nEglvLmVZenOqNRfr2RYdmapa5pv+7vZNb375bSc9glezvsJZ8a/KMpZ1z5t0+HxCpNgJ3tY1\ndVy0dfEi2tWxVXK9lauiICfnIMkN/KAWUnd9MFh5n0ZjLUmI6Wn5b4atJCNDq93p6tbekzIy\nyV8SBjs6l5SmvN/mmjPiKLqDo+QgXscZ752jx/y9v5xlwBJTLPuJUhYBi5qYsOst2ejYuMni\n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\nUCQEUYD/B3YDqx+lN7unAAAAAElFTkSuQmCC" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455137735427_-1023869289", - "id": "20160210-215535_1815168219", - "dateCreated": "2016-02-10 09:55:35.000", - "dateStarted": "2021-07-31 12:59:29.727", - "dateFinished": "2021-07-31 12:59:29.973", - "status": "FINISHED" - }, - { - "text": "%r.ir\n\nplot(iris, col \u003d heat.colors(3))", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:30.027", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 399.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "title": false, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "IMG", - "data": "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\n0/MqmD1T3j/yu/wuw+SJEsWFknpQivL+Uif2bEmLk2K7SJHIIZFscRbLvnlyfL2IiKSKxIs4\nJfesxC0Xe444CyRzhRSeFBGJ3SxHdomI7P9CVgyWwnQ5u0dWD5W0Q+LIlMMTJGPD/2wr5jv5\n5hkpyBJHpmQsFUe6FObLt59J7I7/aZaVJYcPi8MheSmyfbpkHhdxisSLpIqI5CRJ5nFxuS7Y\nBbvExUlOjhQ7ZOW7snvx/+5hjkiciL0kuAKTJ87LvXBDf+Dkl3JksjgdZTluk5wfSx8XO2TF\nZNlVthc5SfLRTbL+ndLQmSeZK6QwsTTct1yei5K175eGWYdk+6uSV7Y2bb3EPSWFZRMsju6Q\ndZ9JUX5pmBIrx9eL0/kb6blcknlccpJ+O3lHgRxfKedOXtSe/gU6eeJ/ZJ2Q7NM/h06nbNok\nu3fLlnmyf5XIPHGslJUDZNtrsmu9HN0ve9fLsb1yfL2k7pXs2ZKzSvY9Ikemy5LZsmujrJ0t\nh7ZKwlpJi5Ws1ZK9T9Z9JkdLjsRikSMiKSJHRDJERBwOOXxYUs7I8ZWSdUJExOmQ9MNSkFmS\ny9atW/k3Tp4oUShyUKTsfbjorKQuleJzpeG5c3LokBSVzUbKT5f0I+IqLg2X9Zd5rcWeWxru\nf0diJpY+dtol5kk58d7PT1w0WHZ8WhoW5MiKj+VkbGmYuF+mdJV9S8o2elL2Tv/5+E06LKs+\nlvyskkgnT/yDmEymoUOH/oknHjlypG7dukDDhg0TEhLatm1bcvPwWrVqHT9+/HKnecm0sFOX\n05Us7NRlpoXdP8W/u7D7h9HC7h/kTxd2t9xyS8eOHTdv3jxo0KB69ep16dIlMzPz7NmzrVq1\nuueeey57npdKL8UqpZRSSl2sTZs2zZkzp23btnXr1g0KCpo8eXLJfxJ77rnnhg0bVt7Z6axY\npZRSSqmLVlBQ4OvrCwQGBprN5vDw0ulNVapUuRr+obYWdkoppZRSFysyMjIhIaHk8YIFC6pV\nq1byOCkp6Wr4b9p6KVYppZRS6mI99NBDeXl5JY/79OlzfvmSJUs6lszULlda2CmllFJKXayn\nnnrqN5d//PHHf3Mmv0kvxSqllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2Cml\nlFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2Cml\nlFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2CmllFJKVRBa2Cml\nlFJKVRBa2CmllFJKVRCW8k5AKaWUUurvJiLLly+/4447frHcYrG8/fbb4eHh5ZLVX6eFnVJK\nKaX+jdzd3f39/X+x0M3Nzc3NrVzyuSy0sFNKKaXUv45hGJ06dZo8eXJ5J3KZ6W/slFJKKaUq\nCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUq\nCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUq\nCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCC3slFJKKaUqCEt5J6CUUkop9Q+zY8eO7du3\np6SkACEhIa1atWrRokV5JwVa2CmllFJKXbykpKS+fftu2bIlNDQ0JCQESElJOXv2bNu2bb/6\n6qvw8PDyTU8vxSqllFJKXazBgwe7XK6YmJjk5OR9+/bt27cvOTk5JibG5XINHjy4vLPTwk4p\npZSq6NauXXvjjTeGh4e7u7tXq1btpptumjNnzhXd4oQJEwzDuKKbKC+rV69+9913GzZseOHC\nhg0bTpo0ac2aNeWV1Xla2CmllFIV2Zw5c7p06ZKTkzNq1KjZs2cPGzYMmDt37hXdaHBw8C9K\nnwrDz88vPj7+18vj4+P9/Pz+/nx+QX9jp5RSSlVkEydOjIqK2rBhg5ubW8mSp556ym63X9GN\nDho0aNCgQVd0E+XliSeeePDBB3fv3t25c+eQkBARSU1NXbt27bRp00aNGlXe2Wlh9zvOnCE+\nnshITCaWLSM0lJ5dcTsCDmgIZyAJGkBQafucHGJj8fQkKoS1z5KbTtfRrPmWI5vp8AA2C8tm\nEN2am4eQOANzJSIGcmwT+enU6snpbzizgag7IIDdHxLWnGsGkvE9hhW/LqxcQNJJ/jMAczap\nPxHSGvdaxMYSFETlEDYvxWTQ7ka8F8EhuJfsIDKP4Vcdmw+psbj7E1QD4yA4oSF4lueo/o6U\nFOLiqFyZWrV+a/VG2AsdoCkuJ6s/49Beut9D7ZYUFbBmBmmn6PQAVRuQn8aeMbiyqfcsQQ3I\nOcP+GRgGjR7CO4ysHzkwGlsgjSbhFsTub1g6ntCa3DcDmzffT2b5FGo1Y+gCgKVDSV6Ibwf6\nzgXI+4aiDbj9B68bAXZ/zqmdNOtHRFtwQRxkQDT44SomNRZHASENcav0941hBeeAWLBDNHgB\n5OayZAmFhfTqhacb27/DkU+NKKw2UgxM0BAkhx+3YMqk9VEKDZZHYbdiScXTQnRjcl18u5fM\nbOxH8bDQpA2+BkHxWD0wdcDlRYpQyYN21bFaQcALovWd89Ic2so7T2AyeP5jqjci/xjJMzAH\nUGUIFm9Or+TEm3jUo/GbWDyZ35flS6hZmZePA2wcyZ6vqNeVGz8AeL0ryTuo1Z1h8wAyPiVn\nN8H98WxVdgxmQsP/PQajcfMuz92/CmRmZlavXv18VVfCZrOVPHjppZfefffdJUuWPP/88/v3\n7/fz8xswYMCYMWPMZnNJg0OHDr300ktr167Ny8urX7/+yy+/3KdPn/P9xMXFjRo1at26ddnZ\n2VWqVOnVq9e7774LTJgwYeTIkSJyvuXv9JOYmDhixIi1a9emp6cHBAQ0a9bso48+qlq16hUd\nlj9t5MiRoaGhU6dOnTRpksvlAkwmU5MmTd5///0BAwaUd3b69vSb7HaGDOGzz7jgL5LroJlB\nZMkSKzjKHgyHCcz4mKefJjubaMiFE+AFdywnEgSGbOBwSS8b8H+D9dAYMkewBU5BAGQA8MPX\npdva/zWrXih9nA0L4TjY3mI8DAeBLwweEgLhHORCF+hwPtF3SDOYJQCGGXEChFm5zUEQEAIf\nwq1XZNz+NJeLp55i2jSKiwG6dmX2bEJDy1YfhXZwtjTaVpVuSWQ7AZhMAz9c2cS5ALwmMsWP\ne7JoC4B8ygY/6paFSa8w34PUAkq+pm6azTYT37hwADsYNZ+m0KLk5YjnIYOb4GYwgHkcnIe3\nGxFFeAGTyfRkXBHexQA7J+MWxAvVMHYB4MHpQSxcSfphAJsv3SfRtPwP9X++H+B+OAZAAEzh\n3RSefbb0b8Zi0AOaC8AsWAzZAFwLt0B76ADfwWBIBsACt0AjALJhCXjCLXBiN4Af9AbfRSwC\nK3QE64WZ1IJZ0Prv2e1/vG5BrEqn5I1zemOmuTGkiCgAHM9xyErdIqoAa8idRjuIARdwgukG\nPaEyGLA1nrUf0hpeAkDms2A++WYSnACmybQJpktVjN0AeHBuEJ+vIOMIgLsf3d+lyf1/945f\nTdq2bTtv3ryxY8f279+/Ro0av25QWFj44IMP/ve//23RosWqVasGDBiQk5MzZcoU4ODBg23a\ntImIiHjnnXeCg4Pnz5/ft2/fr776qqQm27dvX7t27UJDQ8eMGVOjRo2TJ0+uWrXqN3P4/X76\n9euXlpY2ceLEiIiIlJSUdevW5eTkXMkh+asGDhw4cOBAu92elpZmGEZgYOD5Qrn8SYUzd+7c\nsLCwv9TFs89K1aqyebO89pqA+PnJI7eKw1c+8ZJgq2S0EokUcRPZJbJUxEc2DBeLRT74QOK+\nlFCkkyH1A2WEIS8g4UgbixjIHcgoq3yHeCH+yJsW2WWSXORTs0xCxiCTA2Q0Mh6Z7iljkDHI\na4b4GNLXkLGGrKkq7xpiIPe3lo5WOWWSubXFDWnqJ+0biMuQHEOuM2TuzbLLQwTJuUZes8rE\nMFl8l2T7yJwomVpXijNEXhXxEDlwecb6V0aOHNmtW7eLb9+7d+9hw4bJxIkSECCrVonDIQcO\nSMuW0qPHBa2qiriLfC1iF+c7UgnxM2T9HMnLkmdvEZAwk+xdJTnpMqGROJEEk5xYK+mHZJuv\nCLLaSzKOSupBmWOT15DPvSQnVhIXyFDEjAzxkZSjsuQVCUOCkEEhkn5KJt8uQ5EnkY8jJSdJ\nZjaRFOQAkjVBXPmS8YzkItuRnZ+IPUfm3yNjkeU+IqdE7FIwQ942ZOH1kpcqjnzZPkVes8ip\nLZd9qP+6GjVqzJw58yIbFxQUAFu3br2iKf3/UkSCRR4WyRDJE5koLqs0N6RxYzlxQraskOsQ\nEzLUQ2bcIzazXI+kWeVrs7yIPI8IEotYkU6IB/I40h6xITciIcgLyCvIS0h7ZDOyBBmJjEK+\nRQoQpyFbDSk2ZJQhub1FQkT6i4SLZPxtO79161agoKDgItvPnDmzRo0aVzSlizX6NgGpYchP\ny2XDXOmDOJCVwVKQJBmbJdkkgmytLDkn5cBE6YG4I3eaJWm3jIqUMKQKMrWBFKTIJ21kHPIJ\n8lQNSU2QxwIkE1mHpH8mzhw5fJeMR370FUkUsYt9uhQbsq2L5KeJI1+2vSuvWSVx29+zx8OG\nDevdu/fFt+/WrVvJaa0rKikpqXPnziUf+sHBwbfffvs333xzfu2LL74IzJ8///yS8ePHm83m\nxMREEenZs2dYWFhmZub5tT179qxfv37J465duwYGBmZk/MbhMH78+AtrjN/pp7i42Gw2T506\n9bLt8MUxmUxDhw79mzf6N9DJE79l3jxef522bfnsM6KimDOHoqVYfOhxhFQHc7bD93AtfAs9\nYTgL5tGrF0OGsOhFHLDwFJl52AS/PlQ32FNMWy+CvankoKGVsf3IhLRiaidggLeT6N54VSU3\nA18fIiPJyCe8El0n4BJMwnuxeJrxSaTty9T0YcUOrnmMhMEciyfYnWUHaHkAQ/Bcz2E34lZg\nnQmBeO6h6f3c9AGxi/AO5tYdpMeTfARegWhYVN5D/L/mzmXECLp2xWKhfn0++IDvvyczE4AM\nSIQ3oQ+4sSWCHFhk4rq78PQlujYGFJho3BXvAFqbAR71JLITAXU4U5U8CDXwjyKoHk4n4VCp\nLt4NqHI7G6E53BJGcBQ3vcqNkA71GhJQlaELuAX8wfMuvMO4fwNJUBuKbsXw4NxNrIZr4JoH\ncPPmjmG0M1idB1XBjYRgHG7cHIBnEBYPrn2cmt2IXVCu41sBrAELTCt5VeAZDgVzu8HOnURG\n8uMXtLAS4M5+A3sbqtficTdcbqx2I8+gu4limOpOiEENg9rQD+41MMFG8IZU8DTwMNgCb8Ia\nOGhQCFMsGJBpQyAjgncMPooAgZvBDuvLe0z+CeYtwgrHXLToTsc7eS+IFfDcOdzD8G+LSXBB\nQAe8I6j/DLugHQy7jbCmjD5BZzgNPjVwD+b6D+kNJ+DVjQRVY/xcNkFNCLgPkze1h9MG9udC\nFXDjWDCxblwbiEcgFg9aPUlU13/5MRgWFrZmzZqYmJi33367U6dOq1ev7tOnzy9+ANe9e/fz\nj3v06OF0Ojdt2uRwOFavXn3rrbdeOCegd+/eBw8eTE9Pt9vt69ev79evn7+//+8n8Pv9mM3m\nZs2aTZgw4b333tu/f79ceK3sCouPj//yV7799tvikksBl+jRRx9t3779ZU/yUuml2F9xOklO\nJiICICuLevWIjCSoCEcIoeGYTBxyQQREwmkAIjmTTbVqAMmpBIFvFSJtGIW06MUP32J3UjUA\nmwVHLvmedOwP8zlnwrsqKQbeQngHjiWSm4hHEH7ViU/A1596d/L9CHyhcn183MnPJSyaKv7s\nyqFaNSq5kSmEVCI0lGvM4MTUjjBvjHR8IyAEIwPfavhFYi+gKAx3f9x9ySlLuDTzq8aZM6UD\nXiIyEhHOnMHfH+IAaFK6KmY7QHNXaXjqIG5Q4CwN3ZNxQEphaWhOIxd8ykKHExMYZZd0s6AR\nFKSWhgFggZNHAAqyaAo/wL7V3Dke+x78wAI7P6L7WxzfzDmwgBRgeMAZKpkxyt4Fcs7g7Ysp\n6efd8Ysk+yob8H+eM1AZzD8vOGlQzYzFApB1CqcXAZBVRFISERH4nSFTQCgyUVUogDNCkIkc\nJ8GQA35lnYVBLhhgNeHu5CQEA5AHvgbFYC/Gx8w5gwB3jidAFUiGKlfdQXR1ynbhfkHokccZ\nyHSUhp6CA4xjpWEBVIbiWIDCVEp+i7HzB+6FxW/SHwyI/YJWz5OzhSwIgew0fILgDL4Wcsre\nB3LOIH4YZ37erh6DADRs2LBkmmpubu4dd9wxc+bMIUOGtGzZErBYLD4+PudbBgYGAunp6RkZ\nGUVFRf/9739nzpx5fm3Jr8rS09OLi4uLi4sv5pdwv99PYGDg4sWLR48ePX78+GHDhoWFhT34\n4IOvvPKK1Wr9/7u8DERk7dq127Zt+8Vyi8WycePGevXqXWqHUVFRJTtVvvSM3a+YzURHs2IF\nQI0a7NnDkiWcDsQax+IPcLnobobFsAmaArCcxhGsWYPDQZOmnIAvH2NPLsDi59nvxBe2nEYS\ncIOwbCYMAQhxsXMkAUIG7H2X1FjcDLISOL0Vdzh1mu/6AiTDp49yNg8vg9Mz2ZVIqI3vvyfj\nC6qYOZzON3OY7QLIfoBDGZgCiF8B8TitHF3J4WX4hWLbz+nlFGQQ2gSyYUtZ5leNxo1LB7zE\n8uV4eFCnDgCtwYAPS1f9ZwDAG2Uf8K17Ywefsu8n+U2xQefzs0NqEARJvqWRxUYuGHXKVhrE\nQEBZyXgYHNCxH4CHH1+AE+57C8DjOlIgF7q/BdDiAWpDnoHhAUAjjhfjUfar5NBGZKSSGVUa\nOu0cX0vYVTbg/zyN4QCcKgvzaZnPjmJ27wao3grLOU5mU8VB3Uh2/MSRPKo5sLmo5GQ7eENL\nJ0ed+EIMeEKcYAcviIVQKBLynRTDdVAFbOAPBcW4g5+JlGJCz5GeT9doOAghcOiqO4iuTlXd\nyYU1s0rDY560gzplBUSWCRsYnUpDf9gBfvcBuAezD8wweDrAE7Mp+flcq+cBgh+gNhwFn5K5\na42JLyasrAgIjSY8BXvZMVhcyPF1egxeyNvb+5FHHgH2799fsqS4uLjkX2OVOH36NBAYGOjr\n62s2mwcOHLjnAvv27Tt48GD16tX9/PwsFktiYuIfbvH3+wHCw8OnT5+enJwcFxf30EMPjR07\ntmQGxhVlGMbgwYMzfiUlJeVPVHXAM8888+GHH/5xuytMz9j9lnHj6NWLtDRuuomdOxkxgvZt\n2XOQRo8yNpCebeAeKDnz3BeWMnQFM/pz/fXc05/m63jyfW6wkGVQKYVrwMPKbAfzoL6VeQ5+\nSuJ6E9ebqTWBBBM5nqScwhcsPqRkc7qASp4U5HN0Bz5Wugm7P8Bs4qNg4r9H4KXWOFfT3kVs\nD3xW8/C9XFOb5JOEzma9Qe1A3MYAHL6b019xajPNBrFxFdt60bwN/svgIwiAu8t1fH9lzBg6\ndKCwkK5dOXSIadMYM4bS72om6A9fQBw0JuIH2sPYYtZFUDOCVbsB7A4G1SQgmM07+Q7GZvNT\nKA4PuiTggsAMFjUDFy3sfAeJ61gYSLGd9sKP8OB6WlYiy85aaA6L32bhNJx2aoINcq9nvhtV\ni2gN+6BWMI562PbRGmYJR6oQFEnCHnxhiAVegzCqfk1tC5+sodUb2HzZ+xmOfFo+Uq7jWwF0\nhg7QAR4HL/gYvwAWuJjSih49sLmxFjxdNPXhyHA883gR0l2ECacgxoXA08XMhrVggrvADiHQ\nGDzBAslgwCDoCQ6wCe4wSzgBAUXUMXBkccRE2AdQA56DG6FdeY/JP8HsjTRoSff7qD8IgWQH\nu2BhDkeuxZxNhAsgcCLbZ+KVywvwKNz8PNVHkCHEQlOYfSeWATgKsEEv+NDguIloF/1hHiRV\nxb8a8Xs4Ag9aYAyEUu0riix8vor6b2LzYc8nOO20GFLeY1GeDhw40KBBgwuX7N69GwgLCzu/\n5Isvvhg+fHjJ41mzZpnN5vbt27u7u3fu3HnDhg2TJk3y9PyNOyp06tRp/vz5r7/++u9fjf3D\nfs6rW7fua6+9NmvWrJiYmIvfwXIhIr+4A7PT6czMzAwKCvr/nvL30MLut3TvzurVvPEGGzbQ\nvDmnT/PjDrpZmVqHER5wHDpBLrwHjWAbgU3Yto3Ro5kyDZ+GtDnMIQdx0BbqgsXBfQbLhE0O\n3OE+ExMFl5MYD7YY2IvwdcdkpyAbf4NcyM3HbODvhtWgu8F+Nz4vJD+Fhm7MdyP6R5J9eS6S\npUep3ghrGgdP0dZgnhctCzDiKXZnbU1itlG5JRY3EjbhHsx1tWmZCtOhM7wCHuU9xP/r2mvZ\nvJnXX2fCBCpXZsYM7rzzgtWzoTLMgBjwZ900HvyChdv58TSh7sx7g02z2HiAvOPU8WbvawSM\nJjoFE5yykT2e0xOouxcxOBLGjYPYN47EDEwQ7cGHNzHpS1bl4g69PKgTTeJPBBWSDwmedPDH\n5zQ3FJEJsyrRqydu3+C1GYeVjKHkxZC7ifwksNFpHJW94QvIwmhB391sWUjslzjyqdaeO77G\n/Q9+gKL+iAkWwhswF+zQEWMUO6BPH1atQoRa9ehioyAOWzH3ubPDg08MPKCriyY5THdyq7AJ\nxsJSSAU3aAe1IRf2wBYIhd6wAfygITSDGPjeIBF6mOlsJdQDzOAB/eGZkvnS6g/UbsGi6Qwe\nwkEHQLjBkRdpMJXqO3AaJNYkqxthH9AsDQcU+vGYsOQcuwQP6GzQJYqsoxgFmMA9hM+yuLWI\nG1wchmF+PNiEXT9w4AyhNh6cQKgHzIEsaIl5N3W+IXYBxQVUa8/1o3Ev/9vGlqOePXuGhobe\ndtttNWvWLCgo2LRp08cff9ykSZMbbrihpIGbm9ukSZMKCwtbtGixcuXK999//5FHHim5xjpp\n0qR27dq1adPm8ccfr1Gjxrlz5/bv33/48OGSf1zx1ltvtWvX7tprr3322WejoqISExNXrFjx\nm7c+/p1+EhIS7rrrrjvvvLNu3bpWq3X58uUnTpwYO3bs3zlElyQrK2vw4MFLly4NCgp67LHH\nnn766ZJbw+zfv79Zs2Z/528Ef1v5zt24Ei7DrFj1Z/3JWbGqPPyjZsX+q/2DZ8X++1yds2K/\n/PLLu+66q1atWp6enjabrW7dus8+++z5qawvvviil5fXnj17Sk7RhYSEPP/88w6H4/zT4+Pj\n77333rCwMKvVGh4efsMNN8yaNev82tjY2D59+vj7+9tstqioqOHDh5cs/8Ws2N/pJysra9Cg\nQfXr1/fy8qpUqVLz5s0//fTTKz0m8hdmxT788MOVK1eeOXPmu+++GxkZecsttxQWFopIyXnQ\ny53mJdMzdkoppVRF1rdv3759+/5+myZNmmzatOk3V9WsWfPzzz///57YoEGDr7/++tfLR4wY\nMWLEiIvpx9fXd8aMGb+f3lVl8eLFkyZN6tevH3DvvffecsstvXr1WrToarndhE6eUEoppZS6\nWOfOnatcuXLJ44CAgBUrVjidzu7du18lN1XWwiAOHewAAB2oSURBVE4ppZRS6mLVq1dv165d\n50NPT8+lS5d6eHjcffdVMTFRCzullFLq3+v111/Pzc0t7yz+SW6//fZfXFN2d3dfvHhx48aN\nyyulC2lhp5RSSil1sUaMGLFz585fLLTZbEuWLCmZZ1a+tLBTSimllPqrDMNwd3f/43ZXmBZ2\nSimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2\nSimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2\nSimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2SimllFIVhBZ2\nSimllPrXcblcH330UcCvBAUFHTx4sLyz+/Ms5Z2AUkoppdTfzWQy9ejR47HHHvv18jp16pRL\nSpeFFnZKKaWU+jeKiIjo2rVreWdxmemlWKWUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WU\nUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WU\nUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WUUkqpCkILO6WU\nUkqpCkILO6WUUkqpCsJS3gkopZRSSv3D7NixY/v27SkpKUBISEirVq1atGhR3kmBFnZKKaWU\nUhcvKSmpb9++W7ZsCQ0NDQkJAVJSUs6ePdu2bduvvvoqPDy8fNPTS7FKKaWUUhdr8ODBLpcr\nJiYmOTl53759+/btS05OjomJcblcgwcPLu/s9IydUkoppdRFW7169fr16xs2bHjhwoYNG06a\nNKlz587lldV5esZOKaWUUupi+fn5xcfH/3p5fHy8n5/f35/PL+gZO6WUUkqpi/XEE088+OCD\nu3fv7ty5c0hIiIikpqauXbt22rRpo0aNKu/sKnxhd/IHjq/FMOEOG+eQlcM1Tej9H0wJuCJZ\n8DGeR7C7U7srTc+Ci/n+DFtFnp3awdxkw56CLYAqGeTkYjLh5YkjH1wQQL2qWNPJr0fi7Rw9\nQZUqVJ5O0RHMFk62YZWZ/Hx69GDkSID8fJ5+mr17CQ/n1Z5EnwR36AFNy3uA/qFOwwJIg0bQ\n9/L9GRfDAoiBULiD00lM6ERGHr7uDP4cVxjj+1OcjjWUN5bhtZGDzyAFWEO49kfyjnBgIoWZ\nVG5P3XFMasa6/diFaB/eOceY9pz9EQP8GjNmB0sfIX45ZjeaDaD1cwy9m02b8anE8Ge45Q4W\ndiD/KGYvmk6gwa3sf4r0WHyqET0OjxCYA8ehJvSHfJgHZ6A+3MnJZL78kowMmjblttsw/e/5\n+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\n88XbnTt3rlix4uGHH/Zjv5mZmYcOHZo+fbofbT/44IMzZ87ceeedfrTdsmWLYRjjxo3zo+26\ndes6duw4fPhwP9qmp6cPGDDAv3dnli5d+qMf/ejWW2+Njo4eM2aMj61KS0u3bNlivWv71SIx\nMbFXr14+Vj5y5EhWVpZ32eVy3XvvvT/84Q87d+4c2JA2btwYGhoa8D9jeuLEiS1btsyePTuw\n3QKvvfbaxIkTe/ToEdhu33vvveDg4CeeeMJbtNlsEyZMCA9v9OPnhpPOlp965rXn5MmTwMmT\nJ31vkpiYuGTJEt/rP/3007fddpvv9fft2weUlJT43qRr167p6em+109LS5s6darv9bds2eJ0\nOn2vb5pmaGjopk2bGtVErlKrV6/2/iEdPyxZsiQxMdG/tgsXLpwwYYJ/bVNTU2fNmuVf23Hj\nxj311FP+tR0wYMArr7ziX9uYmJg1a9b411auOpWVlcDu3bsD3vPUqVPT0tIC3u369evbtm0b\n8G5N0wwPD//LX/4S8G4feuihe++997v3ExUVtWjRol31rFy5sjWkVfqYi4iIiIivbrrppurq\n6vo/WXfpTd6WpcRORERExFdz584tKyurvz4+Pj49Pb3546lDiZ2IiIiIr5KTky+7vl27dv59\nejiwrPsDxSIiIiLXGCV2IiIiIhZxLb4VGxQUdOlfHzkcjsbWdzgaMbZBQUGGYdjt9m+v2owh\nNaq+HyHJ1cuP0yMgbRt7Gtdpa7P5+VL2O+7X73mhOXVNsdlsdru9KY74dzmBG/Bd5nLDmujM\nb6JxaG0s+Dt2vsjKyurfv7/v9XNycmJjY33/Hd2SkpKioqJu3br5WN80zUOHDjUqpGPHjsXH\nxwcHB/tYv6CgoKqqqlOnTj7Wd7vd2dnZffv29T2kI0eO9OrVq1HpqVylqqurc3Jyevfu7Ufb\nsrKyf/zjHwkJCX60LSoqKi0tjYuL86Ntfn4+0KFDBz/anj59Oioqyr+f/G3s1aO27OzshIQE\n5XbXjkOHDvXt2zfgv82bm5vrdDrbt28f2G5dLtfx48f79OkT2G5psrvJmTNn3G63f38H9ipy\njSZ2IiIiItajz9iJiIiIWIQSOxERERGLUGInIiIiYhFK7EREREQsQomdiIiIiEUosRMRERGx\nCCV2IiIiIhahxE5ERETEIq6VxG7y5MmGYWzevLn+pjlz5hi1LFy4sEkjycrKGj9+fHh4eHR0\ndEpKymXrvPjii507dw4LC5s8eXJubm6TxhMTE2P8sw8++KBOnWYeImnNNmzYMHbs2LZt2xqG\ncf78+Wbb7+LFi/v27RsWFhYTE5OcnHz8+PHm2W9Lnfy+TEy5evk4j5rzXtCARYsWDR48OCIi\nomvXrmlpacXFxZet1kqixefLResJOLCs/0fTgOXLl1dVVTVQYfLkyc8++6x3uWPHjk0XycmT\nJ2+99dY777zz7bffDg4OPnz4cP06K1eufOaZZ5YtW9azZ8958+alpKTs3r276ULavn27y+Xy\nLqenp2dkZAwdOrR+tWYbImnlysrKRo8ePW7cuCeffLI59xsVFfX000937969qKjoueeemzRp\n0tGjR5tn1y1y8vs4MeUq5cs8auZ7QQNWr16dmpqalJSUm5s7f/78s2fPrl69utVGi2+Xi1YV\ncICZVnfq1Km4uLhTp04B77zzTv0KaWlpqampzRPMjBkz7rjjjobrJCUlPf74497lrKws4JNP\nPmn60EzTNIcMGTJv3rz665tziOSqsGvXLqC0tLRF9u69/p49e7YZ9tUaTv4rTUy52jU8j1rw\nXtCAFStWhIWFeTyeOutbZ7TmlS8XrTbg787ib8Wapjlz5sxnn322S5cuDVRbv359aGho9+7d\nH3/88QsXLjRdPBs3bhw4cODIkSPbt28/atSoffv21alQWVl54MCB2267zVvs169fx44dP/74\n46YL6ZIjR47s3bs3NTX1slubbYhEGnbu3Lk33nijb9++0dHRzbPHlj35G56YYlUteC9oWElJ\nifdzArVXttpor3S5aLUBB4TF34pdsmRJaGjozJkzL72pUd/IkSNHjhzZrVu3rKysn/70p7m5\nuW+++WZTBHP+/PmCgoLFixe/8MILL7300tKlS8eOHfvFF19cd911l+oUFBR4PJ7aazp06JCf\nn98U8dSxatWqgQMHJiYm1t/UbEMk0oB169ZNmzbN7Xb36dNn8+bNdW4tTaTFT/4GJqZYWAve\nCxpQWFi4ePHi2bNn11nfCqNt+HLRCgMOICsndseOHfvVr35V/6lYHdOmTfMuDB06tEOHDlOm\nTHn55ZdrH+9A8Xg8QHJy8ty5c4GkpKR33nln7dq1jzzyyKU6pmkCzXPHqhNbRkbG/PnzL7u1\n2YZIpAFjx47dv39/bm7uokWLpk+fvn37drvd3tQ7bdmTv+GJKRbWUveCBpSVlU2ZMmXQoEEL\nFiyos6kVRtvw5aIVBhxAVn4rdu/evXl5efHx8Q6HIyQkBJg4ceJ9993XQJPBgwcD3g/kBVxk\nZGRYWFifPn28xaCgoOuvv/706dO168TExNhsttqvG/Lz8zt06NAU8dT27rvv5uXlNTw4Xk06\nRCINiIqK6t+//+2337527drdu3fv2LGjmQNo/pPf94kpFtNS94IrqaiouOOOO0JDQ1evXl3/\nBVVri5Zvu1y0woADyMqJ3eTJkw8ePLh///79+/d/+umnwG9/+9tFixY10OSzzz4D4uPjmyIe\nwzCGDBnyxRdfeItut/vkyZPdunWrXSc4ODgxMXHr1q3e4qFDh/Ly8m6++eamiKe2VatWjR8/\n3pdv/DXpEIn4orq62jTNZnhcV0fzn/y+T0yxmJa6F1xWZWVlcnJyVVXVhg0bgoOD61doVdHW\ncdnLRWsOOABa8Isbzam6uppa34r99a9//cgjj3iXU1NT161b99FHHy1fvjw2NjYlJaXpwtiw\nYYPT6Xz99dcPHjw4e/bsdu3anTlzpk48y5cvDwkJycjI2LNnz9ChQ4cNG9Z08XgVFxeHhoa+\n9dZbtVe21BBJK1dYWJiZmbly5Urgww8/zMzMLCsra4b9PvDAAxs2bNizZ8/69etvueWWnj17\nXrhwoRn224In/2UnpljDleZRy94LLsvj8UycODEuLm7nzp2ZF7lcrtYZrdeVLhetNuDAukYT\nu4cffnj48OHe5alTp3bq1MnpdCYkJCxYsKCkpKRJI1m6dGn37t3DwsJGjBixb9+++vGYpvn8\n88/HxsaGhIRMmjTp66+/btJ4TNNctmxZ27ZtKyoqaq9swSGS1iw9Pb3Oi8PMzMxm2O/9998f\nFxfndDq7du06ffr0nJycZtip2aIn/2UnpljDleZRy94LLqu8vLz+IyHvI4lWGK3XlS4XrTbg\nwDJM02yKB4EiIiIi0sys/Bk7ERERkWuKEjsRERERi1BiJyIiImIRSuxERERELEKJnYiIiIhF\nKLETERERsQgldiIiIiIWocRORERExCKU2ImIiIhYhBI7EREREYtQYiciIiJiEUrsRERERCxC\niZ2IiIiIRSixExEREbEIJXYiIiIiFqHETkRERMQilNiJiIiIWIQSOxERERGLUGInIiIiYhFK\n7EREREQsQomdiIiIiEUosRMRERGxCCV2IiIiIhahxE5ERETEIpTYiYiIiFiEEjsRERERi1Bi\nJyIiImIRSuxERERELEKJnYiIiIhFKLETERERsQgldiIiIiIWocRORERExCKU2ImIiIhYhBI7\nEREREYtQYiciIiJiEUrsRERERCxCiZ2IiIiIRSixExEREbEIJXYiIiIiFqHETkRERMQilNiJ\niIiIWIQSOxERERGL+D/L6iymlZvWVwAAAABJRU5ErkJggg\u003d\u003d" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455137737773_-549089146", - "id": "20160210-215537_582262164", - "dateCreated": "2016-02-10 09:55:37.000", - "dateStarted": "2021-07-31 12:59:30.032", - "dateFinished": "2021-07-31 12:59:30.301", - "status": "FINISHED" - }, - { - "text": "%r.ir\n\nlibrary(ggplot2)\npres_rating \u003c- data.frame(\n rating \u003d as.numeric(presidents),\n year \u003d as.numeric(floor(time(presidents))),\n quarter \u003d as.numeric(cycle(presidents))\n)\np \u003c- ggplot(pres_rating, aes(x\u003dyear, y\u003dquarter, fill\u003drating))\np + geom_raster()", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:30.332", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 449.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "editorHide": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "title": false, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nAttaching package: ‘ggplot2’\n\n\nThe following object is masked from ‘package:SparkR’:\n\n expr\n\n\n\n" - }, - { - "type": "IMG", - "data": "iVBORw0KGgoAAAANSUhEUgAAA0gAAANICAIAAAByhViMAAAACXBIWXMAABJ0AAASdAHeZh94\nAAAgAElEQVR4nO3deXxU5aH4/zMhqyFssuMGFSwouNSrFNGXerEuxaK+kBYXFK+CVmu9gq2A\n3wIutL1cEau2Ki5U0VIVitQFb6l1o1irgtBbLQjWiqCoSGQL2eb3x9xfGsGGmMnJJM+836/8\nkZk5zznPhDH5eM6cOYlkMhkBANDy5WR6AgAANA5hBwAQCGEHABAIYQcAEAhhBwAQCGEHABAI\nYQcAEAhhBwAQiNxMT+BztmzZUllZmZFN5+fnJxKJnTt3ZmTrLVdBQUFhYeH27dsrKioyPZcW\npqioqKKiIlMv+JarqKgoPz9/y5Yt1dXVmZ5LC1NcXLxjxw4/ty+rdevWrVq1Ki0tzfREWp6S\nkpItW7Y0eHj79u0bcTLZo3mFXXV1dVVVVaa2nkwmM7j1FiqZTObk5PjRNYyfW8Pk5ORk9ndF\nC5VIJPzcGiCRSOTk5Pi5NYCfW0Y4FAsAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcA\nEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEH\nABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhh\nBwAQCGEHABAIYQcAEAhhBwAQCGEHABCIRDKZzPQc/qmioiInJzOtmUgkoihqVj+NFiGRSOTk\n5FRXV/vRfVk5OTnJZNLP7cvKyclJJBJVVVWZnkjLk/pPNdOzaHm85BqsVatW6fzcWrVq1YiT\nyR65mZ7A52zfvr2ioiK+9Z//6IYGj/3Lwz9JZ9NdBhyXzvChnRo+8yiKFrzXJp3hWza8k87w\n0n+8mc7wovZd0hm+z9eHpjO8amdZg8e2/8qAdDadk5efzvBP3no1neEV2z9LZ3jb/b6azvDt\nH69PZ3iXAcemM7xix9YGj920elk6my7p3iud4WWlH6cz/JNVr6UzPCc3rVdsdWV5OsNLuqX1\no6ss25bO8KryHQ0ee1bPhv+SiaLozt++ns7wqoq0tv7msw/X8WiHDh0+/fTTBq+8Y8eODR6b\nzRyKBQAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLAD\nAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISw\nAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiE\nsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAI\nhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMA\nCISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLAD\nAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISw\nAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIRBOF3VtvvXXmmWeeccYZTbM5AIAs\n1BRh99lnn02fPv3www9vgm0BAGSt2MMumUzefPPNQ4YM6d+/f9zbAgDIZrGH3dy5cysrK7/z\nne/EvSEAgCyXG+va33jjjUWLFs2cOTORSHzhAq+++uqtt95ac/Oaa67p169fnDPaEOfKASCL\ntGvXro5Hc3Jy6l6AOMQYdp9++unNN9981VVXtW/f/l8ts2XLljfffLPmZllZWW5uvK0JADSK\nPf7J9je96cX4E3/nnXc2b958/fXXp24mk8lkMnnGGWeMGDHinHPOSd15wgknvPrqqzVDSktL\nP/744/imBAA0lrr/ZHfo0GHTpk0NXnnHjh0bPDabxRh2/fr1u+2222pu/v73v1+4cOGtt95q\nxywAQBxiDLvCwsL999+/5mbqgGztewAAaESuPAEAEIimC7szzzxzwYIFTbY5AIBsY48dAEAg\nhB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBA\nIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0A\nQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQd\nAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCE\nHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAg\nhB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBA\nIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0A\nQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAgcjM9gc8pKioqLi6Ocwsb4lw5AGSRdu3a1fFo\nTk5O3QsQh+YVdjt37qysrIxv/YXtOjd47F6d9k1n08nqqnSGpym/dft0hhe0+Syd4UXtu6Qz\n/D/+vXc6w//U5ZB0hlfu2NrgsQVtOqSz6S3vr0lneH5JWv/oOzatT2d4+bbSdIbnFqX1P3hl\npR+lM3z7xw1/7nnFbdLZdJoK23ZMZ3hJt17pDP9k9evpDK+qKEtneOf+g9MZns5/6VEU7Sz9\nOI3RaT3x1un9q5X+46/pDN+yZUsdj7Zt27buBerWvn1av8SyVvMKu+rq6qqqTAYQAFBPe/yT\n7W960/MeOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCA\nQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsA\ngEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCA\nQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsA\ngEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEDkxrr2F198ceHChe+///7OnTv33nvv\nY4899jvf+U5eXl6sGwUAyE7xhl2rVq2GDBnSvXv3/Pz8t99++5e//OVnn312+eWXx7pRAIDs\nFG/YDRo0qOb7gw466N13312xYkWsWwQAyFpN9B676urqtWvXLl++/NBDD22aLQIAZJt499hF\nUVRRUXH22Wcnk8lkMvmNb3xjzJgxtR/93//93wcffLDm5oUXXtizZ884p7M5zpUDQBYpKSmp\n49FEIlH3AsQh9rDLzc299dZbKyoqVq9ePWfOnDZt2owaNarm0Y0bNy5evLjm5llnnVVQUBD3\nlACA9O3xT7a/6U0v9rBLJBL7779/FEUHHnhgTk7Oz3/+87POOqt169apRwcOHPj444/XLFxQ\nUPDpp5/GPSUAIH11/8lu27ZtaWlpg1fevn37Bo/NZrGHXW2VlZXJZLKysrLmnqKioh49etTc\nLC0traioaMopAQANU1VVleYCNLp4w+7uu+/u06dPly5dqqurV61aNXfu3COPPLJdu3axbhQA\nIDvFG3aFhYWPPvroxo0bc3JyOnfufPbZZ59++umxbhEAIGvFG3ajRo2qfaoEAEAwFi9efNJJ\nJ91///0XXnhhpufyf1wrFgBgD1atWjVlypTmf52FJj15AgCgJVq1atXUqVMPPPDAAQMG1Nx5\n4okn7tixIy8vL4MT24U9dgBA9tq+fXuDx+bk5BQWFrZq1aoR55MmYQcAZIvHHnsskUg88sgj\nU6dO7d27d35+/vXXXx9FUWlp6XXXXXf00Ud37NixoKCgV69e48eP37p1a2rUlClTUmd/nn/+\n+YlEIpFIHH/88VEULV68OJFIzJ49u/bK582b99Of/rRPnz4FBQX77bffTTfdlEwma89h/fr1\n5513Xvv27Vu3bn388ccvXbp0+PDhhYWFjfIEHYoFALLLD3/4wx49ekybNq1r166pA6nvvffe\n3XffPXz48JEjR+bn57/wwgszZsx45ZVXnn/++UQiceGFFxYUFEycOHHixIknnXRSFEV1fHbb\nD37wgz59+vzsZz9r167dPffcc9111+29996XXnpp6tHPPvvsuOOOe+edd8aOHXv44YevWLHi\n5JNP3nfffRvrqQk7ACC75OfnP/fcc7m5/6yg3r17v//++zXvlvvud787YMCASZMm/f73vx8y\nZMgBBxzQv3//KIr69u2b2ldXhw4dOjz11FOJRCKKoqOOOuqFF1742c9+VhN2//3f/71mzZq7\n7777kksuSd1z1FFHjRo1qrEuv+ZQLACQXUaPHl276qIoKigoqKm6ioqKsrKyM888M4qil19+\n+cuuPHW4NvV9Tk7OkUceuWbNmurq6tQ9CxYs6Nix40UXXVSz/HnnnbfPPvs07InsTtgBANml\nZ8+eu985e/bsQYMGFRcX5+fnFxUV9evXL4qiTZs2fdmV73JctU2bNuXl5Vu2bEndXLt27YEH\nHlj7fItEInHQQQd92a38K8IOAMguux/3nDFjxujRozt27HjPPfc899xzS5cufeKJJ6IoqtnT\nVn81u+tqq33+xBcu0Fi8xw4AyHb33ntvz549H3/88ZrqevHFF2sv0Fg11qtXr9WrV1dVVdXs\ntEsmk6tWrWqUlUf22AEA5OTkJJPJqqqq1M2qqqpp06bVXqCkpCRq0JHZXQwbNuzjjz+u+YSU\nKIoefvjh9957L83V1rDHDgDIdsOHD58yZcqpp546YsSILVu2zJ07d5cPnzv00EMLCwtvu+22\n/Pz8du3ade7c+cQTT2zAhsaPH//QQw+NHTt22bJlhx122IoVK2bPnt2vX7+1a9c2yhOxxw4A\nyHaTJk268cYb33nnnSuuuGLmzJmDBw9+9NFHay/Qtm3bhx9+uLi4+Kqrrho5cmTqY40boG3b\nti+++OKIESPmzJnz/e9/f9myZU8//fQ+++xTVFTUGM/DHjsAIGsMHz58l11xKbm5uZMmTZo0\naVLtO3dZ8swzz0x9BkqNIUOG1F7mC1d+55133nnnnbXv6dGjx8MPP1z7ntWrV++///5f5nn8\nS/bYAQA0nbKysto3f/3rX7/zzjsnn3xyo6zcHjsAgKZz2mmn9ezZ88gjj8zLy3vllVfuu+++\nHj16jBs3rlFWLuwAAJrOqaee+tBDD82bN2/btm1dunS54IILpk6d2qlTp0ZZubADAGg611xz\nzTXXXBPTyr3HDgAgEMIOACAQwg4AIBDCDgAgEMIOACAQzooFAMK3rSK58qPqRl9tl+JEz7bN\naDeZsAMAwrdxe/KWP5c3+mpP3D937GHCDgCgKSWjZLLx99hFcawzDcIOAMgOyWSmZxA7YQcA\nhC8ZJZMxhF0c60yHsAMAskMsh02FHQBAk7PHDgAgCMl43mPXvLpO2AEAWSEZy1mxkbNiAQCa\nnj12AABhiOU9ds2s7IQdAJAN4jkU28xOnmhGF8EAAIhL6uSJOL72pLq6etq0aX369CkqKure\nvfu55577j3/8o+bRJ5988rDDDissLNx3330nT55cXZ1WfQo7ACB8yShKJqsb/6seh2KnT58+\nderUCRMmrFy58qGHHlq+fPmwYcNSD7388svDhg0bPHjwn//855tuumn69Ok/+tGP0nmaDsUC\nANkhQydPvPTSS4MHDx49enQURQceeODll19++eWX79y5s6CgYPr06X369Ln99tujKOrfv//q\n1atvueWWiRMn7rXXXg2bjj12AEBWSMZjj9s9/vjjX3vttaVLl0ZRtGHDhkceeeSUU04pKCiI\nomjJkiWnnHJKzZKnnHLKtm3bli1b1uDnaI8dABC+vJzoB8d1qH3Pa+t2/H7Nti+1kr33avUf\n/9a+9j3lVXsOu3HjxpWXlx933HFRFFVWVp588smPPfZYFEXV1dUffvhh165da5ZMfb9+/fov\nNavahB0AEL6KquRPn/sozZV8vK1yl5V8o3frE3oV1z3qsccemz59+u233z5o0KB169b98Ic/\nHDFixBNPPPGvlk8kEg2eobADALJDhj6a5Oqrr77gggvGjh0bRVH//v3bt2//9a9/fenSpYMG\nDerSpcsHH3xQs2Tq+27dujV4W95jBwBkg2SUrI7la0+2b9+ek/PP4kp9X1VVFUXRMcccs2jR\nopqHFi1aVFxcfPjhhzf4SdpjBwBkhViuPFGPVZ555pl33XXXgAEDUodix48f37Nnz6997WtR\nFF1zzTWDBw++4oorxo4du3z58ptvvvnqq69u8CmxkbADALJFLIdi97zOW2+9tVOnTjfccMP7\n77/fvn37wYMHT5s2LVVvAwcOXLBgwXXXXTdr1qxOnTqNHz9+ypQp6cxG2AEAWSAZyx67+nyO\n3V577TVt2rRp06Z94aNDhw4dOnRoY01H2AEA2SCWa8UmoxiuP5sGYQcAZIcYwi5TZ9r+K3s+\nK3b79u3XXnvtK6+80gSzAQCIQzJzV55oSnsOu6KiohkzZlRUVDTBbAAA4pJMNv5XM7PnQ7GJ\nRGK//fbbsGFDE8wGACAWyVjeY9fc2q5eH1B8/vnnz5w5s7KyMu7ZAADEJZY9ds0r7Op18kTf\nvn1nz5598MEHjx49umfPngUFBbUfPeOMM+KZGwBA44nl405aYNh9+9vfTn0zYcKE3R9tbm8b\nBADYXaauPNGU6hV2jz76aNzzAACIUzKWjztpiYdihw8fHvc8AABiFNeVJ1pg2KVUVla+8cYb\nGzdu/PrXv96uXbv45gQA0PgydK3YplSvs2KjKPrVr361zz77HHnkkaeddtpbb70VRdH69es7\nd+48Z86cOKcHANAokslkdQxfLTDsnnnmmXPPPXefffaZPn16zZ3du3cfMGDAvHnzYpsbAEDj\niO3KE5l+Yp9Xr7CbNm3aYYcd9vLLL19xxRW17//617/+xhtvxDMxAIBGlaxu/K8ojhMyGq5e\nYffaa6+dd955ubm7viHPFSkAgJYhGcseu2b2Frv6nTxRVVW1y4cSp2zcuDEvL6+xpwQA0Oji\nubRrMzsWW689dn369HnppZd2uTOZTC5cuPCQQw6JYVYAAI0tlkOxLTDsLrjggkceeeT++++v\nuWfr1q2XXXbZK6+8cuGFF8Y1NQCAxhPHodhkM9tjV69DsVdeeeXixYsvuuiia6+9NoqiUaNG\nvfvuu+Xl5aeffvrFF18c8wwBABpDM4uwONRrj11ubu5vf/vbO+64o2fPnm3atNmwYcMhhxwy\nc+bM3/zmNzk59f0kPACAjIlpd10zi8X6XnmiVatW3/3ud7/73e/GOhsAgLjEca3YZhZ29drf\ndvzxxy9fvnz3+5999tnjjz++kWcEABCDmHbZZfppfU699tg9//zzmzdv3v3+jRs3Pv/88409\nJQCAGMTycSeNv8p01PdQ7BfavHlzYWFhY00FACAmqc8njmO1jb7OdNQVditWrFixYkXq+9/9\n7nfr1q2r/eimTZtuu+22vn37xjg7AIBGkcyK99jVFXbz58+fOnVq6vtp06btvkBRUdHcuXNj\nmRcAQKNKZnnYnXPOOUceeWQURaeffvq0adP69+9f81AikSgpKTnssMPatGkT+xwBANIV00eT\ntJyw69OnT58+faIomjx58siRIw844IAmmhQAQGOL5T12zWyP3Z4/7mT79u1lZWUbN25sgtkA\nAMQl9XnCjfvVzOw57IqKimbMmFFRUdEEswEAiEkyWR3DV/Nquz1/3Ekikdhvv/02bNjQBLMB\nAIhFMqbPsWteYVevK0+cf/75M2fOrKysjHs2AADxiOfCEy3o5Ikaffv2nT179sEHHzx69Oie\nPXsWFBTUfvSMM86IZ24AAI3HlSdSvv3tb6e+mTBhwu6PNrejywAAu0jG8zl29bzyRGlp6eTJ\nk+fNm7dx48Zu3bpdcsklkyZNSj305JNPTpo06a233urUqdNFF100efLknJx6HVD9QvUKu0cf\nfbTBGwAAaB4y8zl2ZWVlJ5xwQkVFxU9+8pMDDzxw06ZNW7ZsST308ssvDxs27NJLL33wwQeX\nLVt26aWXVlVV3XjjjQ2eTb3Cbvjw4Q3eAABAMxDLtWLrc3h35syZ//jHP1atWtWhQ4ddHpo+\nfXqfPn1uv/32KIr69++/evXqW265ZeLEiXvttVfDplOvsGsyhYWFhYWFcW5hc5wrB4AsUlJS\nUsejqYtUNdlk9iwZRdWZuaTYY489duKJJ06aNGnBggWtW7c+4YQTfvzjH++9995RFC1ZsuSc\nc86pWfKUU0658cYbly1bdswxxzRsOvUNu2QyuXjx4j/96U+bNm2q/vzPZebMmQ3b9u7Ky8ur\nqqoaa227yy9u2+CxhW33TmvTJe3TGf7gK2+mM3zv3vunM3zHpg/SGV5W+lE6w+/9fTqjo4O/\nndYratvG9xo8tmpnWTqbzi0qTmd4+bbSdIYnclplcHiaSnr0ztSmyzZ/nM7w3KLW6Qzf/vH6\ndIZv+2hdOsPb7ntQOsOrynekMzxNZZ9+mM7wiu2fNXjs/7Ttl86mcwuXpzM8zf9Ud+yo618t\nLy+v7gXqtsuZmo0initP7HmZNWvWrFy58swzz1y4cOHHH3/8/e9//7TTTlu6dGkURR9++GHX\nrl1rlkx9v359w/9brlfYbdmy5dRTT12yZMkXPtqIYVddXe1DVQCgRdjjn+xm9Tc9r1XOTecN\nqn3PH9/c8OSra7/USjq1LbrqW0fUvmdn5Z73AlZVVbVr1+6BBx7Iz8+PoqiwsPDEE09csmTJ\nv9otl0gkvtSsaqtX2E2ePHnp0qXTpk0744wz+vXr98QTT5SUlNx0002ffvqp8yoAgOavoqpq\n4gMvprmSjZu37bKSbx194KlHHFD3qO7du3fs2DFVdVEUHXLIIVEU/f3vfz/22GO7dOnywQf/\nPCyW+r5bt24NnmG9zqf9zW9+M2LEiAkTJvTs2TOKor333vu444576qmnkslk6u1+AADNXjKe\nrz047rjj1qxZU3N11r/+9a9RFKWa6phjjlm0aFHNkosWLSouLj788MMb/AzrFXbvv//+scce\nG0VR6oNVUjNr1arVd77zHXvsAIAWIHVJsTi+9mTcuHGlpaUXX3zxypUrn3vuucsuu+zoo48e\nNGhQFEXXXHPNqlWrrrjiipUrVz744IM333zzVVdd1eBTYqN6hl1xcXEq5vLz8wsLC2ve09em\nTZva+w8BAJqteC4ptmcHHXTQ4sWL16xZc9RRR5177rkDBw584oknUjvLBg4cuGDBgpdeeunI\nI4+cMGHC+PHjr7/++nSeY73eY9erV6+//e1vqe8PPfTQuXPnjhgxoqqq6te//vU+++yTzuYB\nAJpEvfauffm11mudgwYNeumll77woaFDhw4dOrSxplOvPXbf+MY35s2bl9ppd/HFFy9YsODA\nAw/s3bv373//+9GjRzfWVAAAYpK6pFgMX83rwqr12mN37bXXnnvuuamPr7v44otLS0vvu+++\nnJycKVOmXHvttTHPEACgMcQSYS0w7Nq2bdu27T8/2nfcuHHjxo2LbUoAAI0tGcsHFDezrmtm\nlxQDAIhHPO+xa2ZlJ+wAgKyQTDb+tWJb5HvsWreu6/KFW7dubaTJAADEJnNnxTaZeoXdkCFD\nat+srKx8++23//a3v/Xv379Xr17xTAwAoBElY9lj1xIPxS5YsGD3O+fPnz9mzJhf/epXjT0l\nAIDGloxpj13jrzId9focuy901llnDRs2bPz48Y04GwCAmMRz5YnmVXYND7soigYMGPCvPkYZ\nAKB5ydC1YptSWmfFrlixIpFINNZUAABikoznDNZm1nX1C7tXX311l3s2bdr09NNP33///Wec\ncUYMswIAaFzJKGr8kyea26HYeoXdv/3bv33h/QMHDvzZz37WqPMBAIiHDyhOueWWW2rfTCQS\nHTp0OOigg4466qh4ZgUA0KjiuqRYCwy7q666Ku55AADEq5lFWBxcUgwAyAbJeE6eaF6xKOwA\ngOwQw5UnmttewHqFXWFhYT1XV1ZWlsZkAADiEsseu5Z48sTQoUP/+te/vvnmmz169DjooIMS\nicRbb731/vvv9+3bt1+/fnFPEQAgXcmkPXb/5+qrrz755JPvu+++Cy64ICcnJ4qi6urq++67\n76qrrrrnnnsGDRoU8yQBANIVz/vhWmDYXXvttRdccMHo0aNr7snJybn44otff/31CRMmPP/8\n87FNDwCgkcTycSeNv8p01Otasa+99tqhhx66+/2HH3747helAABoblKXFItDpp/Z59Rrj11+\nfv6yZct2v/+1114rKCho7CkBAMSgmUVYHOq1x27o0KF33XXX3XffXVlZmbqnsrLyzjvvnDVr\n1umnnx7n9AAAGkNMu+uaWSzWa4/d9OnT//SnP40dO3bSpEm9e/dOJpOrV6/+5JNPDjrooP/6\nr/+Ke4oAAI0hhrNim9mb7Oq1x65r166vvfbalClTunfvvmLFipUrV/bo0WPq1ParwAYAABjc\n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\nEHYAAIEQdgAAgcjN9AQ+Jz8/Pz8/P9OzAAD2rLi4uI5HE4lE3QsQh+YVdtXV1dXV1fGtv+/r\nNzd47Ps9Dktn0+8tXZjO8EROq3SGl3Tvlc7wLRvWpjM8maxKZ/j2j9alM3zz3/+SzvCS7l9J\nZ3g68ovbpjO8qEPXdIZXV5anM7xi22fpDG+7/1fTGb41vVdsOj+6NP/VcotapzM8zX+1Dgem\n9Vvu47deSWd4WelH6Qzfq9M+6Qxvs0+fdIZv/vv/Nnhsmi/X7l87KZ3hpe/+NZ3hlZWVaS5A\no2teYVdZWVlRUZHpWQAAe7Zz5846Hi0uLq57gbqVlJQ0eGw28x47AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCA\nQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsA\ngEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQOTGuvZVq1bNmzdvzZo1GzduPOmkk773ve/FujkAgGwW7x67srKybt26nX/+\n+d26dYt1QwAAxLvHbsCAAQMGDIiiaP78+bFuCAAA77EDAAhEvHvs9ugf//jHH/7wh5qbxx13\nXOfOnTM4HwCgnoqKiup4NJFI1L0Acchw2K1Zs+a2226rudm3b9+ePXtmcD4AQD0VFxenuQCN\nLsNhd/DBB//kJz+pudmjR48tW7ZkcD4AQD3V/Se7devWW7dubfDKS0pKGjw2m2U47Dp37jxk\nyJCam6WlpTt37szgfACAeqr7T3ZxcXE6f9OFXcPEG3bl5eXr1q1LfbN169a1a9cmEgkHWwEA\n4hBv2K1bt+6qq65Kff/+++8vXbo0JydnwYIFsW4UACA7xRt2vXr1WrhwYaybAAAgxefYAQAE\nQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEA\nBELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgB\nAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELY\nAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC\n2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAE\nQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEA\nBELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgB\nAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEIjfTE/icvLy83NwYp5RIJNIYm7FNN8LwdAZn\nfPLpDk9ndLo/ugxuOu1/9IwOT2t0Joe33JlHLf23XGZfcmmMz/TM01pBUVFR3SuvewHikEgm\nk5mewz9t3749U/PJy8uLoqiioiIjW2+58vLy8vPzd+7cWVlZmem5tDAFBQWVlZVVVVWZnkgL\nU1BQkJubu2PHjurq6kzPpYUpLCzcuXNns/qd3yIUFRXl5ORs27Yt0xNpefbaa6/t27c3eHhx\ncXEjTiZ7NK89dhUVFZlNqx07dmRw6y1Ufn5+eXn5zp07Mz2RFqZVq1bl5eXl5eWZnkgL06pV\nq9zc3LKyMk38ZaX+H8zP7csqKCjIycnx16EBioqK0vm5CbuG8R47AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQCSSyWSm50AL9vLLLz/7\n7LNnnXXWV7/61UzPhazwxBNPrFixYsyYMR07dsz0XMgKs2fPXr9+/cSJEzM9EagXe+xIy6pV\nq+bPn79+/fpMT4Rs8frrr8+fP3/Lli2ZngjZ4rnnnvvNb36T6VlAfQk7AIBACDsAgEAIOwCA\nQDh5AgAgEPbYAQAEQtgBAARC2AEABCI30xOgeVm1atW8efPWrFmzcePGk0466Xvf+17NQxUV\nFfPmzXvuuec++uijjh07Dh069PTTT0899OSTT951112113PDDTcceuihqe9fffXVBx98cN26\ndW3bth0yZMjIkSMTiUSTPSOauYa95KIo2r59+0MPPbR06dLNmzd36NDhG9/4xogRI1IPeclR\nh4a95K6++uq333679noSicTcuXOLiooiLzmaE2HH55SVlXXr1m3QoEEPP/zwLg/dc889L774\n4mWXXfaVr3xl9erVv/jFLxKJxNChQ1OPlpSU3HDDDTULd+/ePfXN3/72txtvvPHUU0+9+uqr\n16xZ8/Of/7y6uvq8885rmqdD89ewl1x5efnEiROrqqpGjRrVvXv3LVu27NixIzXKS466Newl\nN27cuJ07d9Ys+dOf/rRHjx6pqvOSo1kRdnzOgAEDBgwYEEXR/Pnza9+fTCafffbZ4cOHH3vs\nsVEUde/efd26dY888shpp52Wk5MTRVGrVq169eq1+wrnz5/fo0ePsWPHRlG0//77b9iw4fHH\nHz/77LMLCgqa4vnQ7DXsJbdw4cKPPvrozjvvLCkp2WWFXnLUrWEvuR49etQs+fbbb2/YsOGS\nSy5J3fSSo1nxHjvqpbq6urKysvbvqcLCws2bN7///vupm1u2bBk1atQ555zzgx/8YMmSJTWL\nvfnmm0cccUTNzSOOOKKsrGzt2rVNNnNaqLpfcn/84x8HDBgwZ86cCy64YOzYsXfccUfNRca8\n5GiYPf6Wq/HUU0916dLla1/7WuqmlxzNirCjXlq1anX44Yc/+eST7777bjKZXLt27ZNPPhlF\n0SeffBJF0b777nvZZZdNmjRpwoQJ++23309/+tOFCxdGUZRMJjdv3ty+ffua9aS+37RpU4ae\nBy1G3S+5DRs2/OlPf9q6det11103ZsyYlStXTp06NZlMesnRYHW/5Gps3br1hRdeOOWUU1Lv\novOSo7lxKJb6uvLKK3/xi19ceeWViUSipKTkhBNOWLBgQeo4bM2hjSiK+vfvv23btnnz5n3r\nW9/K6Hxp8ep4yVVXVxcXF//nf/5nbm5uFEX5+fmTJk3661//2q9fv0zPmhasjpdcjcWLFyeT\nySFDhmRqklA3YUd9tWvXbsKECZWVlamTEJ955pkoirp167b7kn379l2yZEllZWVubm67du0+\n/fTTmodS33fo0KHJpk3LVcdLrkOHDm3atElVXRRF++23XxRFGzduPPjgg73kaLA9/pZLJpNP\nP/30Mccc07Zt29Q9iUTCS45mxaFYvpzc3NyOHTtGUfTUU08deOCBnTp12n2ZN998s127dqk/\nun379n399ddrHnr99dcLCwu/8DQL+EJf+JI75JBDPvjgg6qqqtQy7733XhRFXbp0ibzkSFsd\nv+WWLVu2YcOGU089tfbyXnI0K62mTJmS6TnQjJSXl7/77ruffvrpiy++WFRU1KNHj5q3j6xY\nseK1116rrKx8++2377rrrnfffffaa6/de++9oyi64447tm7dWlZWtn79+kcfffS5554bOXJk\n3759oyjq3Lnz/PnzS0tLO3XqtGzZsgceeGDYsGG132hMlmvYS65Hjx4LFy784IMPunXr9t57\n7915551du3Y955xzEomElxx1a9hLLuXee+/Ny8sbNWpU7RV6ydGsJJLJZKbnQDOydu3aq666\nqvY9OTk5CxYsiKLoL3/5y1133bV+/fq8vLx+/fqdd955Nf9LOmvWrFdfffWTTz7Jz8/v0aPH\nt771rdTnBaT8+c9/njNnznvvvZf66M7UX9+mfFI0Zw17yUVR9NZbb91///1r1qxp3br1EUcc\nceGFF7Zp0yb1kJccdWjwS+6jjz665JJLxo4du8seu8hLjuZE2AEABMJ77AAAAiHsAAACIewA\nAAIh7AAAAiHsAAACIewAAAIh7AAAAiHsAAACIewAAAIh7IBwbN++PdNTAMgkYQc0vj/84Q+J\nROKGG27Y5f7zzz8/Nzd33bp1qZuVlZUzZsw47LDDioqKSkpKjj/++P/5n/+pWbi0tPS66647\n+uijO3bsWFBQ0KtXr/Hjx2/durVmgcceeyyRSDzyyCNTp07t3bt3fn7+9ddf3wTPDqDZcq1Y\nIBZf/epXy8rK1q5dm5Pzf/8DuXnz5u7du//7v//7b3/72yiKqqqqTj/99Geeeebss88ePHhw\nWVnZnDlzVqxY8dBDD40cOTKKor/85S8nnnji8OHD+/Tpk5+f/8ILLzzyyCODBw9+/vnnU1dY\nf+yxx84+++wDDjigR48e3//+97t27ZqXlzdw4MAMPmuADEsCxODmm2+OouiZZ56puee2226L\nomjhwoWpm3fccUcURffdd1/NAuXl5UcccUSXLl0qKiqSyWRZWVl5eXntdd50001RFP3ud79L\n3Xz00UejKOrTp09qeQAcigViceGFFxYWFs6aNavmnlmzZu2zzz6nnXZa6uYDDzzQuXPnkSNH\nlv3/qqqqRo4c+eGHH77xxhtRFBUUFOTl5aUWrqioKCsrO/PMM6Moevnll2tvaPTo0bm5uU30\nrACaN78NgVh06NBh+PDhjzzyyEcffdSpU6dXXnllxYoVP/rRj1q1apVa4M033/zss8+Kiop2\nH7tx48bUN7Nnz7777rvfeOON2mdFbNq0qfbCPXv2jO1JALQwwg6Iy6WXXjpnzpwHHnhg3Lhx\ns2bNysnJ+Y//+I+aR6urq3v37v3AAw/sPvCrX/1qFEUzZswYN27c6aeffs8993Tv3r2goOCT\nTz4ZOnRodXV17YULCgrifiIALYWwA+JyzDHHHHLIIffcc8+YMWPmzp178skn77fffjWP9unT\n5y9/+cshhxzSunXrLxx+77339uzZ8/HHH0+dKhFF0YsvvtgU8wZosbzHDojR2LFj33rrrSuu\nuGLr1q1jxoyp/dCoUaPKy8vHjx+f/Py5+evXr099k5OTk0wmq6qqUjerqqqmTZvWNNMGaKHs\nsQNidP755//whz984IEHunXrNnTo0NoPXX755YsXL77rrruWLVs2bNiwTp06vffee0uXLn3j\njTdS77EbPnz4lClTTj311BEjRmzZsmXu3LlJH88EUCdhB8Sobdu23/72t++///6LLrpol3NX\nc3NzH3/88VmzZs2ePfvHP/5xZWVl165dDzvssBkzZqQWmDRpUm5u7v3333/FFVd06dJl+PDh\nV155pVMlAOrgA4qBeF166aWzZs1as2bNAQcckOm5AARO2AEx+vTTT/fdd9/jjjvuqaeeyvRc\nAMLnUCwQi+XLl69cufK+++7bvn37xIkTMz0dgKzgrFggFnPmzBk1atTbb799xx13DB48ONPT\nAcgKDsUCAATCHjsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgED8f8EKN7rwbcpj\nAAAAAElFTkSuQmCC" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1438930880648_-1572054429", - "id": "20150807-090120_1060568667", - "dateCreated": "2015-08-07 09:01:20.000", - "dateStarted": "2021-07-31 12:59:30.337", - "dateFinished": "2021-07-31 12:59:31.004", - "status": "FINISHED" - }, - { - "title": "GoogleViz: Bubble Chart", - "text": "%r.ir\n\nlibrary(googleVis)\nbubble \u003c- gvisBubbleChart(Fruits, idvar\u003d\"Fruit\", \n xvar\u003d\"Sales\", yvar\u003d\"Expenses\",\n colorvar\u003d\"Year\", sizevar\u003d\"Profit\",\n options\u003dlist(\n hAxis\u003d\u0027{minValue:75, maxValue:125}\u0027))\nprint(bubble, tag \u003d \u0027chart\u0027)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:31.038", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "editorMode": "ace/mode/r", - "title": false, - "results": [ - { - "graph": { - "mode": "table", - "height": 189.6666717529297, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "editorHide": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003c!-- BubbleChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\u003c!-- Sat Jul 31 12:59:31 2021 --\u003e\n\n\n\u003c!-- jsHeader --\u003e\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataBubbleChartID34f780e322 () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"Apples\",\n98,\n78,\n2008,\n20\n],\n[\n\"Apples\",\n111,\n79,\n2009,\n32\n],\n[\n\"Apples\",\n89,\n76,\n2010,\n13\n],\n[\n\"Oranges\",\n96,\n81,\n2008,\n15\n],\n[\n\"Bananas\",\n85,\n76,\n2008,\n9\n],\n[\n\"Oranges\",\n93,\n80,\n2009,\n13\n],\n[\n\"Bananas\",\n94,\n78,\n2009,\n16\n],\n[\n\"Oranges\",\n98,\n91,\n2010,\n7\n],\n[\n\"Bananas\",\n81,\n71,\n2010,\n10\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027Fruit\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Sales\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Expenses\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Year\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Profit\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartBubbleChartID34f780e322() {\nvar data \u003d gvisDataBubbleChartID34f780e322();\nvar options \u003d {};\noptions[\"hAxis\"] \u003d {minValue:75, maxValue:125};\n\n\n var chart \u003d new google.visualization.BubbleChart(\n document.getElementById(\u0027BubbleChartID34f780e322\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartBubbleChartID34f780e322);\n})();\nfunction displayChartBubbleChartID34f780e322() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\u003c!-- jsChart --\u003e \n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartBubbleChartID34f780e322\"\u003e\u003c/script\u003e\n \n\u003c!-- divChart --\u003e\n \n\u003cdiv id\u003d\"BubbleChartID34f780e322\" \n style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455141578555_-1713165000", - "id": "20160210-225938_1538591791", - "dateCreated": "2016-02-10 10:59:38.000", - "dateStarted": "2021-07-31 12:59:31.042", - "dateFinished": "2021-07-31 12:59:31.102", - "status": "FINISHED" - }, - { - "title": "GoogleViz: Geo Chart", - "text": "%r.ir\n\nlibrary(googleVis)\ngeo \u003d gvisGeoChart(Exports, locationvar \u003d \"Country\", colorvar\u003d\"Profit\", options\u003dlist(Projection \u003d \"kavrayskiy-vii\"))\nprint(geo, tag \u003d \u0027chart\u0027)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:31.142", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 336.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - }, - "editorHide": false, - "title": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003c!-- GeoChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\u003c!-- Sat Jul 31 12:59:31 2021 --\u003e\n\n\n\u003c!-- jsHeader --\u003e\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataGeoChartID34f7ca42969 () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"Germany\",\n3\n],\n[\n\"Brazil\",\n4\n],\n[\n\"United States\",\n5\n],\n[\n\"France\",\n4\n],\n[\n\"Hungary\",\n3\n],\n[\n\"India\",\n2\n],\n[\n\"Iceland\",\n1\n],\n[\n\"Norway\",\n4\n],\n[\n\"Spain\",\n5\n],\n[\n\"Turkey\",\n1\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027Country\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Profit\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartGeoChartID34f7ca42969() {\nvar data \u003d gvisDataGeoChartID34f7ca42969();\nvar options \u003d {};\noptions[\"width\"] \u003d 556;\noptions[\"height\"] \u003d 347;\noptions[\"Projection\"] \u003d \"kavrayskiy-vii\";\n\n\n var chart \u003d new google.visualization.GeoChart(\n document.getElementById(\u0027GeoChartID34f7ca42969\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"geochart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartGeoChartID34f7ca42969);\n})();\nfunction displayChartGeoChartID34f7ca42969() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\u003c!-- jsChart --\u003e \n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartGeoChartID34f7ca42969\"\u003e\u003c/script\u003e\n \n\u003c!-- divChart --\u003e\n \n\u003cdiv id\u003d\"GeoChartID34f7ca42969\" \n style\u003d\"width: 556; height: 347;\"\u003e\n\u003c/div\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455140544963_1486338978", - "id": "20160210-224224_735421242", - "dateCreated": "2016-02-10 10:42:24.000", - "dateStarted": "2021-07-31 12:59:31.147", - "dateFinished": "2021-07-31 12:59:31.205", - "status": "FINISHED" - }, - { - "text": "%md\n\n## Congratulations, it\u0027s done.\n### You can create your own notebook in \u0027Notebook\u0027 menu. Good luck!", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:59:31.247", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "markdown", - "editOnDblClick": true - }, - "editorMode": "ace/mode/markdown", - "editorHide": true, - "tableHide": false, - "fontSize": 9.0, - "runOnSelectionChange": true, - "title": false, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003ch2\u003eCongratulations, it\u0026rsquo;s done.\u003c/h2\u003e\n\u003ch3\u003eYou can create your own notebook in \u0026lsquo;Notebook\u0026rsquo; menu. Good luck!\u003c/h3\u003e\n\n\u003c/div\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1485626988585_-946362813", - "id": "20170129-030948_1379298104", - "dateCreated": "2017-01-29 03:09:48.000", - "dateStarted": "2021-07-31 12:59:31.252", - "dateFinished": "2021-07-31 12:59:31.260", - "status": "FINISHED" - } - ], - "name": "1. R Basics", - "id": "2BWJFTXKJ", - "defaultInterpreterGroup": "spark", - "noteParams": {}, - "noteForms": {}, - "angularObjects": {}, - "config": { - "looknfeel": "default", - "isZeppelinNotebookCronEnable": false - }, - "info": { - "isRunning": true - } -} \ No newline at end of file diff --git a/notebook/R Tutorial/2. Shiny App_2EZ66TM57.zpln b/notebook/R Tutorial/2. Shiny App_2EZ66TM57.zpln deleted file mode 100644 index 270a139d28c..00000000000 --- a/notebook/R Tutorial/2. Shiny App_2EZ66TM57.zpln +++ /dev/null @@ -1,219 +0,0 @@ -{ - "paragraphs": [ - { - "title": "Introduction", - "text": "%md\n\n[Shiny](https://shiny.rstudio.com/tutorial/) is an R package that makes it easy to build interactive web applications (apps) straight from R. For developing one Shiny App in Zeppelin, you need to at least 3 paragraphs (server paragraph, ui paragraph and run type paragraph)\n", - "user": "anonymous", - "dateUpdated": "2020-02-05 13:31:39.977", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "text", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/text", - "editorHide": true, - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003cp\u003e\u003ca href\u003d\"https://shiny.rstudio.com/tutorial/\"\u003eShiny\u003c/a\u003e is an R package that makes it easy to build interactive web applications (apps) straight from R. For developing one Shiny App in Zeppelin, you need to at least 3 paragraphs (server paragraph, ui paragraph and run type paragraph)\u003c/p\u003e\n\n\u003c/div\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580880646006_750270749", - "id": "paragraph_1580880646006_750270749", - "dateCreated": "2020-02-05 13:30:46.006", - "dateStarted": "2020-02-05 13:31:30.246", - "dateFinished": "2020-02-05 13:31:30.260", - "status": "FINISHED" - }, - { - "title": "Shiny Server", - "text": "%r.shiny(type\u003dserver)\n\n# Define server logic to summarize and view selected dataset ----\nserver \u003c- function(input, output) {\n\n # Return the requested dataset ----\n datasetInput \u003c- reactive({\n switch(input$dataset,\n \"rock\" \u003d rock,\n \"pressure\" \u003d pressure,\n \"cars\" \u003d cars)\n })\n\n # Generate a summary of the dataset ----\n output$summary \u003c- renderPrint({\n dataset \u003c- datasetInput()\n summary(dataset)\n })\n\n # Show the first \"n\" observations ----\n output$view \u003c- renderTable({\n head(datasetInput(), n \u003d input$obs)\n })\n\n}", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:35:50.786", - "progress": 0, - "config": { - "colWidth": 6.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r", - "type": "server", - "runOnSelectionChange": true, - "title": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "Write server.R to /tmp/zeppelin-shiny626071477036151736 successfully." - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580562566379_-876908296", - "id": "paragraph_1580562566379_-876908296", - "dateCreated": "2020-02-01 21:09:26.379", - "dateStarted": "2021-07-31 12:35:50.806", - "dateFinished": "2021-07-31 12:35:56.193", - "status": "FINISHED" - }, - { - "title": "Shiny UI", - "text": "%r.shiny(type\u003dui)\n\n# Define UI for dataset viewer app ----\nui \u003c- fluidPage(\n\n # App title ----\n titlePanel(\"Shiny Text\"),\n\n # Sidebar layout with a input and output definitions ----\n sidebarLayout(\n\n # Sidebar panel for inputs ----\n sidebarPanel(\n \n # Input: Selector for choosing dataset ----\n selectInput(inputId \u003d \"dataset\",\n label \u003d \"Choose a dataset:\",\n choices \u003d c(\"rock\", \"pressure\", \"cars\")),\n \n # Input: Numeric entry for number of obs to view ----\n numericInput(inputId \u003d \"obs\",\n label \u003d \"Number of observations to view:\",\n value \u003d 10)\n ),\n\n # Main panel for displaying outputs ----\n mainPanel(\n \n # Output: Verbatim text for data summary ----\n verbatimTextOutput(\"summary\"),\n \n # Output: HTML table with requested number of observations ----\n tableOutput(\"view\")\n \n )\n )\n)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:36:00.769", - "progress": 0, - "config": { - "runOnSelectionChange": true, - "title": true, - "checkEmpty": true, - "colWidth": 6.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r", - "type": "ui" - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "Write ui.R to /tmp/zeppelin-shiny626071477036151736 successfully." - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580562634044_-1915679343", - "id": "paragraph_1580562634044_-1915679343", - "dateCreated": "2020-02-01 21:10:34.044", - "dateStarted": "2021-07-31 12:36:00.774", - "dateFinished": "2021-07-31 12:36:00.780", - "status": "FINISHED" - }, - { - "title": "Shiny App", - "text": "%r.shiny(type\u003drun)\n\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:36:03.415", - "progress": 0, - "config": { - "runOnSelectionChange": true, - "title": true, - "checkEmpty": true, - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r", - "type": "run" - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003ciframe src\u003d\"http://172.17.0.2:6789\" height \u003d\"500px\" width\u003d\"100%\" frameBorder\u003d\"0\"\u003e\u003c/iframe\u003e\n" - }, - { - "type": "TEXT", - "data": " 123: \u001b[37mhead.data.frame\u001b[39m\n 120: \u001b[34m\u001b[1mrenderTable [/tmp/zeppelin-shiny626071477036151736/server.R#22]\u001b[22m\u001b[39m\n 119: \u001b[37mfunc\u001b[39m\n 106: \u001b[37mrenderFunc\u001b[39m\n 105: \u001b[37moutput$view\u001b[39m\n 25: \u001b[37mrunApp\u001b[39m\nWarning message:\n“Error in if: missing value where TRUE/FALSE needed”\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580562660988_2021181385", - "id": "paragraph_1580562660988_2021181385", - "dateCreated": "2020-02-01 21:11:00.988", - "dateStarted": "2021-07-31 12:36:03.419", - "dateFinished": "2021-07-31 12:36:38.525", - "status": "ABORT" - }, - { - "text": "%r.shiny\n", - "user": "anonymous", - "dateUpdated": "2021-06-15 04:12:42.535", - "progress": 0, - "config": {}, - "settings": { - "params": {}, - "forms": {} - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1623730362535_1317534129", - "id": "paragraph_1623730362535_1317534129", - "dateCreated": "2021-06-15 04:12:42.535", - "status": "READY" - } - ], - "name": "2. Shiny App", - "id": "2EZ66TM57", - "defaultInterpreterGroup": "spark", - "version": "0.9.0-SNAPSHOT", - "noteParams": {}, - "noteForms": {}, - "angularObjects": {}, - "config": { - "isZeppelinNotebookCronEnable": false - }, - "info": {} -} \ No newline at end of file diff --git a/notebook/R Tutorial/3. R Conda Env in Yarn Mode_2GB9HRSH9.zpln b/notebook/R Tutorial/3. R Conda Env in Yarn Mode_2GB9HRSH9.zpln deleted file mode 100644 index 288dc22ac7b..00000000000 --- a/notebook/R Tutorial/3. R Conda Env in Yarn Mode_2GB9HRSH9.zpln +++ /dev/null @@ -1,401 +0,0 @@ -{ - "paragraphs": [ - { - "text": "%md\n\nThis tutorial is for how to use customize R runtime environment via conda in yarn mode.\nIn this approach, the R interpreter runs in yarn container instead of in the zeppelin server host. And remmeber this only works for IRKernel(`%r.ir`) but not for vanilla R(`%r.r`), so make sure you include the following python packages in your conda env.\n* python\n* jupyter\n* grpcio\n* protobuf\n* r-base\n* r-essentials\n* r-irkernel\n\n\n\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:55:29.815", - "progress": 0, - "config": { - "tableHide": false, - "editorSetting": { - "language": "markdown", - "editOnDblClick": true, - "completionKey": "TAB", - "completionSupport": false - }, - "colWidth": 12.0, - "editorMode": "ace/mode/markdown", - "fontSize": 9.0, - "editorHide": false, - "title": false, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "
    \n

    This tutorial is for how to use customize R runtime environment via conda in yarn mode.
    \nIn this approach, the R interpreter runs in yarn container instead of in the zeppelin server host. And remmeber this only works for IRKernel(%r.ir) but not for vanilla R(%r.r), so make sure you include the following python packages in your conda env.

    \n
      \n
    • python
    • \n
    • jupyter
    • \n
    • grpcio
    • \n
    • protobuf
    • \n
    • r-base
    • \n
    • r-essentials
    • \n
    • r-irkernel
    • \n
    \n\n
    " - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096909_1969681448", - "id": "paragraph_1616510705826_532544979", - "dateCreated": "2021-06-19 21:58:16.909", - "dateStarted": "2021-08-09 10:55:29.817", - "dateFinished": "2021-08-09 10:55:29.825", - "status": "FINISHED" - }, - { - "title": "Create R conda env", - "text": "%sh\n\n# make sure you have miniconda, conda-pack and mamba installed.\n# install miniconda: https://docs.conda.io/en/latest/miniconda.html\n# install conda-pack: https://conda.github.io/conda-pack/\n# install mamba: https://github.com/mamba-org/mamba\n\necho \"name: r_env\nchannels:\n - conda-forge\n - defaults\ndependencies:\n - python=3.7 \n - jupyter\n - grpcio\n - protobuf\n - r-base=3\n - r-essentials\n - r-evaluate\n - r-base64enc\n - r-knitr\n - r-ggplot2\n - r-irkernel\n - r-shiny\n - r-googlevis\" > r_env.yml\n \nmamba env remove -n r_env\nmamba env create -f r_env.yml\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:55:29.917", - "progress": 0, - "config": { - "editorSetting": { - "language": "sh", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": false - }, - "colWidth": 12.0, - "editorMode": "ace/mode/sh", - "fontSize": 9.0, - "title": true, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nRemove all packages in environment /mnt/disk1/jzhang/miniconda3/envs/r_env:\n\npkgs/main/noarch \npkgs/main/linux-64 \npkgs/r/linux-64 \nconda-forge/noarch \npkgs/r/noarch \nconda-forge/linux-64 \nTransaction\n\n Prefix: /mnt/disk1/jzhang/miniconda3/envs/r_env\n\n Updating specs:\n\n - python=3.7\n - jupyter\n - grpcio\n - protobuf\n - r-base=3\n - r-essentials\n - r-evaluate\n - r-base64enc\n - r-knitr\n - r-ggplot2\n - r-irkernel\n - r-shiny\n - r-googlevis\n\n\n Package Version Build Channel Size\n────────────────────────────────────────────────────────────────────────────────────────────────────────\n Install:\n────────────────────────────────────────────────────────────────────────────────────────────────────────\n\n + _libgcc_mutex 0.1 conda_forge conda-forge/linux-64 Cached\n + _openmp_mutex 4.5 1_gnu conda-forge/linux-64 Cached\n + _r-mutex 1.0.1 anacondar_1 conda-forge/noarch Cached\n + alsa-lib 1.2.3 h516909a_0 conda-forge/linux-64 Cached\n + argon2-cffi 20.1.0 py37h5e8e339_2 conda-forge/linux-64 Cached\n + async_generator 1.10 py_0 conda-forge/noarch Cached\n + attrs 21.2.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + backcall 0.2.0 pyh9f0ad1d_0 conda-forge/noarch Cached\n + backports 1.0 py_2 conda-forge/noarch Cached\n + backports.functools_lru_cache 1.6.4 pyhd8ed1ab_0 conda-forge/noarch Cached\n + binutils_impl_linux-64 2.36.1 h193b22a_2 conda-forge/linux-64 Cached\n + binutils_linux-64 2.36 hf3e587d_0 conda-forge/linux-64 Cached\n + bleach 4.0.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + bwidget 1.9.14 ha770c72_0 conda-forge/linux-64 Cached\n + bzip2 1.0.8 h7f98852_4 conda-forge/linux-64 Cached\n + c-ares 1.17.1 h7f98852_1 conda-forge/linux-64 Cached\n + ca-certificates 2021.5.30 ha878542_0 conda-forge/linux-64 Cached\n + cairo 1.16.0 h6cf1ce9_1008 conda-forge/linux-64 Cached\n + certifi 2021.5.30 py37h89c1867_0 conda-forge/linux-64 Cached\n + cffi 1.14.6 py37hc58025e_0 conda-forge/linux-64 Cached\n + curl 7.78.0 hea6ffbf_0 conda-forge/linux-64 Cached\n + dbus 1.13.6 h48d8840_2 conda-forge/linux-64 Cached\n + debugpy 1.4.1 py37hcd2ae1e_0 conda-forge/linux-64 Cached\n + decorator 5.0.9 pyhd8ed1ab_0 conda-forge/noarch Cached\n + defusedxml 0.7.1 pyhd8ed1ab_0 conda-forge/noarch Cached\n + entrypoints 0.3 py37hc8dfbb8_1002 conda-forge/linux-64 Cached\n + expat 2.4.1 h9c3ff4c_0 conda-forge/linux-64 Cached\n + font-ttf-dejavu-sans-mono 2.37 hab24e00_0 conda-forge/noarch Cached\n + font-ttf-inconsolata 3.000 h77eed37_0 conda-forge/noarch Cached\n + font-ttf-source-code-pro 2.038 h77eed37_0 conda-forge/noarch Cached\n + font-ttf-ubuntu 0.83 hab24e00_0 conda-forge/noarch Cached\n + fontconfig 2.13.1 hba837de_1005 conda-forge/linux-64 Cached\n + fonts-conda-ecosystem 1 0 conda-forge/noarch Cached\n + fonts-conda-forge 1 0 conda-forge/noarch Cached\n + freetype 2.10.4 h0708190_1 conda-forge/linux-64 Cached\n + fribidi 1.0.10 h36c2ea0_0 conda-forge/linux-64 Cached\n + gcc_impl_linux-64 9.4.0 h03d3576_8 conda-forge/linux-64 Cached\n + gcc_linux-64 9.4.0 h391b98a_0 conda-forge/linux-64 Cached\n + gettext 0.19.8.1 h0b5b191_1005 conda-forge/linux-64 Cached\n + gfortran_impl_linux-64 9.4.0 h0003116_8 conda-forge/linux-64 Cached\n + gfortran_linux-64 9.4.0 hf0ab688_0 conda-forge/linux-64 Cached\n + glib 2.68.3 h9c3ff4c_0 conda-forge/linux-64 Cached\n + glib-tools 2.68.3 h9c3ff4c_0 conda-forge/linux-64 Cached\n + graphite2 1.3.13 h58526e2_1001 conda-forge/linux-64 Cached\n + grpcio 1.38.1 py37hb27c1af_0 conda-forge/linux-64 Cached\n + gsl 2.6 he838d99_2 conda-forge/linux-64 Cached\n + gst-plugins-base 1.18.4 hf529b03_2 conda-forge/linux-64 Cached\n + gstreamer 1.18.4 h76c114f_2 conda-forge/linux-64 Cached\n + gxx_impl_linux-64 9.4.0 h03d3576_8 conda-forge/linux-64 Cached\n + gxx_linux-64 9.4.0 h0316aca_0 conda-forge/linux-64 Cached\n + harfbuzz 2.8.2 h83ec7ef_0 conda-forge/linux-64 Cached\n + icu 68.1 h58526e2_0 conda-forge/linux-64 Cached\n + importlib-metadata 3.10.1 py37h89c1867_0 conda-forge/linux-64 Cached\n + importlib_metadata 3.10.1 hd8ed1ab_0 conda-forge/noarch Cached\n + ipykernel 6.0.3 py37h085eea5_0 conda-forge/linux-64 Cached\n + ipython 7.26.0 py37h6531663_0 conda-forge/linux-64 Cached\n + ipython_genutils 0.2.0 py_1 conda-forge/noarch Cached\n + ipywidgets 7.6.3 pyhd3deb0d_0 conda-forge/noarch Cached\n + jbig 2.1 h7f98852_2003 conda-forge/linux-64 Cached\n + jedi 0.18.0 py37h89c1867_2 conda-forge/linux-64 Cached\n + jinja2 3.0.1 pyhd8ed1ab_0 conda-forge/noarch Cached\n + jpeg 9d h36c2ea0_0 conda-forge/linux-64 Cached\n + jsonschema 3.2.0 py37hc8dfbb8_1 conda-forge/linux-64 Cached\n + jupyter 1.0.0 py37h89c1867_6 conda-forge/linux-64 Cached\n + jupyter_client 6.1.12 pyhd8ed1ab_0 conda-forge/noarch Cached\n + jupyter_console 6.4.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + jupyter_core 4.7.1 py37h89c1867_0 conda-forge/linux-64 Cached\n + jupyterlab_pygments 0.1.2 pyh9f0ad1d_0 conda-forge/noarch Cached\n + jupyterlab_widgets 1.0.0 pyhd8ed1ab_1 conda-forge/noarch Cached\n + kernel-headers_linux-64 2.6.32 he073ed8_14 conda-forge/noarch Cached\n + krb5 1.19.2 hcc1bbae_0 conda-forge/linux-64 Cached\n + ld_impl_linux-64 2.36.1 hea4e1c9_2 conda-forge/linux-64 Cached\n + lerc 2.2.1 h9c3ff4c_0 conda-forge/linux-64 Cached\n + libblas 3.9.0 10_openblas conda-forge/linux-64 Cached\n + libcblas 3.9.0 10_openblas conda-forge/linux-64 Cached\n + libclang 11.1.0 default_ha53f305_1 conda-forge/linux-64 Cached\n + libcurl 7.78.0 h2574ce0_0 conda-forge/linux-64 Cached\n + libdeflate 1.7 h7f98852_5 conda-forge/linux-64 Cached\n + libedit 3.1.20191231 he28a2e2_2 conda-forge/linux-64 Cached\n + libev 4.33 h516909a_1 conda-forge/linux-64 Cached\n + libevent 2.1.10 hcdb4288_3 conda-forge/linux-64 Cached\n + libffi 3.3 h58526e2_2 conda-forge/linux-64 Cached\n + libgcc-devel_linux-64 9.4.0 hd854feb_8 conda-forge/linux-64 Cached\n + libgcc-ng 11.1.0 hc902ee8_8 conda-forge/linux-64 Cached\n + libgfortran-ng 11.1.0 h69a702a_8 conda-forge/linux-64 Cached\n + libgfortran5 11.1.0 h6c583b3_8 conda-forge/linux-64 Cached\n + libglib 2.68.3 h3e27bee_0 conda-forge/linux-64 Cached\n + libgomp 11.1.0 hc902ee8_8 conda-forge/linux-64 Cached\n + libiconv 1.16 h516909a_0 conda-forge/linux-64 Cached\n + liblapack 3.9.0 10_openblas conda-forge/linux-64 Cached\n + libllvm11 11.1.0 hf817b99_2 conda-forge/linux-64 Cached\n + libnghttp2 1.43.0 h812cca2_0 conda-forge/linux-64 Cached\n + libogg 1.3.4 h7f98852_1 conda-forge/linux-64 Cached\n + libopenblas 0.3.17 pthreads_h8fe5266_1 conda-forge/linux-64 Cached\n + libopus 1.3.1 h7f98852_1 conda-forge/linux-64 Cached\n + libpng 1.6.37 h21135ba_2 conda-forge/linux-64 Cached\n + libpq 13.3 hd57d9b9_0 conda-forge/linux-64 Cached\n + libprotobuf 3.17.2 h780b84a_1 conda-forge/linux-64 Cached\n + libsanitizer 9.4.0 h79bfe98_8 conda-forge/linux-64 Cached\n + libsodium 1.0.18 h36c2ea0_1 conda-forge/linux-64 Cached\n + libssh2 1.9.0 ha56f1ee_6 conda-forge/linux-64 Cached\n + libstdcxx-devel_linux-64 9.4.0 hd854feb_8 conda-forge/linux-64 Cached\n + libstdcxx-ng 11.1.0 h56837e0_8 conda-forge/linux-64 Cached\n + libtiff 4.3.0 hf544144_1 conda-forge/linux-64 Cached\n + libuuid 2.32.1 h7f98852_1000 conda-forge/linux-64 Cached\n + libvorbis 1.3.7 h9c3ff4c_0 conda-forge/linux-64 Cached\n + libwebp-base 1.2.0 h7f98852_2 conda-forge/linux-64 Cached\n + libxcb 1.13 h7f98852_1003 conda-forge/linux-64 Cached\n + libxkbcommon 1.0.3 he3ba5ed_0 conda-forge/linux-64 Cached\n + libxml2 2.9.12 h72842e0_0 conda-forge/linux-64 Cached\n + lz4-c 1.9.3 h9c3ff4c_1 conda-forge/linux-64 Cached\n + make 4.3 hd18ef5c_1 conda-forge/linux-64 Cached\n + markupsafe 2.0.1 py37h5e8e339_0 conda-forge/linux-64 Cached\n + matplotlib-inline 0.1.2 pyhd8ed1ab_2 conda-forge/noarch Cached\n + mistune 0.8.4 py37h5e8e339_1004 conda-forge/linux-64 Cached\n + mysql-common 8.0.25 ha770c72_2 conda-forge/linux-64 Cached\n + mysql-libs 8.0.25 hfa10184_2 conda-forge/linux-64 Cached\n + nbclient 0.5.3 pyhd8ed1ab_0 conda-forge/noarch Cached\n + nbconvert 6.1.0 py37h89c1867_0 conda-forge/linux-64 Cached\n + nbformat 5.1.3 pyhd8ed1ab_0 conda-forge/noarch Cached\n + ncurses 6.2 h58526e2_4 conda-forge/linux-64 Cached\n + nest-asyncio 1.5.1 pyhd8ed1ab_0 conda-forge/noarch Cached\n + notebook 6.4.2 pyha770c72_0 conda-forge/noarch Cached\n + nspr 4.30 h9c3ff4c_0 conda-forge/linux-64 Cached\n + nss 3.69 hb5efdd6_0 conda-forge/linux-64 Cached\n + openssl 1.1.1k h7f98852_0 conda-forge/linux-64 Cached\n + packaging 21.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + pandoc 2.14.1 h7f98852_0 conda-forge/linux-64 Cached\n + pandocfilters 1.4.2 py_1 conda-forge/noarch Cached\n + pango 1.48.7 hb8ff022_0 conda-forge/linux-64 Cached\n + parso 0.8.2 pyhd8ed1ab_0 conda-forge/noarch Cached\n + pcre 8.45 h9c3ff4c_0 conda-forge/linux-64 Cached\n + pexpect 4.8.0 py37hc8dfbb8_1 conda-forge/linux-64 Cached\n + pickleshare 0.7.5 py37hc8dfbb8_1002 conda-forge/linux-64 Cached\n + pip 21.2.3 pyhd8ed1ab_0 conda-forge/noarch Cached\n + pixman 0.40.0 h36c2ea0_0 conda-forge/linux-64 Cached\n + prometheus_client 0.11.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + prompt-toolkit 3.0.19 pyha770c72_0 conda-forge/noarch Cached\n + prompt_toolkit 3.0.19 hd8ed1ab_0 conda-forge/noarch Cached\n + protobuf 3.17.2 py37hcd2ae1e_0 conda-forge/linux-64 Cached\n + pthread-stubs 0.4 h36c2ea0_1001 conda-forge/linux-64 Cached\n + ptyprocess 0.7.0 pyhd3deb0d_0 conda-forge/noarch Cached\n + pycparser 2.20 pyh9f0ad1d_2 conda-forge/noarch Cached\n + pygments 2.9.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + pyparsing 2.4.7 pyh9f0ad1d_0 conda-forge/noarch Cached\n + pyqt 5.12.3 py37h89c1867_7 conda-forge/linux-64 Cached\n + pyqt-impl 5.12.3 py37he336c9b_7 conda-forge/linux-64 Cached\n + pyqt5-sip 4.19.18 py37hcd2ae1e_7 conda-forge/linux-64 Cached\n + pyqtchart 5.12 py37he336c9b_7 conda-forge/linux-64 Cached\n + pyqtwebengine 5.12.1 py37he336c9b_7 conda-forge/linux-64 Cached\n + pyrsistent 0.17.3 py37h5e8e339_2 conda-forge/linux-64 Cached\n + python 3.7.10 hffdb5ce_100_cpython conda-forge/linux-64 Cached\n + python-dateutil 2.8.2 pyhd8ed1ab_0 conda-forge/noarch Cached\n + python_abi 3.7 2_cp37m conda-forge/linux-64 Cached\n + pyzmq 22.2.1 py37h336d617_0 conda-forge/linux-64 Cached\n + qt 5.12.9 hda022c4_4 conda-forge/linux-64 Cached\n + qtconsole 5.1.1 pyhd8ed1ab_0 conda-forge/noarch Cached\n + qtpy 1.9.0 py_0 conda-forge/noarch Cached\n + r-askpass 1.1 r36hcfec24a_2 conda-forge/linux-64 Cached\n + r-assertthat 0.2.1 r36h6115d3f_2 conda-forge/noarch Cached\n + r-backports 1.2.1 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-base 3.6.3 hbcea092_8 conda-forge/linux-64 Cached\n + r-base64enc 0.1_3 r36hcfec24a_1004 conda-forge/linux-64 Cached\n + r-blob 1.2.1 r36h6115d3f_1 conda-forge/noarch Cached\n + r-boot 1.3_28 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-brio 1.1.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-broom 0.7.6 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-bslib 0.2.5.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-cachem 1.0.5 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-callr 3.7.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-caret 6.0_88 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-cellranger 1.1.0 r36h6115d3f_1003 conda-forge/noarch Cached\n + r-class 7.3_19 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-cli 2.5.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-clipr 0.7.1 r36h142f84f_0 conda-forge/noarch Cached\n + r-cluster 2.1.2 r36h859d828_0 conda-forge/linux-64 Cached\n + r-codetools 0.2_18 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-colorspace 2.0_1 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-commonmark 1.7 r36hcfec24a_1002 conda-forge/linux-64 Cached\n + r-cpp11 0.2.7 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-crayon 1.4.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-crul 1.1.0 r36h785f33e_0 conda-forge/noarch Cached\n + r-curl 4.3.1 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-data.table 1.14.0 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-dbi 1.1.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-dbplyr 2.1.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-desc 1.3.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-diffobj 0.3.4 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-digest 0.6.27 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-dplyr 1.0.6 r36h03ef668_1 conda-forge/linux-64 Cached\n + r-dtplyr 1.1.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-ellipsis 0.3.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-essentials 3.6 r36_2002 conda-forge/noarch Cached\n + r-evaluate 0.14 r36h6115d3f_2 conda-forge/noarch Cached\n + r-fansi 0.4.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-farver 2.1.0 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-fastmap 1.1.0 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-forcats 0.5.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-foreach 1.5.1 r36h142f84f_0 conda-forge/noarch Cached\n + r-foreign 0.8_76 r36hcdcec82_1 conda-forge/linux-64 Cached\n + r-formatr 1.9 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-fs 1.5.0 r36h0357c0b_0 conda-forge/linux-64 Cached\n + r-gargle 1.1.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-generics 0.1.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-ggplot2 3.3.3 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-gistr 0.9.0 r36h6115d3f_0 conda-forge/noarch Cached\n + r-glmnet 4.1_1 r36h859d828_0 conda-forge/linux-64 Cached\n + r-glue 1.4.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-googledrive 1.0.1 r36h6115d3f_1 conda-forge/noarch Cached\n + r-googlesheets4 0.3.0 r36hc72bb7e_0 conda-forge/linux-64 Cached\n + r-googlevis 0.6.10 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-gower 0.2.2 r36hcdcec82_0 conda-forge/linux-64 Cached\n + r-gtable 0.3.0 r36h6115d3f_3 conda-forge/noarch Cached\n + r-haven 2.4.1 r36h2713e49_0 conda-forge/linux-64 Cached\n + r-hexbin 1.28.2 r36h859d828_0 conda-forge/linux-64 Cached\n + r-highr 0.9 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-hms 1.1.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-htmltools 0.5.1.1 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-htmlwidgets 1.5.3 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-httpcode 0.3.0 r36_1 conda-forge/linux-64 Cached\n + r-httpuv 1.6.1 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-httr 1.4.2 r36h6115d3f_0 conda-forge/noarch Cached\n + r-ids 1.0.1 r36h6115d3f_1 conda-forge/noarch Cached\n + r-ipred 0.9_11 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-irdisplay 1.0 r36hd8ed1ab_0 conda-forge/noarch Cached\n + r-irkernel 1.2 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-isoband 0.2.4 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-iterators 1.0.13 r36h142f84f_0 conda-forge/noarch Cached\n + r-jquerylib 0.1.4 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-jsonlite 1.7.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-kernsmooth 2.23_20 r36h742201e_0 conda-forge/linux-64 Cached\n + r-knitr 1.33 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-labeling 0.4.2 r36h142f84f_0 conda-forge/noarch Cached\n + r-later 1.2.0 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-lattice 0.20_44 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-lava 1.6.9 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-lazyeval 0.2.2 r36hcfec24a_2 conda-forge/linux-64 Cached\n + r-lifecycle 1.0.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-lubridate 1.7.10 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-magrittr 2.0.1 r36hcfec24a_1 conda-forge/linux-64 Cached\n + r-maps 3.3.0 r36hcdcec82_1004 conda-forge/linux-64 Cached\n + r-markdown 1.1 r36hcfec24a_1 conda-forge/linux-64 Cached\n + r-mass 7.3_54 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-matrix 1.3_3 r36he454529_0 conda-forge/linux-64 Cached\n + r-mgcv 1.8_35 r36he454529_0 conda-forge/linux-64 Cached\n + r-mime 0.10 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-modelmetrics 1.2.2.2 r36h0357c0b_1 conda-forge/linux-64 Cached\n + r-modelr 0.1.8 r36h6115d3f_0 conda-forge/noarch Cached\n + r-munsell 0.5.0 r36h6115d3f_1003 conda-forge/noarch Cached\n + r-nlme 3.1_152 r36h859d828_0 conda-forge/linux-64 Cached\n + r-nnet 7.3_16 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-numderiv 2016.8_1.1 r36h6115d3f_3 conda-forge/noarch Cached\n + r-openssl 1.4.4 r36he36bf35_0 conda-forge/linux-64 Cached\n + r-pbdzmq 0.3_5 r36h42bf92c_1 conda-forge/linux-64 Cached\n + r-pillar 1.6.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-pkgconfig 2.0.3 r36h6115d3f_1 conda-forge/noarch Cached\n + r-pkgload 1.2.1 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-plyr 1.8.6 r36h0357c0b_1 conda-forge/linux-64 Cached\n + r-praise 1.0.0 r36h6115d3f_1004 conda-forge/noarch Cached\n + r-prettyunits 1.1.1 r36h6115d3f_1 conda-forge/noarch Cached\n + r-proc 1.17.0.1 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-processx 3.5.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-prodlim 2019.11.13 r36h0357c0b_1 conda-forge/linux-64 Cached\n + r-progress 1.2.2 r36h6115d3f_2 conda-forge/noarch Cached\n + r-promises 1.2.0.1 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-pryr 0.1.4 r36h0357c0b_1004 conda-forge/linux-64 Cached\n + r-ps 1.6.0 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-purrr 0.3.4 r36hcfec24a_1 conda-forge/linux-64 Cached\n + r-quantmod 0.4.18 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-r6 2.5.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-randomforest 4.6_14 r36h580db52_1004 conda-forge/linux-64 Cached\n + r-rappdirs 0.3.3 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-rbokeh 0.5.1 r36h6115d3f_0 conda-forge/noarch Cached\n + r-rcolorbrewer 1.1_2 r36h6115d3f_1003 conda-forge/noarch Cached\n + r-rcpp 1.0.6 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-readr 1.4.0 r36h1b71b39_0 conda-forge/linux-64 Cached\n + r-readxl 1.3.1 r36hde08347_4 conda-forge/linux-64 Cached\n + r-recipes 0.1.16 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-recommended 3.6 r36_1004 conda-forge/noarch Cached\n + r-rematch 1.0.1 r36h6115d3f_1003 conda-forge/noarch Cached\n + r-rematch2 2.1.2 r36h6115d3f_1 conda-forge/noarch Cached\n + r-repr 1.1.3 r36h785f33e_0 conda-forge/noarch Cached\n + r-reprex 2.0.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-reshape2 1.4.4 r36h0357c0b_1 conda-forge/linux-64 Cached\n + r-rlang 0.4.11 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-rmarkdown 2.8 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-rpart 4.1_15 r36hcfec24a_2 conda-forge/linux-64 Cached\n + r-rprojroot 2.0.2 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-rstudioapi 0.13 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-rvest 1.0.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-sass 0.4.0 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-scales 1.1.1 r36h6115d3f_0 conda-forge/noarch Cached\n + r-selectr 0.4_2 r36h6115d3f_1 conda-forge/noarch Cached\n + r-shape 1.4.6 r36ha770c72_0 conda-forge/noarch Cached\n + r-shiny 1.6.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-sourcetools 0.1.7 r36he1b5a44_1002 conda-forge/linux-64 Cached\n + r-spatial 7.3_14 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-squarem 2021.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-stringi 1.6.2 r36hcabe038_0 conda-forge/linux-64 Cached\n + r-stringr 1.4.0 r36h6115d3f_2 conda-forge/noarch Cached\n + r-survival 3.2_11 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-sys 3.4 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-testthat 3.0.2 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-tibble 3.1.2 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-tidyr 1.1.3 r36h03ef668_0 conda-forge/linux-64 Cached\n + r-tidyselect 1.1.1 r36hc72bb7e_0 conda-forge/linux-64 Cached\n + r-tidyverse 1.3.1 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-timedate 3043.102 r36h6115d3f_1002 conda-forge/noarch Cached\n + r-tinytex 0.31 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-triebeard 0.3.0 r36he1b5a44_1003 conda-forge/linux-64 Cached\n + r-ttr 0.24.2 r36hcdcec82_0 conda-forge/linux-64 Cached\n + r-urltools 1.7.3 r36h0357c0b_2 conda-forge/linux-64 Cached\n + r-utf8 1.2.1 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-uuid 0.1_4 r36hcdcec82_1 conda-forge/linux-64 Cached\n + r-vctrs 0.3.8 r36hcfec24a_1 conda-forge/linux-64 Cached\n + r-viridislite 0.4.0 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-waldo 0.2.5 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-withr 2.4.2 r36hc72bb7e_0 conda-forge/noarch Cached\n + r-xfun 0.23 r36hcfec24a_0 conda-forge/linux-64 Cached\n + r-xml2 1.3.2 r36h0357c0b_1 conda-forge/linux-64 Cached\n + r-xtable 1.8_4 r36h6115d3f_3 conda-forge/noarch Cached\n + r-xts 0.12.1 r36hcdcec82_0 conda-forge/linux-64 Cached\n + r-yaml 2.2.1 r36hcfec24a_1 conda-forge/linux-64 Cached\n + r-zoo 1.8_9 r36hcfec24a_0 conda-forge/linux-64 Cached\n + readline 8.1 h46c0cb4_0 conda-forge/linux-64 Cached\n + sed 4.8 he412f7d_0 conda-forge/linux-64 Cached\n + send2trash 1.7.1 pyhd8ed1ab_0 conda-forge/noarch Cached\n + setuptools 49.6.0 py37h89c1867_3 conda-forge/linux-64 Cached\n + six 1.16.0 pyh6c4a22f_0 conda-forge/noarch Cached\n + sqlite 3.36.0 h9cd32fc_0 conda-forge/linux-64 Cached\n + sysroot_linux-64 2.12 he073ed8_14 conda-forge/noarch Cached\n + terminado 0.10.1 py37h89c1867_0 conda-forge/linux-64 Cached\n + testpath 0.5.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + tk 8.6.10 h21135ba_1 conda-forge/linux-64 Cached\n + tktable 2.10 hb7b940f_3 conda-forge/linux-64 Cached\n + tornado 6.1 py37h5e8e339_1 conda-forge/linux-64 Cached\n + traitlets 5.0.5 py_0 conda-forge/noarch Cached\n + typing_extensions 3.10.0.0 pyha770c72_0 conda-forge/noarch Cached\n + wcwidth 0.2.5 pyh9f0ad1d_2 conda-forge/noarch Cached\n + webencodings 0.5.1 py_1 conda-forge/noarch Cached\n + wheel 0.36.2 pyhd3deb0d_0 conda-forge/noarch Cached\n + widgetsnbextension 3.5.1 py37h89c1867_4 conda-forge/linux-64 Cached\n + xorg-kbproto 1.0.7 h7f98852_1002 conda-forge/linux-64 Cached\n + xorg-libice 1.0.10 h7f98852_0 conda-forge/linux-64 Cached\n + xorg-libsm 1.2.3 hd9c2040_1000 conda-forge/linux-64 Cached\n + xorg-libx11 1.7.2 h7f98852_0 conda-forge/linux-64 Cached\n + xorg-libxau 1.0.9 h7f98852_0 conda-forge/linux-64 Cached\n + xorg-libxdmcp 1.1.3 h7f98852_0 conda-forge/linux-64 Cached\n + xorg-libxext 1.3.4 h7f98852_1 conda-forge/linux-64 Cached\n + xorg-libxrender 0.9.10 h7f98852_1003 conda-forge/linux-64 Cached\n + xorg-renderproto 0.11.1 h7f98852_1002 conda-forge/linux-64 Cached\n + xorg-xextproto 7.3.0 h7f98852_1002 conda-forge/linux-64 Cached\n + xorg-xproto 7.0.31 h7f98852_1007 conda-forge/linux-64 Cached\n + xz 5.2.5 h516909a_1 conda-forge/linux-64 Cached\n + zeromq 4.3.4 h9c3ff4c_0 conda-forge/linux-64 Cached\n + zipp 3.5.0 pyhd8ed1ab_0 conda-forge/noarch Cached\n + zlib 1.2.11 h516909a_1010 conda-forge/linux-64 Cached\n + zstd 1.5.0 ha95c52a_0 conda-forge/linux-64 Cached\n\n Summary:\n\n Install: 358 packages\n\n Total download: 0 B\n\n────────────────────────────────────────────────────────────────────────────────────────────────────────\n\n\n\nLooking for: ['python=3.7', 'jupyter', 'grpcio', 'protobuf', 'r-base=3', 'r-essentials', 'r-evaluate', 'r-base64enc', 'r-knitr', 'r-ggplot2', 'r-irkernel', 'r-shiny', 'r-googlevis']\n\n\nPreparing transaction: ...working... done\nVerifying transaction: ...working... done\nExecuting transaction: ...working... Enabling notebook extension jupyter-js-widgets/extension...\n - Validating: \u001b[32mOK\u001b[0m\n\ndone\n#\n# To activate this environment, use\n#\n# $ conda activate r_env\n#\n# To deactivate an active environment, use\n#\n# $ conda deactivate\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096910_1941489893", - "id": "paragraph_1617163651950_276096757", - "dateCreated": "2021-06-19 21:58:16.910", - "dateStarted": "2021-08-09 10:55:29.920", - "dateFinished": "2021-08-09 10:55:59.548", - "status": "FINISHED" - }, - { - "title": "Create R conda tar", - "text": "%sh\n\nrm -rf r_env.tar.gz\nconda pack -n r_env\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:55:59.555", - "progress": 0, - "config": { - "editorSetting": { - "language": "sh", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": false - }, - "colWidth": 12.0, - "editorMode": "ace/mode/sh", - "fontSize": 9.0, - "title": true, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "Collecting packages...\nPacking environment at '/mnt/disk1/jzhang/miniconda3/envs/r_env' to 'r_env.tar.gz'\n\r[ ] | 0% Completed | 0.0s\r[ ] | 0% Completed | 0.1s\r[ ] | 0% Completed | 0.2s\r[ ] | 0% Completed | 0.3s\r[ ] | 0% Completed | 0.4s\r[ ] | 0% Completed | 0.5s\r[ ] | 0% Completed | 0.6s\r[ ] | 0% Completed | 0.7s\r[ ] | 0% Completed | 0.8s\r[ ] | 0% Completed | 0.9s\r[ ] | 1% Completed | 1.0s\r[ ] | 1% Completed | 1.1s\r[ ] | 1% Completed | 1.2s\r[ ] | 1% Completed | 1.3s\r[ ] | 2% Completed | 1.4s\r[ ] | 2% Completed | 1.5s\r[# ] | 2% Completed | 1.6s\r[# ] | 3% Completed | 1.7s\r[# ] | 3% Completed | 1.8s\r[# ] | 3% Completed | 1.9s\r[# ] | 3% Completed | 2.0s\r[# ] | 3% Completed | 2.1s\r[# ] | 3% Completed | 2.2s\r[# ] | 3% Completed | 2.3s\r[# ] | 3% Completed | 2.4s\r[# ] | 3% Completed | 2.5s\r[# ] | 3% Completed | 2.6s\r[# ] | 4% Completed | 2.7s\r[# ] | 4% Completed | 2.8s\r[# ] | 4% Completed | 2.9s\r[# ] | 4% Completed | 3.0s\r[## ] | 5% Completed | 3.1s\r[## ] | 5% Completed | 3.2s\r[## ] | 5% Completed | 3.3s\r[## ] | 5% Completed | 3.4s\r[## ] | 6% Completed | 3.5s\r[## ] | 6% Completed | 3.6s\r[## ] | 6% Completed | 3.7s\r[## ] | 6% Completed | 3.8s\r[## ] | 6% Completed | 3.9s\r[## ] | 7% Completed | 4.0s\r[## ] | 7% Completed | 4.1s\r[### ] | 7% Completed | 4.2s\r[### ] | 7% Completed | 4.3s\r[### ] | 8% Completed | 4.4s\r[### ] | 8% Completed | 4.5s\r[### ] | 8% Completed | 4.6s\r[### ] | 8% Completed | 4.7s\r[### ] | 8% Completed | 4.8s\r[### ] | 8% Completed | 4.9s\r[### ] | 8% Completed | 5.0s\r[### ] | 8% Completed | 5.1s\r[### ] | 9% Completed | 5.2s\r[### ] | 9% Completed | 5.3s\r[### ] | 9% Completed | 5.4s\r[#### ] | 10% Completed | 5.5s\r[#### ] | 10% Completed | 5.6s\r[#### ] | 10% Completed | 5.7s\r[#### ] | 10% Completed | 5.8s\r[#### ] | 10% Completed | 5.9s\r[#### ] | 10% Completed | 6.0s\r[#### ] | 10% Completed | 6.1s\r[#### ] | 10% Completed | 6.2s\r[#### ] | 10% Completed | 6.3s\r[#### ] | 10% Completed | 6.4s\r[#### ] | 11% Completed | 6.5s\r[#### ] | 11% Completed | 6.6s\r[#### ] | 11% Completed | 6.7s\r[#### ] | 11% Completed | 6.8s\r[#### ] | 11% Completed | 6.9s\r[#### ] | 12% Completed | 7.0s\r[#### ] | 12% Completed | 7.1s\r[##### ] | 12% Completed | 7.2s\r[##### ] | 13% Completed | 7.3s\r[##### ] | 13% Completed | 7.4s\r[##### ] | 13% Completed | 7.5s\r[##### ] | 13% Completed | 7.6s\r[##### ] | 13% Completed | 7.7s\r[##### ] | 13% Completed | 7.8s\r[##### ] | 13% Completed | 7.9s\r[##### ] | 14% Completed | 8.0s\r[##### ] | 14% Completed | 8.1s\r[##### ] | 14% Completed | 8.2s\r[##### ] | 14% Completed | 8.3s\r[##### ] | 14% Completed | 8.4s\r[##### ] | 14% Completed | 8.5s\r[##### ] | 14% Completed | 8.6s\r[##### ] | 14% Completed | 8.7s\r[##### ] | 14% Completed | 8.8s\r[##### ] | 14% Completed | 8.9s\r[##### ] | 14% Completed | 9.0s\r[##### ] | 14% Completed | 9.1s\r[##### ] | 14% Completed | 9.2s\r[##### ] | 14% Completed | 9.3s\r[###### ] | 15% Completed | 9.4s\r[###### ] | 15% Completed | 9.5s\r[###### ] | 15% Completed | 9.6s\r[###### ] | 15% Completed | 9.7s\r[###### ] | 15% Completed | 9.8s\r[###### ] | 15% Completed | 9.9s\r[###### ] | 15% Completed | 10.0s\r[###### ] | 16% Completed | 10.1s\r[###### ] | 16% Completed | 10.2s\r[###### ] | 16% Completed | 10.3s\r[###### ] | 16% Completed | 10.4s\r[###### ] | 16% Completed | 10.5s\r[###### ] | 17% Completed | 10.6s\r[###### ] | 17% Completed | 10.7s\r[###### ] | 17% Completed | 10.8s\r[###### ] | 17% Completed | 10.9s\r[###### ] | 17% Completed | 11.0s\r[###### ] | 17% Completed | 11.1s\r[###### ] | 17% Completed | 11.2s\r[###### ] | 17% Completed | 11.3s\r[###### ] | 17% Completed | 11.4s\r[####### ] | 17% Completed | 11.5s\r[####### ] | 17% Completed | 11.6s\r[####### ] | 18% Completed | 11.7s\r[####### ] | 18% Completed | 11.8s\r[####### ] | 18% Completed | 11.9s\r[####### ] | 18% Completed | 12.0s\r[####### ] | 18% Completed | 12.1s\r[####### ] | 18% Completed | 12.2s\r[####### ] | 18% Completed | 12.3s\r[####### ] | 19% Completed | 12.4s\r[####### ] | 19% Completed | 12.5s\r[####### ] | 19% Completed | 12.6s\r[####### ] | 19% Completed | 12.7s\r[####### ] | 19% Completed | 12.8s\r[####### ] | 19% Completed | 12.9s\r[####### ] | 19% Completed | 13.0s\r[####### ] | 19% Completed | 13.1s\r[####### ] | 19% Completed | 13.2s\r[####### ] | 19% Completed | 13.3s\r[####### ] | 19% Completed | 13.4s\r[####### ] | 19% Completed | 13.5s\r[####### ] | 19% Completed | 13.6s\r[####### ] | 19% Completed | 13.7s\r[####### ] | 19% Completed | 13.8s\r[####### ] | 19% Completed | 13.9s\r[####### ] | 19% Completed | 14.0s\r[####### ] | 19% Completed | 14.1s\r[####### ] | 19% Completed | 14.2s\r[####### ] | 19% Completed | 14.3s\r[####### ] | 19% Completed | 14.4s\r[######## ] | 20% Completed | 14.5s\r[######## ] | 20% Completed | 14.6s\r[######## ] | 20% Completed | 14.7s\r[######## ] | 20% Completed | 14.8s\r[######## ] | 21% Completed | 14.9s\r[######## ] | 21% Completed | 15.0s\r[######## ] | 21% Completed | 15.1s\r[######## ] | 21% Completed | 15.2s\r[######## ] | 21% Completed | 15.3s\r[######## ] | 21% Completed | 15.4s\r[######## ] | 21% Completed | 15.5s\r[######## ] | 22% Completed | 15.6s\r[######## ] | 22% Completed | 15.7s\r[######## ] | 22% Completed | 15.8s\r[######### ] | 22% Completed | 15.9s\r[######### ] | 22% Completed | 16.0s\r[######### ] | 22% Completed | 16.1s\r[######### ] | 22% Completed | 16.2s\r[######### ] | 22% Completed | 16.3s\r[######### ] | 22% Completed | 16.4s\r[######### ] | 22% Completed | 16.5s\r[######### ] | 22% Completed | 16.6s\r[######### ] | 22% Completed | 16.7s\r[######### ] | 22% Completed | 16.8s\r[######### ] | 22% Completed | 16.9s\r[######### ] | 23% Completed | 17.0s\r[######### ] | 23% Completed | 17.1s\r[######### ] | 23% Completed | 17.2s\r[######### ] | 23% Completed | 17.3s\r[######### ] | 24% Completed | 17.4s\r[######### ] | 24% Completed | 17.5s\r[######### ] | 24% Completed | 17.6s\r[######### ] | 24% Completed | 17.7s\r[######### ] | 24% Completed | 17.8s\r[######### ] | 24% Completed | 17.9s\r[######### ] | 24% Completed | 18.0s\r[######### ] | 24% Completed | 18.1s\r[######### ] | 24% Completed | 18.2s\r[######### ] | 24% Completed | 18.3s\r[######### ] | 24% Completed | 18.4s\r[######### ] | 24% Completed | 18.5s\r[######### ] | 24% Completed | 18.6s\r[######### ] | 24% Completed | 18.7s\r[######### ] | 24% Completed | 18.8s\r[######### ] | 24% Completed | 18.9s\r[######### ] | 24% Completed | 19.0s\r[######### ] | 24% Completed | 19.1s\r[######### ] | 24% Completed | 19.2s\r[######### ] | 24% Completed | 19.3s\r[######### ] | 24% Completed | 19.4s\r[######### ] | 24% Completed | 19.5s\r[######### ] | 24% Completed | 19.6s\r[######### ] | 24% Completed | 19.7s\r[######### ] | 24% Completed | 19.8s\r[######### ] | 24% Completed | 19.9s\r[######### ] | 24% Completed | 20.0s\r[######### ] | 24% Completed | 20.1s\r[######### ] | 24% Completed | 20.2s\r[######### ] | 24% Completed | 20.3s\r[######### ] | 24% Completed | 20.4s\r[######### ] | 24% Completed | 20.5s\r[######### ] | 24% Completed | 20.6s\r[######### ] | 24% Completed | 20.7s\r[######### ] | 24% Completed | 20.8s\r[######### ] | 24% Completed | 20.9s\r[######### ] | 24% Completed | 21.0s\r[######### ] | 24% Completed | 21.1s\r[######### ] | 24% Completed | 21.2s\r[######### ] | 24% Completed | 21.3s\r[######### ] | 24% Completed | 21.4s\r[########## ] | 25% Completed | 21.5s\r[########## ] | 25% Completed | 21.6s\r[########## ] | 25% Completed | 21.7s\r[########## ] | 25% Completed | 21.8s\r[########## ] | 25% Completed | 21.9s\r[########## ] | 26% Completed | 22.0s\r[########## ] | 26% Completed | 22.1s\r[########## ] | 27% Completed | 22.2s\r[########### ] | 28% Completed | 22.3s\r[########### ] | 28% Completed | 22.4s\r[########### ] | 29% Completed | 22.5s\r[############ ] | 30% Completed | 22.6s\r[############ ] | 30% Completed | 22.7s\r[############ ] | 31% Completed | 22.8s\r[############ ] | 31% Completed | 22.9s\r[############ ] | 31% Completed | 23.0s\r[############ ] | 32% Completed | 23.1s\r[############ ] | 32% Completed | 23.2s\r[############ ] | 32% Completed | 23.3s\r[############# ] | 32% Completed | 23.4s\r[############# ] | 32% Completed | 23.5s\r[############# ] | 32% Completed | 23.6s\r[############# ] | 33% Completed | 23.7s\r[############# ] | 33% Completed | 23.8s\r[############# ] | 34% Completed | 23.9s\r[############# ] | 34% Completed | 24.0s\r[############# ] | 34% Completed | 24.1s\r[############## ] | 35% Completed | 24.2s\r[############## ] | 35% Completed | 24.3s\r[############## ] | 36% Completed | 24.4s\r[############## ] | 36% Completed | 24.5s\r[############## ] | 36% Completed | 24.6s\r[############## ] | 36% Completed | 24.7s\r[############## ] | 36% Completed | 24.8s\r[############## ] | 37% Completed | 24.9s\r[############## ] | 37% Completed | 25.0s\r[############## ] | 37% Completed | 25.1s\r[############## ] | 37% Completed | 25.2s\r[############### ] | 37% Completed | 25.3s\r[############### ] | 38% Completed | 25.4s\r[############### ] | 38% Completed | 25.5s\r[############### ] | 38% Completed | 25.6s\r[############### ] | 38% Completed | 25.7s\r[############### ] | 38% Completed | 25.8s\r[############### ] | 38% Completed | 25.9s\r[############### ] | 39% Completed | 26.0s\r[############### ] | 39% Completed | 26.1s\r[################ ] | 40% Completed | 26.2s\r[################ ] | 40% Completed | 26.3s\r[################ ] | 41% Completed | 26.4s\r[################ ] | 41% Completed | 26.5s\r[################ ] | 41% Completed | 26.6s\r[################ ] | 41% Completed | 26.7s\r[################ ] | 42% Completed | 26.8s\r[################ ] | 42% Completed | 26.9s\r[################# ] | 42% Completed | 27.0s\r[################# ] | 42% Completed | 27.1s\r[################# ] | 43% Completed | 27.2s\r[################# ] | 43% Completed | 27.3s\r[################# ] | 43% Completed | 27.4s\r[################# ] | 43% Completed | 27.5s\r[################# ] | 44% Completed | 27.6s\r[################# ] | 44% Completed | 27.7s\r[################# ] | 44% Completed | 27.8s\r[################# ] | 44% Completed | 27.9s\r[################# ] | 44% Completed | 28.0s\r[################# ] | 44% Completed | 28.1s\r[################# ] | 44% Completed | 28.2s\r[################# ] | 44% Completed | 28.3s\r[################# ] | 44% Completed | 28.4s\r[################# ] | 44% Completed | 28.5s\r[################# ] | 44% Completed | 28.6s\r[################# ] | 44% Completed | 28.7s\r[################# ] | 44% Completed | 28.8s\r[################## ] | 45% Completed | 29.0s\r[################## ] | 45% Completed | 29.1s\r[################## ] | 45% Completed | 29.2s\r[################## ] | 45% Completed | 29.3s\r[################## ] | 45% Completed | 29.4s\r[################## ] | 45% Completed | 29.5s\r[################## ] | 46% Completed | 29.6s\r[################## ] | 46% Completed | 29.7s\r[################## ] | 46% Completed | 29.8s\r[################## ] | 46% Completed | 29.9s\r[################## ] | 46% Completed | 30.0s\r[################## ] | 46% Completed | 30.1s\r[################## ] | 46% Completed | 30.2s\r[################## ] | 46% Completed | 30.3s\r[################## ] | 47% Completed | 30.4s\r[################## ] | 47% Completed | 30.5s\r[################## ] | 47% Completed | 30.6s\r[################## ] | 47% Completed | 30.7s\r[################### ] | 47% Completed | 30.8s\r[################### ] | 47% Completed | 30.9s\r[################### ] | 47% Completed | 31.0s\r[################### ] | 48% Completed | 31.1s\r[################### ] | 48% Completed | 31.2s\r[################### ] | 48% Completed | 31.3s\r[################### ] | 48% Completed | 31.4s\r[################### ] | 48% Completed | 31.5s\r[################### ] | 48% Completed | 31.6s\r[################### ] | 48% Completed | 31.7s\r[################### ] | 48% Completed | 31.8s\r[################### ] | 48% Completed | 31.9s\r[################### ] | 48% Completed | 32.0s\r[################### ] | 48% Completed | 32.1s\r[################### ] | 48% Completed | 32.2s\r[################### ] | 48% Completed | 32.3s\r[################### ] | 48% Completed | 32.4s\r[################### ] | 48% Completed | 32.5s\r[################### ] | 48% Completed | 32.6s\r[################### ] | 48% Completed | 32.7s\r[################### ] | 48% Completed | 32.8s\r[################### ] | 48% Completed | 32.9s\r[################### ] | 48% Completed | 33.0s\r[################### ] | 48% Completed | 33.1s\r[################### ] | 48% Completed | 33.2s\r[################### ] | 48% Completed | 33.3s\r[################### ] | 48% Completed | 33.4s\r[################### ] | 48% Completed | 33.5s\r[################### ] | 48% Completed | 33.6s\r[################### ] | 48% Completed | 33.7s\r[################### ] | 48% Completed | 33.8s\r[################### ] | 48% Completed | 33.9s\r[################### ] | 48% Completed | 34.0s\r[################### ] | 48% Completed | 34.1s\r[################### ] | 48% Completed | 34.2s\r[################### ] | 48% Completed | 34.3s\r[################### ] | 48% Completed | 34.4s\r[################### ] | 48% Completed | 34.5s\r[################### ] | 48% Completed | 34.6s\r[################### ] | 48% Completed | 34.7s\r[################### ] | 48% Completed | 34.8s\r[################### ] | 48% Completed | 34.9s\r[################### ] | 48% Completed | 35.0s\r[################### ] | 48% Completed | 35.1s\r[################### ] | 48% Completed | 35.2s\r[################### ] | 48% Completed | 35.3s\r[################### ] | 48% Completed | 35.4s\r[################### ] | 48% Completed | 35.5s\r[################### ] | 48% Completed | 35.6s\r[################### ] | 48% Completed | 35.7s\r[################### ] | 48% Completed | 35.8s\r[################### ] | 48% Completed | 35.9s\r[################### ] | 48% Completed | 36.0s\r[################### ] | 48% Completed | 36.1s\r[################### ] | 48% Completed | 36.2s\r[################### ] | 48% Completed | 36.3s\r[################### ] | 48% Completed | 36.4s\r[################### ] | 49% Completed | 36.5s\r[################### ] | 49% Completed | 36.6s\r[################### ] | 49% Completed | 36.7s\r[################### ] | 49% Completed | 36.8s\r[################### ] | 49% Completed | 36.9s\r[################### ] | 49% Completed | 37.0s\r[################### ] | 49% Completed | 37.1s\r[#################### ] | 50% Completed | 37.2s\r[#################### ] | 50% Completed | 37.3s\r[#################### ] | 50% Completed | 37.4s\r[#################### ] | 50% Completed | 37.5s\r[#################### ] | 50% Completed | 37.6s\r[#################### ] | 51% Completed | 37.7s\r[#################### ] | 51% Completed | 37.8s\r[#################### ] | 51% Completed | 37.9s\r[#################### ] | 51% Completed | 38.0s\r[#################### ] | 51% Completed | 38.1s\r[#################### ] | 52% Completed | 38.2s\r[#################### ] | 52% Completed | 38.3s\r[#################### ] | 52% Completed | 38.4s\r[#################### ] | 52% Completed | 38.5s\r[#################### ] | 52% Completed | 38.6s\r[#################### ] | 52% Completed | 38.7s\r[#################### ] | 52% Completed | 38.8s\r[##################### ] | 52% Completed | 38.9s\r[##################### ] | 52% Completed | 39.0s\r[##################### ] | 53% Completed | 39.1s\r[##################### ] | 53% Completed | 39.2s\r[##################### ] | 53% Completed | 39.3s\r[##################### ] | 53% Completed | 39.4s\r[##################### ] | 53% Completed | 39.5s\r[##################### ] | 53% Completed | 39.6s\r[##################### ] | 53% Completed | 39.7s\r[##################### ] | 53% Completed | 39.8s\r[##################### ] | 54% Completed | 39.9s\r[##################### ] | 54% Completed | 40.0s\r[##################### ] | 54% Completed | 40.1s\r[##################### ] | 54% Completed | 40.2s\r[##################### ] | 54% Completed | 40.3s\r[##################### ] | 54% Completed | 40.4s\r[###################### ] | 55% Completed | 40.5s\r[###################### ] | 55% Completed | 40.6s\r[###################### ] | 55% Completed | 40.7s\r[###################### ] | 55% Completed | 40.8s\r[###################### ] | 55% Completed | 40.9s\r[###################### ] | 55% Completed | 41.0s\r[###################### ] | 55% Completed | 41.1s\r[###################### ] | 55% Completed | 41.2s\r[###################### ] | 55% Completed | 41.3s\r[###################### ] | 55% Completed | 41.4s\r[###################### ] | 55% Completed | 41.5s\r[###################### ] | 55% Completed | 41.6s\r[###################### ] | 55% Completed | 41.7s\r[###################### ] | 56% Completed | 41.8s\r[###################### ] | 56% Completed | 41.9s\r[###################### ] | 56% Completed | 42.0s\r[###################### ] | 56% Completed | 42.1s\r[###################### ] | 57% Completed | 42.2s\r[###################### ] | 57% Completed | 42.3s\r[###################### ] | 57% Completed | 42.4s\r[###################### ] | 57% Completed | 42.5s\r[###################### ] | 57% Completed | 42.6s\r[####################### ] | 57% Completed | 42.7s\r[####################### ] | 57% Completed | 42.8s\r[####################### ] | 58% Completed | 42.9s\r[####################### ] | 58% Completed | 43.0s\r[####################### ] | 58% Completed | 43.1s\r[####################### ] | 59% Completed | 43.2s\r[####################### ] | 59% Completed | 43.3s\r[####################### ] | 59% Completed | 43.4s\r[####################### ] | 59% Completed | 43.5s\r[####################### ] | 59% Completed | 43.6s\r[####################### ] | 59% Completed | 43.7s\r[####################### ] | 59% Completed | 43.8s\r[####################### ] | 59% Completed | 43.9s\r[####################### ] | 59% Completed | 44.0s\r[####################### ] | 59% Completed | 44.1s\r[####################### ] | 59% Completed | 44.2s\r[####################### ] | 59% Completed | 44.3s\r[####################### ] | 59% Completed | 44.4s\r[####################### ] | 59% Completed | 44.5s\r[####################### ] | 59% Completed | 44.6s\r[####################### ] | 59% Completed | 44.7s\r[######################## ] | 60% Completed | 44.8s\r[######################## ] | 60% Completed | 44.9s\r[######################## ] | 60% Completed | 45.0s\r[######################## ] | 60% Completed | 45.1s\r[######################## ] | 60% Completed | 45.2s\r[######################## ] | 61% Completed | 45.3s\r[######################## ] | 61% Completed | 45.4s\r[######################## ] | 62% Completed | 45.5s\r[######################## ] | 62% Completed | 45.6s\r[######################### ] | 62% Completed | 45.7s\r[######################### ] | 62% Completed | 45.8s\r[######################### ] | 63% Completed | 45.9s\r[######################### ] | 63% Completed | 46.0s\r[######################### ] | 63% Completed | 46.1s\r[######################### ] | 64% Completed | 46.2s\r[######################### ] | 64% Completed | 46.3s\r[########################## ] | 65% Completed | 46.4s\r[########################## ] | 65% Completed | 46.5s\r[########################## ] | 65% Completed | 46.6s\r[########################## ] | 66% Completed | 46.7s\r[########################## ] | 66% Completed | 46.8s\r[########################## ] | 66% Completed | 46.9s\r[########################## ] | 67% Completed | 47.0s\r[########################## ] | 67% Completed | 47.1s\r[########################### ] | 67% Completed | 47.2s\r[########################### ] | 67% Completed | 47.3s\r[########################### ] | 68% Completed | 47.4s\r[########################### ] | 68% Completed | 47.5s\r[########################### ] | 68% Completed | 47.6s\r[########################### ] | 69% Completed | 47.7s\r[########################### ] | 69% Completed | 47.8s\r[########################### ] | 69% Completed | 47.9s\r[########################### ] | 69% Completed | 48.0s\r[############################ ] | 70% Completed | 48.1s\r[############################ ] | 70% Completed | 48.2s\r[############################ ] | 70% Completed | 48.3s\r[############################ ] | 71% Completed | 48.4s\r[############################ ] | 71% Completed | 48.5s\r[############################ ] | 72% Completed | 48.6s\r[############################# ] | 72% Completed | 48.7s\r[############################# ] | 73% Completed | 48.8s\r[############################# ] | 73% Completed | 48.9s\r[############################# ] | 73% Completed | 49.0s\r[############################# ] | 74% Completed | 49.1s\r[############################# ] | 74% Completed | 49.2s\r[############################## ] | 75% Completed | 49.3s\r[############################## ] | 75% Completed | 49.4s\r[############################## ] | 75% Completed | 49.5s\r[############################## ] | 75% Completed | 49.6s\r[############################## ] | 75% Completed | 49.7s\r[############################## ] | 75% Completed | 49.8s\r[############################## ] | 75% Completed | 49.9s\r[############################## ] | 75% Completed | 50.0s\r[############################## ] | 75% Completed | 50.1s\r[############################## ] | 75% Completed | 50.2s\r[############################## ] | 75% Completed | 50.3s\r[############################## ] | 75% Completed | 50.4s\r[############################## ] | 75% Completed | 50.5s\r[############################## ] | 75% Completed | 50.6s\r[############################## ] | 75% Completed | 50.7s\r[############################## ] | 75% Completed | 50.8s\r[############################## ] | 75% Completed | 50.9s\r[############################## ] | 75% Completed | 51.0s\r[############################## ] | 75% Completed | 51.1s\r[############################## ] | 75% Completed | 51.2s\r[############################## ] | 75% Completed | 51.3s\r[############################## ] | 75% Completed | 51.4s\r[############################## ] | 75% Completed | 51.5s\r[############################## ] | 75% Completed | 51.6s\r[############################## ] | 75% Completed | 51.7s\r[############################## ] | 75% Completed | 51.8s\r[############################## ] | 75% Completed | 51.9s\r[############################## ] | 75% Completed | 52.0s\r[############################## ] | 75% Completed | 52.1s\r[############################## ] | 75% Completed | 52.2s\r[############################## ] | 75% Completed | 52.3s\r[############################## ] | 75% Completed | 52.4s\r[############################## ] | 75% Completed | 52.5s\r[############################## ] | 75% Completed | 52.6s\r[############################## ] | 75% Completed | 52.7s\r[############################## ] | 75% Completed | 52.8s\r[############################## ] | 75% Completed | 52.9s\r[############################## ] | 75% Completed | 53.0s\r[############################## ] | 75% Completed | 53.1s\r[############################## ] | 75% Completed | 53.2s\r[############################## ] | 75% Completed | 53.3s\r[############################## ] | 75% Completed | 53.4s\r[############################## ] | 75% Completed | 53.5s\r[############################## ] | 75% Completed | 53.6s\r[############################## ] | 75% Completed | 53.7s\r[############################## ] | 75% Completed | 53.8s\r[############################## ] | 75% Completed | 53.9s\r[############################## ] | 75% Completed | 54.0s\r[############################## ] | 76% Completed | 54.1s\r[############################## ] | 76% Completed | 54.2s\r[############################## ] | 77% Completed | 54.3s\r[############################## ] | 77% Completed | 54.4s\r[############################## ] | 77% Completed | 54.5s\r[############################## ] | 77% Completed | 54.6s\r[############################## ] | 77% Completed | 54.7s\r[############################## ] | 77% Completed | 54.8s\r[############################### ] | 77% Completed | 54.9s\r[############################### ] | 77% Completed | 55.0s\r[############################### ] | 78% Completed | 55.1s\r[############################### ] | 79% Completed | 55.2s\r[############################### ] | 79% Completed | 55.3s\r[############################### ] | 79% Completed | 55.4s\r[############################### ] | 79% Completed | 55.5s\r[############################### ] | 79% Completed | 55.6s\r[############################### ] | 79% Completed | 55.7s\r[############################### ] | 79% Completed | 55.8s\r[############################### ] | 79% Completed | 55.9s\r[############################### ] | 79% Completed | 56.0s\r[################################ ] | 80% Completed | 56.1s\r[################################ ] | 80% Completed | 56.2s\r[################################ ] | 80% Completed | 56.3s\r[################################ ] | 81% Completed | 56.4s\r[################################ ] | 81% Completed | 56.5s\r[################################ ] | 81% Completed | 56.6s\r[################################ ] | 81% Completed | 56.7s\r[################################ ] | 82% Completed | 56.8s\r[################################ ] | 82% Completed | 56.9s\r[################################ ] | 82% Completed | 57.0s\r[################################ ] | 82% Completed | 57.1s\r[################################ ] | 82% Completed | 57.2s\r[################################ ] | 82% Completed | 57.3s\r[################################ ] | 82% Completed | 57.4s\r[################################ ] | 82% Completed | 57.5s\r[################################ ] | 82% Completed | 57.6s\r[################################ ] | 82% Completed | 57.7s\r[################################ ] | 82% Completed | 57.8s\r[################################ ] | 82% Completed | 57.9s\r[################################ ] | 82% Completed | 58.0s\r[################################# ] | 82% Completed | 58.1s\r[################################# ] | 82% Completed | 58.2s\r[################################# ] | 83% Completed | 58.3s\r[################################# ] | 83% Completed | 58.4s\r[################################# ] | 83% Completed | 58.5s\r[################################# ] | 83% Completed | 58.6s\r[################################# ] | 84% Completed | 58.7s\r[################################# ] | 84% Completed | 58.8s\r[################################# ] | 84% Completed | 58.9s\r[################################# ] | 84% Completed | 59.0s\r[################################# ] | 84% Completed | 59.1s\r[################################# ] | 84% Completed | 59.2s\r[################################# ] | 84% Completed | 59.3s\r[################################# ] | 84% Completed | 59.4s\r[################################# ] | 84% Completed | 59.5s\r[################################# ] | 84% Completed | 59.6s\r[################################# ] | 84% Completed | 59.7s\r[################################# ] | 84% Completed | 59.8s\r[################################# ] | 84% Completed | 59.9s\r[################################# ] | 84% Completed | 1min 0.0s\r[################################# ] | 84% Completed | 1min 0.1s\r[################################# ] | 84% Completed | 1min 0.2s\r[################################# ] | 84% Completed | 1min 0.3s\r[################################# ] | 84% Completed | 1min 0.4s\r[################################# ] | 84% Completed | 1min 0.5s\r[################################# ] | 84% Completed | 1min 0.6s\r[################################# ] | 84% Completed | 1min 0.7s\r[################################# ] | 84% Completed | 1min 0.8s\r[################################# ] | 84% Completed | 1min 0.9s\r[################################# ] | 84% Completed | 1min 1.0s\r[################################# ] | 84% Completed | 1min 1.1s\r[################################## ] | 85% Completed | 1min 1.2s\r[################################## ] | 85% Completed | 1min 1.3s\r[################################## ] | 85% Completed | 1min 1.4s\r[################################## ] | 85% Completed | 1min 1.5s\r[################################## ] | 86% Completed | 1min 1.6s\r[################################## ] | 86% Completed | 1min 1.7s\r[################################## ] | 87% Completed | 1min 1.8s\r[################################### ] | 87% Completed | 1min 1.9s\r[################################### ] | 88% Completed | 1min 2.0s\r[################################### ] | 88% Completed | 1min 2.1s\r[################################### ] | 89% Completed | 1min 2.2s\r[################################### ] | 89% Completed | 1min 2.3s\r[################################### ] | 89% Completed | 1min 2.4s\r[################################### ] | 89% Completed | 1min 2.5s\r[#################################### ] | 90% Completed | 1min 2.6s\r[#################################### ] | 90% Completed | 1min 2.7s\r[#################################### ] | 90% Completed | 1min 2.8s\r[#################################### ] | 90% Completed | 1min 2.9s\r[#################################### ] | 90% Completed | 1min 3.0s\r[#################################### ] | 90% Completed | 1min 3.1s\r[#################################### ] | 91% Completed | 1min 3.2s\r[#################################### ] | 91% Completed | 1min 3.3s\r[#################################### ] | 91% Completed | 1min 3.4s\r[#################################### ] | 92% Completed | 1min 3.5s\r[#################################### ] | 92% Completed | 1min 3.6s\r[##################################### ] | 92% Completed | 1min 3.7s\r[##################################### ] | 93% Completed | 1min 3.8s\r[##################################### ] | 93% Completed | 1min 3.9s\r[##################################### ] | 93% Completed | 1min 4.0s\r[##################################### ] | 93% Completed | 1min 4.1s\r[##################################### ] | 93% Completed | 1min 4.2s\r[##################################### ] | 94% Completed | 1min 4.3s\r[##################################### ] | 94% Completed | 1min 4.4s\r[###################################### ] | 96% Completed | 1min 4.5s\r[###################################### ] | 97% Completed | 1min 4.6s\r[####################################### ] | 97% Completed | 1min 4.7s\r[####################################### ] | 97% Completed | 1min 4.8s\r[####################################### ] | 98% Completed | 1min 4.9s\r[####################################### ] | 98% Completed | 1min 5.0s\r[####################################### ] | 98% Completed | 1min 5.1s\r[####################################### ] | 98% Completed | 1min 5.2s\r[####################################### ] | 98% Completed | 1min 5.3s\r[####################################### ] | 98% Completed | 1min 5.4s\r[####################################### ] | 98% Completed | 1min 5.5s\r[####################################### ] | 98% Completed | 1min 5.6s\r[####################################### ] | 98% Completed | 1min 5.7s\r[####################################### ] | 98% Completed | 1min 5.8s\r[####################################### ] | 98% Completed | 1min 5.9s\r[####################################### ] | 98% Completed | 1min 6.0s\r[####################################### ] | 98% Completed | 1min 6.1s\r[####################################### ] | 98% Completed | 1min 6.2s\r[####################################### ] | 98% Completed | 1min 6.3s\r[####################################### ] | 98% Completed | 1min 6.4s\r[####################################### ] | 98% Completed | 1min 6.5s\r[####################################### ] | 98% Completed | 1min 6.6s\r[####################################### ] | 98% Completed | 1min 6.7s\r[####################################### ] | 98% Completed | 1min 6.8s\r[####################################### ] | 98% Completed | 1min 6.9s\r[####################################### ] | 99% Completed | 1min 7.0s\r[####################################### ] | 99% Completed | 1min 7.1s\r[####################################### ] | 99% Completed | 1min 7.2s\r[####################################### ] | 99% Completed | 1min 7.3s\r[########################################] | 100% Completed | 1min 7.4s\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096910_883123029", - "id": "paragraph_1617170106834_1523620028", - "dateCreated": "2021-06-19 21:58:16.910", - "dateStarted": "2021-08-09 10:55:59.557", - "dateFinished": "2021-08-09 10:57:09.103", - "status": "FINISHED" - }, - { - "title": "Upload R conda tar to hdfs (Optional)", - "text": "%sh\n\nhadoop fs -rmr /tmp/r_env.tar.gz\nhadoop fs -put r_env.tar.gz /tmp\n# The python conda tar should be publicly accessible by others, so need to change permission here.\nhadoop fs -chmod 644 /tmp/r_env.tar.gz\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:57:09.143", - "progress": 0, - "config": { - "editorSetting": { - "language": "sh", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": false - }, - "colWidth": 12.0, - "editorMode": "ace/mode/sh", - "fontSize": 9.0, - "title": true, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "rmr: DEPRECATED: Please use '-rm -r' instead.\n21/08/09 10:57:10 INFO fs.TrashPolicyDefault: Moved: 'hdfs://emr-header-1.cluster-46718:9000/tmp/r_env.tar.gz' to trash at: hdfs://emr-header-1.cluster-46718:9000/user/hadoop/.Trash/Current/tmp/r_env.tar.gz1628477830555\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096911_217029483", - "id": "paragraph_1617163700271_1335210825", - "dateCreated": "2021-06-19 21:58:16.911", - "dateStarted": "2021-08-09 10:57:09.148", - "dateFinished": "2021-08-09 10:57:16.029", - "status": "FINISHED" - }, - { - "title": "Configure R Interpreter", - "text": "%r.conf\n\n# set zeppelin.interpreter.launcher to be yarn, so that R interpreter run in yarn container, \n# otherwise R interpreter run as local process in the zeppelin server host.\nzeppelin.interpreter.launcher yarn\n\n# zeppelin.yarn.dist.archives can be either local file or hdfs file\nzeppelin.yarn.dist.archives hdfs:///tmp/r_env.tar.gz#environment\n\nzeppelin.interpreter.conda.env.name environment\n\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:57:16.052", - "progress": 0, - "config": { - "editorSetting": { - "language": "text", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": false - }, - "colWidth": 12.0, - "editorMode": "ace/mode/text", - "fontSize": 9.0, - "title": true, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096911_1248279804", - "id": "paragraph_1616750271530_2029224504", - "dateCreated": "2021-06-19 21:58:16.911", - "dateStarted": "2021-08-09 10:57:16.057", - "dateFinished": "2021-08-09 10:57:16.058", - "status": "FINISHED" - }, - { - "title": "Base plotting", - "text": "%r.ir\n\npairs(iris)\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:57:16.155", - "progress": 0, - "config": { - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true - }, - "colWidth": 12.0, - "editorMode": "ace/mode/r", - "fontSize": 9.0, - "results": {}, - "enabled": true, - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "IMG", - "data": "iVBORw0KGgoAAAANSUhEUgAAA0gAAANICAMAAADKOT/pAAADAFBMVEUAAAABAQECAgIDAwME\nBAQFBQUGBgYHBwcICAgJCQkKCgoLCwsMDAwNDQ0ODg4PDw8QEBARERESEhITExMUFBQVFRUW\nFhYXFxcYGBgZGRkaGhobGxscHBwdHR0eHh4fHx8gICAhISEiIiIjIyMkJCQlJSUmJiYnJyco\nKCgpKSkqKiorKyssLCwtLS0uLi4vLy8wMDAxMTEyMjIzMzM0NDQ1NTU2NjY3Nzc4ODg5OTk6\nOjo7Ozs8PDw9PT0+Pj4/Pz9AQEBBQUFCQkJDQ0NERERFRUVGRkZHR0dISEhJSUlKSkpLS0tM\nTExNTU1OTk5PT09QUFBRUVFSUlJTU1NUVFRVVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1e\nXl5fX19gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29w\ncHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGC\ngoKDg4OEhISFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OU\nlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJydnZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWm\npqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4\nuLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLDw8PExMTFxcXGxsbHx8fIyMjJycnK\nysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc\n3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u\n7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7////i\nsF19AAAACXBIWXMAABJ0AAASdAHeZh94AAAgAElEQVR4nOydBXgURxvH37XT3F3cjQgJEMEJ\nENw1uDsUKW4FijsULe5e3KVAi1Oc4lLkKw4t7iRE5pu5EHKX28tJNpek7P952Cy7M7Nzu/vb\n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\n143vRQp0iZQ0TASoeZYqYqSHpgJil2x0J68SaYDD/hf7HJLLkC9wAqj96FI135T38Ft7cu4i\ngZ58avH+ERefzuEO6a7JHPmDSImh5f55tliwO7Pdn1s5CTlnyTV8I1LAMBzX4v7druqHN+T9\nH9xua5MlT9E0yIhI24XLnp0LK5eBNnpHKgaQyIM4aTOqqbWBXleWS2yM7sQX6BJphtn258e8\nWprSGMfnkMgs23xGyKtEsqQK3FqrlBXtaMmN11xKwYNdZp8S3uPK3+k2cZKln/cWbUw5fP4g\n0iW+bl3XBpntvsYh4XMcLk3dQhLiE2YWJ/JcYtEFk+jodILTCqN7kxGR6tHCBHcyqjs/wzfp\nw6dEt8WxGrIpqVC+JuuF6nWhSyS/6eTPb9xH49vaAz/gR9hWYHpv8iqRYoCm4TiFUixymjrx\nyfnnklM8dtNT0WYLz74xFUw5fP4g0s9SquLMKJnZ7hP46O6WnTS/NEkTIr/rzl+zilnKG54G\nGREpYDaZJIn0uI4now/P+2rJddFoJj382JQylcnQJRKtMYgfwg29m2eIgUBfvqEF0djgQqMV\nJ7ulrOhTnjw8V9CF5N+/iclbOd5nfKp9d4yhsWBvVsBpck8r9jTl8PmDSPeBaji12ma2+07V\nc7KTmzZDw492Tw4feWi9Zr7LR/xmp1z7Snp58HhW3+AZEaklTYL/e0aFIJY4Pjl89KFl8uNm\nSTOqDgXevr1zzG9Z7EJq6BIpjN6t1bKsZnJOhXPQYd24UzKxCd3A+P3Rw2/zLpFWiQZvHyz6\n4vR1x6zexvnOUSm/Eyt5Lt5Qxf7flAVXzImY6/J+jZkQsd02NVClcXDMKvIHkXBH21mbmkkN\nj1VqEV+6xPK1ZV21w9UfHDmW5Yp8fOse1k2KkA3NP4sXy0Ws4+Gs9SYjIl2QtNw806ZrBnu/\nt+dYhnNNbmIRFBtQHYWRuetqcuOcX2etD6mgS6T9XM+tYxWTjW6JwIw3Now1Zded1pxAvTHP\nEglvLmVZenOqNRfr2RYdmapa5pv+7vZNb375bSc9glezvsJZ8a/KMpZ1z5t0+HxCpNgJ3tY1\ndVy0dfEi2tWxVXK9lauiICfnIMkN/KAWUnd9MFh5n0ZjLUmI6Wn5b4atJCNDq93p6tbekzIy\nyV8SBjs6l5SmvN/mmjPiKLqDo+QgXscZ752jx/y9v5xlwBJTLPuJUhYBi5qYsOst2ejYuMni\n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\nUCQEUYD/B3YDqx+lN7unAAAAAElFTkSuQmCC" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624114803899_1367546113", - "id": "paragraph_1624114803899_1367546113", - "dateCreated": "2021-06-19 23:00:03.899", - "dateStarted": "2021-08-09 10:57:16.158", - "dateFinished": "2021-08-09 10:57:47.946", - "status": "FINISHED" - }, - { - "title": "Use ggplot2", - "text": "%r.ir\n\nlibrary(ggplot2)\npres_rating <- data.frame(\n rating = as.numeric(presidents),\n year = as.numeric(floor(time(presidents))),\n quarter = as.numeric(cycle(presidents))\n)\np <- ggplot(pres_rating, aes(x=year, y=quarter, fill=rating))\np + geom_raster()\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:57:47.983", - "progress": 0, - "config": { - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "colWidth": 6.0, - "editorMode": "ace/mode/r", - "fontSize": 9.0, - "title": true, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nAttaching package: ‘ggplot2’\n\n\nThe following object is masked from ‘package:SparkR’:\n\n expr\n\n\n\n" - }, - { - "type": "IMG", - "data": "iVBORw0KGgoAAAANSUhEUgAAA0gAAANICAIAAAByhViMAAAACXBIWXMAABJ0AAASdAHeZh94\nAAAgAElEQVR4nO3deXxU5aH4/zMhqyFssuMGFSwouNSrFNGXerEuxaK+kBYXFK+CVmu9gq2A\n3wIutL1cEau2Ki5U0VIVitQFb6l1o1irgtBbLQjWiqCoSGQL2eb3x9xfGsGGmMnJJM+836/8\nkZk5zznPhDH5eM6cOYlkMhkBANDy5WR6AgAANA5hBwAQCGEHABAIYQcAEAhhBwAQCGEHABAI\nYQcAEAhhBwAQiNxMT+BztmzZUllZmZFN5+fnJxKJnTt3ZmTrLVdBQUFhYeH27dsrKioyPZcW\npqioqKKiIlMv+JarqKgoPz9/y5Yt1dXVmZ5LC1NcXLxjxw4/ty+rdevWrVq1Ki0tzfREWp6S\nkpItW7Y0eHj79u0bcTLZo3mFXXV1dVVVVaa2nkwmM7j1FiqZTObk5PjRNYyfW8Pk5ORk9ndF\nC5VIJPzcGiCRSOTk5Pi5NYCfW0Y4FAsAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcA\nEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEH\nABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhhBwAQCGEHABAIYQcAEAhh\nBwAQCGEHABAIYQcAEAhhBwAQCGEHABCIRDKZzPQc/qmioiInJzOtmUgkoihqVj+NFiGRSOTk\n5FRXV/vRfVk5OTnJZNLP7cvKyclJJBJVVVWZnkjLk/pPNdOzaHm85BqsVatW6fzcWrVq1YiT\nyR65mZ7A52zfvr2ioiK+9Z//6IYGj/3Lwz9JZ9NdBhyXzvChnRo+8yiKFrzXJp3hWza8k87w\n0n+8mc7wovZd0hm+z9eHpjO8amdZg8e2/8qAdDadk5efzvBP3no1neEV2z9LZ3jb/b6azvDt\nH69PZ3iXAcemM7xix9YGj920elk6my7p3iud4WWlH6cz/JNVr6UzPCc3rVdsdWV5OsNLuqX1\no6ss25bO8KryHQ0ee1bPhv+SiaLozt++ns7wqoq0tv7msw/X8WiHDh0+/fTTBq+8Y8eODR6b\nzRyKBQAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLAD\nAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISw\nAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiE\nsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAI\nhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMA\nCISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLAD\nAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISw\nAwAIhLADAAiEsAMACISwAwAIhLADAAiEsAMACISwAwAIRBOF3VtvvXXmmWeeccYZTbM5AIAs\n1BRh99lnn02fPv3www9vgm0BAGSt2MMumUzefPPNQ4YM6d+/f9zbAgDIZrGH3dy5cysrK7/z\nne/EvSEAgCyXG+va33jjjUWLFs2cOTORSHzhAq+++uqtt95ac/Oaa67p169fnDPaEOfKASCL\ntGvXro5Hc3Jy6l6AOMQYdp9++unNN9981VVXtW/f/l8ts2XLljfffLPmZllZWW5uvK0JADSK\nPf7J9je96cX4E3/nnXc2b958/fXXp24mk8lkMnnGGWeMGDHinHPOSd15wgknvPrqqzVDSktL\nP/744/imBAA0lrr/ZHfo0GHTpk0NXnnHjh0bPDabxRh2/fr1u+2222pu/v73v1+4cOGtt95q\nxywAQBxiDLvCwsL999+/5mbqgGztewAAaESuPAEAEIimC7szzzxzwYIFTbY5AIBsY48dAEAg\nhB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBA\nIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0A\nQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQd\nAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCE\nHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAg\nhB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBA\nIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAghB0A\nQCCEHQBAIIQdAEAghB0AQCCEHQBAIIQdAEAgcjM9gc8pKioqLi6Ocwsb4lw5AGSRdu3a1fFo\nTk5O3QsQh+YVdjt37qysrIxv/YXtOjd47F6d9k1n08nqqnSGpym/dft0hhe0+Syd4UXtu6Qz\n/D/+vXc6w//U5ZB0hlfu2NrgsQVtOqSz6S3vr0lneH5JWv/oOzatT2d4+bbSdIbnFqX1P3hl\npR+lM3z7xw1/7nnFbdLZdJoK23ZMZ3hJt17pDP9k9evpDK+qKEtneOf+g9MZns5/6VEU7Sz9\nOI3RaT3x1un9q5X+46/pDN+yZUsdj7Zt27buBerWvn1av8SyVvMKu+rq6qqqTAYQAFBPe/yT\n7W960/MeOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCA\nQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsA\ngEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCA\nQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsA\ngEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEDkxrr2F198ceHChe+///7OnTv33nvv\nY4899jvf+U5eXl6sGwUAyE7xhl2rVq2GDBnSvXv3/Pz8t99++5e//OVnn312+eWXx7pRAIDs\nFG/YDRo0qOb7gw466N13312xYkWsWwQAyFpN9B676urqtWvXLl++/NBDD22aLQIAZJt499hF\nUVRRUXH22Wcnk8lkMvmNb3xjzJgxtR/93//93wcffLDm5oUXXtizZ884p7M5zpUDQBYpKSmp\n49FEIlH3AsQh9rDLzc299dZbKyoqVq9ePWfOnDZt2owaNarm0Y0bNy5evLjm5llnnVVQUBD3\nlACA9O3xT7a/6U0v9rBLJBL7779/FEUHHnhgTk7Oz3/+87POOqt169apRwcOHPj444/XLFxQ\nUPDpp5/GPSUAIH11/8lu27ZtaWlpg1fevn37Bo/NZrGHXW2VlZXJZLKysrLmnqKioh49etTc\nLC0traioaMopAQANU1VVleYCNLp4w+7uu+/u06dPly5dqqurV61aNXfu3COPPLJdu3axbhQA\nIDvFG3aFhYWPPvroxo0bc3JyOnfufPbZZ59++umxbhEAIGvFG3ajRo2qfaoEAEAwFi9efNJJ\nJ91///0XXnhhpufyf1wrFgBgD1atWjVlypTmf52FJj15AgCgJVq1atXUqVMPPPDAAQMG1Nx5\n4okn7tixIy8vL4MT24U9dgBA9tq+fXuDx+bk5BQWFrZq1aoR55MmYQcAZIvHHnsskUg88sgj\nU6dO7d27d35+/vXXXx9FUWlp6XXXXXf00Ud37NixoKCgV69e48eP37p1a2rUlClTUmd/nn/+\n+YlEIpFIHH/88VEULV68OJFIzJ49u/bK582b99Of/rRPnz4FBQX77bffTTfdlEwma89h/fr1\n5513Xvv27Vu3bn388ccvXbp0+PDhhYWFjfIEHYoFALLLD3/4wx49ekybNq1r166pA6nvvffe\n3XffPXz48JEjR+bn57/wwgszZsx45ZVXnn/++UQiceGFFxYUFEycOHHixIknnXRSFEV1fHbb\nD37wgz59+vzsZz9r167dPffcc9111+29996XXnpp6tHPPvvsuOOOe+edd8aOHXv44YevWLHi\n5JNP3nfffRvrqQk7ACC75OfnP/fcc7m5/6yg3r17v//++zXvlvvud787YMCASZMm/f73vx8y\nZMgBBxzQv3//KIr69u2b2ldXhw4dOjz11FOJRCKKoqOOOuqFF1742c9+VhN2//3f/71mzZq7\n7777kksuSd1z1FFHjRo1qrEuv+ZQLACQXUaPHl276qIoKigoqKm6ioqKsrKyM888M4qil19+\n+cuuPHW4NvV9Tk7OkUceuWbNmurq6tQ9CxYs6Nix40UXXVSz/HnnnbfPPvs07InsTtgBANml\nZ8+eu985e/bsQYMGFRcX5+fnFxUV9evXL4qiTZs2fdmV73JctU2bNuXl5Vu2bEndXLt27YEH\nHlj7fItEInHQQQd92a38K8IOAMguux/3nDFjxujRozt27HjPPfc899xzS5cufeKJJ6IoqtnT\nVn81u+tqq33+xBcu0Fi8xw4AyHb33ntvz549H3/88ZrqevHFF2sv0Fg11qtXr9WrV1dVVdXs\ntEsmk6tWrWqUlUf22AEA5OTkJJPJqqqq1M2qqqpp06bVXqCkpCRq0JHZXQwbNuzjjz+u+YSU\nKIoefvjh9957L83V1rDHDgDIdsOHD58yZcqpp546YsSILVu2zJ07d5cPnzv00EMLCwtvu+22\n/Pz8du3ade7c+cQTT2zAhsaPH//QQw+NHTt22bJlhx122IoVK2bPnt2vX7+1a9c2yhOxxw4A\nyHaTJk268cYb33nnnSuuuGLmzJmDBw9+9NFHay/Qtm3bhx9+uLi4+Kqrrho5cmTqY40boG3b\nti+++OKIESPmzJnz/e9/f9myZU8//fQ+++xTVFTUGM/DHjsAIGsMHz58l11xKbm5uZMmTZo0\naVLtO3dZ8swzz0x9BkqNIUOG1F7mC1d+55133nnnnbXv6dGjx8MPP1z7ntWrV++///5f5nn8\nS/bYAQA0nbKysto3f/3rX7/zzjsnn3xyo6zcHjsAgKZz2mmn9ezZ88gjj8zLy3vllVfuu+++\nHj16jBs3rlFWLuwAAJrOqaee+tBDD82bN2/btm1dunS54IILpk6d2qlTp0ZZubADAGg611xz\nzTXXXBPTyr3HDgAgEMIOACAQwg4AIBDCDgAgEMIOACAQzooFAMK3rSK58qPqRl9tl+JEz7bN\naDeZsAMAwrdxe/KWP5c3+mpP3D937GHCDgCgKSWjZLLx99hFcawzDcIOAMgOyWSmZxA7YQcA\nhC8ZJZMxhF0c60yHsAMAskMsh02FHQBAk7PHDgAgCMl43mPXvLpO2AEAWSEZy1mxkbNiAQCa\nnj12AABhiOU9ds2s7IQdAJAN4jkU28xOnmhGF8EAAIhL6uSJOL72pLq6etq0aX369CkqKure\nvfu55577j3/8o+bRJ5988rDDDissLNx3330nT55cXZ1WfQo7ACB8yShKJqsb/6seh2KnT58+\nderUCRMmrFy58qGHHlq+fPmwYcNSD7388svDhg0bPHjwn//855tuumn69Ok/+tGP0nmaDsUC\nANkhQydPvPTSS4MHDx49enQURQceeODll19++eWX79y5s6CgYPr06X369Ln99tujKOrfv//q\n1atvueWWiRMn7rXXXg2bjj12AEBWSMZjj9s9/vjjX3vttaVLl0ZRtGHDhkceeeSUU04pKCiI\nomjJkiWnnHJKzZKnnHLKtm3bli1b1uDnaI8dABC+vJzoB8d1qH3Pa+t2/H7Nti+1kr33avUf\n/9a+9j3lVXsOu3HjxpWXlx933HFRFFVWVp588smPPfZYFEXV1dUffvhh165da5ZMfb9+/fov\nNavahB0AEL6KquRPn/sozZV8vK1yl5V8o3frE3oV1z3qsccemz59+u233z5o0KB169b98Ic/\nHDFixBNPPPGvlk8kEg2eobADALJDhj6a5Oqrr77gggvGjh0bRVH//v3bt2//9a9/fenSpYMG\nDerSpcsHH3xQs2Tq+27dujV4W95jBwBkg2SUrI7la0+2b9+ek/PP4kp9X1VVFUXRMcccs2jR\nopqHFi1aVFxcfPjhhzf4SdpjBwBkhViuPFGPVZ555pl33XXXgAEDUodix48f37Nnz6997WtR\nFF1zzTWDBw++4oorxo4du3z58ptvvvnqq69u8CmxkbADALJFLIdi97zOW2+9tVOnTjfccMP7\n77/fvn37wYMHT5s2LVVvAwcOXLBgwXXXXTdr1qxOnTqNHz9+ypQp6cxG2AEAWSAZyx67+nyO\n3V577TVt2rRp06Z94aNDhw4dOnRoY01H2AEA2SCWa8UmoxiuP5sGYQcAZIcYwi5TZ9r+K3s+\nK3b79u3XXnvtK6+80gSzAQCIQzJzV55oSnsOu6KiohkzZlRUVDTBbAAA4pJMNv5XM7PnQ7GJ\nRGK//fbbsGFDE8wGACAWyVjeY9fc2q5eH1B8/vnnz5w5s7KyMu7ZAADEJZY9ds0r7Op18kTf\nvn1nz5598MEHjx49umfPngUFBbUfPeOMM+KZGwBA44nl405aYNh9+9vfTn0zYcKE3R9tbm8b\nBADYXaauPNGU6hV2jz76aNzzAACIUzKWjztpiYdihw8fHvc8AABiFNeVJ1pg2KVUVla+8cYb\nGzdu/PrXv96uXbv45gQA0PgydK3YplSvs2KjKPrVr361zz77HHnkkaeddtpbb70VRdH69es7\nd+48Z86cOKcHANAokslkdQxfLTDsnnnmmXPPPXefffaZPn16zZ3du3cfMGDAvHnzYpsbAEDj\niO3KE5l+Yp9Xr7CbNm3aYYcd9vLLL19xxRW17//617/+xhtvxDMxAIBGlaxu/K8ojhMyGq5e\nYffaa6+dd955ubm7viHPFSkAgJYhGcseu2b2Frv6nTxRVVW1y4cSp2zcuDEvL6+xpwQA0Oji\nubRrMzsWW689dn369HnppZd2uTOZTC5cuPCQQw6JYVYAAI0tlkOxLTDsLrjggkceeeT++++v\nuWfr1q2XXXbZK6+8cuGFF8Y1NQCAxhPHodhkM9tjV69DsVdeeeXixYsvuuiia6+9NoqiUaNG\nvfvuu+Xl5aeffvrFF18c8wwBABpDM4uwONRrj11ubu5vf/vbO+64o2fPnm3atNmwYcMhhxwy\nc+bM3/zmNzk59f0kPACAjIlpd10zi8X6XnmiVatW3/3ud7/73e/GOhsAgLjEca3YZhZ29drf\ndvzxxy9fvnz3+5999tnjjz++kWcEABCDmHbZZfppfU699tg9//zzmzdv3v3+jRs3Pv/88409\nJQCAGMTycSeNv8p01PdQ7BfavHlzYWFhY00FACAmqc8njmO1jb7OdNQVditWrFixYkXq+9/9\n7nfr1q2r/eimTZtuu+22vn37xjg7AIBGkcyK99jVFXbz58+fOnVq6vtp06btvkBRUdHcuXNj\nmRcAQKNKZnnYnXPOOUceeWQURaeffvq0adP69+9f81AikSgpKTnssMPatGkT+xwBANIV00eT\ntJyw69OnT58+faIomjx58siRIw844IAmmhQAQGOL5T12zWyP3Z4/7mT79u1lZWUbN25sgtkA\nAMQl9XnCjfvVzOw57IqKimbMmFFRUdEEswEAiEkyWR3DV/Nquz1/3Ekikdhvv/02bNjQBLMB\nAIhFMqbPsWteYVevK0+cf/75M2fOrKysjHs2AADxiOfCEy3o5Ikaffv2nT179sEHHzx69Oie\nPXsWFBTUfvSMM86IZ24AAI3HlSdSvv3tb6e+mTBhwu6PNrejywAAu0jG8zl29bzyRGlp6eTJ\nk+fNm7dx48Zu3bpdcsklkyZNSj305JNPTpo06a233urUqdNFF100efLknJx6HVD9QvUKu0cf\nfbTBGwAAaB4y8zl2ZWVlJ5xwQkVFxU9+8pMDDzxw06ZNW7ZsST308ssvDxs27NJLL33wwQeX\nLVt26aWXVlVV3XjjjQ2eTb3Cbvjw4Q3eAABAMxDLtWLrc3h35syZ//jHP1atWtWhQ4ddHpo+\nfXqfPn1uv/32KIr69++/evXqW265ZeLEiXvttVfDplOvsGsyhYWFhYWFcW5hc5wrB4AsUlJS\nUsejqYtUNdlk9iwZRdWZuaTYY489duKJJ06aNGnBggWtW7c+4YQTfvzjH++9995RFC1ZsuSc\nc86pWfKUU0658cYbly1bdswxxzRsOvUNu2QyuXjx4j/96U+bNm2q/vzPZebMmQ3b9u7Ky8ur\nqqoaa227yy9u2+CxhW33TmvTJe3TGf7gK2+mM3zv3vunM3zHpg/SGV5W+lE6w+/9fTqjo4O/\nndYratvG9xo8tmpnWTqbzi0qTmd4+bbSdIYnclplcHiaSnr0ztSmyzZ/nM7w3KLW6Qzf/vH6\ndIZv+2hdOsPb7ntQOsOrynekMzxNZZ9+mM7wiu2fNXjs/7Ttl86mcwuXpzM8zf9Ud+yo618t\nLy+v7gXqtsuZmo0initP7HmZNWvWrFy58swzz1y4cOHHH3/8/e9//7TTTlu6dGkURR9++GHX\nrl1rlkx9v359w/9brlfYbdmy5dRTT12yZMkXPtqIYVddXe1DVQCgRdjjn+xm9Tc9r1XOTecN\nqn3PH9/c8OSra7/USjq1LbrqW0fUvmdn5Z73AlZVVbVr1+6BBx7Iz8+PoqiwsPDEE09csmTJ\nv9otl0gkvtSsaqtX2E2ePHnp0qXTpk0744wz+vXr98QTT5SUlNx0002ffvqp8yoAgOavoqpq\n4gMvprmSjZu37bKSbx194KlHHFD3qO7du3fs2DFVdVEUHXLIIVEU/f3vfz/22GO7dOnywQf/\nPCyW+r5bt24NnmG9zqf9zW9+M2LEiAkTJvTs2TOKor333vu444576qmnkslk6u1+AADNXjKe\nrz047rjj1qxZU3N11r/+9a9RFKWa6phjjlm0aFHNkosWLSouLj788MMb/AzrFXbvv//+scce\nG0VR6oNVUjNr1arVd77zHXvsAIAWIHVJsTi+9mTcuHGlpaUXX3zxypUrn3vuucsuu+zoo48e\nNGhQFEXXXHPNqlWrrrjiipUrVz744IM333zzVVdd1eBTYqN6hl1xcXEq5vLz8wsLC2ve09em\nTZva+w8BAJqteC4ptmcHHXTQ4sWL16xZc9RRR5177rkDBw584oknUjvLBg4cuGDBgpdeeunI\nI4+cMGHC+PHjr7/++nSeY73eY9erV6+//e1vqe8PPfTQuXPnjhgxoqqq6te//vU+++yTzuYB\nAJpEvfauffm11mudgwYNeumll77woaFDhw4dOrSxplOvPXbf+MY35s2bl9ppd/HFFy9YsODA\nAw/s3bv373//+9GjRzfWVAAAYpK6pFgMX83rwqr12mN37bXXnnvuuamPr7v44otLS0vvu+++\nnJycKVOmXHvttTHPEACgMcQSYS0w7Nq2bdu27T8/2nfcuHHjxo2LbUoAAI0tGcsHFDezrmtm\nlxQDAIhHPO+xa2ZlJ+wAgKyQTDb+tWJb5HvsWreu6/KFW7dubaTJAADEJnNnxTaZeoXdkCFD\nat+srKx8++23//a3v/Xv379Xr17xTAwAoBElY9lj1xIPxS5YsGD3O+fPnz9mzJhf/epXjT0l\nAIDGloxpj13jrzId9focuy901llnDRs2bPz48Y04GwCAmMRz5YnmVXYND7soigYMGPCvPkYZ\nAKB5ydC1YptSWmfFrlixIpFINNZUAABikoznDNZm1nX1C7tXX311l3s2bdr09NNP33///Wec\ncUYMswIAaFzJKGr8kyea26HYeoXdv/3bv33h/QMHDvzZz37WqPMBAIiHDyhOueWWW2rfTCQS\nHTp0OOigg4466qh4ZgUA0KjiuqRYCwy7q666Ku55AADEq5lFWBxcUgwAyAbJeE6eaF6xKOwA\ngOwQw5UnmttewHqFXWFhYT1XV1ZWlsZkAADiEsseu5Z48sTQoUP/+te/vvnmmz169DjooIMS\nicRbb731/vvv9+3bt1+/fnFPEQAgXcmkPXb/5+qrrz755JPvu+++Cy64ICcnJ4qi6urq++67\n76qrrrrnnnsGDRoU8yQBANIVz/vhWmDYXXvttRdccMHo0aNr7snJybn44otff/31CRMmPP/8\n87FNDwCgkcTycSeNv8p01Otasa+99tqhhx66+/2HH3747helAABoblKXFItDpp/Z59Rrj11+\nfv6yZct2v/+1114rKCho7CkBAMSgmUVYHOq1x27o0KF33XXX3XffXVlZmbqnsrLyzjvvnDVr\n1umnnx7n9AAAGkNMu+uaWSzWa4/d9OnT//SnP40dO3bSpEm9e/dOJpOrV6/+5JNPDjrooP/6\nr/+Ke4oAAI0hhrNim9mb7Oq1x65r166vvfbalClTunfvvmLFipUrV/bo0WPq1ParwAYAABjc\nSURBVKmvvvpqly5d4p4iAEAjSO1ga/Sv5qS+V54oKSmZPHny5MmTY50NAEBM4jjRoXllnUuK\nAQDZIpaPO2leaSfsAIBskEzGcOWJFnlJMQCAli1pjx0AQChi+TDh5tV1wg4AyBKuFQsAEIBk\nTO+xcygWACADsmCPXb0+oBgAoGVLxnVRsfr74x//mJeXl5v7ud1qTz755GGHHVZYWLjvvvtO\nnjy5ujqt3YrCDgDIEsl4vurl448/Hjly5Mknn1z7zpdffnnYsGGDBw/+85//fNNNN02fPv1H\nP/pROs/QoVgAIBvEc/mv+q2zurr63HPPHT16dOvWrRctWlRz//Tp0/v06XP77bdHUdS/f//V\nq1ffcsstEydO3GuvvRo2HXvsAICskMEDsTfccEN5efnue+OWLFlyyimn1Nw85ZRTtm3btmzZ\nsgY/R3vsAIDskKE9dosXL77zzjtff/31nJzP7VCrrq7+8MMPu3btWnNP6vv169c3eDrCDgAI\nX15uqxsuP7v2PX98Y9VTL365fWOd2rf5/rmn1r5nl1bb3QcffHDeeef98pe/7NatWz23kkgk\nvtSsahN2AED4Kiorr7ttbpor+WhT6S4rGXHy10d8Y2AdQ5YvX/7hhx9+85vfTN1MJpPV1dW5\nubmTJk2aOnVqly5dPvjgg5qFU9/XPwF3J+wAgCyQzMwlxQYPHrxy5cqam7Nnz545c+by5cs7\nd+4cRdExxxyzaNGiGTNmpB5dtGhRcXHx4Ycf3uDpCDsAIDvEcOWJKNrDOlu3bn3IIYfU3Ey9\ni67mnmuuuWbw4MFXXHHF2LFjly9ffvPNN1999dUNPiU2EnYAQDZIxnP5rzRXOXDgwAULFlx3\n3XWzZs3q1KnT+PHjp0yZks4KhR0AkA2+xIcJf8nVfgnjx48fP3587XuGDh06dOjQxpqNsAMA\nskMs14ptXoQdAJAV4jkU27xiUdgBAFkgmbEPKG5Kwg4AyArNbe9aHIQdAJANkvbYAQAEIrmn\nz5xr0DqFHQBA04tl75qwAwBoYskoWR1DhMVxMYs0CDsAIBsk46kwe+wAAJqeQ7EAAAGI7Vqx\nwg4AoOnF8nEnjb/KdAg7ACAbJGPZY9fMyk7YAQBZwnvsAAACkIzn/XDNq+uEHQCQJZwVCwAQ\nCHvsAACCEM/JEz7uBAAgA5KuPAEAEIC4Tp4QdgAATa+ZRVgchB0AkA2ScXyYsA8oBgDIBIdi\nAQAC4eNOAAACkIyiZAxnxToUCwDQ5JIOxQIABCKWkyea27FYYQcAZIdmtnctDsIOAMgODsUC\nAIQhnmvFNvoq0yLsAIAs4T126Vm8ePHzzz//97//fefOnd27d//mN7950kknxbpFAIAvkEwm\nqx2KTc+zzz578MEHDxs2bK+99vrjH/942223VVZWnnrqqbFuFABgF23blpx+0uBGX+2hB/du\n9HWmI96wmzZtWs33/fr1e+edd5YsWSLsAIAmtn+PrvffMjnTs4hdTlNurLy8vG3btk25RQCA\n7NF0J08sXrz47bffHjNmTO07165d++STT9bcPO2007p3795kUwIAGqy4uLiORxOJRN0LEIcm\nCrsXX3zxzjvv/M///M/evT93KPrdd9/95S9/WXPz6KOP/spXvhLnRMriXDkAZJGioqI0F6DR\nNUXYPf300/fee+/48eMHDhy4y0NHHnnkgw8+WHNz77333rx5c5xzKYxz5QCQRer+k92mTZvP\nPvuswStv165dg8dms9jDbu7cufPnz/9//+//HXroobs/WlJS0rdv35qbpaWlFRUVcU8JAEhf\nZWVlmgvQ6OINu1mzZj311FNjxowpKSlZu3ZtFEV5eXn77rtvrBsFAMhO8Ybdc889V1VV9Ytf\n/KLmnq5du959992xbhQAIDvFG3YPPfRQrOsHAKBGk36OHQAA8RF2AACBEHYAAIEQdgAAgRB2\nAACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQ\ndgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACB\nEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAA\ngRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYA\nAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2\nAACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQ\ndgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACBEHYAAIEQdgAAgRB2AACB\nEHYAAIEQdgAAgcjN9AQ+Jz8/Pz8/P9OzAAD2rLi4uI5HE4lE3QsQh+YVdtXV1dXV1fGtv+/r\nNzd47Ps9Dktn0+8tXZjO8EROq3SGl3Tvlc7wLRvWpjM8maxKZ/j2j9alM3zz3/+SzvCS7l9J\nZ3g68ovbpjO8qEPXdIZXV5anM7xi22fpDG+7/1fTGb41vVdsOj+6NP/VcotapzM8zX+1Dgem\n9Vvu47deSWd4WelH6Qzfq9M+6Qxvs0+fdIZv/vv/Nnhsmi/X7l87KZ3hpe/+NZ3hlZWVaS5A\no2teYVdZWVlRUZHpWQAAe7Zz5846Hi0uLq57gbqVlJQ0eGw28x47AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCA\nQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsA\ngEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQOTGuvZVq1bNmzdvzZo1GzduPOmkk773ve/FujkAgGwW7x67srKybt26nX/+\n+d26dYt1QwAAxLvHbsCAAQMGDIiiaP78+bFuCAAA77EDAAhEvHvs9ugf//jHH/7wh5qbxx13\nXOfOnTM4HwCgnoqKiup4NJFI1L0Acchw2K1Zs+a2226rudm3b9+ePXtmcD4AQD0VFxenuQCN\nLsNhd/DBB//kJz+pudmjR48tW7ZkcD4AQD3V/Se7devWW7dubfDKS0pKGjw2m2U47Dp37jxk\nyJCam6WlpTt37szgfACAeqr7T3ZxcXE6f9OFXcPEG3bl5eXr1q1LfbN169a1a9cmEgkHWwEA\n4hBv2K1bt+6qq65Kff/+++8vXbo0JydnwYIFsW4UACA7xRt2vXr1WrhwYaybAAAgxefYAQAE\nQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEA\nBELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgB\nAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELY\nAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC\n2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAE\nQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEA\nBELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEQtgB\nAARC2AEABELYAQAEQtgBAARC2AEABELYAQAEIjfTE/icvLy83NwYp5RIJNIYm7FNN8LwdAZn\nfPLpDk9ndLo/ugxuOu1/9IwOT2t0Joe33JlHLf23XGZfcmmMz/TM01pBUVFR3SuvewHikEgm\nk5mewz9t3749U/PJy8uLoqiioiIjW2+58vLy8vPzd+7cWVlZmem5tDAFBQWVlZVVVVWZnkgL\nU1BQkJubu2PHjurq6kzPpYUpLCzcuXNns/qd3yIUFRXl5ORs27Yt0xNpefbaa6/t27c3eHhx\ncXEjTiZ7NK89dhUVFZlNqx07dmRw6y1Ufn5+eXn5zp07Mz2RFqZVq1bl5eXl5eWZnkgL06pV\nq9zc3LKyMk38ZaX+H8zP7csqKCjIycnx16EBioqK0vm5CbuG8R47AIBACDsAgEAIOwCAQAg7\nAIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAI\nOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBA\nCDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQCSSyWSm50AL9vLLLz/7\n7LNnnXXWV7/61UzPhazwxBNPrFixYsyYMR07dsz0XMgKs2fPXr9+/cSJEzM9EagXe+xIy6pV\nq+bPn79+/fpMT4Rs8frrr8+fP3/Lli2ZngjZ4rnnnvvNb36T6VlAfQk7AIBACDsAgEAIOwCA\nQDh5AgAgEPbYAQAEQtgBAARC2AEABCI30xOgeVm1atW8efPWrFmzcePGk0466Xvf+17NQxUV\nFfPmzXvuuec++uijjh07Dh069PTTT0899OSTT951112113PDDTcceuihqe9fffXVBx98cN26\ndW3bth0yZMjIkSMTiUSTPSOauYa95KIo2r59+0MPPbR06dLNmzd36NDhG9/4xogRI1IPeclR\nh4a95K6++uq333679noSicTcuXOLiooiLzmaE2HH55SVlXXr1m3QoEEPP/zwLg/dc889L774\n4mWXXfaVr3xl9erVv/jFLxKJxNChQ1OPlpSU3HDDDTULd+/ePfXN3/72txtvvPHUU0+9+uqr\n16xZ8/Of/7y6uvq8885rmqdD89ewl1x5efnEiROrqqpGjRrVvXv3LVu27NixIzXKS466Newl\nN27cuJ07d9Ys+dOf/rRHjx6pqvOSo1kRdnzOgAEDBgwYEEXR/Pnza9+fTCafffbZ4cOHH3vs\nsVEUde/efd26dY888shpp52Wk5MTRVGrVq169eq1+wrnz5/fo0ePsWPHRlG0//77b9iw4fHH\nHz/77LMLCgqa4vnQ7DXsJbdw4cKPPvrozjvvLCkp2WWFXnLUrWEvuR49etQs+fbbb2/YsOGS\nSy5J3fSSo1nxHjvqpbq6urKysvbvqcLCws2bN7///vupm1u2bBk1atQ555zzgx/8YMmSJTWL\nvfnmm0cccUTNzSOOOKKsrGzt2rVNNnNaqLpfcn/84x8HDBgwZ86cCy64YOzYsXfccUfNRca8\n5GiYPf6Wq/HUU0916dLla1/7WuqmlxzNirCjXlq1anX44Yc/+eST7777bjKZXLt27ZNPPhlF\n0SeffBJF0b777nvZZZdNmjRpwoQJ++23309/+tOFCxdGUZRMJjdv3ty+ffua9aS+37RpU4ae\nBy1G3S+5DRs2/OlPf9q6det11103ZsyYlStXTp06NZlMesnRYHW/5Gps3br1hRdeOOWUU1Lv\novOSo7lxKJb6uvLKK3/xi19ceeWViUSipKTkhBNOWLBgQeo4bM2hjSiK+vfvv23btnnz5n3r\nW9/K6Hxp8ep4yVVXVxcXF//nf/5nbm5uFEX5+fmTJk3661//2q9fv0zPmhasjpdcjcWLFyeT\nySFDhmRqklA3YUd9tWvXbsKECZWVlamTEJ955pkoirp167b7kn379l2yZEllZWVubm67du0+\n/fTTmodS33fo0KHJpk3LVcdLrkOHDm3atElVXRRF++23XxRFGzduPPjgg73kaLA9/pZLJpNP\nP/30Mccc07Zt29Q9iUTCS45mxaFYvpzc3NyOHTtGUfTUU08deOCBnTp12n2ZN998s127dqk/\nun379n399ddrHnr99dcLCwu/8DQL+EJf+JI75JBDPvjgg6qqqtQy7733XhRFXbp0ibzkSFsd\nv+WWLVu2YcOGU089tfbyXnI0K62mTJmS6TnQjJSXl7/77ruffvrpiy++WFRU1KNHj5q3j6xY\nseK1116rrKx8++2377rrrnfffffaa6/de++9oyi64447tm7dWlZWtn79+kcfffS5554bOXJk\n3759oyjq3Lnz/PnzS0tLO3XqtGzZsgceeGDYsGG132hMlmvYS65Hjx4LFy784IMPunXr9t57\n7915551du3Y955xzEomElxx1a9hLLuXee+/Ny8sbNWpU7RV6ydGsJJLJZKbnQDOydu3aq666\nqvY9OTk5CxYsiKLoL3/5y1133bV+/fq8vLx+/fqdd955Nf9LOmvWrFdfffWTTz7Jz8/v0aPH\nt771rdTnBaT8+c9/njNnznvvvZf66M7UX9+mfFI0Zw17yUVR9NZbb91///1r1qxp3br1EUcc\nceGFF7Zp0yb1kJccdWjwS+6jjz665JJLxo4du8seu8hLjuZE2AEABMJ77AAAAiHsAAACIewA\nAAIh7AAAAiHsAAACIewAAAIh7AAAAiHsAAACIewAAAIh7IBwbN++PdNTAMgkYQc0vj/84Q+J\nROKGG27Y5f7zzz8/Nzd33bp1qZuVlZUzZsw47LDDioqKSkpKjj/++P/5n/+pWbi0tPS66647\n+uijO3bsWFBQ0KtXr/Hjx2/durVmgcceeyyRSDzyyCNTp07t3bt3fn7+9ddf3wTPDqDZcq1Y\nIBZf/epXy8rK1q5dm5Pzf/8DuXnz5u7du//7v//7b3/72yiKqqqqTj/99Geeeebss88ePHhw\nWVnZnDlzVqxY8dBDD40cOTKKor/85S8nnnji8OHD+/Tpk5+f/8ILLzzyyCODBw9+/vnnU1dY\nf+yxx84+++wDDjigR48e3//+97t27ZqXlzdw4MAMPmuADEsCxODmm2+OouiZZ56puee2226L\nomjhwoWpm3fccUcURffdd1/NAuXl5UcccUSXLl0qKiqSyWRZWVl5eXntdd50001RFP3ud79L\n3Xz00UejKOrTp09qeQAcigViceGFFxYWFs6aNavmnlmzZu2zzz6nnXZa6uYDDzzQuXPnkSNH\nlv3/qqqqRo4c+eGHH77xxhtRFBUUFOTl5aUWrqioKCsrO/PMM6Moevnll2tvaPTo0bm5uU30\nrACaN78NgVh06NBh+PDhjzzyyEcffdSpU6dXXnllxYoVP/rRj1q1apVa4M033/zss8+Kiop2\nH7tx48bUN7Nnz7777rvfeOON2mdFbNq0qfbCPXv2jO1JALQwwg6Iy6WXXjpnzpwHHnhg3Lhx\ns2bNysnJ+Y//+I+aR6urq3v37v3AAw/sPvCrX/1qFEUzZswYN27c6aeffs8993Tv3r2goOCT\nTz4ZOnRodXV17YULCgrifiIALYWwA+JyzDHHHHLIIffcc8+YMWPmzp178skn77fffjWP9unT\n5y9/+cshhxzSunXrLxx+77339uzZ8/HHH0+dKhFF0YsvvtgU8wZosbzHDojR2LFj33rrrSuu\nuGLr1q1jxoyp/dCoUaPKy8vHjx+f/Py5+evXr099k5OTk0wmq6qqUjerqqqmTZvWNNMGaKHs\nsQNidP755//whz984IEHunXrNnTo0NoPXX755YsXL77rrruWLVs2bNiwTp06vffee0uXLn3j\njTdS77EbPnz4lClTTj311BEjRmzZsmXu3LlJH88EUCdhB8Sobdu23/72t++///6LLrpol3NX\nc3NzH3/88VmzZs2ePfvHP/5xZWVl165dDzvssBkzZqQWmDRpUm5u7v3333/FFVd06dJl+PDh\nV155pVMlAOrgA4qBeF166aWzZs1as2bNAQcckOm5AARO2AEx+vTTT/fdd9/jjjvuqaeeyvRc\nAMLnUCwQi+XLl69cufK+++7bvn37xIkTMz0dgKzgrFggFnPmzBk1atTbb799xx13DB48ONPT\nAcgKDsUCAATCHjsAgEAIOwCAQAg7AIBACDsAgEAIOwCAQAg7AIBACDsAgED8f8EKN7rwbcpj\nAAAAAElFTkSuQmCC" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096911_1421779245", - "id": "paragraph_1623916874799_812799753", - "dateCreated": "2021-06-19 21:58:16.911", - "dateStarted": "2021-08-09 10:57:47.986", - "dateFinished": "2021-08-09 10:57:48.701", - "status": "FINISHED" - }, - { - "title": "Use googleVis", - "text": "%r.ir\n\nlibrary(googleVis)\ndf=data.frame(country=c(\"US\", \"GB\", \"BR\"), \n val1=c(10,13,14), \n val2=c(23,12,32))\nBar <- gvisBarChart(df)\nprint(Bar, tag = 'chart')\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:57:48.786", - "progress": 0, - "config": { - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "colWidth": 6.0, - "editorMode": "ace/mode/r", - "fontSize": 9.0, - "title": true, - "results": {}, - "enabled": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nWelcome to googleVis version 0.6.10\n\nPlease read Google's Terms of Use\nbefore you start using the package:\nhttps://developers.google.com/terms/\n\nNote, the plot method of googleVis will by default use\nthe standard browser to display its output.\n\nSee the googleVis package vignettes for more details,\nor visit https://github.com/mages/googleVis.\n\nTo suppress this message use:\nsuppressPackageStartupMessages(library(googleVis))\n\n\n\n" - }, - { - "type": "HTML", - "data": "\n\n\n\n\n\n \n \n\n \n\n \n
    \n
    \n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624111096911_1956298431", - "id": "paragraph_1616751026390_1945717741", - "dateCreated": "2021-06-19 21:58:16.911", - "dateStarted": "2021-08-09 10:57:48.789", - "dateFinished": "2021-08-09 10:57:48.851", - "status": "FINISHED" - }, - { - "text": "%r.ir\n", - "user": "anonymous", - "dateUpdated": "2021-08-09 10:57:48.889", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true - }, - "editorMode": "ace/mode/r" - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1624114845053_735333148", - "id": "paragraph_1624114845053_735333148", - "dateCreated": "2021-06-19 23:00:45.054", - "dateStarted": "2021-08-09 10:57:48.891", - "dateFinished": "2021-08-09 10:57:48.946", - "status": "FINISHED" - } - ], - "name": "3. R Conda Env in Yarn Mode", - "id": "2GB9HRSH9", - "defaultInterpreterGroup": "r", - "version": "0.10.0-SNAPSHOT", - "noteParams": {}, - "noteForms": {}, - "angularObjects": {}, - "config": { - "personalizedMode": "false", - "looknfeel": "default", - "isZeppelinNotebookCronEnable": false - }, - "info": { - "isRunning": true - } -} \ No newline at end of file diff --git a/notebook/Spark Tutorial/7. Spark Delta Lake Tutorial_2F8VDBMMT.zpln b/notebook/Spark Tutorial/5. Spark Delta Lake Tutorial_2F8VDBMMT.zpln similarity index 100% rename from notebook/Spark Tutorial/7. Spark Delta Lake Tutorial_2F8VDBMMT.zpln rename to notebook/Spark Tutorial/5. Spark Delta Lake Tutorial_2F8VDBMMT.zpln diff --git a/notebook/Spark Tutorial/5. SparkR Basics_2BWJFTXKM.zpln b/notebook/Spark Tutorial/5. SparkR Basics_2BWJFTXKM.zpln deleted file mode 100644 index 378698d1a30..00000000000 --- a/notebook/Spark Tutorial/5. SparkR Basics_2BWJFTXKM.zpln +++ /dev/null @@ -1,1063 +0,0 @@ -{ - "paragraphs": [ - { - "title": "Overview", - "text": "%md\n\nRegarding using R in Zeppelin, you can refer the R tutorial. This tutorial is for using SparkR in Zeppelin, where you not only be able to use all the R features, but also can use Spark.\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:04.822", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "text", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/text", - "title": true, - "editorHide": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003cp\u003eRegarding using R in Zeppelin, you can refer the R tutorial. This tutorial is for using SparkR in Zeppelin, where you not only be able to use all the R features, but also can use Spark.\u003c/p\u003e\n\n\u003c/div\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1581045239881_1714679133", - "id": "paragraph_1581045239881_1714679133", - "dateCreated": "2020-02-07 11:13:59.881", - "dateStarted": "2021-07-31 12:58:04.849", - "dateFinished": "2021-07-31 12:58:07.175", - "status": "FINISHED" - }, - { - "title": "Hello R", - "text": "%spark.r\n\nfoo \u003c- TRUE\nprint(foo)\nbare \u003c- c(1, 2.5, 4)\nprint(bare)\ndouble \u003c- 15.0\nprint(double)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:07.247", - "progress": 0, - "config": { - "colWidth": 12.0, - "editorMode": "ace/mode/r", - "enabled": true, - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 84.64583587646484, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "runOnSelectionChange": true, - "checkEmpty": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\n[1] TRUE\n[1] 1.0 2.5 4.0\n[1] 15\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1429882946244_-381648689", - "id": "20150424-154226_261270952", - "dateCreated": "2015-04-24 03:42:26.000", - "dateStarted": "2021-07-31 12:58:07.257", - "dateFinished": "2021-07-31 12:58:20.780", - "status": "FINISHED" - }, - { - "title": "Load R Librairies", - "text": "%spark.r\n\nlibrary(data.table)\ndt \u003c- data.table(1:3)\nprint(dt)\nfor (i in 1:5) {\n print(i*2)\n}\nprint(1:50)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:20.867", - "progress": 0, - "config": { - "colWidth": 12.0, - "editorMode": "ace/mode/r", - "enabled": true, - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 193.33334350585938, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nV1\n1: 1\n2: 2\n3: 3\n[1] 2\n[1] 4\n[1] 6\n[1] 8\n[1] 10\n [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25\n[26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1429882976611_1352445253", - "id": "20150424-154256_645296307", - "dateCreated": "2015-04-24 03:42:56.000", - "dateStarted": "2021-07-31 12:58:20.885", - "dateFinished": "2021-07-31 12:58:21.035", - "status": "FINISHED" - }, - { - "title": "Load Iris Dataset", - "text": "%spark.r\n\ncolnames(iris)\niris$Petal.Length\niris$Sepal.Length", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:21.081", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "editorMode": "ace/mode/r", - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 169.33334350585938, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\n[1] “Sepal.Length” “Sepal.Width” “Petal.Length” “Petal.Width” “Species”\n [1] 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 1.5 1.6 1.4 1.1 1.2 1.5 1.3 1.4\n [19] 1.7 1.5 1.7 1.5 1.0 1.7 1.9 1.6 1.6 1.5 1.4 1.6 1.6 1.5 1.5 1.4 1.5 1.2\n [37] 1.3 1.4 1.3 1.5 1.3 1.3 1.3 1.6 1.9 1.4 1.6 1.4 1.5 1.4 4.7 4.5 4.9 4.0\n [55] 4.6 4.5 4.7 3.3 4.6 3.9 3.5 4.2 4.0 4.7 3.6 4.4 4.5 4.1 4.5 3.9 4.8 4.0\n [73] 4.9 4.7 4.3 4.4 4.8 5.0 4.5 3.5 3.8 3.7 3.9 5.1 4.5 4.5 4.7 4.4 4.1 4.0\n [91] 4.4 4.6 4.0 3.3 4.2 4.2 4.2 4.3 3.0 4.1 6.0 5.1 5.9 5.6 5.8 6.6 4.5 6.3\n[109] 5.8 6.1 5.1 5.3 5.5 5.0 5.1 5.3 5.5 6.7 6.9 5.0 5.7 4.9 6.7 4.9 5.7 6.0\n[127] 4.8 4.9 5.6 5.8 6.1 6.4 5.6 5.1 5.6 6.1 5.6 5.5 4.8 5.4 5.6 5.1 5.1 5.9\n[145] 5.7 5.2 5.0 5.2 5.4 5.1\n [1] 5.1 4.9 4.7 4.6 5.0 5.4 4.6 5.0 4.4 4.9 5.4 4.8 4.8 4.3 5.8 5.7 5.4 5.1\n [19] 5.7 5.1 5.4 5.1 4.6 5.1 4.8 5.0 5.0 5.2 5.2 4.7 4.8 5.4 5.2 5.5 4.9 5.0\n [37] 5.5 4.9 4.4 5.1 5.0 4.5 4.4 5.0 5.1 4.8 5.1 4.6 5.3 5.0 7.0 6.4 6.9 5.5\n [55] 6.5 5.7 6.3 4.9 6.6 5.2 5.0 5.9 6.0 6.1 5.6 6.7 5.6 5.8 6.2 5.6 5.9 6.1\n [73] 6.3 6.1 6.4 6.6 6.8 6.7 6.0 5.7 5.5 5.5 5.8 6.0 5.4 6.0 6.7 6.3 5.6 5.5\n [91] 5.5 6.1 5.8 5.0 5.6 5.7 5.7 6.2 5.1 5.7 6.3 5.8 7.1 6.3 6.5 7.6 4.9 7.3\n[109] 6.7 7.2 6.5 6.4 6.8 5.7 5.8 6.4 6.5 7.7 7.7 6.0 6.9 5.6 7.7 6.3 6.7 7.2\n[127] 6.2 6.1 6.4 7.2 7.4 7.9 6.4 6.3 6.1 7.7 6.3 6.4 6.0 6.9 6.7 6.9 5.8 6.8\n[145] 6.7 6.7 6.3 6.5 6.2 5.9\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455138077044_161383897", - "id": "20160210-220117_115873183", - "dateCreated": "2016-02-10 10:01:17.000", - "dateStarted": "2021-07-31 12:58:21.093", - "dateFinished": "2021-07-31 12:58:21.171", - "status": "FINISHED" - }, - { - "title": "Create a Spark Dataframe", - "text": "%spark\n\nimport org.apache.commons.io.IOUtils\nimport java.net.URL\nimport java.nio.charset.Charset\n\nval bankText \u003d sc.parallelize(\n IOUtils.toString(\n new URL(\"https://raw.githubusercontent.com/apache/zeppelin/master/testing/resources/bank.csv\"),\n Charset.forName(\"utf8\")).split(\"\\n\"))\n\ncase class Bank(age: Integer, job: String, marital: String, education: String, balance: Integer)\n\nval bank \u003d bankText.map(s \u003d\u003e s.split(\";\")).filter(s \u003d\u003e s(0) !\u003d \"\\\"age\\\"\").map(\n s \u003d\u003e Bank(s(0).toInt, \n s(1).replaceAll(\"\\\"\", \"\"),\n s(2).replaceAll(\"\\\"\", \"\"),\n s(3).replaceAll(\"\\\"\", \"\"),\n s(5).replaceAll(\"\\\"\", \"\").toInt\n )\n).toDF()\nbank.registerTempTable(\"bank\")", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:21.193", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "lineNumbers": false, - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 91.27083587646484, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "scala", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/scala", - "editorHide": false, - "tableHide": false, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\u001b[33mwarning: \u001b[0mthere was one deprecation warning; re-run with -deprecation for details\nimport sqlContext.implicits._\nimport org.apache.commons.io.IOUtils\nimport java.net.URL\nimport java.nio.charset.Charset\n\u001b[1m\u001b[34mbankText\u001b[0m: \u001b[1m\u001b[32morg.apache.spark.rdd.RDD[String]\u001b[0m \u003d ParallelCollectionRDD[0] at parallelize at \u003cconsole\u003e:22\ndefined class Bank\n\u001b[1m\u001b[34mbank\u001b[0m: \u001b[1m\u001b[32morg.apache.spark.sql.DataFrame\u001b[0m \u003d [age: int, job: string ... 3 more fields]\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455142039343_-233762796", - "id": "20160210-230719_2111095838", - "dateCreated": "2016-02-10 11:07:19.000", - "dateStarted": "2021-07-31 12:58:21.215", - "dateFinished": "2021-07-31 12:58:28.692", - "status": "FINISHED" - }, - { - "title": "Read the Spark Dataframe from R", - "text": "%spark.r\n\ndf \u003c- sql(\"select count(*) from bank\")\nprintSchema(df)\nSparkR::head(df)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:28.721", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "editorMode": "ace/mode/r", - "tableHide": false, - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 110.64583587646484, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nroot\n |– count(1): long (nullable \u003d false)\n count(1)\n1 4521\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": { - "jobUrl": { - "propertyName": "jobUrl", - "label": "SPARK JOB", - "tooltip": "View in Spark web UI", - "group": "spark", - "values": [ - { - "jobUrl": "http://172.17.0.2:4040/jobs/job?id\u003d0" - } - ], - "interpreterSettingId": "spark" - } - }, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455142043062_1598026718", - "id": "20160210-230723_1811469598", - "dateCreated": "2016-02-10 11:07:23.000", - "dateStarted": "2021-07-31 12:58:28.735", - "dateFinished": "2021-07-31 12:58:31.647", - "status": "FINISHED" - }, - { - "title": "Create a R Dataframe", - "text": "%spark.r \n\nlocalNames \u003c- data.frame(name\u003dc(\"John\", \"Smith\", \"Sarah\"), budget\u003dc(19, 53, 18))\nnames \u003c- createDataFrame(localNames)\nprintSchema(names)\nregisterTempTable(names, \"names\")\n\n# SparkR::head(names)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:31.738", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "title": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 84.64583587646484, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorHide": false, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\nroot\n |– name: string (nullable \u003d true)\n |– budget: double (nullable \u003d true)\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": { - "jobUrl": { - "propertyName": "jobUrl", - "label": "SPARK JOB", - "tooltip": "View in Spark web UI", - "group": "spark", - "values": [ - { - "jobUrl": "http://172.17.0.2:4040/jobs/job?id\u003d1" - } - ], - "interpreterSettingId": "spark" - } - }, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455142112413_519883679", - "id": "20160210-230832_1847721959", - "dateCreated": "2016-02-10 11:08:32.000", - "dateStarted": "2021-07-31 12:58:31.750", - "dateFinished": "2021-07-31 12:58:32.072", - "status": "FINISHED" - }, - { - "title": "Read the R Dataframe from Spark", - "text": "%spark\n\nsqlContext.sql(\"select * from names\").head", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:32.149", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "editorMode": "ace/mode/scala", - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 92.64583587646484, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "scala", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorHide": false, - "tableHide": false, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "\u001b[1m\u001b[34mres3\u001b[0m: \u001b[1m\u001b[32morg.apache.spark.sql.Row\u001b[0m \u003d [John,19.0]\n" - } - ] - }, - "apps": [], - "runtimeInfos": { - "jobUrl": { - "propertyName": "jobUrl", - "label": "SPARK JOB", - "tooltip": "View in Spark web UI", - "group": "spark", - "values": [ - { - "jobUrl": "http://172.17.0.2:4040/jobs/job?id\u003d2" - } - ], - "interpreterSettingId": "spark" - } - }, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455188357108_95477841", - "id": "20160211-115917_445850505", - "dateCreated": "2016-02-11 11:59:17.000", - "dateStarted": "2021-07-31 12:58:32.186", - "dateFinished": "2021-07-31 12:58:34.068", - "status": "FINISHED" - }, - { - "title": "Query the R Datafame with SQL", - "text": "%spark.sql\n\nselect * from names\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:34.090", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "editorMode": "ace/mode/sql", - "title": true, - "results": [ - { - "graph": { - "mode": "pieChart", - "height": 263.3125, - "optionOpen": false, - "keys": [ - { - "name": "name", - "index": 0.0, - "aggr": "sum" - } - ], - "values": [ - { - "name": "budget", - "index": 1.0, - "aggr": "sum" - } - ], - "groups": [], - "scatter": { - "xAxis": { - "name": "name", - "index": 0.0, - "aggr": "sum" - } - }, - "setting": { - "multiBarChart": {} - }, - "commonSetting": {} - }, - "helium": {} - } - ], - "editorSetting": { - "language": "sql", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TABLE", - "data": "name\tbudget\nJohn\t19.0\nSmith\t53.0\nSarah\t18.0\n" - } - ] - }, - "apps": [], - "runtimeInfos": { - "jobUrl": { - "propertyName": "jobUrl", - "label": "SPARK JOB", - "tooltip": "View in Spark web UI", - "group": "spark", - "values": [ - { - "jobUrl": "http://172.17.0.2:4040/jobs/job?id\u003d3" - } - ], - "interpreterSettingId": "spark" - } - }, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455142115582_-1840950897", - "id": "20160210-230835_19876971", - "dateCreated": "2016-02-10 11:08:35.000", - "dateStarted": "2021-07-31 12:58:34.108", - "dateFinished": "2021-07-31 12:58:34.294", - "status": "FINISHED" - }, - { - "title": "R builtin Plotting", - "text": "%spark.r\n\npairs(iris)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:34.305", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 1857.0, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cp\u003e\u003cimg src\u003d\"data:image/png;base64,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\u003d\" title\u003d\"plot of chunk unnamed-chunk-1\" alt\u003d\"plot of chunk unnamed-chunk-1\" width\u003d\"100%\"\u003e\u003c/p\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455137735427_-1023869289", - "id": "20160210-215535_1815168219", - "dateCreated": "2016-02-10 09:55:35.000", - "dateStarted": "2021-07-31 12:58:34.313", - "dateFinished": "2021-07-31 12:58:34.641", - "status": "FINISHED" - }, - { - "title": "R builtin Plotting", - "text": "%spark.r\n\nplot(iris, col \u003d heat.colors(3))", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:34.713", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 399.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "fontSize": 9.0, - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cp\u003e\u003cimg src\u003d\"data:image/png;base64,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AgOv3DVSdZUbpZRSSil1tWvatOnGjRuLfg4ICPjtt9/OfHfXrl316tUrjXadF03olVJKKaXU1W7UqFFHjhz507fcbndcXFyJPKDqb6IJvVJKKaWUutp16tSpU6dOf/qW2WxetmzZZW7PBdE59EoppZRSSpVhmtArpZRSSilVhmlCr5RSSimlVBmmCb1SSimllFJlmCb0SimllFJKlWGa0CullFJKKVWGaUKvlFJKKaVUGaYJvVJKKaWUUmWYJvRKKaWUUkqVYZrQK6WUUkopVYZpQq+UUkoppVQZpgm9UkoppZRSZZgm9EoppZRSSpVhmtArpZRSSilVhmlCr5RSSimlVBmmCb1SSimllFJlmCb0SimllFJKlWGa0CullFJKKVWGaUKvlFJKKaVUGaYJvVJKKaWUUmWYJvRKKaWUUkqVYZrQK6WUUkopVYb5lXYDlFJKKaWUukgFBQXAtGnTNm7c+KcFbrzxxn79+l3eRl1umtArpZRSSqmyKj8/H9izZ098fPyfFoiKitKEXimllFJKqStUuXLlgHHjxt17772l3ZZSo3PolVJKKaWUKsM0oVdKKaWUUqoM04ReKaWUUkqpMkwTeqWUUkoppcowTeiVUkoppZQqwzShV0oppZRSqgzThF4ppZRSSqkyTBN6pZRSSimlyjBN6JVSSimllCrDNKFXSimllFKqDNOEXimllFJKqTJME3qllFJKKaXKME3olVJKKaWUKsM0oVdKKaWUUqoM04ReKaWUUkqpMkwTeqWUUkoppcowTeiVUkoppZQqwzShV0oppZRSqgzThF4ppZRSSqkyTBN6pZRSSimlyjBN6JVSSimllCrDNKFXSimllFLqLB6Px+PxlHYrzpcm9EoppZRSSpGdnT1u3LgOHTpERESYzWaz2RwREdGhQ4e33347JyentFv33/iVdgOUUkoppa4iS5cu/fjjjzdu3JiWlhYSEhIdHd2iRYvu3bsPGTLEZrNd/vY2oqpjAAAgAElEQVQUFhYGBATUq1dv3759l3/vV47Dhw9369YtISGhVatWN910U3h4OJCZmbl79+7nn3/+008//fXXX2vUqFHazfxzmtArpZRSSl0mo0ePfu2114DKlSu3a9fObDYfOHBg+vTp06dPb9OmTf369Uu7gVevkSNHBgUF7d27t27dur97a9++fQMGDHjiiSfmzZtX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PdWxY8dLVmjWrFnRRlQMlNCLiIiIiLuyWq1AixYtIiIiijuWYqObYkVERERE3JgSehERERERN6aEXkRERETEjSmhFxERERFxY0roRURERETcmBJ6ERERERE3poReRERERMSNKaEXEREREXFjSuhFRERERNyYEnoRERERETemhF5ERERExI0poRcRERERcWNK6EVERERE3JgSehERERERN6aEXkRERETEjSmhFxERERFxY0roRURERETcmBJ6ERERERE3poReRERERMSNKaEXEREREXFjSuhFRERERP7C5XK5XK7ijiKvlNCLiIiIiJCYmDhu3Lg2bdoEBQV5eHh4eHgEBQW1adPm/fffT0pKKu7orsRW3AGIiIiIiBSzQ4cOdezYMSoqqmXLlr179y5dujQQFxe3c+fOYcOGff7556tXr65WrVpxh3lpSuhFRERE5Eb34osv+vn57d69Oyws7KKP9uzZ07NnzxdeeGHRokXFEttVaciNiIiIiNzoVq9ePXLkyL9n80DdunWHDx/+3//+t+ijyiMl9CIiIiJyo7NYLBkZGZf7NCMjw8PDoyjjyRcl9CIiIiJyo7vjjjveeOON33777e8frV+//p133unWrVvRR5VHGkMvIiIiIje68ePHd+7cuXXr1jVr1mzYsGFQUJAxJuum2IMHD9arV2/8+PHFHeNlKaHP5ewB/lyLI5ny4SRHsn4WGRk07UrrCNgIwM0sGI9jDS5Pgh+kWzn4BUpzrgcRY/hjL2UCGDQAx6+c3Y1fBVrdzeEJnDuHjzfVe7D3P5ACvjQZRvp6OIq1AZWGsXk3J05Qvz6VN3D4S9LPEVyX1DeYt4jkZNq145lnLgT5zTcsW4bNxj33cH9F2AY+0AbqFFOryWbYDFZoBY0Lc0WHYC0kQEPoABamRbDtB5wuajXh5bUAw59g1yosHtzyAC+NxWTwRycSd2D1pepAqr6LK4VDH3F6M/5VuWkgAU3ZPY9J/YhOo6ydfv/kttf4eQbzh+KMx16Wp+ZRuxUHl7F+AkkxhLbgzk+w+/PdTGZMIymJ227j7fF4ePDTq0QvxOWkwh10+QIgagoxP2LzpkoEId3BBT9BJARBW6gGDlgFeyEU2kMFkpNZuZIjR6halS5dCAy8RDMcO8bPPxMbS4MGdOrEdfwBNOMch1YRdwhnOlZPghK46RCuM3y5jqMp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6bpSpUo9evSYPHlyfmfM+hlrx44dDRs2zO+87du3t9lsP/6op33LdbB58+aWLVsuXry4R48eBVnOggUL7rvvvj/++KNRo0YFWc6ECRNeeumluLi40qVLX7325b3yyitTp05NSEi4etUrioiI2LNnz44dOwq4nFatWoWEhCxdurSAy6lQoULv3r0/++yzAi5H5Lzw8PC6devOnTu3sFc0aNCgJUuWHD9+vLBXNH369IEDBx4+fPgaTnjyZd++fXXq1Jk1a1bfvn0LdUVA2bJlH3zwwYm53zx4PXh5ebVq1er222+/5Kc7d+789ttvS2zarJtiRURERORG16hRo6CgoLfeeuuSn86bN+/bb78t4pDyTs+hFxEREZEb3c0337xp06ar1yuRdIVeRERERG50Q4cOvffee10u1yUf1NO7d++83HVZXJTQi4iIiMiNrmrVqlWrVr3cp1artSQ/GU9DbkRERERE3JgSehERERERN6aEXkRERETEjXmMGDGiuGNwAxkZGeHh4c2bN8/vjH5+ftHR0Q8//HBgYGB+57VYLJUqVWrfvn1+Z7TZbKdOnerdu/c1vDHebrfb7faePXvmd0YgOTm5Q4cOYWFh+Z3R19c3Pj7+4Ycfttvt+Z3X4XA0atSoWbNm+Z1R5O+ydthHHnmkVKlSBVxOXFzctX2lc/P29jbG3HfffXl53ckVeHh4hISEdOnSpSALAVwuV82aNQv+1pj09PRmzZo1adKkgMtJSkrq1KlT7dq1C7gckfNSU1NbtWp1DS9FyS+LxRIaGtqhQ4fCXpGPj09KSsqDDz5osxXubZO+vr7Hjx/v27dvmTJlCnVFQFJSUufOnWvVqlXYK3IjerGUiIiIiIgb05AbERERERE3poReRERERMSNKaEXEREREXFjSuhFRERERNyYEnoRERERETemhF5ERERExI0poRcRERERcWNK6EVERERE3JgSehERERERN6aEXkRERETEjSmhFxERERFxY0roL6Fr164Wi+XVV1+9XIUlS5ZY/qpu3bpFGWGW+fPn33LLLX5+fkFBQe3atdu2bdvlakZHR/fp06d06dIBAQE9e/Y8dOhQUcYJ9OjRw/I3d9999yUrl5DmlRvKn3/++eyzz958881eXl4WiyU+Pr4Yg/nll1/uuuuuSpUqeXl5VapUKSIiIjIyshjjKWm7ZL76E5Hc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\u003d\" title\u003d\"plot of chunk unnamed-chunk-1\" alt\u003d\"plot of chunk unnamed-chunk-1\" width\u003d\"100%\"\u003e\u003c/p\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455137737773_-549089146", - "id": "20160210-215537_582262164", - "dateCreated": "2016-02-10 09:55:37.000", - "dateStarted": "2021-07-31 12:58:34.720", - "dateFinished": "2021-07-31 12:58:35.079", - "status": "FINISHED" - }, - { - "title": "ggplot2", - "text": "%spark.r\n\nlibrary(ggplot2)\npres_rating \u003c- data.frame(\n rating \u003d as.numeric(presidents),\n year \u003d as.numeric(floor(time(presidents))),\n quarter \u003d as.numeric(cycle(presidents))\n)\np \u003c- ggplot(pres_rating, aes(x\u003dyear, y\u003dquarter, fill\u003drating))\np + geom_raster()", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:35.120", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 449.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorHide": false, - "fontSize": 9.0, - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cp\u003e\u003cimg src\u003d\"data:image/png;base64,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iSf++te/nj59eqdOnYYPH97ymLKyssGDB7cc6dixo+cHAEBb5VJQJSUlaYVWY2NjKvOQo8IEfUsjR468/fbbH3300VZB37dv33vuuaflSFVV1caNG/O7OgCA8HIpqG7dulVVVaXS4qWlpaWlpe2fhxwVfofT9u3bGxoaqqurC70QAACIJ99Bv2LFilZvtrj//vuTJDnssMPyvBIAANgH5HvLzZw5c1577bWhQ4d269Zty5YtS5YsWb58+UEHHTR27Ng8rwQAAPYB+Q76E044ob6+/g9/+MPGjRuLiop69ep1zjnnjBs3br/99svzSgAAYB+Q76AfNmzYsGHD8nxSAABoq+7du69bt27z5s1p3dBzDyn8m2IBAKBQOnXqlMlkamtrC72QD6/wt60EAIC90PXXX79169YcP2e3gAQ9AADsxL/9278Vegk5seUGAICoMplMSUlJkiSzZ8/+5Cc/2aVLl+b9M08++eTXvva1o48+ukePHqWlpX369JkwYcKiRYuaf3fmzJmZTKampiZJkoqKisx7Vq1a1XRA9+7dM5lMy49Laj7d3LlzP/nJT3bq1KlLly6jR49+5plndlzb4sWLzzjjjAMOOKBjx45HH330nXfeWV9fn8lkysvL030QXKEHACC2q6666sYbbzzssMOGDRu2dOnSps+7nTx58osvvjh48OBjjjmmQ4cOr7766ty5c//3f/933rx5Z555ZpIkw4YN+/a3v33DDTfU1dV961vfair1JEl2+xbYb3/729ddd92gQYNGjhy5ZMmSRx555Iknnvjtb3979NFHNx/zi1/84swzz9y+ffuRRx55+OGHr1ixYtKkSS+//PKe+OsLegAAAmtoaJgxY8Yvf/nL0aNHJ0mSzWYzmUySJFdeeeWIESN69+7dfORPfvKTz3/+8//6r/96yimnlJeXN9198eabb66rq7vmmmtyvHDe0NDwgx/8YMGCBaNGjUqSpK6u7vOf//zcuXOnTp06f/78pmOqqqr++Z//efv27bfddttXv/rVpsGnnnrqlFNOSffv3sSWGwAAYrv88subaj5JkqaaT5Lkc5/7XMuaT5LkvPPOGzt27OrVq5944on2nO473/lOU80nSdKhQ4fvfve7SZI8/vjj2Wy2afC+++5bs2bN8OHDm2s+SZIRI0bsoU35rtADABDbxIkTdzq+ffv2p556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sG7duhkzZnTt2vV73/te0wEDBw6cPHnyLbfccvrpp48ZM+bFF1+cNWvWySefPHbs2FQW0Lag79KlS11dXdP3TTc0XbFixaGHHvruXCUlq1alecNBAADYiZwvn7f/TLkcdOmll3bv3v373//+tddeW1ZWNmrUqBtuuOGww96/Ee20adP69Okzc+bMRx55pGfPnpdffvnUqVMzOdxCJxdtC/qDDz74rbfefUNx0wfbPvLII01Bv23btoULF/bu3TuVZQEAwK5k83WFPveTnH/++eeff/6uflpUVDR58uTJkyens6y/1bag/8xnPjNjxoyVK1f27t175MiR3bt3v+yyyzZs2NC3b98f//jHK1asuPDCC/fEKgEA4H35u0IfQNuCfvz48QsXLly4cOHZZ59dVlb2gx/84Pzzz//mN7/Z9NOePXted911e2CRAADwN7K5bYb5e9DmK/SLFi1q/uO5557bv3//2bNnr169esCAAZMmTbLlBgCAfHCF/j3t/WyqYcOGpXUHTQAAyIktNy2k8GGzAACQT9kkm802FnoVewtBDwBAQHvTbSsLq21B3/TptR+surr6wy4GAABom7YFfU1NzR5aBwAA5Cpry837itp09NYd1NTULFmy5Prrr+/YsePUqVO3bt26hxYKAADvyb77vtg9/RVB267Ql5eX7zg4ZMiQIUOGDB069Mwzzxw6dOi4ceNSWhsAAOxMNk+fFBtC267Qf4DPfvazhx122M0335zWhAAAsGvZvHwFkOZdbj760Y8++eSTKU4IAAA7k6/9MBGSPrWgb2xsfPXVVzOZTFoTAgDATmVtuWkhnS0369evv/jii5cvXz58+PBUJgQAgF3Lz36bGK8Z2naFftCgQTsObt68edWqVY2NjR06dPj2t7+d0sIAAGDXfLDUe9oW9K+99tpOx0tLS0eMGDF16tQRI0aksSoAANi1bNaWm2ZtC/o333xzx8HS0tIePXp06NAhpSUBAMDuCPr3tC3o+/Xrt2eWAQAAucomrtC/L83bVgIAQL4I+ncJegAAosnacvO+tgV9eXl5m46vra1t0/EAAJCDPG25CfGioW1Bv23btj20DgAAyFXertBHKPq2fbBUXV3dV77ylfLy8q985SvPPffcmjVr1qxZ8/zzzzcNfvWrX637W3to0QAA/D1relNsHoQo+rZdob/zzjtnzJjx6KOPHn/88c2D3bt3HzZs2NixY0eNGnX44YdfdNFFKa8RAABaC5Da+dG2K/QzZ848/vjjW9Z8sxNOOOG444774Q9/mM66AABgV7LZPH1F0Lagf/311/v06bOrn1ZWVu7qo2QBACBF+dpyE0DbttyUlZW99NJLu/rpSy+9VFZW1u4lAQDA7gSp7Txo2xX6kSNH/v73v58+ffqOP5o+ffrvf//7kSNHprQwAADYufxcnt83r9BPnTp1wYIFl1122Zw5c84///yPfvSjSZIsX7783nvvff7558vKyqZMmbJHlgkAAO/LJkljodewt2hb0B911FEPPvjgF77whUWLFi1atKjlj3r27Dl79uyjjjoq1eUBAMDOxLh6ng9tC/okSUaPHr1s2bL77rvvN7/5zdtvv50kSZ8+fY477rjzzjuvc+fOe2CFAADwt7JJvvbDBHjd0OagT5Kkc+fOX/rSl770pS+lvhoAAMhBNsnmZctNgJ5v45tiAQCAvcqHuUIPAACFFOcWNHkg6AEACEjQv0fQAwAQTDabzeZnD30E9tADAEBgrtADABCQLTfvEfQAAISTty03AV42CHoAAKLJZl2hb2YPPQAApOP1118vLy/PZDJ33XVXy/FsNnv77bcPGjSorKysb9++V1555datW9M6qaAHACCY7Ls3utnz2riwiy++uKRkJ1tgrrrqqksvvfSQQw658cYbTzzxxGnTpo0bNy6VhyKx5QYAgHiy2SQ/e+jbUvSzZ89euHDht771rWuvvbbl+NKlS2+55ZZTTz315z//eSaTSZKkV69eN954489+9rOzzjqr/Wt0hR4AgHj2tgv0GzZsuPzyy7/xjW8MGDCg1Y/mzp3b0NBw2WWXNdV8kiRN38+ZMyeVh0LQAwBAe1111VUdO3a8+uqrd/zR888/nyTJscce2zzSs2fP/v37N423ny03AABEs5fd5ebpp5/+r//6rwcffLCiomLHn65YsaJLly6dO3duOVhZWfnUU0+lcnZBDwBAMH17d7/rukmtBh945Nn/+83iDz3nlElnf7SyZ6vBoqLMbn+xvr5+0qRJZ5xxxumnn77TA7Zs2VJWVtZqsLy8vK6urr6+fqdvom0TQQ8AQDBvv7Puttk/bzVYu72uPZftb7rrwZLi4laDD/7gG7v9xenTpy9dunT+/Pm7OqC8vHzbtm2tBmtra0tK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2kxdXd3ixYs7deo0YMCAw4cPn37AwYMHZ86ceezYsbKysg996EPbtm1buHDh3r17Z8yY0fyw4uLiIUOGpL/t2bNn858+8cQTK1asuOaaayZMmPDmm2+uWLFi165dzYsfLo7zMvB79+79/ve/f/z48eHDh/fq1evkyZNVVVUHDx5MB72B5xLR+oEfNmxYx44dmz9k8+bNr7322jXXXJNeMfCQIuhpM3l5eY899li3bt1CCBMnTjz9gGXLltXU1Hz3u98dNWpUauU3v/nNqlWrxo0bN2jQoPRhQ4YMue222/7tH7F3796VK1eWlJTMmTMnkUiEELp06bJ8+fJXX311xIgR5/8pwX/W+oFPJpMPPvhgRkbGL37xi759+55+BgPPpaP1Az906NChQ4c2f0h5eXlOTs51112X+tbAQ5p76GkzGRkZqdf6/2Tz5s3t2rVLv9aHEMaNGxdCWL9+fYsja2pqqqurT38P1hdffLGpqWnixImp1/oQQurrF154ofX7hw+k9QP/+uuvV1VV3X777X379q2tra2rq2txBgPPpeM8vsKn7N69e/v27SNHjszPz0+tGHhIc4WeS9epU6dyc3Obr6S+raysbL745JNPLl68OITQoUOHsrKyKVOmpD98Z8eOHSGE5pfzO3Xq1LNnz9Q6XFLOOPAVFRUhhK5du86aNSu1eNVVV91xxx3FxcWpAww8ETnLV/i0devWhRDGjh2bXjHwkOYKPZeuPn36HDlyZPfu3emVf/zjHyGEgwcPpr5NJBIDBw6cPHnyPffcM3369MLCwuXLl993333p4w8dOpSfn5+Xl9f8tAUFBYcOHboozwA+gDMO/J49exKJxEMPPdS+ffuZM2fedddd1dXVc+fO3bJlS+oAA09EzjjwzTU2Nq5fv7579+5FRUXpRQMPaYKeS9eNN94YQvjpT3+6adOmd9999/nnn1+wYEFmZmb6ToPOnTs/+OCDX/jCFz71qU9NmjTpZz/7WXFxcXl5eXl5eeqAurq69NX6tJycnMbGxsbGxov5XOCMzjjwJ0+eTCaTffr0mTNnzg033HDTTTfNmzevqakp9T9UwcATlTMOfHMVFRWHDx8eM2ZM+u6aYOChGbfccOkqKSm5++67Fy5cmHrLgszMzFtvvfUvf/nLv325Tx0wefLk11577W9/+9u1114bQsjJyTl16lSLw+rr6zMzMzMzMy/w9uGDOePAp9qledNceeWVAwYM2LJlS1NTU0ZGhoEnIh/oFX7dunWJRGLMmDHNFw08pAl6Lmnjx4//9Kc/vXPnzrq6uv79++fk5Dz55JPN36SyhdTvYB0/fjz1bUFBwRtvvFFbW9uuXbv0MdXV1QUFBRd653AO3n/gCwsLQwhdunRp/pAuXbo0NjbW1tbm5+cbeOJylq/wR44c2bhxY1FRUfrtWVMMPKS55YZLXXZ29sCBA4uKijp06PDKK680NjaWlJT8p4Pfeeed0Kx4BgwYEELYvn17+oCjR4/u3bv36quvvsC7hnP0PgM/cODAcNodxgcOHMjJyUnd9xfbbAAAB8lJREFURmzgic7ZvML/+c9/bmxsbP7rsCkGHtIEPZeuZDLZ/D7IgwcPLlq0qFOnTumX9T179jR/q8oTJ0789re/DSEMGzYstTJ69OhEItH8swZXrVqVTCZvuOGGi/EE4IM448CPGDEiNzd3zZo1DQ0NqZWtW7e++eabJSUlqZtwDDwROePAp61bty4/P3/kyJEt1g08pLnlhrb03HPPpT5BMJlM7tu3b+nSpSGEQYMGpT5M5L333vvqV79aWlrarVu36urql156qaGhYfbs2R06dEg9fOnSpVu2bCkqKiooKKipqdmwYcORI0fGjx8/ePDg1AG9e/e++eabV65c+cMf/rC0tHTnzp1r164dOnSozxyhTbRy4Dt16vTlL3/50Ucf/c53vjN69Ohjx46tXr06Pz9/2rRpqQMMPJeUVg58SmVl5dtvvz1+/PicnJwW5zfwkJY4/bN44KL51re+tXPnzhaLN91001133RVCOHXq1Pz58//5z38eOnToiiuuKCoqmjx5cr9+/dJHvvTSS2vXrt21a9fRo0ezs7P79++fuiOz+dmSyeSqVav+9Kc/7du3r3Pnztddd92UKVNavPkxXBytHPiU9evXP/3007t3787Kyvr4xz/+pS99qfmnxhp4Lh3nZeB//etf//GPf3zggQeav998moGHFEEPAAARcw89AABETNADAEDEBD0AAERM0AMAQMQEPQAAREzQAwBAxAQ9AABETNADAEDEBD0AAERM0AMAQMQEPQAAREzQAwBAxAQ9wLl44403MjMzCwsLa2trW/yovr6+e/fuGRkZ27dvTy8eO3bsJz/5SWlpaceOHfPy8gYPHjx37txjx461eOxf//rXb3/72yUlJd26dcvJyendu/dtt91WXl7e4rBEIpGVlRVC+N3vfvfJT36yY8eOiUTi9J0AcDlIJJPJtt4DQJRuvPHG1atXL1y4cNq0ac3XFy9ePHXq1LFjx65duza1smvXrrKysh07dhQUFAwdOjQ3N7e8vHz//v1Dhgx54YUXunbtmn7stdde+/e///2jH/1o3759s7Ozt23bVllZmZ2dvWzZsptvvjl9WCKRyMzMnDVr1v333z9o0KBevXrt2LFj+/bt+fn5F+e5A3DpEPQA52jNmjWf+cxnhg8fvmHDhubro0aNevnll5966qmJEyeGEJqamoYNG7Zp06avfe1rDzzwwBVXXBFCOHHixJ133rl06dKpU6cuWrQo/dhly5aNHj26Z8+e6ZUlS5ZMnTq1sLDwrbfeateuXWoxkUiEENq3b798+fKysrIQQjKZTC0CcLkR9ADnKJlMfuQjH6msrCwvLy8tLU0tvv7668XFxX379t25c2dmZmYI4amnnpo0adLw4cNfeeWVjIz/vdHx+PHjV111VXV19f79+5tfpD/dLbfcsnz58jVr1qTaPfz/oJ8zZ87cuXMv0LMDIBZZbb0BgFglEokZM2Z885vfnD9//uOPP55anD9/fgjhK1/5SqrmQwjPPvtsCGHSpEnNaz6E0L59+0984hPPPPNMRUXFuHHj0uv19fUvvvjili1bampqGhoaQgj79+8PIWzfvj0d9ClTpky5gE8PgEi4Qg9w7o4dO9a7d++GhoZ33nmna9euR48e7dWr16lTp95+++0ePXqkjhkzZszzzz//PidZsmTJ5MmTU18vW7ZsxowZqYJv4Uc/+tEPfvCD1NepK/S1tbW5ubnn8/kAECFX6AHOXYcOHaZPn/6rX/1qwYIFM2fOfOKJJ06cOPHFL34xXfMhhMbGxhDCLbfcMnjw4H97ko997GOpLyoqKiZPnpybm/vwww+XlZX17t07Ly8vkUjce++99913X4vrL5mZmWoegCDoAVppxowZDz/88COPPHLPPfc88sgjIYS77767+QF9+/YNIaTep/L9T7Vo0aKmpqbZs2e3OMOOHTvO86YB+C/ifegBWmXgwIFlZWVVVVX33nvvli1biouLR40a1fyACRMmhBCWLFly8uTJ9z9V6k6bK6+8svnigQMH1q1bd753DcB/D0EP0Frf+MY3Qgj3339/COHrX/96i5/eeuutRUVFlZWVt99++7vvvtv8R1VVVT//+c/T3w4YMCCE8Pjjj9fV1aVWjh8/fscdd9TU1FzQ/QMQNb8UC9BayWRy4MCBVVVVnTp12rNnT+qd5pvbtWvXZz/72a1bt+bn5xcXF/fr16+6uvqtt96qrKzs0aNHuvL/9a9/FRcXHzhwoHfv3qNGjWpsbFy/fn12dvaECRMWLFgwb9682bNnp45MfbBU6j1wALjMuUIP0FqJRGLs2LEhhOnTp59e8yGE/v37V1RU/PKXvywtLd22bduKFSs2b97csWPHWbNmrVixIn1Yz549N23aNG3atKysrKeffnrjxo2f//znN23a1K9fv4v3ZACIjSv0AK1VX1/fr1+//fv3b926ddCgQW29HQAuL67QA7TW/Pnz9+3b97nPfU7NA3DxuUIPcI62bt360EMP7d27d82aNVlZWRUVFUOGDGnrTQFw2fE+9ADnaM+ePY899lhubu7QoUN//OMfq3kA2oQr9AAAEDH30AMAQMQEPQAAREzQAwBAxAQ9AABETNADAEDEBD0AAERM0AMAQMQEPQAAREzQAwBAxAQ9AABE7H8AUIW0YsKKxrsAAAAASUVORK5CYII\u003d\" title\u003d\"plot of chunk unnamed-chunk-1\" alt\u003d\"plot of chunk unnamed-chunk-1\" width\u003d\"100%\"\u003e\u003c/p\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1438930880648_-1572054429", - "id": "20150807-090120_1060568667", - "dateCreated": "2015-08-07 09:01:20.000", - "dateStarted": "2021-07-31 12:58:35.127", - "dateFinished": "2021-07-31 12:58:36.116", - "status": "FINISHED" - }, - { - "title": "GoogleVis: Bar Chart", - "text": "%spark.r\n\nlibrary(googleVis)\ndf\u003ddata.frame(country\u003dc(\"US\", \"GB\", \"BR\"), \n val1\u003dc(10,13,14), \n val2\u003dc(23,12,32))\nBar \u003c- gvisBarChart(df)\nprint(Bar, tag \u003d \u0027chart\u0027)\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:36.128", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "results": { - "0": { - "graph": { - "mode": "table", - "height": 300.0, - "optionOpen": false - } - } - }, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorMode": "ace/mode/r", - "editorHide": false, - "tableHide": false, - "title": true, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\n\u003c!-- BarChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\n\u003c!-- Sat Jul 31 12:58:36 2021 --\u003e\n\n\u003c!-- jsHeader --\u003e\n\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataBarChartID13f59e73eea () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"US\",\n10,\n23\n],\n[\n\"GB\",\n13,\n12\n],\n[\n\"BR\",\n14,\n32\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027country\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val1\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val2\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartBarChartID13f59e73eea() {\nvar data \u003d gvisDataBarChartID13f59e73eea();\nvar options \u003d {};\noptions[\"allowHtml\"] \u003d true;\n\n var chart \u003d new google.visualization.BarChart(\n document.getElementById(\u0027BarChartID13f59e73eea\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartBarChartID13f59e73eea);\n})();\nfunction displayChartBarChartID13f59e73eea() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\n\u003c!-- jsChart --\u003e \n\n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartBarChartID13f59e73eea\"\u003e\u003c/script\u003e\n \n\n\u003c!-- divChart --\u003e\n\n\u003cdiv id\u003d\"BarChartID13f59e73eea\" style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1485626417184_-1153542135", - "id": "20170129-030017_426747323", - "dateCreated": "2017-01-29 03:00:17.000", - "dateStarted": "2021-07-31 12:58:36.159", - "dateFinished": "2021-07-31 12:58:36.284", - "status": "FINISHED" - }, - { - "title": "GoogleVis: Candlestick Chart", - "text": "%spark.r\n\nlibrary(googleVis)\n\nCandle \u003c- gvisCandlestickChart(OpenClose, \n options\u003dlist(legend\u003d\u0027none\u0027))\n\nprint(Candle, tag \u003d \u0027chart\u0027)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:36.351", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "results": { - "0": { - "graph": { - "mode": "table", - "height": 84.64583587646484, - "optionOpen": false - } - } - }, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorMode": "ace/mode/r", - "editorHide": false, - "tableHide": false, - "title": true, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\n\u003c!-- CandlestickChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\n\u003c!-- Sat Jul 31 12:58:36 2021 --\u003e\n\n\u003c!-- jsHeader --\u003e\n\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataCandlestickChartID13f1459b8bb () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"Mon\",\n20,\n28,\n38,\n45\n],\n[\n\"Tues\",\n31,\n38,\n55,\n66\n],\n[\n\"Wed\",\n50,\n55,\n77,\n80\n],\n[\n\"Thurs\",\n50,\n77,\n66,\n77\n],\n[\n\"Fri\",\n15,\n66,\n22,\n68\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027Weekday\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Low\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Open\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Close\u0027);\ndata.addColumn(\u0027number\u0027,\u0027High\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartCandlestickChartID13f1459b8bb() {\nvar data \u003d gvisDataCandlestickChartID13f1459b8bb();\nvar options \u003d {};\noptions[\"allowHtml\"] \u003d true;\noptions[\"legend\"] \u003d \"none\";\n\n var chart \u003d new google.visualization.CandlestickChart(\n document.getElementById(\u0027CandlestickChartID13f1459b8bb\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartCandlestickChartID13f1459b8bb);\n})();\nfunction displayChartCandlestickChartID13f1459b8bb() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\n\u003c!-- jsChart --\u003e \n\n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartCandlestickChartID13f1459b8bb\"\u003e\u003c/script\u003e\n \n\n\u003c!-- divChart --\u003e\n\n\u003cdiv id\u003d\"CandlestickChartID13f1459b8bb\" style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1485627113560_-130863711", - "id": "20170129-031153_758721410", - "dateCreated": "2017-01-29 03:11:53.000", - "dateStarted": "2021-07-31 12:58:36.361", - "dateFinished": "2021-07-31 12:58:36.531", - "status": "FINISHED" - }, - { - "title": "GoogleVis: Line chart", - "text": "%spark.r\n\nlibrary(googleVis)\ndf\u003ddata.frame(country\u003dc(\"US\", \"GB\", \"BR\"), \n val1\u003dc(10,13,14), \n val2\u003dc(23,12,32))\n\nLine \u003c- gvisLineChart(df)\n\nprint(Line, tag \u003d \u0027chart\u0027)\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:36.561", - "progress": 0, - "config": { - "colWidth": 4.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 61.458335876464844, - "optionOpen": false - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorHide": false, - "tableHide": false, - "title": true, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\n\u003c!-- LineChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\n\u003c!-- Sat Jul 31 12:58:36 2021 --\u003e\n\n\u003c!-- jsHeader --\u003e\n\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataLineChartID13f607c42e3 () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"US\",\n10,\n23\n],\n[\n\"GB\",\n13,\n12\n],\n[\n\"BR\",\n14,\n32\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027country\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val1\u0027);\ndata.addColumn(\u0027number\u0027,\u0027val2\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartLineChartID13f607c42e3() {\nvar data \u003d gvisDataLineChartID13f607c42e3();\nvar options \u003d {};\noptions[\"allowHtml\"] \u003d true;\n\n var chart \u003d new google.visualization.LineChart(\n document.getElementById(\u0027LineChartID13f607c42e3\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartLineChartID13f607c42e3);\n})();\nfunction displayChartLineChartID13f607c42e3() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\n\u003c!-- jsChart --\u003e \n\n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartLineChartID13f607c42e3\"\u003e\u003c/script\u003e\n \n\n\u003c!-- divChart --\u003e\n\n\u003cdiv id\u003d\"LineChartID13f607c42e3\" style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455138857313_92355963", - "id": "20160210-221417_1400405266", - "dateCreated": "2016-02-10 10:14:17.000", - "dateStarted": "2021-07-31 12:58:36.569", - "dateFinished": "2021-07-31 12:58:36.652", - "status": "FINISHED" - }, - { - "title": "GoogleViz: Bubble Chart", - "text": "%spark.r\n\nlibrary(googleVis)\nbubble \u003c- gvisBubbleChart(Fruits, idvar\u003d\"Fruit\", \n xvar\u003d\"Sales\", yvar\u003d\"Expenses\",\n colorvar\u003d\"Year\", sizevar\u003d\"Profit\",\n options\u003dlist(\n hAxis\u003d\u0027{minValue:75, maxValue:125}\u0027))\nprint(bubble, tag \u003d \u0027chart\u0027)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:36.667", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "editorMode": "ace/mode/r", - "title": true, - "results": [ - { - "graph": { - "mode": "table", - "height": 189.6666717529297, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorHide": false, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\n\u003c!-- BubbleChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\n\u003c!-- Sat Jul 31 12:58:36 2021 --\u003e\n\n\u003c!-- jsHeader --\u003e\n\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataBubbleChartID13f7d6e8475 () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"Apples\",\n98,\n78,\n2008,\n20\n],\n[\n\"Apples\",\n111,\n79,\n2009,\n32\n],\n[\n\"Apples\",\n89,\n76,\n2010,\n13\n],\n[\n\"Oranges\",\n96,\n81,\n2008,\n15\n],\n[\n\"Bananas\",\n85,\n76,\n2008,\n9\n],\n[\n\"Oranges\",\n93,\n80,\n2009,\n13\n],\n[\n\"Bananas\",\n94,\n78,\n2009,\n16\n],\n[\n\"Oranges\",\n98,\n91,\n2010,\n7\n],\n[\n\"Bananas\",\n81,\n71,\n2010,\n10\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027Fruit\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Sales\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Expenses\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Year\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Profit\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartBubbleChartID13f7d6e8475() {\nvar data \u003d gvisDataBubbleChartID13f7d6e8475();\nvar options \u003d {};\noptions[\"hAxis\"] \u003d {minValue:75, maxValue:125};\n\n var chart \u003d new google.visualization.BubbleChart(\n document.getElementById(\u0027BubbleChartID13f7d6e8475\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"corechart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartBubbleChartID13f7d6e8475);\n})();\nfunction displayChartBubbleChartID13f7d6e8475() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\n\u003c!-- jsChart --\u003e \n\n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartBubbleChartID13f7d6e8475\"\u003e\u003c/script\u003e\n \n\n\u003c!-- divChart --\u003e\n\n\u003cdiv id\u003d\"BubbleChartID13f7d6e8475\" style\u003d\"width: 500; height: automatic;\"\u003e\n\u003c/div\u003e\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455141578555_-1713165000", - "id": "20160210-225938_1538591791", - "dateCreated": "2016-02-10 10:59:38.000", - "dateStarted": "2021-07-31 12:58:36.674", - "dateFinished": "2021-07-31 12:58:36.753", - "status": "FINISHED" - }, - { - "title": "GoogleViz: Geo Chart", - "text": "%spark.r\n\nlibrary(googleVis)\ngeo \u003d gvisGeoChart(Exports, locationvar \u003d \"Country\", colorvar\u003d\"Profit\", options\u003dlist(Projection \u003d \"kavrayskiy-vii\"))\nprint(geo, tag \u003d \u0027chart\u0027)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:36.773", - "progress": 0, - "config": { - "colWidth": 6.0, - "enabled": true, - "editorMode": "ace/mode/r", - "results": [ - { - "graph": { - "mode": "table", - "height": 336.66668701171875, - "optionOpen": false, - "keys": [], - "values": [], - "groups": [], - "scatter": {} - } - } - ], - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - }, - "editorHide": false, - "title": true, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\n\u003c!-- GeoChart generated in R 3.6.3 by googleVis 0.6.10 package --\u003e\n\n\u003c!-- Sat Jul 31 12:58:36 2021 --\u003e\n\n\u003c!-- jsHeader --\u003e\n\n\u003cscript type\u003d\"text/javascript\"\u003e\n \n// jsData \nfunction gvisDataGeoChartID13f437c2543 () {\nvar data \u003d new google.visualization.DataTable();\nvar datajson \u003d\n[\n [\n\"Germany\",\n3\n],\n[\n\"Brazil\",\n4\n],\n[\n\"United States\",\n5\n],\n[\n\"France\",\n4\n],\n[\n\"Hungary\",\n3\n],\n[\n\"India\",\n2\n],\n[\n\"Iceland\",\n1\n],\n[\n\"Norway\",\n4\n],\n[\n\"Spain\",\n5\n],\n[\n\"Turkey\",\n1\n] \n];\ndata.addColumn(\u0027string\u0027,\u0027Country\u0027);\ndata.addColumn(\u0027number\u0027,\u0027Profit\u0027);\ndata.addRows(datajson);\nreturn(data);\n}\n \n// jsDrawChart\nfunction drawChartGeoChartID13f437c2543() {\nvar data \u003d gvisDataGeoChartID13f437c2543();\nvar options \u003d {};\noptions[\"width\"] \u003d 556;\noptions[\"height\"] \u003d 347;\noptions[\"Projection\"] \u003d \"kavrayskiy-vii\";\n\n var chart \u003d new google.visualization.GeoChart(\n document.getElementById(\u0027GeoChartID13f437c2543\u0027)\n );\n chart.draw(data,options);\n \n\n}\n \n \n// jsDisplayChart\n(function() {\nvar pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\nvar callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\nvar chartid \u003d \"geochart\";\n \n// Manually see if chartid is in pkgs (not all browsers support Array.indexOf)\nvar i, newPackage \u003d true;\nfor (i \u003d 0; newPackage \u0026\u0026 i \u003c pkgs.length; i++) {\nif (pkgs[i] \u003d\u003d\u003d chartid)\nnewPackage \u003d false;\n}\nif (newPackage)\n pkgs.push(chartid);\n \n// Add the drawChart function to the global list of callbacks\ncallbacks.push(drawChartGeoChartID13f437c2543);\n})();\nfunction displayChartGeoChartID13f437c2543() {\n var pkgs \u003d window.__gvisPackages \u003d window.__gvisPackages || [];\n var callbacks \u003d window.__gvisCallbacks \u003d window.__gvisCallbacks || [];\n window.clearTimeout(window.__gvisLoad);\n // The timeout is set to 100 because otherwise the container div we are\n // targeting might not be part of the document yet\n window.__gvisLoad \u003d setTimeout(function() {\n var pkgCount \u003d pkgs.length;\n google.load(\"visualization\", \"1\", { packages:pkgs, callback: function() {\n if (pkgCount !\u003d pkgs.length) {\n // Race condition where another setTimeout call snuck in after us; if\n // that call added a package, we must not shift its callback\n return;\n}\nwhile (callbacks.length \u003e 0)\ncallbacks.shift()();\n} });\n}, 100);\n}\n \n// jsFooter\n\u003c/script\u003e\n \n\n\u003c!-- jsChart --\u003e \n\n\u003cscript type\u003d\"text/javascript\" src\u003d\"https://www.google.com/jsapi?callback\u003ddisplayChartGeoChartID13f437c2543\"\u003e\u003c/script\u003e\n \n\n\u003c!-- divChart --\u003e\n\n\u003cdiv id\u003d\"GeoChartID13f437c2543\" style\u003d\"width: 556; height: 347;\"\u003e\n\u003c/div\u003e\n\n\n\n" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1455140544963_1486338978", - "id": "20160210-224224_735421242", - "dateCreated": "2016-02-10 10:42:24.000", - "dateStarted": "2021-07-31 12:58:36.788", - "dateFinished": "2021-07-31 12:58:36.879", - "status": "FINISHED" - }, - { - "text": "%md\n\n## Congratulations, it\u0027s done.\n### You can create your own notebook in \u0027Notebook\u0027 menu. Good luck!", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:58:36.888", - "progress": 0, - "config": { - "colWidth": 12.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "markdown", - "editOnDblClick": true - }, - "editorMode": "ace/mode/markdown", - "editorHide": true, - "tableHide": false, - "fontSize": 9.0 - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003ch2\u003eCongratulations, it\u0026rsquo;s done.\u003c/h2\u003e\n\u003ch3\u003eYou can create your own notebook in \u0026lsquo;Notebook\u0026rsquo; menu. Good luck!\u003c/h3\u003e\n\n\u003c/div\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1485626988585_-946362813", - "id": "20170129-030948_1379298104", - "dateCreated": "2017-01-29 03:09:48.000", - "dateStarted": "2021-07-31 12:58:36.896", - "dateFinished": "2021-07-31 12:58:36.911", - "status": "FINISHED" - } - ], - "name": "5. SparkR Basics", - "id": "2BWJFTXKM", - "defaultInterpreterGroup": "spark", - "noteParams": {}, - "noteForms": {}, - "angularObjects": {}, - "config": { - "looknfeel": "default", - "isZeppelinNotebookCronEnable": false - }, - "info": { - "isRunning": true - } -} \ No newline at end of file diff --git a/notebook/Spark Tutorial/8. PySpark Conda Env in Yarn Mode_2GE79Y5FV.zpln b/notebook/Spark Tutorial/6. PySpark Conda Env in Yarn Mode_2GE79Y5FV.zpln similarity index 100% rename from notebook/Spark Tutorial/8. PySpark Conda Env in Yarn Mode_2GE79Y5FV.zpln rename to notebook/Spark Tutorial/6. PySpark Conda Env in Yarn Mode_2GE79Y5FV.zpln diff --git a/notebook/Spark Tutorial/6. SparkR Shiny App_2F1CHQ4TT.zpln b/notebook/Spark Tutorial/6. SparkR Shiny App_2F1CHQ4TT.zpln deleted file mode 100644 index 69fd1c54029..00000000000 --- a/notebook/Spark Tutorial/6. SparkR Shiny App_2F1CHQ4TT.zpln +++ /dev/null @@ -1,274 +0,0 @@ -{ - "paragraphs": [ - { - "title": "Introduction", - "text": "%md\n\n[Shiny](https://shiny.rstudio.com/tutorial/) is an R package that makes it easy to build interactive web applications (apps) straight from R. For developing one Shiny App in Zeppelin, you need to at least 3 paragraphs (server paragraph, ui paragraph and run type paragraph). User are not only able to build shiny app in R interpreter, but also in SparkR interpreter where you can use Spark.", - "user": "anonymous", - "dateUpdated": "2020-02-06 17:26:32.533", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "text", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/text", - "editorHide": true, - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "HTML", - "data": "\u003cdiv class\u003d\"markdown-body\"\u003e\n\u003cp\u003e\u003ca href\u003d\"https://shiny.rstudio.com/tutorial/\"\u003eShiny\u003c/a\u003e is an R package that makes it easy to build interactive web applications (apps) straight from R. For developing one Shiny App in Zeppelin, you need to at least 3 paragraphs (server paragraph, ui paragraph and run type paragraph). User are not only able to build shiny app in R interpreter, but also in SparkR interpreter where you can use Spark.\u003c/p\u003e\n\n\u003c/div\u003e" - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580981119260_-2080233417", - "id": "paragraph_1580981119260_-2080233417", - "dateCreated": "2020-02-06 17:25:19.260", - "dateStarted": "2020-02-06 17:26:18.906", - "dateFinished": "2020-02-06 17:26:20.705", - "status": "FINISHED" - }, - { - "title": "Shiny Server", - "text": "%spark.shiny(type\u003dserver)\n\n# Define server logic to summarize and view selected dataset ----\nserver \u003c- function(input, output) {\n\n # Return the requested dataset ----\n datasetInput \u003c- reactive({\n switch(input$dataset,\n \"rock\" \u003d as.DataFrame(rock),\n \"pressure\" \u003d as.DataFrame(pressure),\n \"cars\" \u003d as.DataFrame(cars))\n })\n\n # Generate a summary of the dataset ----\n output$summary \u003c- renderPrint({\n dataset \u003c- datasetInput()\n showDF(summary(dataset))\n })\n\n # Show the first \"n\" observations ----\n output$view \u003c- renderTable({\n head(datasetInput(), n \u003d input$obs)\n })\n\n}\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:37:18.062", - "progress": 0, - "config": { - "colWidth": 6.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r", - "type": "server", - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "Write server.R to /tmp/zeppelin-shiny7021485758031533052 successfully." - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580981178904_-1694112525", - "id": "paragraph_1580981178904_-1694112525", - "dateCreated": "2020-02-06 17:26:18.904", - "dateStarted": "2021-07-31 12:37:18.065", - "dateFinished": "2021-07-31 12:37:34.674", - "status": "FINISHED" - }, - { - "title": "Shiny UI", - "text": "%spark.shiny(type\u003dui)\n\n# Define UI for dataset viewer app ----\nui \u003c- fluidPage(\n\n # App title ----\n titlePanel(paste(\"Spark Version\", sparkR.version(), sep\u003d\":\")),\n\n # Sidebar layout with a input and output definitions ----\n sidebarLayout(\n\n # Sidebar panel for inputs ----\n sidebarPanel(\n\n # Input: Selector for choosing dataset ----\n selectInput(inputId \u003d \"dataset\",\n label \u003d \"Choose a dataset:\",\n choices \u003d c(\"rock\", \"pressure\", \"cars\")),\n\n # Input: Numeric entry for number of obs to view ----\n numericInput(inputId \u003d \"obs\",\n label \u003d \"Number of observations to view:\",\n value \u003d 10)\n ),\n\n # Main panel for displaying outputs ----\n mainPanel(\n \n # Output: Verbatim text for data summary ----\n verbatimTextOutput(\"summary\"),\n \n # Output: HTML table with requested number of observations ----\n tableOutput(\"view\")\n \n )\n )\n)", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:38:08.606", - "progress": 0, - "config": { - "colWidth": 6.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r", - "type": "ui", - "title": true - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "Write ui.R to /tmp/zeppelin-shiny7021485758031533052 successfully." - } - ] - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580981253412_-1490669900", - "id": "paragraph_1580981253412_-1490669900", - "dateCreated": "2020-02-06 17:27:33.412", - "dateStarted": "2021-07-31 12:38:08.609", - "dateFinished": "2021-07-31 12:38:08.617", - "status": "FINISHED" - }, - { - "title": "Shiny App", - "text": "%spark.shiny(type\u003drun)\n", - "user": "anonymous", - "dateUpdated": "2021-07-31 12:38:11.571", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r", - "title": true, - "type": "run" - }, - "settings": { - "params": {}, - "forms": {} - }, - "results": { - "code": "SUCCESS", - "msg": [ - { - "type": "TEXT", - "data": "" - }, - { - "type": "HTML", - "data": "\u003ciframe src\u003d\"http://172.17.0.2:37569\" height \u003d\"500px\" width\u003d\"100%\" frameBorder\u003d\"0\"\u003e\u003c/iframe\u003e\n" - } - ] - }, - "apps": [], - "runtimeInfos": { - "jobUrl": { - "propertyName": "jobUrl", - "label": "SPARK JOB", - "tooltip": "View in Spark web UI", - "group": "spark", - "values": [ - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d0" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d1" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d2" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d3" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d4" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d5" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d6" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d7" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d8" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d9" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d10" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d11" - }, - { - "jobUrl": "http://5c3bcd393555:4040/jobs/job?id\u003d12" - } - ], - "interpreterSettingId": "spark" - } - }, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580981260311_-1138471389", - "id": "paragraph_1580981260311_-1138471389", - "dateCreated": "2020-02-06 17:27:40.311", - "dateStarted": "2021-07-31 12:38:11.573", - "dateFinished": "2020-02-06 17:30:52.885", - "status": "ABORT" - }, - { - "text": "%spark.shiny\n", - "user": "anonymous", - "dateUpdated": "2020-03-11 14:09:23.435", - "progress": 0, - "config": { - "colWidth": 12.0, - "fontSize": 9.0, - "enabled": true, - "results": {}, - "editorSetting": { - "language": "r", - "editOnDblClick": false, - "completionKey": "TAB", - "completionSupport": true - }, - "editorMode": "ace/mode/r" - }, - "settings": { - "params": {}, - "forms": {} - }, - "apps": [], - "runtimeInfos": {}, - "progressUpdateIntervalMs": 500, - "jobName": "paragraph_1580981251266_390385714", - "id": "paragraph_1580981251266_390385714", - "dateCreated": "2020-02-06 17:27:31.266", - "status": "READY" - } - ], - "name": "6. SparkR Shiny App", - "id": "2F1CHQ4TT", - "defaultInterpreterGroup": "spark", - "version": "0.9.0-SNAPSHOT", - "noteParams": {}, - "noteForms": {}, - "angularObjects": {}, - "config": { - "isZeppelinNotebookCronEnable": false - }, - "info": {} -} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8eb5254405c..0b3a1803014 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,6 @@ zeppelin-interpreter-parent zeppelin-interpreter zeppelin-interpreter-shaded - rlang zeppelin-jupyter-interpreter zeppelin-jupyter-interpreter-shaded groovy diff --git a/rlang/pom.xml b/rlang/pom.xml deleted file mode 100644 index c7d19ae0468..00000000000 --- a/rlang/pom.xml +++ /dev/null @@ -1,246 +0,0 @@ - - - - - 4.0.0 - - - zeppelin-interpreter-parent - org.apache.zeppelin - 0.13.0-SNAPSHOT - ../zeppelin-interpreter-parent/pom.xml - - - r - jar - Zeppelin: R - Zeppelin R support - - - r - 3.5.3 - - spark-${spark.version} - - https://www.apache.org/dyn/closer.lua/spark/${spark.archive}/${spark.archive}-bin-without-hadoop.tgz?action=download - - zeppelin-interpreter-r - - - - - - org.apache.zeppelin - zeppelin-jupyter-interpreter-shaded - ${project.version} - - - - io.grpc - grpc-netty - ${grpc.version} - test - - - - io.grpc - grpc-protobuf - ${grpc.version} - test - - - - io.grpc - grpc-stub - ${grpc.version} - test - - - - org.apache.zeppelin - zeppelin-jupyter-interpreter - test - tests - ${project.version} - - - - org.apache.commons - commons-lang3 - - - - org.apache.httpcomponents - httpclient - - - - ch.qos.reload4j - reload4j - - - - org.mockito - mockito-core - test - - - - org.apache.spark - spark-core_2.12 - ${spark.version} - - - - org.jsoup - jsoup - ${jsoup.version} - - - - org.apache.hadoop - hadoop-client-api - - - - org.apache.hadoop - hadoop-client-runtime - - - - com.mashape.unirest - unirest-java - 1.4.9 - test - - - - - - - maven-enforcer-plugin - - - - - com.googlecode.maven-download-plugin - download-maven-plugin - - - download-sparkr-files - validate - - wget - - - 60000 - 5 - ${spark.bin.download.url} - true - ${project.build.directory} - ${spark.archive}-bin-without-hadoop.tgz - - - - - - - maven-resources-plugin - - - copy-sparkr-files - generate-resources - - copy-resources - - - ${project.build.directory}/../../interpreter/r/R/lib - - - - ${project.build.directory}/spark-${spark.version}-bin-without-hadoop/R/lib - - - - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - - *:* - - - - - - reference.conf - - - - - org.apache.zeppelin:zeppelin-interpreter-shaded - log4j:log4j - - - ${project.build.directory}/../../interpreter/r/${interpreter.jar.name}-${project.version}.jar - - - - package - - shade - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - 1 - false - -Xmx2048m -XX:MaxMetaspaceSize=512m - - ${basedir}/../ - - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - - test-jar - - - - - - - diff --git a/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java deleted file mode 100644 index 6407459354e..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/IRInterpreter.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.jupyter.proto.ExecuteRequest; -import org.apache.zeppelin.interpreter.jupyter.proto.ExecuteResponse; -import org.apache.zeppelin.interpreter.jupyter.proto.ExecuteStatus; -import org.apache.zeppelin.interpreter.remote.RemoteInterpreterUtils; -import org.apache.zeppelin.jupyter.JupyterKernelInterpreter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.Map; -import java.util.Properties; - -/** - * R Interpreter which use the IRKernel (https://github.com/IRkernel/IRkernel), - * Besides that it use Spark to setup communication channel between JVM and R process, so that user - * can use ZeppelinContext. - */ -public class IRInterpreter extends JupyterKernelInterpreter { - - private static final Logger LOGGER = LoggerFactory.getLogger(IRInterpreter.class); - private static RZeppelinContext z; - - // It is used to store shiny related code (ui.R & server.R) - // only one shiny app can be hosted in one R session. - private File shinyAppFolder; - private SparkRBackend sparkRBackend; - private String shinyPortRange; - - public IRInterpreter(Properties properties) { - super("ir", properties); - } - - /** - * RInterpreter just use spark-core for the communication between R process and jvm process. - * SparkContext is not created in this RInterpreter. - * Sub class can override this, e.g. SparkRInterpreter - * @return - */ - protected boolean isSparkSupported() { - return false; - } - - /** - * The spark version specified in pom.xml - * Sub class can override this, e.g. SparkRInterpreter - * @return - */ - protected int sparkVersion() { - return 20404; - } - - @Override - public void open() throws InterpreterException { - super.open(); - - this.sparkRBackend = SparkRBackend.get(); - // Share the same SparkRBackend across sessions - synchronized (sparkRBackend) { - if (!sparkRBackend.isStarted()) { - try { - sparkRBackend.init(); - } catch (Exception e) { - throw new InterpreterException("Fail to init SparkRBackend", e); - } - sparkRBackend.start(); - } - } - - synchronized (IRInterpreter.class) { - if (this.z == null) { - z = new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), - Integer.parseInt(getProperty("zeppelin.R.maxResult", "1000"))); - } - } - - try { - initIRKernel(); - } catch (IOException e) { - throw new InterpreterException("Fail to init IR Kernel:\n" + - ExceptionUtils.getStackTrace(e), e); - } - - try { - this.shinyAppFolder = Files.createTempDirectory("zeppelin-shiny").toFile(); - this.shinyAppFolder.deleteOnExit(); - this.shinyPortRange = properties.getProperty("zeppelin.R.shiny.portRange", ":"); - } catch (IOException e) { - throw new InterpreterException(e); - } - } - - /** - * Init IRKernel by execute R script zeppelin-isparkr.R - * @throws IOException - * @throws InterpreterException - */ - protected void initIRKernel() throws IOException, InterpreterException { - String timeout = getProperty("spark.r.backendConnectionTimeout", "6000"); - InputStream input = - getClass().getClassLoader().getResourceAsStream("R/zeppelin_isparkr.R"); - String code = IOUtils.toString(input, StandardCharsets.UTF_8) - .replace("${Port}", sparkRBackend.port() + "") - .replace("${version}", sparkVersion() + "") - .replace("${libPath}", "\"" + SparkRUtils.getSparkRLib(isSparkSupported()) + "\"") - .replace("${timeout}", timeout) - .replace("${isSparkSupported}", "\"" + isSparkSupported() + "\"") - .replace("${authSecret}", "\"" + sparkRBackend.socketSecret() + "\""); - LOGGER.debug("Init IRKernel via script:\n{}", code); - ExecuteResponse response = jupyterKernelClient.block_execute(ExecuteRequest.newBuilder() - .setCode(code).build()); - if (response.getStatus() != ExecuteStatus.SUCCESS) { - throw new IOException("Fail to setup JVMGateway\n" + response.getOutput()); - } - } - - @Override - protected Map setupKernelEnv() throws IOException { - Map envs = super.setupKernelEnv(); - String pathEnv = envs.getOrDefault("PATH", ""); - if (condaEnv != null) { - // add ${PWD}/${condaEnv}/bin to PATH, otherwise JupyterKernelInterpreter will fail to - // find R to launch IRKernel - pathEnv = new File(".").getAbsolutePath() + File.separator + condaEnv + - File.separator + "bin" + File.pathSeparator + pathEnv; - envs.put("PATH", pathEnv); - } - return envs; - } - - @Override - public String getKernelName() { - return "ir"; - } - - @Override - public ZeppelinContext buildZeppelinContext() { - return new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), - Integer.parseInt(getProperty("zeppelin.r.maxResult", "1000"))); - } - - public InterpreterResult shinyUI(String st, - InterpreterContext context) throws InterpreterException { - File uiFile = new File(shinyAppFolder, "ui.R"); - try (FileWriter writer = new FileWriter(uiFile)){ - IOUtils.copy(new StringReader(st), writer); - return new InterpreterResult(InterpreterResult.Code.SUCCESS, "Write ui.R to " - + shinyAppFolder.getAbsolutePath() + " successfully."); - } catch (IOException e) { - throw new InterpreterException("Fail to write shiny file ui.R", e); - } - } - - public InterpreterResult shinyServer(String st, - InterpreterContext context) throws InterpreterException { - File serverFile = new File(shinyAppFolder, "server.R"); - try (FileWriter writer = new FileWriter(serverFile);){ - IOUtils.copy(new StringReader(st), writer); - return new InterpreterResult(InterpreterResult.Code.SUCCESS, "Write server.R to " - + shinyAppFolder.getAbsolutePath() + " successfully."); - } catch (IOException e) { - throw new InterpreterException("Fail to write shiny file server.R", e); - } - } - - public InterpreterResult runShinyApp(InterpreterContext context) - throws IOException, InterpreterException { - // redirect R kernel process to InterpreterOutput of current paragraph - // because the error message after shiny app launched is printed in R kernel process - getKernelProcessLauncher().setRedirectedContext(context); - try { - StringBuilder builder = new StringBuilder("library(shiny)\n"); - String host = RemoteInterpreterUtils.findAvailableHostAddress(); - int port = RemoteInterpreterUtils.findAvailablePort(shinyPortRange); - builder.append("runApp(appDir='" + shinyAppFolder.getAbsolutePath() + "', " + - "port=" + port + ", host='" + host + "', launch.browser=FALSE)"); - // shiny app will launch and block there until user cancel the paragraph. - LOGGER.info("Run shiny app code: {}", builder.toString()); - return internalInterpret(builder.toString(), context); - } finally { - getKernelProcessLauncher().setRedirectedContext(null); - } - } - - public static RZeppelinContext getRZeppelinContext() { - return z; - } -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/RInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/RInterpreter.java deleted file mode 100644 index b4837db1c32..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/RInterpreter.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.zeppelin.interpreter.AbstractInterpreter; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.scheduler.Scheduler; -import org.apache.zeppelin.scheduler.SchedulerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.atomic.AtomicBoolean; - - -/** - * R interpreter with visualization support. - */ -public class RInterpreter extends AbstractInterpreter { - private static final Logger LOGGER = LoggerFactory.getLogger(RInterpreter.class); - private static RZeppelinContext z; - - private SparkRBackend sparkRBackend; - private ZeppelinR zeppelinR; - private String renderOptions; - private boolean useKnitr; - private AtomicBoolean rbackendDead = new AtomicBoolean(false); - - public RInterpreter(Properties property) { - super(property); - } - - /** - * RInterpreter just use spark-core for the communication between R process and jvm process. - * SparkContext is not created in this RInterpreter. - * Sub class can override this, e.g. SparkRInterpreter - * @return - */ - protected boolean isSparkSupported() { - return false; - } - - /** - * The spark version specified in pom.xml - * Sub class can override this, e.g. SparkRInterpreter - * @return - */ - protected int sparkVersion() { - return 20403; - } - - @Override - public void open() throws InterpreterException { - this.sparkRBackend = SparkRBackend.get(); - // Share the same SparkRBackend across sessions - synchronized (sparkRBackend) { - if (!sparkRBackend.isStarted()) { - try { - sparkRBackend.init(); - } catch (Exception e) { - throw new InterpreterException("Fail to init SparkRBackend", e); - } - sparkRBackend.start(); - } - } - - synchronized (RInterpreter.class) { - if (this.z == null) { - z = new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), - Integer.parseInt(getProperty("zeppelin.R.maxResult", "1000"))); - } - } - this.renderOptions = getProperty("zeppelin.R.render.options", - "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, " + - "warning = F, fig.retina = 2"); - this.useKnitr = Boolean.parseBoolean(getProperty("zeppelin.R.knitr", "true")); - zeppelinR = new ZeppelinR(this); - try { - zeppelinR.open(); - LOGGER.info("ZeppelinR is opened successfully."); - } catch (IOException e) { - throw new InterpreterException("Exception while opening RInterpreter", e); - } - - if (useKnitr) { - zeppelinR.eval("library('knitr')"); - } - } - - @Override - public InterpreterResult internalInterpret(String lines, InterpreterContext interpreterContext) - throws InterpreterException { - - String imageWidth = getProperty("zeppelin.R.image.width", "100%"); - // paragraph local propery 'imageWidth' can override this - if (interpreterContext.getLocalProperties().containsKey("imageWidth")) { - imageWidth = interpreterContext.getLocalProperties().get("imageWidth"); - } - try { - // render output with knitr - if (rbackendDead.get()) { - return new InterpreterResult(InterpreterResult.Code.ERROR, - "sparkR backend is dead"); - } - if (useKnitr) { - zeppelinR.setInterpreterOutput(null); - zeppelinR.set(".zcmd", "\n```{r " + renderOptions + "}\n" + lines + "\n```"); - zeppelinR.eval(".zres <- knit2html(text=.zcmd)"); - String html = zeppelinR.getS0(".zres"); - RDisplay rDisplay = ZeppelinRDisplay.render(html, imageWidth); - return new InterpreterResult( - rDisplay.getCode(), - rDisplay.getTyp(), - rDisplay.getContent() - ); - } else { - // alternatively, stream the output (without knitr) - zeppelinR.setInterpreterOutput(interpreterContext.out); - zeppelinR.eval(lines); - return new InterpreterResult(InterpreterResult.Code.SUCCESS, ""); - } - } catch (Exception e) { - LOGGER.error("Exception while connecting to R", e); - return new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage()); - } - } - - @Override - public void close() throws InterpreterException { - if (this.zeppelinR != null) { - zeppelinR.close(); - } - } - - @Override - public void cancel(InterpreterContext context) throws InterpreterException { - - } - - @Override - public FormType getFormType() { - return FormType.NATIVE; - } - - @Override - public int getProgress(InterpreterContext context) throws InterpreterException { - return 0; - } - - @Override - public Scheduler getScheduler() { - return SchedulerFactory.singleton().createOrGetFIFOScheduler( - RInterpreter.class.getName() + this.hashCode()); - } - - @Override - public ZeppelinContext getZeppelinContext() { - return this.z; - } - - @Override - public List completion(String buf, int cursor, - InterpreterContext interpreterContext) { - return new ArrayList<>(); - } - - public AtomicBoolean getRbackendDead() { - return rbackendDead; - } - - public static RZeppelinContext getRZeppelinContext() { - return z; - } -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/RZeppelinContext.java b/rlang/src/main/java/org/apache/zeppelin/r/RZeppelinContext.java deleted file mode 100644 index 85d63842027..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/RZeppelinContext.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.InterpreterHookRegistry; - -import java.util.List; -import java.util.Map; - -/** - * ZeppelinContext for R, only contains the basic function of ZeppelinContext. - */ -public class RZeppelinContext extends ZeppelinContext { - - public RZeppelinContext(InterpreterHookRegistry hooks, int maxResult) { - super(hooks, maxResult); - } - - @Override - public Map getInterpreterClassMap() { - return null; - } - - @Override - public List getSupportedClasses() { - return null; - } - - @Override - public String showData(Object obj, int maxResult) { - return null; - } -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java b/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java deleted file mode 100644 index 499ef4a4407..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/ShinyInterpreter.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.commons.lang3.StringUtils; -import org.apache.zeppelin.interpreter.AbstractInterpreter; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -/** - * One shiny Interpreter can host more than one Shiny app. - * They are organized by app name which you specify by paragraph local properties. - * e.g. %shiny(app=app_1) - * - * If you don't specify 'app', then default app name 'default' will be used. - * - * One shiny app is composed of at least 3 paragraph (last one is optional) - *

    - *

      - *
    • UI paragraph e.g. %r.shiny(type=ui)
    • - *
    • Server paragraph e.g. %r.shiny(type=server)
    • - *
    • Run paragraph e.g. %r.shiny(type=run)
    • - *
    • Normal R code paragraph(optional) e.g. %r.shiny
    • - *
    - *

    - */ -public class ShinyInterpreter extends AbstractInterpreter { - - private static final Logger LOGGER = LoggerFactory.getLogger(ShinyInterpreter.class); - - private static final String DEFAULT_APP_NAME = "default"; - private Map shinyIRInterpreters = new HashMap<>(); - private RZeppelinContext z; - - public ShinyInterpreter(Properties properties) { - super(properties); - } - - @Override - public void open() throws InterpreterException { - this.z = new RZeppelinContext(getInterpreterGroup().getInterpreterHookRegistry(), 1000); - } - - - @Override - public void close() throws InterpreterException { - for (Map.Entry entry : shinyIRInterpreters.entrySet()) { - LOGGER.info("Closing IRInterpreter: {}", entry.getKey()); - // Stop shiny app first otherwise the R process can not be terminated. - entry.getValue().cancel(InterpreterContext.get()); - entry.getValue().close(); - } - } - - @Override - public void cancel(InterpreterContext context) throws InterpreterException { - String shinyApp = context.getStringLocalProperty("app", DEFAULT_APP_NAME); - IRInterpreter irInterpreter = getIRInterpreter(shinyApp); - irInterpreter.cancel(context); - } - - @Override - public FormType getFormType() throws InterpreterException { - return FormType.NATIVE; - } - - @Override - public int getProgress(InterpreterContext context) throws InterpreterException { - return 0; - } - - @Override - public ZeppelinContext getZeppelinContext() { - return this.z; - } - - @Override - public InterpreterResult internalInterpret(String st, InterpreterContext context) - throws InterpreterException { - String shinyApp = context.getStringLocalProperty("app", DEFAULT_APP_NAME); - String shinyType = context.getStringLocalProperty("type", ""); - IRInterpreter irInterpreter = getIRInterpreter(shinyApp); - if (StringUtils.isBlank(shinyType)) { - return irInterpreter.internalInterpret(st, context); - } else if (shinyType.equals("run")) { - try { - return irInterpreter.runShinyApp(context); - } catch (IOException e) { - throw new InterpreterException(e); - } - } else if (shinyType.equals("ui")) { - return irInterpreter.shinyUI(st, context); - } else if (shinyType.equals("server")) { - return irInterpreter.shinyServer(st, context); - } else { - throw new InterpreterException("Unknown shiny type: " + shinyType); - } - } - - /** - * Get the specific IRInterpreter for this shinyApp. - * One ShinyApp is owned by one IRInterpreter(R session). - * - * @param shinyApp - * @return - * @throws InterpreterException - */ - private IRInterpreter getIRInterpreter(String shinyApp) throws InterpreterException { - IRInterpreter irInterpreter = null; - synchronized (shinyIRInterpreters) { - irInterpreter = shinyIRInterpreters.get(shinyApp); - if (irInterpreter == null) { - irInterpreter = createIRInterpreter(); - irInterpreter.setInterpreterGroup(getInterpreterGroup()); - irInterpreter.open(); - shinyIRInterpreters.put(shinyApp, irInterpreter); - } - } - return irInterpreter; - } - - /** - * Subclass can overwrite this. e.g. SparkShinyInterpreter. - * @return - */ - protected IRInterpreter createIRInterpreter() { - return new IRInterpreter(properties); - } - -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/SparkRBackend.java b/rlang/src/main/java/org/apache/zeppelin/r/SparkRBackend.java deleted file mode 100644 index 7c482e04322..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/SparkRBackend.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.zeppelin.r; - -import org.apache.spark.api.r.RBackend; -import scala.Tuple2; - - -/** - * SparkRBackend is responsible for communication between r process and jvm process. - * It uses Spark's RBackend to start a SocketServer in JVM side to listen request from R process. - */ -public class SparkRBackend { - private static SparkRBackend singleton; - - private RBackend backend = new RBackend(); - private boolean started = false; - private int portNumber = 0; - private String secret = ""; - private Thread backendThread; - - public synchronized static SparkRBackend get() { - if (singleton == null) { - singleton = new SparkRBackend(); - } - return singleton; - } - - private SparkRBackend() { - this.backendThread = new Thread("SparkRBackend") { - @Override - public void run() { - backend.run(); - } - }; - } - - public void init() throws Exception { - Tuple2 result = - (Tuple2) RBackend.class.getMethod("init").invoke(backend); - portNumber = result._1; - Object rAuthHelper = result._2; - secret = (String) rAuthHelper.getClass().getMethod("secret").invoke(rAuthHelper); - } - - public void start() { - backendThread.start(); - started = true; - } - - public void close(){ - backend.close(); - try { - backendThread.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - public boolean isStarted() { - return started; - } - - public int port(){ - return portNumber; - } - - public String socketSecret() { - return secret; - } -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/SparkRUtils.java b/rlang/src/main/java/org/apache/zeppelin/r/SparkRUtils.java deleted file mode 100644 index 532ff252e6d..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/SparkRUtils.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.zeppelin.interpreter.InterpreterException; - -import java.io.File; - -public class SparkRUtils { - - public static String getSparkRLib(boolean isSparkSupported) throws InterpreterException { - String sparkRLibPath; - - if (System.getenv("SPARK_HOME") != null) { - // local or yarn-client mode when SPARK_HOME is specified - sparkRLibPath = System.getenv("SPARK_HOME") + "/R/lib"; - } else if (System.getenv("ZEPPELIN_HOME") != null){ - // embedded mode when SPARK_HOME is not specified or for native R support - String interpreter = "r"; - if (isSparkSupported) { - interpreter = "spark"; - } - sparkRLibPath = System.getenv("ZEPPELIN_HOME") + "/interpreter/" + interpreter + "/R/lib"; - // workaround to make sparkr work without SPARK_HOME - System.setProperty("spark.test.home", System.getenv("ZEPPELIN_HOME") + "/interpreter/" + interpreter); - } else { - // yarn-cluster mode - sparkRLibPath = "sparkr"; - } - if (!new File(sparkRLibPath).exists()) { - throw new InterpreterException(String.format("sparkRLib '%s' doesn't exist", sparkRLibPath)); - } - - return sparkRLibPath; - } -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/ZeppelinR.java b/rlang/src/main/java/org/apache/zeppelin/r/ZeppelinR.java deleted file mode 100644 index 91871c39c3f..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/ZeppelinR.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.zeppelin.r; - -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.environment.EnvironmentUtils; -import org.apache.commons.io.IOUtils; -import org.apache.zeppelin.r.SparkRBackend; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.util.ProcessLauncher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * R repl interaction - */ -public class ZeppelinR { - private static final Logger LOGGER = LoggerFactory.getLogger(ZeppelinR.class); - - private RInterpreter rInterpreter; - private RProcessLogOutputStream processOutputStream; - static Map zeppelinR = Collections.synchronizedMap(new HashMap()); - private RProcessLauncher rProcessLauncher; - - /** - * Request to R repl - */ - private Request rRequestObject = null; - private Integer rRequestNotifier = Integer.valueOf(0); - - /** - * Response from R repl - */ - private Object rResponseValue = null; - private boolean rResponseError = false; - private Integer rResponseNotifier = Integer.valueOf(0); - - public ZeppelinR(RInterpreter rInterpreter) { - this.rInterpreter = rInterpreter; - } - - /** - * Start R repl - * @throws IOException - */ - public void open() throws IOException, InterpreterException { - - String rCmdPath = rInterpreter.getProperty("zeppelin.R.cmd", "R"); - String sparkRLibPath; - - if (System.getenv("SPARK_HOME") != null) { - // local or yarn-client mode when SPARK_HOME is specified - sparkRLibPath = System.getenv("SPARK_HOME") + "/R/lib"; - } else if (System.getenv("ZEPPELIN_HOME") != null){ - // embedded mode when SPARK_HOME is not specified or for native R support - String interpreter = "r"; - if (rInterpreter.isSparkSupported()) { - interpreter = "spark"; - } - sparkRLibPath = System.getenv("ZEPPELIN_HOME") + "/interpreter/" + interpreter + "/R/lib"; - // workaround to make sparkr work without SPARK_HOME - System.setProperty("spark.test.home", System.getenv("ZEPPELIN_HOME") + "/interpreter/" + interpreter); - } else { - // yarn-cluster mode - sparkRLibPath = "sparkr"; - } - if (!new File(sparkRLibPath).exists()) { - throw new InterpreterException(String.format("sparkRLib %s doesn't exist", sparkRLibPath)); - } - - File scriptFile = File.createTempFile("zeppelin_sparkr-", ".R"); - FileOutputStream out = null; - InputStream in = null; - try { - out = new FileOutputStream(scriptFile); - in = getClass().getClassLoader().getResourceAsStream("R/zeppelin_sparkr.R"); - IOUtils.copy(in, out); - } catch (IOException e) { - throw new InterpreterException(e); - } finally { - if (out != null) { - out.close(); - } - if (in != null) { - in.close(); - } - } - - zeppelinR.put(hashCode(), this); - String timeout = rInterpreter.getProperty("spark.r.backendConnectionTimeout", "6000"); - - CommandLine cmd = CommandLine.parse(rCmdPath); - cmd.addArgument("--no-save"); - cmd.addArgument("--no-restore"); - cmd.addArgument("-f"); - cmd.addArgument(scriptFile.getAbsolutePath()); - cmd.addArgument("--args"); - cmd.addArgument(Integer.toString(hashCode())); - cmd.addArgument(Integer.toString(SparkRBackend.get().port())); - cmd.addArgument(sparkRLibPath); - cmd.addArgument(rInterpreter.sparkVersion() + ""); - cmd.addArgument(timeout); - cmd.addArgument(rInterpreter.isSparkSupported() + ""); - cmd.addArgument(SparkRBackend.get().socketSecret()); - // dump out the R command to facilitate manually running it, e.g. for fault diagnosis purposes - LOGGER.info("R Command: {}", cmd); - processOutputStream = new RProcessLogOutputStream(rInterpreter); - Map env = EnvironmentUtils.getProcEnvironment(); - rProcessLauncher = new RProcessLauncher(cmd, env, processOutputStream); - rProcessLauncher.launch(); - rProcessLauncher.waitForReady(30 * 1000); - - if (!rProcessLauncher.isRunning()) { - if (rProcessLauncher.isLaunchTimeout()) { - throw new IOException("Launch r process is time out.\n" + - rProcessLauncher.getErrorMessage()); - } else { - throw new IOException("Fail to launch r process.\n" + - rProcessLauncher.getErrorMessage()); - } - } - // flush output - eval("cat('')"); - } - - public void setInterpreterOutput(InterpreterOutput out) { - processOutputStream.setInterpreterOutput(out); - } - - /** - * Request object - * - * type : "eval", "set", "get" - * stmt : statement to evaluate when type is "eval" - * key when type is "set" or "get" - * value : value object when type is "put" - */ - public static class Request { - String type; - String stmt; - Object value; - - public Request(String type, String stmt, Object value) { - this.type = type; - this.stmt = stmt; - this.value = value; - } - - public String getType() { - return type; - } - - public String getStmt() { - return stmt; - } - - public Object getValue() { - return value; - } - } - - /** - * Evaluate expression - * @param expr - * @return - */ - public Object eval(String expr) throws InterpreterException { - synchronized (this) { - rRequestObject = new Request("eval", expr, null); - return request(); - } - } - - /** - * assign value to key - * @param key - * @param value - */ - public void set(String key, Object value) throws InterpreterException { - synchronized (this) { - rRequestObject = new Request("set", key, value); - request(); - } - } - - /** - * get value of key - * @param key - * @return - */ - public Object get(String key) throws InterpreterException { - synchronized (this) { - rRequestObject = new Request("get", key, null); - return request(); - } - } - - /** - * get value of key, as a string - * @param key - * @return - */ - public String getS0(String key) throws InterpreterException { - synchronized (this) { - rRequestObject = new Request("getS", key, null); - return (String) request(); - } - } - - private boolean isRProcessInitialized() { - return rProcessLauncher != null && rProcessLauncher.isRunning(); - } - - /** - * Send request to r repl and return response - * @return responseValue - */ - private Object request() throws RuntimeException { - if (!isRProcessInitialized()) { - throw new RuntimeException("r repl is not running"); - } - - rResponseValue = null; - synchronized (rRequestNotifier) { - rRequestNotifier.notify(); - } - - Object respValue = null; - synchronized (rResponseNotifier) { - while (rResponseValue == null && isRProcessInitialized()) { - try { - rResponseNotifier.wait(1000); - } catch (InterruptedException e) { - LOGGER.error(e.getMessage(), e); - } - } - respValue = rResponseValue; - rResponseValue = null; - } - - if (rResponseError) { - throw new RuntimeException(respValue.toString()); - } else { - return respValue; - } - } - - /** - * invoked by src/main/resources/R/zeppelin_sparkr.R - * @return - */ - public Request getRequest() { - synchronized (rRequestNotifier) { - while (rRequestObject == null) { - try { - rRequestNotifier.wait(1000); - } catch (InterruptedException e) { - LOGGER.error(e.getMessage(), e); - } - } - - Request req = rRequestObject; - rRequestObject = null; - return req; - } - } - - /** - * invoked by src/main/resources/R/zeppelin_sparkr.R - * @param value - * @param error - */ - public void setResponse(Object value, boolean error) { - synchronized (rResponseNotifier) { - rResponseValue = value; - rResponseError = error; - rResponseNotifier.notify(); - } - } - - /** - * invoked by src/main/resources/R/zeppelin_sparkr.R - */ - public void onScriptInitialized() { - rProcessLauncher.initialized(); - } - - /** - * Terminate this R repl - */ - public void close() { - if (rProcessLauncher != null) { - rProcessLauncher.stop(); - } - zeppelinR.remove(hashCode()); - } - - /** - * Get instance - * This method will be invoded from zeppelin_sparkr.R - * @param hashcode - * @return - */ - public static ZeppelinR getZeppelinR(int hashcode) { - return zeppelinR.get(hashcode); - } - - class RProcessLauncher extends ProcessLauncher { - - public RProcessLauncher(CommandLine commandLine, - Map envs, - ProcessLogOutputStream processLogOutput) { - super(commandLine, envs, processLogOutput); - } - - @Override - public void waitForReady(int timeout) { - long startTime = System.currentTimeMillis(); - synchronized (this) { - while (state == State.LAUNCHED) { - LOGGER.info("Waiting for R process initialized"); - try { - wait(100); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - if ((System.currentTimeMillis() - startTime) > timeout) { - onTimeout(); - break; - } - } - } - } - - public void initialized() { - synchronized (this) { - this.state = State.RUNNING; - notify(); - } - } - } - - public static class RProcessLogOutputStream extends ProcessLauncher.ProcessLogOutputStream { - - private InterpreterOutput interpreterOutput; - private RInterpreter rInterpreter; - - public RProcessLogOutputStream(RInterpreter rInterpreter) { - this.rInterpreter = rInterpreter; - } - - /** - * Redirect r process output to interpreter output. - * @param interpreterOutput - */ - public void setInterpreterOutput(InterpreterOutput interpreterOutput) { - this.interpreterOutput = interpreterOutput; - } - - @Override - protected void processLine(String s, int i) { - super.processLine(s, i); - if (s.contains("Java SparkR backend might have failed") // spark 2.x - || s.contains("Execution halted")) { // spark 1.x - rInterpreter.getRbackendDead().set(true); - } - if (interpreterOutput != null) { - try { - interpreterOutput.write(s); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - @Override - public void close() throws IOException { - super.close(); - if (interpreterOutput != null) { - interpreterOutput.close(); - } - } - } -} diff --git a/rlang/src/main/java/org/apache/zeppelin/r/ZeppelinRDisplay.java b/rlang/src/main/java/org/apache/zeppelin/r/ZeppelinRDisplay.java deleted file mode 100644 index fe65b22926e..00000000000 --- a/rlang/src/main/java/org/apache/zeppelin/r/ZeppelinRDisplay.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.zeppelin.interpreter.InterpreterResult.Code; -import org.apache.zeppelin.interpreter.InterpreterResult.Type; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Document.OutputSettings; -import org.jsoup.safety.Safelist; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -class RDisplay { - private String content; - private Type typ; - private Code code; - - public RDisplay(String content, Type typ, Code code) { - this.content = content; - this.typ = typ; - this.code = code; - } - - public String getContent() { - return content; - } - - public Type getTyp() { - return typ; - } - - public Code getCode() { - return code; - } -} - -public class ZeppelinRDisplay { - - private static Pattern pattern = Pattern.compile("^ *\\[\\d*\\]"); - - public static RDisplay render( String html, String imageWidth) { - - Document document = Jsoup.parse(html); - document.outputSettings().prettyPrint(false); - - Element body = document.body(); - - if (body.getElementsByTag("p").isEmpty()) { - return new RDisplay(body.html(), Type.HTML, Code.SUCCESS); - } - - String bodyHtml = body.html(); - - if (! bodyHtml.contains("= 20000) { - assign(".sparkRsession", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkSession"), envir = SparkR:::.sparkREnv) - assign("spark", get(".sparkRsession", envir = SparkR:::.sparkREnv), envir = .GlobalEnv) - assign(".sparkRjsc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getJavaSparkContext"), envir = SparkR:::.sparkREnv) - } - assign(".sqlc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSqlContext"), envir = SparkR:::.sparkREnv) - assign("sqlContext", get(".sqlc", envir = SparkR:::.sparkREnv), envir = .GlobalEnv) - assign(".zeppelinContext", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getZeppelinContext"), envir = .GlobalEnv) -} else { - assign(".zeppelinContext", SparkR:::callJStatic("org.apache.zeppelin.r.IRInterpreter", "getRZeppelinContext"), envir = .GlobalEnv) -} - -z.put <- function(name, object) { - SparkR:::callJMethod(.zeppelinContext, "put", name, object) -} - -z.get <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "get", name) -} - -z.getAsDataFrame <- function(name) { - stringValue <- z.get(name) - read.table(text=stringValue, header=TRUE, sep="\t") -} - -z.angular <- function(name, noteId=NULL, paragraphId=NULL) { - SparkR:::callJMethod(.zeppelinContext, "angular", name, noteId, paragraphId) -} - -z.angularBind <- function(name, value, noteId=NULL, paragraphId=NULL) { - SparkR:::callJMethod(.zeppelinContext, "angularBind", name, value, noteId, paragraphId) -} - -z.textbox <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "textbox", name, value) -} - -z.noteTextbox <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "noteTextbox", name, value) -} - -z.password <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "password", name) -} - -z.notePassword <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "notePassword", name) -} - -z.run <- function(paragraphId) { - SparkR:::callJMethod(.zeppelinContext, "run", paragraphId) -} - -z.runNote <- function(noteId) { - SparkR:::callJMethod(.zeppelinContext, "runNote", noteId) -} - -z.runAll <- function() { - SparkR:::callJMethod(.zeppelinContext, "runAll") -} - -z.angular <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "angular", name) -} - -z.angularBind <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "angularBind", name, value) -} - -z.angularUnbind <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "angularUnbind", name) -} - -z.show <- function(data, maxRows=SparkR:::callJMethod(.zeppelinContext, "getMaxResult")) { - if (is.data.frame(data)) { - resultString = c(paste(colnames(data), collapse ="\t")) - for (row in 1: min(nrow(data), maxRows)) { - rowString <- paste(data[row,], collapse ="\t") - resultString = c(resultString, rowString) - } - a=paste(resultString, collapse="\n") - cat("\n%table ", a, "\n\n%text ", sep="") - if (nrow(data) > maxRows) { - cat("\n%html Results are limited by ", maxRows, " rows.", "\n%text ", sep="") - } - } else { - cat(data) - } -} \ No newline at end of file diff --git a/rlang/src/main/resources/R/zeppelin_sparkr.R b/rlang/src/main/resources/R/zeppelin_sparkr.R deleted file mode 100644 index 94fa6a7bb22..00000000000 --- a/rlang/src/main/resources/R/zeppelin_sparkr.R +++ /dev/null @@ -1,170 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -args <- commandArgs(trailingOnly = TRUE) - -hashCode <- as.integer(args[1]) -port <- as.integer(args[2]) -libPath <- args[3] -version <- as.integer(args[4]) -timeout <- as.integer(args[5]) -isSparkSupported <- args[6] -authSecret <- NULL -if (length(args) >= 7) { - authSecret <- args[7] -} - -rm(args) - -print(paste("Port ", toString(port))) -print(paste("LibPath ", libPath)) - -.libPaths(c(file.path(libPath), .libPaths())) -library(SparkR) - -if (is.null(authSecret)) { - SparkR:::connectBackend("localhost", port, timeout) -} else { - SparkR:::connectBackend("localhost", port, timeout, authSecret) -} - -# scStartTime is needed by R/pkg/R/sparkR.R -assign(".scStartTime", as.integer(Sys.time()), envir = SparkR:::.sparkREnv) - -# getZeppelinR -.zeppelinR = SparkR:::callJStatic("org.apache.zeppelin.r.ZeppelinR", "getZeppelinR", hashCode) - -if (isSparkSupported == "true") { - # setup spark env - assign(".sc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkContext"), envir = SparkR:::.sparkREnv) - assign("sc", get(".sc", envir = SparkR:::.sparkREnv), envir=.GlobalEnv) - if (version >= 20000) { - assign(".sparkRsession", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSparkSession"), envir = SparkR:::.sparkREnv) - assign("spark", get(".sparkRsession", envir = SparkR:::.sparkREnv), envir = .GlobalEnv) - assign(".sparkRjsc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getJavaSparkContext"), envir = SparkR:::.sparkREnv) - } - assign(".sqlc", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getSqlContext"), envir = SparkR:::.sparkREnv) - assign("sqlContext", get(".sqlc", envir = SparkR:::.sparkREnv), envir = .GlobalEnv) - assign(".zeppelinContext", SparkR:::callJStatic("org.apache.zeppelin.spark.ZeppelinRContext", "getZeppelinContext"), envir = .GlobalEnv) -} else { - assign(".zeppelinContext", SparkR:::callJStatic("org.apache.zeppelin.r.RInterpreter", "getRZeppelinContext"), envir = .GlobalEnv) -} - -z.put <- function(name, object) { - SparkR:::callJMethod(.zeppelinContext, "put", name, object) -} - -z.get <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "get", name) -} - -z.getAsDataFrame <- function(name) { - stringValue <- z.get(name) - read.table(text=stringValue, header=TRUE, sep="\t") -} - -z.angular <- function(name, noteId=NULL, paragraphId=NULL) { - SparkR:::callJMethod(.zeppelinContext, "angular", name, noteId, paragraphId) -} - -z.angularBind <- function(name, value, noteId=NULL, paragraphId=NULL) { - SparkR:::callJMethod(.zeppelinContext, "angularBind", name, value, noteId, paragraphId) -} - -z.textbox <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "textbox", name, value) -} - -z.noteTextbox <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "noteTextbox", name, value) -} - -z.password <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "password", name) -} - -z.notePassword <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "notePassword", name) -} - -z.run <- function(paragraphId) { - SparkR:::callJMethod(.zeppelinContext, "run", paragraphId) -} - -z.runNote <- function(noteId) { - SparkR:::callJMethod(.zeppelinContext, "runNote", noteId) -} - -z.runAll <- function() { - SparkR:::callJMethod(.zeppelinContext, "runAll") -} - -z.angular <- function(name) { - SparkR:::callJMethod(.zeppelinContext, "angular", name) -} - -z.angularBind <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "angularBind", name, value) -} - -z.angularUnbind <- function(name, value) { - SparkR:::callJMethod(.zeppelinContext, "angularUnbind", name) -} - -# notify script is initialized -SparkR:::callJMethod(.zeppelinR, "onScriptInitialized") - -while (TRUE) { - req <- SparkR:::callJMethod(.zeppelinR, "getRequest") - type <- SparkR:::callJMethod(req, "getType") - stmt <- SparkR:::callJMethod(req, "getStmt") - value <- SparkR:::callJMethod(req, "getValue") - - if (type == "eval") { - tryCatch({ - ret <- eval(parse(text=stmt)) - SparkR:::callJMethod(.zeppelinR, "setResponse", "", FALSE) - }, error = function(e) { - SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE) - }) - } else if (type == "set") { - tryCatch({ - ret <- assign(stmt, value) - SparkR:::callJMethod(.zeppelinR, "setResponse", "", FALSE) - }, error = function(e) { - SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE) - }) - } else if (type == "get") { - tryCatch({ - ret <- eval(parse(text=stmt)) - SparkR:::callJMethod(.zeppelinR, "setResponse", ret, FALSE) - }, error = function(e) { - SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE) - }) - } else if (type == "getS") { - tryCatch({ - ret <- eval(parse(text=stmt)) - SparkR:::callJMethod(.zeppelinR, "setResponse", toString(ret), FALSE) - }, error = function(e) { - SparkR:::callJMethod(.zeppelinR, "setResponse", toString(e), TRUE) - }) - } else { - # unsupported type - SparkR:::callJMethod(.zeppelinR, "setResponse", paste("Unsupported type ", type), TRUE) - } -} diff --git a/rlang/src/main/resources/interpreter-setting.json b/rlang/src/main/resources/interpreter-setting.json deleted file mode 100644 index 654c1ee794f..00000000000 --- a/rlang/src/main/resources/interpreter-setting.json +++ /dev/null @@ -1,94 +0,0 @@ -[ - { - "group": "r", - "name": "r", - "className": "org.apache.zeppelin.r.RInterpreter", - "properties": { - "zeppelin.R.knitr": { - "envName": "ZEPPELIN_R_KNITR", - "propertyName": "zeppelin.R.knitr", - "defaultValue": true, - "description": "Whether use knitr or not", - "type": "checkbox" - }, - "zeppelin.R.cmd": { - "envName": "ZEPPELIN_R_CMD", - "propertyName": "zeppelin.R.cmd", - "defaultValue": "R", - "description": "R binary executable path", - "type": "string" - }, - "zeppelin.R.maxResult": { - "envName": null, - "propertyName": "zeppelin.R.maxResult", - "defaultValue": "1000", - "description": "Max number of dataframe rows to display.", - "type": "number" - }, - "zeppelin.R.image.width": { - "envName": "ZEPPELIN_R_IMAGE_WIDTH", - "propertyName": "zeppelin.R.image.width", - "defaultValue": "100%", - "description": "Image width of R plotting", - "type": "number" - }, - "zeppelin.R.render.options": { - "envName": "ZEPPELIN_R_RENDER_OPTIONS", - "propertyName": "zeppelin.R.render.options", - "defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2", - "description": "", - "type": "textarea" - }, - "zeppelin.R.shiny.portRange": { - "envName": "", - "propertyName": "zeppelin.R.shiny.portRange", - "defaultValue": ":", - "description": "Shiny app would launch a web app at some port, this property is to specify the portRange via format ':', e.g. '5000:5001'. By default it is ':' which means any port", - "type": "string" - } - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true - } - }, - { - "group": "r", - "name": "ir", - "className": "org.apache.zeppelin.r.IRInterpreter", - "properties": { - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true - } - }, - { - "group": "r", - "name": "shiny", - "className": "org.apache.zeppelin.r.ShinyInterpreter", - "properties": { - "zeppelin.R.shiny.iframe_width": { - "envName": "", - "propertyName": "zeppelin.R.shiny.iframe_width", - "defaultValue": "100%", - "description": "Width of iframe of R shiny app", - "type": "text" - }, - "zeppelin.R.shiny.iframe_height": { - "envName": "", - "propertyName": "zeppelin.R.shiny.iframe_height", - "defaultValue": "500px", - "description": "Height of iframe of R shiny app", - "type": "text" - } - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true - } - } -] diff --git a/rlang/src/test/java/org/apache/zeppelin/r/IRInterpreterTest.java b/rlang/src/test/java/org/apache/zeppelin/r/IRInterpreterTest.java deleted file mode 100644 index 76cf96d0e32..00000000000 --- a/rlang/src/test/java/org/apache/zeppelin/r/IRInterpreterTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessage; -import org.apache.zeppelin.jupyter.IRKernelTest; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Properties; - - -public class IRInterpreterTest extends IRKernelTest { - - @Override - protected Interpreter createInterpreter(Properties properties) { - return new IRInterpreter(properties); - } - - @Override - protected InterpreterContext getInterpreterContext() { - InterpreterContext context = InterpreterContext.builder() - .setNoteId("note_1") - .setParagraphId("paragraph_1") - .setInterpreterOut(new InterpreterOutput()) - .setLocalProperties(new HashMap<>()) - .build(); - return context; - } - - @Test - public void testZShow() throws InterpreterException, IOException { - InterpreterContext context = getInterpreterContext(); - InterpreterResult result = interpreter.interpret( - "df=data.frame(country=c(\"US\", \"GB\", \"BR\"),\n" + - "val1=c(10,13,14),\n" + - "val2=c(23,12,32))", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - context = getInterpreterContext(); - result = interpreter.interpret("z.show(df)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - List resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.TABLE, resultMessages.get(0).getType(), - resultMessages.toString()); - assertEquals("country\tval1\tval2\n" + - "3\t10\t23\n" + - "2\t13\t12\n" + - "1\t14\t32\n", - resultMessages.get(0).getData()); - - context = getInterpreterContext(); - result = interpreter.interpret("z.show(df, maxRows=1)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(2, resultMessages.size()); - assertEquals(InterpreterResult.Type.TABLE, resultMessages.get(0).getType(), resultMessages.toString()); - assertEquals("country\tval1\tval2\n" + - "3\t10\t23\n", - resultMessages.get(0).getData()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(1).getType(), - resultMessages.toString()); - assertEquals("Results are limited by 1 rows.\n", - resultMessages.get(1).getData()); - } -} diff --git a/rlang/src/test/java/org/apache/zeppelin/r/RInterpreterTest.java b/rlang/src/test/java/org/apache/zeppelin/r/RInterpreterTest.java deleted file mode 100644 index 7f1711c38f8..00000000000 --- a/rlang/src/test/java/org/apache/zeppelin/r/RInterpreterTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.zeppelin.r; - -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.LazyOpenInterpreter; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Properties; - -class RInterpreterTest { - - private RInterpreter rInterpreter; - - @BeforeEach - public void setUp() throws InterpreterException { - Properties properties = new Properties(); - properties.setProperty("zeppelin.R.knitr", "true"); - properties.setProperty("spark.r.backendConnectionTimeout", "10"); - - InterpreterContext context = getInterpreterContext(); - InterpreterContext.set(context); - rInterpreter = new RInterpreter(properties); - - InterpreterGroup interpreterGroup = new InterpreterGroup(); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(rInterpreter), "session_1"); - rInterpreter.setInterpreterGroup(interpreterGroup); - - rInterpreter.open(); - } - - @AfterEach - public void tearDown() throws InterpreterException { - rInterpreter.close(); - } - - @Test - void testSparkRInterpreter() throws InterpreterException, InterruptedException, IOException { - InterpreterResult result = rInterpreter.interpret("1+1", getInterpreterContext()); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertTrue(result.message().get(0).getData().contains("2")); - - InterpreterContext context = getInterpreterContext(); - result = rInterpreter.interpret("foo <- TRUE\n" + - "print(foo)\n" + - "bare <- c(1, 2.5, 4)\n" + - "print(bare)\n" + - "double <- 15.0\n" + - "print(double)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertTrue(result.message().get(0).getData().contains("[1] TRUE\n" + - "[1] 1.0 2.5 4.0\n" + - "[1] 15\n"), result.toString()); - - // plotting - context = getInterpreterContext(); - context.getLocalProperties().put("imageWidth", "100"); - result = rInterpreter.interpret("hist(mtcars$mpg)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertEquals(1, result.message().size()); - assertEquals(InterpreterResult.Type.HTML, result.message().get(0).getType()); - assertTrue(result.message().get(0).getData().contains("()) - .build(); - return context; - } -} diff --git a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java b/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java deleted file mode 100644 index 1afffa196e3..00000000000 --- a/rlang/src/test/java/org/apache/zeppelin/r/ShinyInterpreterTest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.r; - -import com.mashape.unirest.http.HttpResponse; -import com.mashape.unirest.http.Unirest; -import com.mashape.unirest.http.exceptions.UnirestException; -import org.apache.commons.io.IOUtils; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessage; -import org.apache.zeppelin.interpreter.LazyOpenInterpreter; -import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; - -public class ShinyInterpreterTest { - - protected ShinyInterpreter interpreter; - - @BeforeEach - public void setUp() throws InterpreterException { - Properties properties = new Properties(); - - InterpreterContext context = getInterpreterContext(); - InterpreterContext.set(context); - interpreter = new ShinyInterpreter(properties); - - InterpreterGroup interpreterGroup = new InterpreterGroup(); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(interpreter), "session_1"); - interpreter.setInterpreterGroup(interpreterGroup); - - interpreter.open(); - } - - @AfterEach - public void tearDown() throws InterpreterException { - if (interpreter != null) { - interpreter.close(); - } - } - - @Test - void testShinyApp() throws - IOException, InterpreterException, InterruptedException, UnirestException { - /****************** Launch Shiny app with default app name *****************************/ - InterpreterContext context = getInterpreterContext(); - context.getLocalProperties().put("type", "ui"); - InterpreterResult result = - interpreter.interpret(IOUtils.toString(getClass().getResource("/ui.R"), StandardCharsets.UTF_8), context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - context = getInterpreterContext(); - context.getLocalProperties().put("type", "server"); - result = interpreter.interpret(IOUtils.toString(getClass().getResource("/server.R"), StandardCharsets.UTF_8), context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - final InterpreterContext context2 = getInterpreterContext(); - context2.getLocalProperties().put("type", "run"); - Thread thread = new Thread(() -> { - try { - interpreter.interpret("", context2); - } catch (Exception e) { - e.printStackTrace(); - } - }); - thread.start(); - // wait for the shiny app start - Thread.sleep(5 * 1000); - // extract shiny url - List resultMessages = context2.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size(), resultMessages.toString()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType()); - String resultMessageData = resultMessages.get(0).getData(); - assertTrue(resultMessageData.contains(" response = Unirest.get(shinyURL).asString(); - assertEquals(200, response.getStatus()); - assertTrue(response.getBody().contains("Shiny Text"), response.getBody()); - - /************************ Launch another shiny app (app2) *****************************/ - context = getInterpreterContext(); - context.getLocalProperties().put("type", "ui"); - context.getLocalProperties().put("app", "app2"); - result = - interpreter.interpret(IOUtils.toString(getClass().getResource("/ui.R"), StandardCharsets.UTF_8), context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - context = getInterpreterContext(); - context.getLocalProperties().put("type", "server"); - context.getLocalProperties().put("app", "app2"); - result = interpreter.interpret(IOUtils.toString(getClass().getResource("/server.R"), StandardCharsets.UTF_8), context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - final InterpreterContext context3 = getInterpreterContext(); - context3.getLocalProperties().put("type", "run"); - context3.getLocalProperties().put("app", "app2"); - thread = new Thread(() -> { - try { - interpreter.interpret("", context3); - } catch (Exception e) { - e.printStackTrace(); - } - }); - thread.start(); - // wait for the shiny app start - Thread.sleep(5 * 1000); - // extract shiny url - resultMessages = context3.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType()); - resultMessageData = resultMessages.get(0).getData(); - assertTrue(resultMessageData.contains(" { - try { - interpreter.interpret("", context2); - } catch (Exception e) { - e.printStackTrace(); - } - }); - thread.start(); - // wait for the shiny app start - Thread.sleep(5 * 1000); - List resultMessages = context2.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size(), resultMessages.toString()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType()); - String resultMessageData = resultMessages.get(0).getData(); - assertTrue(resultMessageData.contains(" response = Unirest.get(shinyURL).asString(); - assertEquals(500, response.getStatus()); - - resultMessages = context2.out.toInterpreterResultMessage(); - assertTrue(resultMessages.get(1).getData().contains("Invalid_code"), - resultMessages.get(1).getData()); - // depends on JVM language - // assertTrue(resultMessages.get(1).getData().contains("object 'Invalid_code' not found"), - // resultMessages.get(1).getData()); - - // cancel paragraph to stop shiny app - interpreter.cancel(getInterpreterContext()); - // wait for shiny app to be stopped - Thread.sleep(1000); - try { - Unirest.get(shinyURL).asString(); - fail("Should fail to connect to shiny app"); - } catch (Exception e) { - assertTrue(e.getMessage().contains("Connection refused"), e.getMessage()); - } - } - - protected InterpreterContext getInterpreterContext() { - InterpreterContext context = InterpreterContext.builder() - .setNoteId("note_1") - .setParagraphId("paragraph_1") - .setInterpreterOut(new InterpreterOutput()) - .setLocalProperties(new HashMap<>()) - .setInterpreterClassName(ShinyInterpreter.class.getName()) - .setIntpEventClient(mock(RemoteInterpreterEventClient.class)) - .build(); - return context; - } -} diff --git a/rlang/src/test/resources/invalid_ui.R b/rlang/src/test/resources/invalid_ui.R deleted file mode 100644 index 9f08258b3f6..00000000000 --- a/rlang/src/test/resources/invalid_ui.R +++ /dev/null @@ -1 +0,0 @@ -Invalid_code \ No newline at end of file diff --git a/rlang/src/test/resources/log4j.properties b/rlang/src/test/resources/log4j.properties deleted file mode 100644 index fa1988008d0..00000000000 --- a/rlang/src/test/resources/log4j.properties +++ /dev/null @@ -1,27 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -# Root logger option -log4j.rootLogger=INFO, stdout - -# Direct log messages to stdout -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%5p [%d] ({%t} %F[%M]:%L) - %m%n - -#log4j.logger.org.apache.zeppelin.interpreter.util=DEBUG -log4j.logger.org.apache.zeppelin.jupyter=DEBUG diff --git a/rlang/src/test/resources/server.R b/rlang/src/test/resources/server.R deleted file mode 100644 index eb67ffb9240..00000000000 --- a/rlang/src/test/resources/server.R +++ /dev/null @@ -1,23 +0,0 @@ -# Define server logic to summarize and view selected dataset ---- -server <- function(input, output) { - - # Return the requested dataset ---- - datasetInput <- reactive({ - switch(input$dataset, - "rock" = rock, - "pressure" = pressure, - "cars" = cars) - }) - - # Generate a summary of the dataset ---- - output$summary <- renderPrint({ - dataset <- datasetInput() - summary(dataset) - }) - - # Show the first "n" observations ---- - output$view <- renderTable({ - head(datasetInput(), n = input$obs) - }) - -} \ No newline at end of file diff --git a/rlang/src/test/resources/ui.R b/rlang/src/test/resources/ui.R deleted file mode 100644 index 282a9d5c47a..00000000000 --- a/rlang/src/test/resources/ui.R +++ /dev/null @@ -1,35 +0,0 @@ -# Define UI for dataset viewer app ---- -ui <- fluidPage( - -# App title ---- -titlePanel("Shiny Text"), - -# Sidebar layout with a input and output definitions ---- -sidebarLayout( - -# Sidebar panel for inputs ---- -sidebarPanel( - -# Input: Selector for choosing dataset ---- -selectInput(inputId = "dataset", -label = "Choose a dataset:", -choices = c("rock", "pressure", "cars")), - -# Input: Numeric entry for number of obs to view ---- -numericInput(inputId = "obs", -label = "Number of observations to view:", -value = 10) -), - -# Main panel for displaying outputs ---- -mainPanel( - -# Output: Verbatim text for data summary ---- -verbatimTextOutput("summary"), - -# Output: HTML table with requested number of observations ---- -tableOutput("view") - -) -) -) \ No newline at end of file diff --git a/scripts/docker/zeppelin-interpreter/Dockerfile b/scripts/docker/zeppelin-interpreter/Dockerfile index ed949959e48..63dfb352dab 100644 --- a/scripts/docker/zeppelin-interpreter/Dockerfile +++ b/scripts/docker/zeppelin-interpreter/Dockerfile @@ -49,13 +49,13 @@ COPY --from=zeppelin-distribution /opt/zeppelin/interpreter ${ZEPPELIN_HOME}/int ### COPY --from=zeppelin-distribution /opt/zeppelin/interpreter/${interpreter_name} ${ZEPPELIN_HOME}/interpreter/${interpreter_name} -# Decide: Install conda to manage python and R packages. Maybe adjust the packages env_python_3_with_R -# Install python and R packages via conda -COPY env_python_3_with_R.yml /env_python_3_with_R.yml +# Decide: Install conda to manage python packages. Maybe adjust the packages env_python_3 +# Install python packages via conda +COPY env_python_3.yml /env_python_3.yml # To improve the build time, the Zeppelin team recommends a conda proxy # COPY condarc /etc/conda/condarc RUN set -ex && \ - micromamba create -y -p /opt/conda -f env_python_3_with_R.yml && \ + micromamba create -y -p /opt/conda -f env_python_3.yml && \ micromamba clean -ay ENV PATH=/opt/conda/bin:$PATH \ diff --git a/scripts/docker/zeppelin-interpreter/env_python_3_with_R.yml b/scripts/docker/zeppelin-interpreter/env_python_3.yml similarity index 69% rename from scripts/docker/zeppelin-interpreter/env_python_3_with_R.yml rename to scripts/docker/zeppelin-interpreter/env_python_3.yml index a2a9a0e2f3f..bfdc93c1711 100644 --- a/scripts/docker/zeppelin-interpreter/env_python_3_with_R.yml +++ b/scripts/docker/zeppelin-interpreter/env_python_3.yml @@ -1,10 +1,10 @@ -name: python_3_with_R +name: python_3 channels: - conda-forge - defaults dependencies: - python >=3.9,<3.10 - - pyspark=3.5.3 + - pyspark=3.5.8 - pycodestyle - scipy - numpy @@ -27,12 +27,3 @@ dependencies: - pip: # works for regular pip packages - bkzep==0.6.1 - - r-base=3 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis diff --git a/scripts/docker/zeppelin/bin/Dockerfile b/scripts/docker/zeppelin/bin/Dockerfile index e6e59b823c2..e4e91e30aa8 100644 --- a/scripts/docker/zeppelin/bin/Dockerfile +++ b/scripts/docker/zeppelin/bin/Dockerfile @@ -36,12 +36,12 @@ RUN echo "$LOG_TAG install basic packages" && \ apt-get autoclean && \ apt-get clean -# Install conda to manage python and R packages +# Install conda to manage python packages ARG miniconda_version="py39_24.1.2-0" # Hashes via https://docs.conda.io/en/latest/miniconda_hashes.html ARG miniconda_sha256="2ec135e4ae2154bb41e8df9ecac7ef23a7d6ca59fc1c8071cfe5298505c19140" -# Install python and R packages via conda -COPY env_python_3_with_R.yml /env_python_3_with_R.yml +# Install python packages via conda +COPY env_python_3.yml /env_python_3.yml RUN set -ex && \ wget -nv https://repo.anaconda.com/miniconda/Miniconda3-${miniconda_version}-Linux-x86_64.sh -O miniconda.sh && \ @@ -52,7 +52,7 @@ RUN set -ex && \ conda config --set always_yes yes --set changeps1 no && \ conda info -a && \ conda install mamba -c conda-forge && \ - mamba env update -f /env_python_3_with_R.yml --prune && \ + mamba env update -f /env_python_3.yml --prune && \ # Cleanup rm -v miniconda.sh anaconda.sha256 && \ # Cleanup based on https://github.com/ContinuumIO/docker-images/commit/cac3352bf21a26fa0b97925b578fb24a0fe8c383 @@ -61,7 +61,7 @@ RUN set -ex && \ mamba clean -ay # Allow to modify conda packages. This allows malicious code to be injected into other interpreter sessions, therefore it is disabled by default # chmod -R ug+rwX /opt/conda -ENV PATH /opt/conda/envs/python_3_with_R/bin:/opt/conda/bin:$PATH +ENV PATH /opt/conda/envs/python_3/bin:/opt/conda/bin:$PATH RUN echo "$LOG_TAG Download Zeppelin binary" && \ mkdir -p ${ZEPPELIN_HOME} && \ diff --git a/scripts/docker/zeppelin/bin/env_python_3_with_R.yml b/scripts/docker/zeppelin/bin/env_python_3.yml similarity index 68% rename from scripts/docker/zeppelin/bin/env_python_3_with_R.yml rename to scripts/docker/zeppelin/bin/env_python_3.yml index 26d77759c2d..4282e0c1717 100644 --- a/scripts/docker/zeppelin/bin/env_python_3_with_R.yml +++ b/scripts/docker/zeppelin/bin/env_python_3.yml @@ -1,4 +1,4 @@ -name: python_3_with_R +name: python_3 channels: - conda-forge - defaults @@ -23,12 +23,3 @@ dependencies: - vega_datasets - plotly - pip - - r-base=3 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis diff --git a/scripts/vagrant/zeppelin-dev/README.md b/scripts/vagrant/zeppelin-dev/README.md index 3b2d3556720..cc19c416b90 100644 --- a/scripts/vagrant/zeppelin-dev/README.md +++ b/scripts/vagrant/zeppelin-dev/README.md @@ -15,15 +15,14 @@ limitations under the License. This script creates a virtual machine that launches a repeatable, known set of core dependencies required for developing Zeppelin. It can also be used to run an existing Zeppelin build if you don't plan to build from source. For PySpark users, this script includes several helpful [Python Libraries](#python-extras). -For SparkR users, this script includes several helpful [R Libraries](#r-extras). - -####Installing the required components to launch a virtual machine. + +#### Installing the required components to launch a virtual machine. This script requires three applications, [Ansible](http://docs.ansible.com/ansible/intro_installation.html#latest-releases-via-pip "Ansible"), [Vagrant](http://www.vagrantup.com "Vagrant") and [Virtual Box](https://www.virtualbox.org/ "Virtual Box"). All of these applications are freely available as Open Source projects and extremely easy to set up on most operating systems. ### Create a Zeppelin Ready VM in 4 Steps (5 on Windows) -*If you are running Windows and don't yet have python installed, install Python 2.7.x* [Python Windows Installer](https://www.python.org/downloads/release/python-2710/) +* If you are running Windows and don't yet have python installed, install Python 2.7.x* [Python Windows Installer](https://www.python.org/downloads/release/python-2710/) 1. Download and Install Vagrant: [Vagrant Downloads](http://www.vagrantup.com/downloads) 2. Install Ansible: [Ansible Python pip install](http://docs.ansible.com/ansible/intro_installation.html#latest-releases-via-pip) @@ -33,7 +32,7 @@ This script requires three applications, [Ansible](http://docs.ansible.com/ansib 3. Install Virtual Box: [Virtual Box Downloads](https://www.virtualbox.org/ "Virtual Box") 4. Type `vagrant up` from within the `/scripts/vagrant/zeppelin-dev` directory -Thats it! +That's it! You can now run `vagrant ssh` and this will place you into the guest machines terminal prompt. @@ -79,11 +78,10 @@ The virtual machine consists of: - libfontconfig to avoid phatomJs missing dependency issues - openjdk-8-jdk - Python addons: pip, matplotlib, scipy, numpy, pandas - - [R](https://www.r-project.org/) and R Packages required to run the R Interpreter and the related R tutorial notebook, including: Knitr, devtools, repr, rCharts, ggplot2, googleVis, mplot, htmltools, base64enc, data.table ### How to build & run Zeppelin -This assumes you've already cloned the project either on the host machine in the zeppelin-dev directory (to be shared with the guest machine) or cloned directly into a directory while running inside the guest machine. The following build steps will also include Python and R support via PySpark and SparkR: +This assumes you've already cloned the project either on the host machine in the zeppelin-dev directory (to be shared with the guest machine) or cloned directly into a directory while running inside the guest machine. The following build steps will also include Python support via PySpark: ``` cd /zeppelin @@ -162,8 +160,3 @@ plt.title('How fast do you want to go today?') show(plt) ``` - -### R Extras - -With zeppelin running, an R Tutorial notebook will be available. The R packages required to run the examples and graphs in this tutorial notebook were installed by this virtual machine. -The installed R Packages include: Knitr, devtools, repr, rCharts, ggplot2, googleVis, mplot, htmltools, base64enc, data.table diff --git a/scripts/vagrant/zeppelin-dev/ansible-roles.yml b/scripts/vagrant/zeppelin-dev/ansible-roles.yml index ee7ee8e000a..985829877e3 100644 --- a/scripts/vagrant/zeppelin-dev/ansible-roles.yml +++ b/scripts/vagrant/zeppelin-dev/ansible-roles.yml @@ -37,4 +37,3 @@ - nodejs - maven - python-addons - - r diff --git a/scripts/vagrant/zeppelin-dev/roles/r/defaults/main.yml b/scripts/vagrant/zeppelin-dev/roles/r/defaults/main.yml deleted file mode 100644 index 0072470c6de..00000000000 --- a/scripts/vagrant/zeppelin-dev/roles/r/defaults/main.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# defaults variables for r role ---- -r_cran_mirror: http://cran.rstudio.com/ - -r_repository: - - type: deb - url: "{{ r_cran_mirror }}/bin/linux/ubuntu {{ ansible_distribution_release }}/" - -r_packages_repos: "{{ r_cran_mirror }}" \ No newline at end of file diff --git a/scripts/vagrant/zeppelin-dev/roles/r/tasks/main.yml b/scripts/vagrant/zeppelin-dev/roles/r/tasks/main.yml deleted file mode 100644 index 071b4b869a3..00000000000 --- a/scripts/vagrant/zeppelin-dev/roles/r/tasks/main.yml +++ /dev/null @@ -1,50 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Install R binaries and CRAN packages ---- - -- name: Install R. This may take a while. - apt: pkg=r-base state=present - -- name: openssl and libcurl required for R devtools package - apt: pkg={{item}} state=present - with_items: - - libssl-dev - - libcurl4-openssl-dev - -# knitr will also pull in the `evaluate` R package as a dependency -- name: Install R packages required for the R interpreter. This may take a while. - shell: /usr/bin/Rscript --slave --no-save --no-restore-history -e "if (! ('{{item}}' %in% installed.packages()[,'Package'])) install.packages(pkgs=c('{{item}}'), repos=c('{{r_packages_repos}}'))" - with_items: - - knitr - - devtools - -- name: Install rCharts (requires devtools first). - shell: /usr/bin/Rscript --slave --no-save --no-restore-history -e "if (! ('rCharts' %in% installed.packages()[,'Package'])) devtools::install_github('rCharts', 'ramnathv')" - -- name: Install R repr package recommended for the R interpreter display system (requires devtools first). - shell: /usr/bin/Rscript --slave --no-save --no-restore-history -e "if (! ('repr' %in% installed.packages()[,'Package'])) devtools::install_github('IRkernel/repr')" - -- name: Install R packages recommended for the R interpreter. - shell: /usr/bin/Rscript --slave --no-save --no-restore-history -e "if (! ('{{item}}' %in% installed.packages()[,'Package'])) install.packages(pkgs=c('{{item}}'), repos=c('{{r_packages_repos}}'))" - with_items: - - ggplot2 - - googleVis - - mplot - - htmltools - - base64enc - - data.table - diff --git a/scripts/vagrant/zeppelin-dev/show-instructions.sh b/scripts/vagrant/zeppelin-dev/show-instructions.sh index 8e896a23dcd..4ddeb5c1bd7 100644 --- a/scripts/vagrant/zeppelin-dev/show-instructions.sh +++ b/scripts/vagrant/zeppelin-dev/show-instructions.sh @@ -32,7 +32,7 @@ echo echo 'cd /vagrant/zeppelin' echo 'mvn clean package -DskipTests' echo -echo '# or for a specific Spark/Hadoop build with additional options such as python and R support' +echo '# or for a specific Spark/Hadoop build with additional options such as python support' echo echo 'mvn clean package -Pspark-1.6 -Phadoop-2.4 -DskipTests' echo './bin/zeppelin-daemon.sh start' diff --git a/spark/README.md b/spark/README.md index 4f8405ac533..2064638ff2a 100644 --- a/spark/README.md +++ b/spark/README.md @@ -7,7 +7,7 @@ Spark interpreter is the first and most important interpreter of Zeppelin. It su * interpreter - This module is the entry module of Spark interpreter. All the interpreters are defined here. SparkInterpreter is the most important one, - SparkContext/SparkSession is created here, other interpreters (PySparkInterpreter,IPySparkInterpreter, SparkRInterpreter and etc) are all depends on SparkInterpreter. + SparkContext/SparkSession is created here, other interpreters (PySparkInterpreter, IPySparkInterpreter and etc) are all depends on SparkInterpreter. Due to incompatibility between Scala versions, there are several scala-x modules for each supported Scala version. Due to incompatibility between Spark versions, there are several spark-shims modules for each supported Spark version. * spark-scala-parent diff --git a/spark/interpreter/pom.xml b/spark/interpreter/pom.xml index 2207cdd0b8d..0e276a49ba5 100644 --- a/spark/interpreter/pom.xml +++ b/spark/interpreter/pom.xml @@ -40,7 +40,7 @@ 2.7 - 3.5.3 + 3.5.8 3.21.12 0.10.9.7 2.12.20 @@ -50,9 +50,6 @@ https://www.apache.org/dyn/closer.lua/spark/${spark.archive}/${spark.archive}.tgz?action=download - - https://www.apache.org/dyn/closer.lua/spark/${spark.archive}/${spark.archive}-bin-without-hadoop.tgz?action=download - ${spark.scala.version} @@ -111,20 +108,6 @@ - - org.apache.zeppelin - r - ${project.version} - tests - test - - - org.apache.spark - spark-core_2.12 - - - - org.apache.zeppelin zeppelin-jupyter-interpreter @@ -139,18 +122,6 @@ - - ${project.groupId} - r - ${project.version} - - - * - * - - - - org.apache.spark spark-repl_${spark.scala.binary.version} @@ -283,22 +254,6 @@ ${spark.archive}.tgz - - - download-sparkr-files - validate - - wget - - - 60000 - 5 - ${spark.bin.download.url} - true - ${project.build.directory} - ${spark.archive}-bin-without-hadoop.tgz - - @@ -326,23 +281,6 @@ maven-resources-plugin - - copy-sparkr-files - generate-resources - - copy-resources - - - ${project.build.directory}/../../../interpreter/spark/R/lib - - - - ${project.build.directory}/spark-${spark.version}-bin-without-hadoop/R/lib - - - - - copy-interpreter-setting package @@ -580,7 +518,7 @@ spark-3.5 - 3.5.3 + 3.5.8 3.21.12 0.10.9.7 diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java deleted file mode 100644 index 3477eb07480..00000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkIRInterpreter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.zeppelin.spark; - -import org.apache.spark.SparkContext; -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.r.IRInterpreter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Properties; - -/** - * SparkR Interpreter which uses irkernel underneath. - */ -public class SparkIRInterpreter extends IRInterpreter { - - private static final Logger LOGGER = LoggerFactory.getLogger(SparkRInterpreter.class); - - private SparkInterpreter sparkInterpreter; - private SparkVersion sparkVersion; - private SparkContext sc; - private JavaSparkContext jsc; - - public SparkIRInterpreter(Properties properties) { - super(properties); - } - - protected boolean isSparkSupported() { - return true; - } - - protected int sparkVersion() { - return this.sparkVersion.toNumber(); - } - - /** - * We can inject SparkInterpreter in the case that SparkIRInterpreter is used by - * SparkShinyInterpreter in which case it is not in the same InterpreterGroup of - * SparkInterpreter. - * @param sparkInterpreter - */ - public void setSparkInterpreter(SparkInterpreter sparkInterpreter) { - this.sparkInterpreter = sparkInterpreter; - } - - public void open() throws InterpreterException { - if (sparkInterpreter == null) { - this.sparkInterpreter = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); - } - this.sc = sparkInterpreter.getSparkContext(); - this.jsc = sparkInterpreter.getJavaSparkContext(); - this.sparkVersion = new SparkVersion(sc.version()); - - ZeppelinRContext.setSparkContext(sc); - ZeppelinRContext.setJavaSparkContext(jsc); - ZeppelinRContext.setSparkSession(sparkInterpreter.getSparkSession()); - ZeppelinRContext.setSqlContext(sparkInterpreter.getSQLContext()); - ZeppelinRContext.setZeppelinContext(sparkInterpreter.getZeppelinContext()); - super.open(); - } - - @Override - public InterpreterResult internalInterpret(String lines, InterpreterContext context) throws InterpreterException { - Utils.printDeprecateMessage(sparkInterpreter.getSparkVersion(), - context, properties); - String jobGroup = Utils.buildJobGroupId(context); - String jobDesc = Utils.buildJobDesc(context); - sparkInterpreter.getSparkContext().setJobGroup(jobGroup, jobDesc, false); - // assign setJobGroup to dummy__ - String setJobGroup = "dummy__ <- setJobGroup(\"" + jobGroup + "\", \" +" + jobDesc + "\", TRUE)"; - lines = setJobGroup + "\n" + lines; - - String setPoolStmt = "setLocalProperty('spark.scheduler.pool', NULL)"; - if (context.getLocalProperties().containsKey("pool")) { - setPoolStmt = "setLocalProperty('spark.scheduler.pool', '" + - context.getLocalProperties().get("pool") + "')"; - } - lines = setPoolStmt + "\n" + lines; - return super.internalInterpret(lines, context); - } -} diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java deleted file mode 100644 index 0a66ed5fd80..00000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkRInterpreter.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import org.apache.spark.SparkContext; -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.zeppelin.interpreter.ZeppelinContext; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.r.RInterpreter; -import org.apache.zeppelin.scheduler.Scheduler; -import org.apache.zeppelin.scheduler.SchedulerFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - -/** - * R and SparkR interpreter with visualization support. - */ -public class SparkRInterpreter extends RInterpreter { - private static final Logger LOGGER = LoggerFactory.getLogger(SparkRInterpreter.class); - - private SparkInterpreter sparkInterpreter; - private SparkVersion sparkVersion; - private SparkContext sc; - private JavaSparkContext jsc; - - public SparkRInterpreter(Properties property) { - super(property); - } - - @Override - protected boolean isSparkSupported() { - return true; - } - - @Override - protected int sparkVersion() { - return new SparkVersion(sc.version()).toNumber(); - } - - @Override - public void open() throws InterpreterException { - this.sparkInterpreter = getInterpreterInTheSameSessionByClassName(SparkInterpreter.class); - this.sc = sparkInterpreter.getSparkContext(); - this.jsc = sparkInterpreter.getJavaSparkContext(); - this.sparkVersion = new SparkVersion(sc.version()); - - LOGGER.info("SparkRInterpreter: SPARK_HOME={}", sc.getConf().getenv("SPARK_HOME")); - Arrays.stream(sc.getConf().getAll()) - .forEach(x -> LOGGER.info("SparkRInterpreter: conf, {}={}", x._1, x._2)); - properties.entrySet().stream().forEach(x -> - LOGGER.info("SparkRInterpreter: prop, {}={}", x.getKey(), x.getValue())); - - ZeppelinRContext.setSparkContext(sc); - ZeppelinRContext.setJavaSparkContext(jsc); - ZeppelinRContext.setSparkSession(sparkInterpreter.getSparkSession()); - ZeppelinRContext.setSqlContext(sparkInterpreter.getSQLContext()); - ZeppelinRContext.setZeppelinContext(sparkInterpreter.getZeppelinContext()); - super.open(); - } - - @Override - public InterpreterResult internalInterpret(String lines, InterpreterContext interpreterContext) - throws InterpreterException { - Utils.printDeprecateMessage(sparkInterpreter.getSparkVersion(), - interpreterContext, properties); - String jobGroup = Utils.buildJobGroupId(interpreterContext); - String jobDesc = Utils.buildJobDesc(interpreterContext); - sparkInterpreter.getSparkContext().setJobGroup(jobGroup, jobDesc, false); - String setJobGroup = ""; - // assign setJobGroup to dummy__, otherwise it would print NULL for this statement - setJobGroup = "dummy__ <- setJobGroup(\"" + jobGroup + - "\", \" +" + jobDesc + "\", TRUE)"; - lines = setJobGroup + "\n" + lines; - - String setPoolStmt = "setLocalProperty('spark.scheduler.pool', NULL)"; - if (interpreterContext.getLocalProperties().containsKey("pool")) { - setPoolStmt = "setLocalProperty('spark.scheduler.pool', '" + - interpreterContext.getLocalProperties().get("pool") + "')"; - } - lines = setPoolStmt + "\n" + lines; - return super.internalInterpret(lines, interpreterContext); - } - - @Override - public void close() throws InterpreterException { - super.close(); - } - - @Override - public void cancel(InterpreterContext context) { - if (this.sc != null) { - sc.cancelJobGroup(Utils.buildJobGroupId(context)); - } - } - - @Override - public FormType getFormType() { - return FormType.NATIVE; - } - - @Override - public int getProgress(InterpreterContext context) throws InterpreterException { - if (sparkInterpreter != null) { - return sparkInterpreter.getProgress(context); - } else { - return 0; - } - } - - @Override - public Scheduler getScheduler() { - return SchedulerFactory.singleton().createOrGetFIFOScheduler( - SparkRInterpreter.class.getName() + this.hashCode()); - } - - @Override - public ZeppelinContext getZeppelinContext() { - return sparkInterpreter.getZeppelinContext(); - } - -} diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java deleted file mode 100644 index c5dc1428d47..00000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/SparkShinyInterpreter.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.r.IRInterpreter; -import org.apache.zeppelin.r.ShinyInterpreter; - -import java.util.Properties; - -/** - * The same function as ShinyInterpreter, but support Spark as well. - */ -public class SparkShinyInterpreter extends ShinyInterpreter { - public SparkShinyInterpreter(Properties properties) { - super(properties); - } - - protected IRInterpreter createIRInterpreter() { - SparkIRInterpreter interpreter = new SparkIRInterpreter(properties); - try { - interpreter.setSparkInterpreter(getInterpreterInTheSameSessionByClassName(SparkInterpreter.class)); - return interpreter; - } catch (InterpreterException e) { - throw new RuntimeException("Fail to set spark interpreter for SparkIRInterpreter", e); - } - } -} diff --git a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java b/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java deleted file mode 100644 index 13427ce2353..00000000000 --- a/spark/interpreter/src/main/java/org/apache/zeppelin/spark/ZeppelinRContext.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import org.apache.spark.SparkContext; -import org.apache.spark.api.java.JavaSparkContext; -import org.apache.zeppelin.interpreter.ZeppelinContext; - -/** - * Contains the Spark and Zeppelin Contexts made available to SparkR. - */ -public class ZeppelinRContext { - private static SparkContext sparkContext; - private static Object sqlContext; - private static ZeppelinContext zeppelinContext; - private static Object sparkSession; - private static JavaSparkContext javaSparkContext; - - public static void setSparkContext(SparkContext sparkContext) { - ZeppelinRContext.sparkContext = sparkContext; - } - - public static void setZeppelinContext(ZeppelinContext zeppelinContext) { - ZeppelinRContext.zeppelinContext = zeppelinContext; - } - - public static void setSqlContext(Object sqlContext) { - ZeppelinRContext.sqlContext = sqlContext; - } - - public static void setSparkSession(Object sparkSession) { - ZeppelinRContext.sparkSession = sparkSession; - } - - public static SparkContext getSparkContext() { - return sparkContext; - } - - public static Object getSqlContext() { - return sqlContext; - } - - public static ZeppelinContext getZeppelinContext() { - return zeppelinContext; - } - - public static Object getSparkSession() { - return sparkSession; - } - - public static void setJavaSparkContext(JavaSparkContext jsc) { javaSparkContext = jsc; } - - public static JavaSparkContext getJavaSparkContext() { return javaSparkContext; } -} diff --git a/spark/interpreter/src/main/resources/interpreter-setting.json b/spark/interpreter/src/main/resources/interpreter-setting.json index 70c00dc9772..edcacf748f7 100644 --- a/spark/interpreter/src/main/resources/interpreter-setting.json +++ b/spark/interpreter/src/main/resources/interpreter-setting.json @@ -256,79 +256,5 @@ "completionSupport": true, "completionKey": "TAB" } - }, - { - "group": "spark", - "name": "r", - "className": "org.apache.zeppelin.spark.SparkRInterpreter", - "properties": { - "zeppelin.R.knitr": { - "envName": null, - "propertyName": "zeppelin.R.knitr", - "defaultValue": true, - "description": "Whether use knitr or not", - "type": "checkbox" - }, - "zeppelin.R.cmd": { - "envName": null, - "propertyName": "zeppelin.R.cmd", - "defaultValue": "R", - "description": "R binary executable path", - "type": "string" - }, - "zeppelin.R.image.width": { - "envName": null, - "propertyName": "zeppelin.R.image.width", - "defaultValue": "100%", - "description": "Image width of R plotting", - "type": "number" - }, - "zeppelin.R.render.options": { - "envName": null, - "propertyName": "zeppelin.R.render.options", - "defaultValue": "out.format = 'html', comment = NA, echo = FALSE, results = 'asis', message = F, warning = F, fig.retina = 2", - "description": "", - "type": "textarea" - }, - "zeppelin.R.shiny.portRange": { - "envName": "", - "propertyName": "zeppelin.R.shiny.portRange", - "defaultValue": ":", - "description": "Shiny app would launch a web app at some port, this property is to specify the portRange via format ':', e.g. '5000:5001'. By default it is ':' which means any port", - "type": "string" - } - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionSupport": false, - "completionKey": "TAB" - } - }, - { - "group": "spark", - "name": "ir", - "className": "org.apache.zeppelin.spark.SparkIRInterpreter", - "properties": { - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - } - }, - { - "group": "spark", - "name": "shiny", - "className": "org.apache.zeppelin.spark.SparkShinyInterpreter", - "properties": { - }, - "editor": { - "language": "r", - "editOnDblClick": false, - "completionSupport": true, - "completionKey": "TAB" - } } ] diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkIRInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkIRInterpreterTest.java deleted file mode 100644 index 73832a9b458..00000000000 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkIRInterpreterTest.java +++ /dev/null @@ -1,144 +0,0 @@ - -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessage; -import org.apache.zeppelin.interpreter.LazyOpenInterpreter; -import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient; -import org.apache.zeppelin.r.IRInterpreterTest; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -public class SparkIRInterpreterTest extends IRInterpreterTest { - - private RemoteInterpreterEventClient mockRemoteIntpEventClient = mock(RemoteInterpreterEventClient.class); - - @Override - protected Interpreter createInterpreter(Properties properties) { - return new SparkIRInterpreter(properties); - } - - @Override - @BeforeEach - public void setUp() throws InterpreterException { - Properties properties = new Properties(); - properties.setProperty(SparkStringConstants.MASTER_PROP_NAME, "local"); - properties.setProperty(SparkStringConstants.APP_NAME_PROP_NAME, "test"); - properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("spark.r.backendConnectionTimeout", "10"); - properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); - properties.setProperty("spark.sql.execution.arrow.sparkr.enabled", "false"); - - InterpreterContext context = getInterpreterContext(); - InterpreterContext.set(context); - interpreter = createInterpreter(properties); - - InterpreterGroup interpreterGroup = new InterpreterGroup(); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(interpreter), "session_1"); - interpreter.setInterpreterGroup(interpreterGroup); - - SparkInterpreter sparkInterpreter = new SparkInterpreter(properties); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkInterpreter), "session_1"); - sparkInterpreter.setInterpreterGroup(interpreterGroup); - - interpreter.open(); - } - - - @Test - public void testSparkRInterpreter() throws InterpreterException, InterruptedException, IOException { - InterpreterContext context = getInterpreterContext(); - InterpreterResult result = interpreter.interpret("1+1", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - List interpreterResultMessages = context.out.toInterpreterResultMessage(); - assertTrue(interpreterResultMessages.get(0).getData().contains("2")); - - context = getInterpreterContext(); - result = interpreter.interpret("sparkR.version()", context); - - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - interpreterResultMessages = context.out.toInterpreterResultMessage(); - if (interpreterResultMessages.get(0).getData().contains("2.2")) { - ENABLE_GOOGLEVIS_TEST = false; - } - context = getInterpreterContext(); - result = interpreter.interpret("df <- as.DataFrame(faithful)\nhead(df)", context); - interpreterResultMessages = context.out.toInterpreterResultMessage(); - assertEquals(InterpreterResult.Code.SUCCESS, result.code(), context.out.toString()); - assertTrue(interpreterResultMessages.get(0).getData().contains(">eruptions")); - // spark job url is sent - verify(mockRemoteIntpEventClient, atLeastOnce()).onParaInfosReceived(any(Map.class)); - - // cancel - final InterpreterContext context2 = getInterpreterContext(); - Thread thread = new Thread() { - @Override - public void run() { - try { - InterpreterResult result = interpreter.interpret("ldf <- dapplyCollect(\n" + - " df,\n" + - " function(x) {\n" + - " Sys.sleep(3)\n" + - " x <- cbind(x, \"waiting_secs\" = x$waiting * 60)\n" + - " })\n" + - "head(ldf, 3)", context2); - assertTrue(result.message().get(0).getData().contains("cancelled")); - } catch (InterpreterException e) { - fail("Should not throw InterpreterException"); - } - } - }; - thread.setName("Cancel-Thread"); - thread.start(); - Thread.sleep(1000); - interpreter.cancel(context2); - } - - @Override - protected InterpreterContext getInterpreterContext() { - InterpreterContext context = InterpreterContext.builder() - .setNoteId("note_1") - .setParagraphId("paragraph_1") - .setInterpreterOut(new InterpreterOutput()) - .setLocalProperties(new HashMap<>()) - .setIntpEventClient(mockRemoteIntpEventClient) - .build(); - return context; - } -} diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java deleted file mode 100644 index 3f0baa72391..00000000000 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkRInterpreterTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.LazyOpenInterpreter; -import org.apache.zeppelin.interpreter.remote.RemoteInterpreterEventClient; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -class SparkRInterpreterTest { - - private SparkRInterpreter sparkRInterpreter; - private SparkInterpreter sparkInterpreter; - private RemoteInterpreterEventClient mockRemoteIntpEventClient = mock(RemoteInterpreterEventClient.class); - - @BeforeEach - public void setUp() throws InterpreterException { - Properties properties = new Properties(); - properties.setProperty(SparkStringConstants.MASTER_PROP_NAME, "local"); - properties.setProperty(SparkStringConstants.APP_NAME_PROP_NAME, "test"); - properties.setProperty("zeppelin.spark.maxResult", "100"); - properties.setProperty("zeppelin.R.knitr", "true"); - properties.setProperty("spark.r.backendConnectionTimeout", "10"); - properties.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); - properties.setProperty("spark.sql.execution.arrow.sparkr.enabled", "false"); - - InterpreterContext context = getInterpreterContext(); - InterpreterContext.set(context); - sparkRInterpreter = new SparkRInterpreter(properties); - sparkInterpreter = new SparkInterpreter(properties); - - InterpreterGroup interpreterGroup = new InterpreterGroup(); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkRInterpreter), "session_1"); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkInterpreter), "session_1"); - sparkRInterpreter.setInterpreterGroup(interpreterGroup); - sparkInterpreter.setInterpreterGroup(interpreterGroup); - - sparkRInterpreter.open(); - } - - @AfterEach - public void tearDown() throws InterpreterException { - sparkInterpreter.close(); - } - - @Test - void testSparkRInterpreter() throws InterpreterException, InterruptedException { - InterpreterResult result = sparkRInterpreter.interpret("1+1", getInterpreterContext()); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertTrue(result.message().get(0).getData().contains("2")); - - result = sparkRInterpreter.interpret("sparkR.version()", getInterpreterContext()); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - result = sparkRInterpreter.interpret("df <- as.DataFrame(faithful)\nhead(df)", getInterpreterContext()); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertTrue(result.message().get(0).getData().contains("eruptions waiting"), result.toString()); - // spark job url is sent - verify(mockRemoteIntpEventClient, atLeastOnce()).onParaInfosReceived(any(Map.class)); - - // cancel - InterpreterContext context = getInterpreterContext(); - InterpreterContext finalContext = context; - Thread thread = new Thread() { - @Override - public void run() { - try { - InterpreterResult result = sparkRInterpreter.interpret("ldf <- dapplyCollect(\n" + - " df,\n" + - " function(x) {\n" + - " Sys.sleep(3)\n" + - " x <- cbind(x, \"waiting_secs\" = x$waiting * 60)\n" + - " })\n" + - "head(ldf, 3)", finalContext); - assertTrue(result.message().get(0).getData().contains("cancelled")); - } catch (InterpreterException e) { - fail("Should not throw InterpreterException"); - } - } - }; - thread.setName("Cancel-Thread"); - thread.start(); - Thread.sleep(1000); - sparkRInterpreter.cancel(context); - - // plotting - context = getInterpreterContext(); - context.getLocalProperties().put("imageWidth", "100"); - result = sparkRInterpreter.interpret("hist(mtcars$mpg)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - assertEquals(1, result.message().size()); - assertEquals(InterpreterResult.Type.HTML, result.message().get(0).getType()); - assertTrue(result.message().get(0).getData().contains("()) - .build(); - return context; - } -} - diff --git a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java b/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java deleted file mode 100644 index 33b60f621b9..00000000000 --- a/spark/interpreter/src/test/java/org/apache/zeppelin/spark/SparkShinyInterpreterTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.spark; - -import com.mashape.unirest.http.HttpResponse; -import com.mashape.unirest.http.Unirest; -import com.mashape.unirest.http.exceptions.UnirestException; -import org.apache.commons.io.IOUtils; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessage; -import org.apache.zeppelin.interpreter.LazyOpenInterpreter; -import org.apache.zeppelin.r.ShinyInterpreterTest; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Properties; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -class SparkShinyInterpreterTest extends ShinyInterpreterTest { - - private SparkInterpreter sparkInterpreter; - - @Override - @BeforeEach - public void setUp() throws InterpreterException { - Properties properties = new Properties(); - properties.setProperty(SparkStringConstants.MASTER_PROP_NAME, "local[*]"); - properties.setProperty(SparkStringConstants.APP_NAME_PROP_NAME, "test"); - - InterpreterContext context = getInterpreterContext(); - InterpreterContext.set(context); - interpreter = new SparkShinyInterpreter(properties); - - InterpreterGroup interpreterGroup = new InterpreterGroup(); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(interpreter), "session_1"); - interpreter.setInterpreterGroup(interpreterGroup); - - sparkInterpreter = new SparkInterpreter(properties); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(sparkInterpreter), "session_1"); - sparkInterpreter.setInterpreterGroup(interpreterGroup); - - interpreter.open(); - } - - @Override - @AfterEach - public void tearDown() throws InterpreterException { - if (interpreter != null) { - interpreter.close(); - } - } - - @Test - void testSparkShinyApp() - throws IOException, InterpreterException, InterruptedException, UnirestException { - /****************** Launch Shiny app with default app name *****************************/ - InterpreterContext context = getInterpreterContext(); - context.getLocalProperties().put("type", "ui"); - InterpreterResult result = - interpreter.interpret( - IOUtils.toString(getClass().getResource("/spark_ui.R"), StandardCharsets.UTF_8), context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - context = getInterpreterContext(); - context.getLocalProperties().put("type", "server"); - result = interpreter.interpret( - IOUtils.toString(getClass().getResource("/spark_server.R"), StandardCharsets.UTF_8), context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - - final InterpreterContext context2 = getInterpreterContext(); - context2.getLocalProperties().put("type", "run"); - Thread thread = new Thread(() -> { - try { - interpreter.interpret("", context2); - } catch (Exception e) { - e.printStackTrace(); - } - }); - thread.start(); - // wait for the shiny app start - Thread.sleep(5 * 1000); - // extract shiny url - List resultMessages = context2.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size(), resultMessages.toString()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType()); - String resultMessageData = resultMessages.get(0).getData(); - assertTrue(resultMessageData.contains(" response = Unirest.get(shinyURL).asString(); - assertEquals(200, response.getStatus()); - assertTrue(response.getBody().contains("Spark Version"), response.getBody()); - } -} diff --git a/spark/interpreter/src/test/resources/spark_server.R b/spark/interpreter/src/test/resources/spark_server.R deleted file mode 100644 index 071631dd79f..00000000000 --- a/spark/interpreter/src/test/resources/spark_server.R +++ /dev/null @@ -1,23 +0,0 @@ -# Define server logic to summarize and view selected dataset ---- -server <- function(input, output) { - - # Return the requested dataset ---- - datasetInput <- reactive({ - switch(input$dataset, - "rock" = as.DataFrame(rock), - "pressure" = as.DataFrame(pressure), - "cars" = as.DataFrame(cars)) - }) - - # Generate a summary of the dataset ---- - output$summary <- renderPrint({ - dataset <- datasetInput() - showDF(summary(dataset)) - }) - - # Show the first "n" observations ---- - output$view <- renderTable({ - head(datasetInput(), n = input$obs) - }) - -} \ No newline at end of file diff --git a/spark/interpreter/src/test/resources/spark_ui.R b/spark/interpreter/src/test/resources/spark_ui.R deleted file mode 100644 index a81ad0c2bcd..00000000000 --- a/spark/interpreter/src/test/resources/spark_ui.R +++ /dev/null @@ -1,35 +0,0 @@ -# Define UI for dataset viewer app ---- -ui <- fluidPage( - -# App title ---- -titlePanel(paste("Spark Version", sparkR.version(), sep=":")), - -# Sidebar layout with a input and output definitions ---- -sidebarLayout( - -# Sidebar panel for inputs ---- -sidebarPanel( - -# Input: Selector for choosing dataset ---- -selectInput(inputId = "dataset", -label = "Choose a dataset:", -choices = c("rock", "pressure", "cars")), - -# Input: Numeric entry for number of obs to view ---- -numericInput(inputId = "obs", -label = "Number of observations to view:", -value = 10) -), - -# Main panel for displaying outputs ---- -mainPanel( - -# Output: Verbatim text for data summary ---- -verbatimTextOutput("summary"), - -# Output: HTML table with requested number of observations ---- -tableOutput("view") - -) -) -) \ No newline at end of file diff --git a/spark/pom.xml b/spark/pom.xml index f4d1662f218..7222cb8e301 100644 --- a/spark/pom.xml +++ b/spark/pom.xml @@ -35,7 +35,7 @@ spark - 3.5.3 + 3.5.8 3.21.12 0.10.9.7 2.12.20 @@ -47,9 +47,6 @@ https://www.apache.org/dyn/closer.lua/spark/${spark.archive}/${spark.archive}.tgz?action=download - - https://www.apache.org/dyn/closer.lua/spark/${spark.archive}/${spark.archive}-bin-without-hadoop.tgz?action=download - diff --git a/spark/scala-2.12/pom.xml b/spark/scala-2.12/pom.xml index 5ceb762e34a..b3b0e3d2fb0 100644 --- a/spark/scala-2.12/pom.xml +++ b/spark/scala-2.12/pom.xml @@ -31,7 +31,7 @@ Zeppelin: Spark Interpreter Scala_2.12 - 3.5.3 + 3.5.8 2.12.20 2.12 ${spark.scala.version} diff --git a/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala b/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala index 0d62dad0f9b..b98d112d1a9 100644 --- a/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala +++ b/spark/scala-2.12/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala @@ -41,8 +41,7 @@ class SparkZeppelinContext(val sc: SparkContext, "spark" -> "org.apache.zeppelin.spark.SparkInterpreter", "sql" -> "org.apache.zeppelin.spark.SparkSqlInterpreter", "pyspark" -> "org.apache.zeppelin.spark.PySparkInterpreter", - "ipyspark" -> "org.apache.zeppelin.spark.IPySparkInterpreter", - "r" -> "org.apache.zeppelin.spark.SparkRInterpreter" + "ipyspark" -> "org.apache.zeppelin.spark.IPySparkInterpreter" ) private val supportedClasses = scala.collection.mutable.ArrayBuffer[Class[_]]() diff --git a/spark/scala-2.13/pom.xml b/spark/scala-2.13/pom.xml index 540754cc64a..91f7a6a5a2c 100644 --- a/spark/scala-2.13/pom.xml +++ b/spark/scala-2.13/pom.xml @@ -31,7 +31,7 @@ Zeppelin: Spark Interpreter Scala_2.13 - 3.5.3 + 3.5.8 2.13.16 2.13 ${spark.scala.version} diff --git a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala index 0d62dad0f9b..b98d112d1a9 100644 --- a/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala +++ b/spark/scala-2.13/src/main/scala/org/apache/zeppelin/spark/SparkZeppelinContext.scala @@ -41,8 +41,7 @@ class SparkZeppelinContext(val sc: SparkContext, "spark" -> "org.apache.zeppelin.spark.SparkInterpreter", "sql" -> "org.apache.zeppelin.spark.SparkSqlInterpreter", "pyspark" -> "org.apache.zeppelin.spark.PySparkInterpreter", - "ipyspark" -> "org.apache.zeppelin.spark.IPySparkInterpreter", - "r" -> "org.apache.zeppelin.spark.SparkRInterpreter" + "ipyspark" -> "org.apache.zeppelin.spark.IPySparkInterpreter" ) private val supportedClasses = scala.collection.mutable.ArrayBuffer[Class[_]]() diff --git a/testing/env_python_3.7_with_R.yml b/testing/env_python_3.7.yml similarity index 68% rename from testing/env_python_3.7_with_R.yml rename to testing/env_python_3.7.yml index 2aa63346c7f..20bd686c65f 100644 --- a/testing/env_python_3.7_with_R.yml +++ b/testing/env_python_3.7.yml @@ -1,4 +1,4 @@ -name: python_3_with_R +name: python_3 channels: - conda-forge - defaults @@ -7,7 +7,7 @@ dependencies: - scipy - numpy=1.19.5 - grpcio - - protobuf + - protobuf<4 - pandasql - ipython - ipython_genutils @@ -25,12 +25,3 @@ dependencies: - plotly - jinja2=3.0.3 - pip - - r-base=3.6 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis diff --git a/testing/env_python_3.9_with_R.yml b/testing/env_python_3.8.yml similarity index 69% rename from testing/env_python_3.9_with_R.yml rename to testing/env_python_3.8.yml index 67a61373da2..d125b9ce70c 100644 --- a/testing/env_python_3.9_with_R.yml +++ b/testing/env_python_3.8.yml @@ -1,4 +1,4 @@ -name: python_3_with_R +name: python_3 channels: - conda-forge - defaults @@ -7,7 +7,7 @@ dependencies: - scipy - numpy=1.19.5 - grpcio - - protobuf + - protobuf<4 - pandasql - sqlalchemy=1.4.46 - ipython @@ -26,12 +26,3 @@ dependencies: - plotly - jinja2=3.0.3 - pip - - r-base=3.6 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis diff --git a/testing/env_python_3.8_with_R.yml b/testing/env_python_3.9.yml similarity index 69% rename from testing/env_python_3.8_with_R.yml rename to testing/env_python_3.9.yml index 67a61373da2..d125b9ce70c 100644 --- a/testing/env_python_3.8_with_R.yml +++ b/testing/env_python_3.9.yml @@ -1,4 +1,4 @@ -name: python_3_with_R +name: python_3 channels: - conda-forge - defaults @@ -7,7 +7,7 @@ dependencies: - scipy - numpy=1.19.5 - grpcio - - protobuf + - protobuf<4 - pandasql - sqlalchemy=1.4.46 - ipython @@ -26,12 +26,3 @@ dependencies: - plotly - jinja2=3.0.3 - pip - - r-base=3.6 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis diff --git a/testing/env_python_3.yml b/testing/env_python_3.yml index b1565b08d08..b4f280eb527 100644 --- a/testing/env_python_3.yml +++ b/testing/env_python_3.yml @@ -4,21 +4,26 @@ channels: - defaults dependencies: - pycodestyle - - numpy=1.19.5 - - pandas=1.4.4 - scipy + - numpy=1.19.5 - grpcio - - hvplot - - protobuf + - protobuf<4 - pandasql + - sqlalchemy=1.4.46 - ipython - - matplotlib + - ipython_genutils - ipykernel - jupyter_client=5 - - bokeh=2.4 - - panel=0.6.0 + - hvplot - holoviews=1.16 + - plotnine + - seaborn + - bokeh=2.4 + - intake + - intake-parquet + - intake-xarray + - altair + - vega_datasets + - plotly - jinja2=3.0.3 - pip - - pip: - - bkzep==0.6.1 diff --git a/testing/env_python_3_with_R_and_tensorflow.yml b/testing/env_python_3_with_R_and_tensorflow.yml deleted file mode 100644 index 80997525db3..00000000000 --- a/testing/env_python_3_with_R_and_tensorflow.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: python_3_with_R_and_tensorflow -channels: - - conda-forge - - defaults -dependencies: - - pycodestyle - - scipy - - numpy=1.19.5 - - grpcio - - protobuf - - pandasql - - sqlalchemy=1.4.46 - - ipython - - ipython_genutils - - ipykernel - - jupyter_client=5 - - hvplot - - holoviews=1.16 - - plotnine - - seaborn - - bokeh=2.4 - - intake - - intake-parquet - - intake-xarray - - altair - - vega_datasets - - plotly - - jinja2=3.0.3 - - pip - - r-base=3.6 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis - - tensorflow diff --git a/testing/env_python_3_with_R.yml b/testing/env_python_3_with_tensorflow.yml similarity index 70% rename from testing/env_python_3_with_R.yml rename to testing/env_python_3_with_tensorflow.yml index ddd3f2e24b9..bf94d8c66b9 100644 --- a/testing/env_python_3_with_R.yml +++ b/testing/env_python_3_with_tensorflow.yml @@ -1,4 +1,4 @@ -name: python_3_with_R +name: python_3_with_tensorflow channels: - conda-forge - defaults @@ -7,7 +7,7 @@ dependencies: - scipy - numpy=1.19.5 - grpcio - - protobuf + - protobuf<4 - pandasql - sqlalchemy=1.4.46 - ipython @@ -27,12 +27,4 @@ dependencies: - plotly - jinja2=3.0.3 - pip - - r-base=3.6 - - r-data.table - - r-evaluate - - r-base64enc - - r-knitr - - r-ggplot2 - - r-irkernel - - r-shiny - - r-googlevis + - tensorflow diff --git a/zeppelin-client-examples/src/main/java/org/apache/zeppelin/client/examples/SparkExample.java b/zeppelin-client-examples/src/main/java/org/apache/zeppelin/client/examples/SparkExample.java index 001c603cc33..0b1f8c16189 100644 --- a/zeppelin-client-examples/src/main/java/org/apache/zeppelin/client/examples/SparkExample.java +++ b/zeppelin-client-examples/src/main/java/org/apache/zeppelin/client/examples/SparkExample.java @@ -85,10 +85,6 @@ public static void main(String[] args) { System.out.println("Matplotlib result, type: " + result.getResults().get(0).getType() + ", data: " + result.getResults().get(0).getData()); - // sparkr - result = session.execute("r", "df <- as.DataFrame(faithful)\nhead(df)"); - System.out.println("Sparkr dataframe: " + result.getResults().get(0).getData()); - // spark sql result = session.execute("sql", "select * from df"); System.out.println("Spark Sql dataframe: " + result.getResults().get(0).getData()); diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest.java index c2d1757a44a..a3b1b4c2a7c 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/SparkIntegrationTest.java @@ -188,13 +188,6 @@ private void testInterpreterBasics() throws IOException, InterpreterException, X assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code(), interpreterResult.toString()); assertEquals(InterpreterResult.Type.TABLE, interpreterResult.message().get(0).getType(), interpreterResult.toString()); assertEquals("c\n2\n", interpreterResult.message().get(0).getData(), interpreterResult.toString()); - - // test SparkRInterpreter - Interpreter sparkrInterpreter = interpreterFactory.getInterpreter("spark.r", new ExecutionContext("user1", "note1", "test")); - interpreterResult = sparkrInterpreter.interpret("df <- as.DataFrame(faithful)\nhead(df)", context); - assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code(), interpreterResult.toString()); - assertEquals(InterpreterResult.Type.TEXT, interpreterResult.message().get(0).getType(), interpreterResult.toString()); - assertTrue( interpreterResult.message().get(0).getData().contains("eruptions waiting"), interpreterResult.toString()); } @Test @@ -242,7 +235,6 @@ public void testYarnClientMode() throws IOException, YarnException, InterruptedE sparkInterpreterSetting.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); sparkInterpreterSetting.setProperty("spark.user.name", "#{user}"); sparkInterpreterSetting.setProperty("zeppelin.spark.run.asLoginUser", "false"); - sparkInterpreterSetting.setProperty("spark.r.command", getRScriptExec()); try { setUpSparkInterpreterSetting(sparkInterpreterSetting); @@ -292,8 +284,6 @@ public void testYarnClusterMode() throws IOException, YarnException, Interrupted sparkInterpreterSetting.setProperty("zeppelin.pyspark.useIPython", "false"); sparkInterpreterSetting.setProperty("PYSPARK_PYTHON", getPythonExec()); sparkInterpreterSetting.setProperty("spark.pyspark.python", getPythonExec()); - sparkInterpreterSetting.setProperty("zeppelin.R.cmd", getRExec()); - sparkInterpreterSetting.setProperty("spark.r.command", getRScriptExec()); sparkInterpreterSetting.setProperty("spark.driver.memory", "512m"); sparkInterpreterSetting.setProperty("zeppelin.spark.scala.color", "false"); sparkInterpreterSetting.setProperty("zeppelin.spark.deprecatedMsg.show", "false"); @@ -400,20 +390,4 @@ private String getPythonExec() throws IOException, InterruptedException { } return IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8).trim(); } - - private String getRScriptExec() throws IOException, InterruptedException { - Process process = Runtime.getRuntime().exec(new String[]{"which", "Rscript"}); - if (process.waitFor() != 0) { - throw new RuntimeException("Fail to run command: which Rscript."); - } - return IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8).trim(); - } - - private String getRExec() throws IOException, InterruptedException { - Process process = Runtime.getRuntime().exec(new String[]{"which", "R"}); - if (process.waitFor() != 0) { - throw new RuntimeException("Fail to run command: which R."); - } - return IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8).trim(); - } } diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java index db8b36d3f20..5d491c49f82 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZSessionIntegrationTest.java @@ -225,14 +225,6 @@ void testZSession_Spark() throws Exception { "+---+---+", result.getResults().get(0).getData().trim()); assertTrue(result.getJobUrls().size() > 0); - // sparkr - result = session.execute("r", "df <- as.DataFrame(faithful)\nhead(df)"); - assertEquals(Status.FINISHED, result.getStatus()); - assertEquals(1, result.getResults().size()); - assertEquals("TEXT", result.getResults().get(0).getType()); - assertTrue(result.getResults().get(0).getData().contains("eruptions waiting"), result.getResults().get(0).getData()); - assertTrue(result.getJobUrls().size() > 0); - // spark sql result = session.execute("sql", "select * from df"); assertEquals(Status.FINISHED, result.getStatus()); @@ -295,15 +287,6 @@ void testZSession_Spark_Submit() throws Exception { "+---+---+", result.getResults().get(0).getData().trim()); assertTrue(result.getJobUrls().size() > 0); - // sparkr - result = session.submit("r", "df <- as.DataFrame(faithful)\nhead(df)"); - result = session.waitUntilFinished(result.getStatementId()); - assertEquals(Status.FINISHED, result.getStatus()); - assertEquals(1, result.getResults().size()); - assertEquals("TEXT", result.getResults().get(0).getType()); - assertTrue(result.getResults().get(0).getData().contains("eruptions waiting"), result.getResults().get(0).getData()); - assertTrue(result.getJobUrls().size() > 0); - // spark sql result = session.submit("sql", "select * from df"); result = session.waitUntilFinished(result.getStatementId()); diff --git a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java index d3c087f313a..06580746c33 100644 --- a/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java +++ b/zeppelin-interpreter-integration/src/test/java/org/apache/zeppelin/integration/ZeppelinSparkClusterTest.java @@ -365,15 +365,6 @@ public void sparkSQLTest() throws IOException { assertEquals(InterpreterResult.Type.TABLE, p.getReturn().message().get(0).getType()); assertEquals("name\tage\nhello\t20\n", p.getReturn().message().get(0).getData()); - // get resource from sparkr - p = note.addNewParagraph(anonymous); - p.setText("%spark.r df=z.getAsDataFrame('table_result')\ndf"); - note.run(p.getId(), true); - assertEquals(Status.FINISHED, p.getStatus()); - assertEquals(InterpreterResult.Type.TEXT, p.getReturn().message().get(0).getType()); - assertTrue(p.getReturn().message().get(0).getData().contains("name age\n1 hello 20"), - p.getReturn().toString()); - // test display DataSet p = note.addNewParagraph(anonymous); p.setText("%spark val ds=spark.createDataset(Seq((\"hello\",20)))\n" + @@ -391,34 +382,6 @@ public void sparkSQLTest() throws IOException { } } - @Test - public void sparkRTest() throws IOException { - assumeTrue(isHadoopVersionMatch(), "Hadoop version mismatch, skip test"); - - String noteId = null; - try { - noteId = zepServer.getService(Notebook.class).createNote("note1", anonymous); - zepServer.getService(Notebook.class).processNote(noteId, - note -> { - Paragraph p = note.addNewParagraph(anonymous); - - p.setText("%spark.r localDF <- data.frame(name=c(\"a\", \"b\", \"c\"), age=c(19, 23, 18))\n" + - "df <- createDataFrame(localDF)\n" + - "count(df)" - ); - - note.run(p.getId(), true); - assertEquals(Status.FINISHED, p.getStatus()); - assertEquals("[1] 3", p.getReturn().message().get(0).getData().trim()); - return null; - }); - } finally { - if (null != noteId) { - zepServer.getService(Notebook.class).removeNote(noteId, anonymous); - } - } - } - @Test public void pySparkTest() throws IOException { assumeTrue(isHadoopVersionMatch(), "Hadoop version mismatch, skip test"); @@ -585,18 +548,14 @@ public void testZeppelinContextResource() throws IOException { Paragraph p3 = note.addNewParagraph(anonymous); p3.setText("%spark.pyspark print(z.get(\"var_1\"))"); - Paragraph p4 = note.addNewParagraph(anonymous); - p4.setText("%spark.r z.get(\"var_1\")"); - // resources across interpreter processes (via DistributedResourcePool) - Paragraph p5 = note.addNewParagraph(anonymous); - p5.setText("%python print(z.get('var_1'))"); + Paragraph p4 = note.addNewParagraph(anonymous); + p4.setText("%python print(z.get('var_1'))"); note.run(p1.getId(), true); note.run(p2.getId(), true); note.run(p3.getId(), true); note.run(p4.getId(), true); - note.run(p5.getId(), true); assertEquals(Status.FINISHED, p1.getStatus()); assertEquals(Status.FINISHED, p2.getStatus()); @@ -604,10 +563,7 @@ public void testZeppelinContextResource() throws IOException { assertEquals(Status.FINISHED, p3.getStatus()); assertEquals("hello world\n", p3.getReturn().message().get(0).getData()); assertEquals(Status.FINISHED, p4.getStatus()); - assertTrue(p4.getReturn().message().get(0).getData().contains("hello world"), - p4.getReturn().toString()); - assertEquals(Status.FINISHED, p5.getStatus()); - assertEquals("hello world\n", p5.getReturn().message().get(0).getData()); + assertEquals("hello world\n", p4.getReturn().message().get(0).getData()); return null; }); } finally { @@ -1040,42 +996,6 @@ public void testPythonNoteDynamicForms() throws IOException { } } - @Test - public void testRNoteDynamicForms() throws IOException { - assumeTrue(isHadoopVersionMatch(), "Hadoop version mismatch, skip test"); - - String noteId = null; - try { - noteId = zepServer.getService(Notebook.class).createNote("note1", anonymous); - zepServer.getService(Notebook.class).processNote(noteId, - note -> { - Paragraph p1 = note.addNewParagraph(anonymous); - - // create TextBox - p1.setText("%spark.r z.noteTextbox(\"name\", \"world\")"); - note.run(p1.getId(), true); - assertEquals(Status.FINISHED, p1.getStatus()); - Input input = p1.getNote().getNoteForms().get("name"); - assertTrue(input instanceof TextBox); - TextBox inputTextBox = (TextBox) input; - assertEquals("name", inputTextBox.getDisplayName()); - assertEquals("world", inputTextBox.getDefaultValue()); - assertEquals("world", p1.getNote().getNoteParams().get("name")); - - Paragraph p2 = note.addNewParagraph(anonymous); - p2.setText("%md hello $${name}"); - note.run(p2.getId(), true); - assertEquals(Status.FINISHED, p2.getStatus()); - assertTrue(p2.getReturn().toString().contains("hello world"), p2.getReturn().toString()); - return null; - }); - } finally { - if (null != noteId) { - zepServer.getService(Notebook.class).removeNote(noteId, anonymous); - } - } - } - @Test public void testConfInterpreter() throws IOException { assumeTrue(isHadoopVersionMatch(), "Hadoop version mismatch, skip test"); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/util/ProcessLauncher.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/util/ProcessLauncher.java index 400e89f158f..266094e18b6 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/util/ProcessLauncher.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/util/ProcessLauncher.java @@ -73,7 +73,6 @@ public ProcessLauncher(CommandLine commandLine, /** * In some cases we need to redirect process output to paragraph's InterpreterOutput. - * e.g. In %r.shiny for shiny app * @param redirectedContext */ public void setRedirectedContext(InterpreterContext redirectedContext) { diff --git a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java index a8d4c58dbe5..efb373bec5d 100644 --- a/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java +++ b/zeppelin-jupyter-interpreter/src/main/java/org/apache/zeppelin/jupyter/JupyterKernelClient.java @@ -45,8 +45,6 @@ import java.util.Properties; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Grpc client for Jupyter kernel @@ -54,9 +52,6 @@ public class JupyterKernelClient { private static final Logger LOGGER = LoggerFactory.getLogger(JupyterKernelClient.class.getName()); - // used for matching shiny url - private static final Pattern SHINY_LISTENING_PATTERN = - Pattern.compile(".*Listening on (http:\\S*).*", Pattern.DOTALL); private final ManagedChannel channel; private final JupyterKernelGrpc.JupyterKernelBlockingStub blockingStub; @@ -100,39 +95,6 @@ public void setInterpreterContext(InterpreterContext context) { this.context = context; } - /** - * This is for shiny interpreter. It's better not to put this in the general - * JupyterKernelClient, we may need to create a specififc JupyterKernelClient for R Kernel. - * @param response - * @return true if shiny url is matched - * @throws IOException - */ - private boolean checkForShinyApp(String response) throws IOException { - String intpClassName = context.getInterpreterClassName(); - if (intpClassName != null && - (intpClassName.equals("org.apache.zeppelin.r.ShinyInterpreter") || - intpClassName.equals("org.apache.zeppelin.spark.SparkShinyInterpreter"))) { - Matcher matcher = SHINY_LISTENING_PATTERN.matcher(response); - if (matcher.matches()) { - String url = matcher.group(1); - LOGGER.info("Matching shiny app url: {}", url); - context.out.clear(); - String defaultHeight = properties.getProperty("zeppelin.R.shiny.iframe_height", "500px"); - String height = context.getLocalProperties().getOrDefault("height", defaultHeight); - String defaultWidth = properties.getProperty("zeppelin.R.shiny.iframe_width", "100%"); - String width = context.getLocalProperties().getOrDefault("width", defaultWidth); - context.out.write("\n%html " + ""); - context.out.flush(); - context.out.write("\n%text "); - context.getIntpEventClient().checkpointOutput(context.getNoteId(), - context.getParagraphId()); - return true; - } - } - return false; - } - // execute the code and make the output as streaming by writing it to InterpreterOutputStream // one by one. public ExecuteResponse stream_execute(ExecuteRequest request, @@ -152,9 +114,6 @@ public void onNext(ExecuteResponse executeResponse) { switch (executeResponse.getType()) { case TEXT: try { - if (checkForShinyApp(executeResponse.getOutput())) { - break; - } if (executeResponse.getOutput().startsWith("%")) { // the output from jupyter kernel maybe specify format already. interpreterOutput.write((executeResponse.getOutput()).getBytes()); diff --git a/zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IRKernelTest.java b/zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IRKernelTest.java deleted file mode 100644 index 703778b6e7f..00000000000 --- a/zeppelin-jupyter-interpreter/src/test/java/org/apache/zeppelin/jupyter/IRKernelTest.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.zeppelin.jupyter; - -import org.apache.zeppelin.interpreter.Interpreter; -import org.apache.zeppelin.interpreter.InterpreterContext; -import org.apache.zeppelin.interpreter.InterpreterException; -import org.apache.zeppelin.interpreter.InterpreterGroup; -import org.apache.zeppelin.interpreter.InterpreterOutput; -import org.apache.zeppelin.interpreter.InterpreterResult; -import org.apache.zeppelin.interpreter.InterpreterResultMessage; -import org.apache.zeppelin.interpreter.LazyOpenInterpreter; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -/** - * This test class is also used in the module rlang - * - * @author pdallig - */ -@SuppressWarnings("java:S5786") -public class IRKernelTest { - - protected Interpreter interpreter; - protected static boolean ENABLE_GOOGLEVIS_TEST = true; - - protected Interpreter createInterpreter(Properties properties) { - return new JupyterInterpreter(properties); - } - - @BeforeEach - public void setUp() throws InterpreterException { - Properties properties = new Properties(); - - InterpreterContext context = getInterpreterContext(); - InterpreterContext.set(context); - interpreter = createInterpreter(properties); - - InterpreterGroup interpreterGroup = new InterpreterGroup(); - interpreterGroup.addInterpreterToSession(new LazyOpenInterpreter(interpreter), "session_1"); - interpreter.setInterpreterGroup(interpreterGroup); - - interpreter.open(); - } - - @AfterEach - public void tearDown() throws InterpreterException { - if (interpreter != null) { - interpreter.close(); - } - } - - @Test - void testIRInterpreter() throws InterpreterException, IOException { - InterpreterContext context = getInterpreterContext(); - InterpreterResult result = interpreter.interpret("1+1", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - List resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(0).getType(), - resultMessages.toString()); - assertEquals("2", resultMessages.get(0).getData(), resultMessages.toString()); - - // error - context = getInterpreterContext(); - result = interpreter.interpret("unknown_var", context); - assertEquals(InterpreterResult.Code.ERROR, result.code()); - resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.TEXT, resultMessages.get(0).getType(), result.toString()); - assertTrue(resultMessages.get(0).getData().contains("unknown_var"), resultMessages.toString()); - // depends on JVM language - // assertTrue(resultMessages.get(0).getData().contains("object 'unknown_var' not found"), - // resultMessages.toString()); - - context = getInterpreterContext(); - result = interpreter.interpret("foo <- TRUE\n" + - "print(foo)\n" + - "bare <- c(1, 2.5, 4)\n" + - "print(bare)\n" + - "double <- 15.0\n" + - "print(double)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.TEXT, resultMessages.get(0).getType(), result.toString()); - assertTrue(resultMessages.get(0).getData().contains("[1] TRUE\n" + - "[1] 1.0 2.5 4.0\n" + - "[1] 15\n"), resultMessages.toString()); - - // plotting - context = getInterpreterContext(); - result = interpreter.interpret("hist(mtcars$mpg)", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.IMG, resultMessages.get(0).getType(), - resultMessages.toString()); - - // ggplot2 - result = interpreter.interpret("library(ggplot2)\n" + - "ggplot(diamonds, aes(x=carat, y=price, color=cut)) + geom_point()", - getInterpreterContext()); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(1, resultMessages.size()); - assertEquals(InterpreterResult.Type.IMG, resultMessages.get(0).getType(), - resultMessages.toString()); - - // googlevis - // TODO(zjffdu) It is weird that googlevis doesn't work with spark 2.2 - if (ENABLE_GOOGLEVIS_TEST) { - context = getInterpreterContext(); - result = interpreter.interpret("library(googleVis)\n" + - "df=data.frame(country=c(\"US\", \"GB\", \"BR\"), \n" + - " val1=c(10,13,14), \n" + - " val2=c(23,12,32))\n" + - "Bar <- gvisBarChart(df)\n" + - "print(Bar, tag = 'chart')", context); - assertEquals(InterpreterResult.Code.SUCCESS, result.code()); - resultMessages = context.out.toInterpreterResultMessage(); - assertEquals(2, resultMessages.size()); - assertEquals(InterpreterResult.Type.HTML, resultMessages.get(1).getType(), - resultMessages.toString()); - assertTrue(resultMessages.get(1).getData().contains("javascript"), - resultMessages.get(1).getData()); - } - } - - protected InterpreterContext getInterpreterContext() { - Map localProperties = new HashMap<>(); - localProperties.put("kernel", "ir"); - InterpreterContext context = InterpreterContext.builder() - .setNoteId("note_1") - .setParagraphId("paragraph_1") - .setInterpreterOut(new InterpreterOutput()) - .setLocalProperties(localProperties) - .build(); - return context; - } -} diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java index d131c816e0b..7b66b821dfb 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java @@ -93,7 +93,6 @@ public Map buildEnvFromProperties(InterpreterLaunchContext conte } setupPropertiesForPySpark(sparkProperties, context); - setupPropertiesForSparkR(sparkProperties, context); String condaEnvName = context.getProperties().getProperty("zeppelin.interpreter.conda.env.name"); if (StringUtils.isNotBlank(condaEnvName)) { @@ -375,34 +374,6 @@ private void mergeSparkProperty(Properties sparkProperties, String propertyName, } } - private void setupPropertiesForSparkR(Properties sparkProperties, - InterpreterLaunchContext context) { - if (isYarnMode(context)) { - String sparkHome = getEnv("SPARK_HOME", context); - File sparkRBasePath = null; - if (sparkHome == null) { - if (!getSparkMaster(context).startsWith("local")) { - throw new RuntimeException("SPARK_HOME is not specified in interpreter-setting" + - " for non-local mode, if you specify it in zeppelin-env.sh, please move that into " + - " interpreter setting"); - } - String zeppelinHome = zConf.getString(ZeppelinConfiguration.ConfVars.ZEPPELIN_HOME); - sparkRBasePath = new File(zeppelinHome, - "interpreter" + File.separator + "spark" + File.separator + "R"); - } else { - sparkRBasePath = new File(sparkHome, "R" + File.separator + "lib"); - } - - File sparkRPath = new File(sparkRBasePath, "sparkr.zip"); - if (sparkRPath.exists() && sparkRPath.isFile()) { - mergeSparkProperty(sparkProperties, "spark.yarn.dist.archives", - sparkRPath.getAbsolutePath() + "#sparkr"); - } else { - LOGGER.warn("sparkr.zip is not found, SparkR may not work."); - } - } - } - /** * Returns cached Spark Master value if it's present, or calculate it * diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Paragraph.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Paragraph.java index db195ae8f1e..de9382150c4 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Paragraph.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Paragraph.java @@ -314,7 +314,7 @@ public boolean shouldSkipRunParagraph() { boolean checkEmptyConfig = (Boolean) config.getOrDefault(InterpreterSetting.PARAGRAPH_CONFIG_CHECK_EMTPY, true); // don't skip paragraph when local properties is not empty. - // local properties can customize the behavior of interpreter. e.g. %r.shiny(type=run) + // local properties can customize the behavior of interpreter. e.g. %spark(pool=pool1) return checkEmptyConfig && StringUtils.isEmpty(scriptText) && localProperties.isEmpty(); } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncherTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncherTest.java index 52ac5a09b57..c90745c882e 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncherTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncherTest.java @@ -142,10 +142,8 @@ void testYarnClientMode_1() throws IOException { assertEquals(sparkHome, interpreterProcess.getEnv().get("SPARK_HOME")); String sparkJars = "jar_1"; - String sparkrZip = sparkHome + "/R/lib/sparkr.zip#sparkr"; String sparkFiles = "file_1"; - String expected = "--conf|spark.yarn.dist.archives=" + sparkrZip + - "|--conf|spark.files=" + sparkFiles + "|--conf|spark.jars=" + sparkJars + + String expected = "--conf|spark.files=" + sparkFiles + "|--conf|spark.jars=" + sparkJars + "|--conf|spark.yarn.isPython=true|--conf|spark.app.name=intpGroupId|--conf|spark.master=yarn-client"; assertTrue(CollectionUtils.isEqualCollection(Arrays.asList(expected.split("\\|")), Arrays.asList(interpreterProcess.getEnv().get("ZEPPELIN_SPARK_CONF").split("\\|")))); @@ -176,10 +174,8 @@ void testYarnClientMode_2() throws IOException { assertEquals(sparkHome, interpreterProcess.getEnv().get("SPARK_HOME")); String sparkJars = "jar_1"; - String sparkrZip = sparkHome + "/R/lib/sparkr.zip#sparkr"; String sparkFiles = "file_1"; - String expected = "--conf|spark.yarn.dist.archives=" + sparkrZip + - "|--conf|spark.files=" + sparkFiles + "|--conf|spark.jars=" + sparkJars + + String expected = "--conf|spark.files=" + sparkFiles + "|--conf|spark.jars=" + sparkJars + "|--conf|spark.submit.deployMode=client" + "|--conf|spark.yarn.isPython=true|--conf|spark.app.name=intpGroupId|--conf|spark.master=yarn"; assertTrue(CollectionUtils.isEqualCollection(Arrays.asList(expected.split("\\|")), @@ -214,10 +210,8 @@ void testYarnClusterMode_1() throws IOException { zeppelinHome + "/interpreter/spark/scala-2.12/spark-scala-2.12-" + Util.getVersion() + ".jar," + zeppelinHome + "/interpreter/zeppelin-interpreter-shaded-" + Util.getVersion() + ".jar"; - String sparkrZip = sparkHome + "/R/lib/sparkr.zip#sparkr"; String sparkFiles = "file_1," + zeppelinHome + "/conf/log4j_yarn_cluster.properties"; - String expected = "--conf|spark.yarn.dist.archives=" + sparkrZip + - "|--conf|spark.yarn.maxAppAttempts=1" + + String expected = "--conf|spark.yarn.maxAppAttempts=1" + "|--conf|spark.files=" + sparkFiles + "|--conf|spark.jars=" + sparkJars + "|--conf|spark.yarn.isPython=true" + @@ -263,9 +257,8 @@ void testYarnClusterMode_2() throws IOException { zeppelinHome + "/interpreter/spark/scala-2.12/spark-scala-2.12-" + Util.getVersion() + ".jar," + zeppelinHome + "/interpreter/zeppelin-interpreter-shaded-" + Util.getVersion() + ".jar"; - String sparkrZip = sparkHome + "/R/lib/sparkr.zip#sparkr"; String sparkFiles = "file_1," + zeppelinHome + "/conf/log4j_yarn_cluster.properties"; - String expected = "--proxy-user|user1|--conf|spark.yarn.dist.archives=" + sparkrZip + + String expected = "--proxy-user|user1" + "|--conf|spark.yarn.isPython=true|--conf|spark.app.name=intpGroupId" + "|--conf|spark.yarn.maxAppAttempts=1" + "|--conf|spark.master=yarn" + @@ -313,11 +306,9 @@ void testYarnClusterMode_3() throws IOException { zeppelinHome + "/interpreter/spark/scala-2.12/spark-scala-2.12-" + Util.getVersion() + ".jar," + zeppelinHome + "/interpreter/zeppelin-interpreter-shaded-" + Util.getVersion() + ".jar"; - String sparkrZip = sparkHome + "/R/lib/sparkr.zip#sparkr"; // escape special characters String sparkFiles = "{}," + zeppelinHome + "/conf/log4j_yarn_cluster.properties"; String expected = "--proxy-user|user1" + - "|--conf|spark.yarn.dist.archives=" + sparkrZip + "|--conf|spark.yarn.isPython=true" + "|--conf|spark.app.name=intpGroupId" + "|--conf|spark.yarn.maxAppAttempts=1" + diff --git a/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java b/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java index f72511f2a0f..8a7dd6bdc4d 100644 --- a/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java +++ b/zeppelin-test/src/main/java/org/apache/zeppelin/test/DownloadUtils.java @@ -65,7 +65,7 @@ public class DownloadUtils { private static final int PROGRESS_BAR_UPDATE_INTERVAL; private static String downloadFolder = System.getProperty("user.home") + "/.cache"; - public static final String DEFAULT_SPARK_VERSION = "3.5.6"; + public static final String DEFAULT_SPARK_VERSION = "3.5.8"; public static final String DEFAULT_SPARK_HADOOP_VERSION = "3"; diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts index dfbaf4bf189..d13c3e8c496 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/message-common.interface.ts @@ -10,16 +10,10 @@ * limitations under the License. */ -export type EditorMode = - | 'ace/mode/scala' - | 'ace/mode/python' - | 'ace/mode/r' - | 'ace/mode/sql' - | 'ace/mode/markdown' - | 'ace/mode/sh'; +export type EditorMode = 'ace/mode/scala' | 'ace/mode/python' | 'ace/mode/sql' | 'ace/mode/markdown' | 'ace/mode/sh'; export type EditorCompletionKey = 'TAB' | string; -export type EditorLanguage = 'scala' | 'python' | 'r' | 'sql' | 'markdown' | 'sh' | string; +export type EditorLanguage = 'scala' | 'python' | 'sql' | 'markdown' | 'sh' | string; export interface Ticket { principal: string; From d9021efff83e8145bf9d398e73b68ba30e1d3050 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Wed, 8 Jul 2026 11:38:01 +0900 Subject: [PATCH 060/179] [ZEPPELIN-6430] Clean up removed R interpreter docs ## What changed This cleans up documentation references left behind after the R interpreter, SparkR, and rlang code removal in ZEPPELIN-6430. - Removed R build/runtime requirements from docs where they are no longer Zeppelin requirements. - Removed `%spark.r` and R example blocks, and updated the generic interpreter example to use `%spark.sql`. - Updated stale `env_python_3_with_R.yml` links to the current Python environment file. - Removed R example links and support-list entries from interpreter, quickstart, Livy, VM, ZeppelinContext, and SDK docs. ## Why The code removal left docs that still implied R interpreter or SparkR support. These updates avoid sending users toward removed functionality while keeping supported Python, Spark, SQL, and Mahout docs intact. ## Validation - `git diff --check` - `rg -n "SparkR|R interpreter|r-base|r-cran|IRkernel|R Tutorial|%spark\\.r|%r\\b|env_python_3_with_R" docs --glob "*.md"` - Additional strict search for actual R feature remnants returned no matches; the broad search only leaves false positives such as `interpreter-base` / `interpreter-based`. Closes #5282 from jongyoul/codex/cleanup-r-docs. Signed-off-by: Jongyoul Lee --- docs/interpreter/livy.md | 4 +- docs/interpreter/mahout.md | 38 +------------------ docs/interpreter/python.md | 2 +- docs/interpreter/spark.md | 10 ++--- docs/quickstart/install.md | 4 +- docs/setup/basics/how_to_build.md | 2 - docs/setup/deployment/virtual_machine.md | 1 - docs/usage/interpreter/overview.md | 2 +- docs/usage/other_features/zeppelin_context.md | 21 +--------- docs/usage/zeppelin_sdk/session_api.md | 2 - 10 files changed, 12 insertions(+), 74 deletions(-) diff --git a/docs/interpreter/livy.md b/docs/interpreter/livy.md index d6ba00864db..b48ad0472ba 100644 --- a/docs/interpreter/livy.md +++ b/docs/interpreter/livy.md @@ -26,7 +26,7 @@ limitations under the License. ## Overview [Livy](http://livy.io/) is an open source REST interface for interacting with Spark from anywhere. It supports executing snippets of code or programs in a Spark context that runs locally or in YARN. -* Interactive Scala, Python and R shells +* Interactive Scala and Python shells * Batch submissions in Scala, Java, Python * Multi users can share the same server (impersonation support) * Can be used for submitting jobs from anywhere with REST @@ -237,7 +237,7 @@ select * from products where ${product_id=1} And creating dynamic format programmatically is not feasible in livy interpreter, because ZeppelinContext is not available in livy interpreter. ## Shared SparkContext -Starting from livy 0.5 which is supported by Zeppelin 0.8.0, SparkContext is shared between scala, python, r and sql. +Starting from livy 0.5 which is supported by Zeppelin 0.8.0, SparkContext is shared between scala, python and sql. That means you can query the table via `%livy.sql` when this table is registered in `%livy.spark`, `%livy.pyspark`. ## FAQ diff --git a/docs/interpreter/mahout.md b/docs/interpreter/mahout.md index c07edc68994..ecab15668c6 100644 --- a/docs/interpreter/mahout.md +++ b/docs/interpreter/mahout.md @@ -159,7 +159,7 @@ val Xty = drmXty.collect(::, 0) val beta = solve(XtX, Xty) ``` -## Leveraging Resource Pools and R for Visualization +## Leveraging Resource Pools for Visualization Resource Pools are a powerful Zeppelin feature that lets us share information between interpreters. A fun trick is to take the output of our work in Mahout and analyze it in other languages. @@ -184,39 +184,3 @@ val z = InterpreterContext.get().getResourcePool() ``` Now we can access the resource pool in a consistent manner from the `%flinkMahout` interpreter. - - -### Passing a variable from Mahout to R and Plotting - -In this simple example, we use Mahout (on Flink or Spark, the code is the same) to create a random matrix and then take the Sin of each element. We then randomly sample the matrix and create a tab separated string. Finally we pass that string to R where it is read as a .tsv file, and a DataFrame is created and plotted using native R plotting libraries. - -```scala -val mxRnd = Matrices.symmetricUniformView(5000, 2, 1234) -val drmRand = drmParallelize(mxRnd) - - -val drmSin = drmRand.mapBlock() {case (keys, block) => - val blockB = block.like() - for (i <- 0 until block.nrow) { - blockB(i, 0) = block(i, 0) - blockB(i, 1) = Math.sin((block(i, 0) * 8)) - } - keys -> blockB -} - -z.put("sinDrm", org.apache.mahout.math.drm.drmSampleToTSV(drmSin, 0.85)) -``` - -And then in an R paragraph... - -```r -%spark.r {"imageWidth": "400px"} - -library("ggplot2") - -sinStr = z.get("flinkSinDrm") - -data <- read.table(text= sinStr, sep="\t", header=FALSE) - -plot(data, col="red") -``` diff --git a/docs/interpreter/python.md b/docs/interpreter/python.md index 93567dc211c..8600975c1d2 100644 --- a/docs/interpreter/python.md +++ b/docs/interpreter/python.md @@ -79,7 +79,7 @@ Zeppelin supports python language which is very popular in data analytics and ma For beginner, we would suggest you to play Python in Zeppelin docker first. In the Zeppelin docker image, we have already installed -miniconda and lots of [useful python libraries](https://github.com/apache/zeppelin/blob/branch-0.10/scripts/docker/zeppelin/bin/env_python_3_with_R.yml) +miniconda and lots of [useful python libraries](https://github.com/apache/zeppelin/blob/master/scripts/docker/zeppelin/bin/env_python_3.yml) including IPython's prerequisites, so `%python` would use IPython. Without any extra configuration, you can run most of tutorial notes under folder `Python Tutorial` directly. diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md index 2b31a055cc5..f7311a2133e 100644 --- a/docs/interpreter/spark.md +++ b/docs/interpreter/spark.md @@ -1,7 +1,7 @@ --- layout: page title: "Apache Spark Interpreter for Apache Zeppelin" -description: "Apache Spark is a fast and general-purpose cluster computing system. It provides high-level APIs in Java, Scala, Python and R, and an optimized engine that supports general execution engine." +description: "Apache Spark is a fast and general-purpose cluster computing system. It provides high-level APIs including Java, Scala and Python, and an optimized engine that supports general execution engine." group: interpreter --- + +# AGENTS.md + +> E2E (Playwright) conventions for `zeppelin-web-angular/e2e/`. A scoped companion +> to the repository-root AGENTS.md, loaded only when working under `e2e/`. +> See [AGENTS.md specification](https://github.com/agentsmd/agents.md). + +Config: `zeppelin-web-angular/playwright.config.js`. This file is the shared source +of truth for E2E conventions; Codex and agents.md-native tools read it directly. +Claude Code / Gemini users can symlink `CLAUDE.md` / `GEMINI.md` to it locally +(both gitignored, personal, not committed). + +## Tooling: Use e2e-skills + +Generate, review, and debug with [e2e-skills](https://github.com/voidmatcha/e2e-skills) +instead of ad-hoc prompts. It encodes the rules below and adds a deterministic +silent-pass scanner. + +```bash +npx skills add voidmatcha/e2e-skills -g --all # or -a +``` + +| Task | Skill | +| --- | --- | +| Generate new Playwright coverage | `playwright-test-generator` | +| Review specs for silent-pass smells | `e2e-reviewer` | +| Debug a failed Playwright report | `playwright-debugger` | +| Deterministic local scan | `bash skills/e2e-reviewer/scripts/scan.sh e2e/` | + +Always run `e2e-reviewer` on generated specs. It catches always-passing +assertions (`toBeDefined()`, `not.toBeNull()`) that pass while the feature is broken. + +## Layout + +- Specs: `e2e/tests//.spec.ts` (areas: `authentication`, `home`, + `login`, `notebook`, `share`, `theme`, `workspace`). +- Page Objects (POM), split by role: + - `e2e/models/.ts`: locators + primitive actions (click, fill, navigate, simple state checks). + - `e2e/models/.util.ts`: workflows, composite verification, scenario helpers. +- Shared helpers: `e2e/utils.ts`. + +## Style + +- English only. No unnecessary comments. +- BDD via `test.step('Given/When/Then …', …)`, as in existing specs. +- One `test.describe` per feature; construct the POM in `beforeEach`. + +## Locators + +Prefer user-facing, in this order: + +1. `getByRole('button' | 'link' | 'textbox', { name })`, `getByLabel`, `getByText`. +2. Last resort: `data-testid` (attribute selector) when a role/label is unavailable + and a CSS chain would be brittle. +3. Forbidden: raw CSS chains and XPath. + +## Assertions + +- Web-first, auto-waiting assertions only: `toBeVisible`, `toHaveURL`, + `toHaveText`, `toHaveCount`. +- No `waitForTimeout`. When waiting on a count, use `toHaveCount`. +- No one-shot boolean checks (`expect(await el.isVisible())`) and no + always-true assertions (`toBeDefined`, `not.toBeNull`). + +## Readiness & Auth + +- After navigation, wait with `waitForZeppelinReady(page)` from `e2e/utils.ts` + (not fixed sleeps). +- Auth is programmatic: the `setup` project logs in once and writes + `playwright/.auth/user.json`; browser projects consume it via `storageState`. + Do not add per-test login races. For logged-out scenarios use a fresh context. + +## Coverage Annotation (Required) + +Every `describe` must declare the page/component it exercises so coverage is +attributed: + +```ts +import { addPageAnnotationBeforeEach, PAGES } from '../../utils'; + +test.describe('Home Page - Core Elements', () => { + addPageAnnotationBeforeEach(PAGES.WORKSPACE.HOME); + // … +}); +``` + +Use an existing key from the `PAGES` object in `e2e/utils.ts`; add a new one +there if the page is missing. `PAGES` is also the coverage-instrumentation set +(`getCoverageTransformPaths`), so it defines the coverage denominator. Purely +structural / non-page components (lifecycle hooks, shared UI primitives like the +spinner or resize handle) are intentionally omitted from `PAGES`. They are +exercised transitively and are not counted. + +## Running + +- Node: `nvm use` (pinned in `.nvmrc`, currently 22.21.1). +- Dev server: `npm run start` at `http://localhost:4200` (Playwright reuses a + running one via `webServer.reuseExistingServer`). + +| Command | Purpose | +| --- | --- | +| `npm run e2e` | Full suite | +| `npm run e2e:fast` | Chromium only (fast) | +| `npm run e2e:ui` | Playwright Test UI | +| `npm run e2e:headed` | Headed run | +| `npm run e2e:debug` | Step-by-step debugger | +| `npm run e2e:report` | Open last HTML report | +| `npm run e2e:ci` | CI mode (`CI=true`, baseURL `:8080`) | +| `npm run e2e:codegen` | Record against `:4200` | +| `npm run e2e:cleanup` | Delete leftover test notebooks (`e2e/cleanup-util.ts`) | + +## Adding a Test (Agents Start Here) + +1. Pick/confirm the target route and the `PAGES` key. +2. Copy the shape of an existing spec in the same ``; reuse or extend the + matching POM (`models/.ts` + `.util.ts`). Do not inline selectors the + POM already owns. +3. Annotate the page (`addPageAnnotationBeforeEach`), navigate, then + `waitForZeppelinReady`. +4. Run `npm run e2e:fast` and iterate until green; then run `e2e-reviewer`. + +## Migration (Angular to React Microfrontend) + +Pages are moving from Angular to React fragments incrementally. Today this is +narrow: the published paragraph route reads a `?react=true` flag +(`published/paragraph/paragraph.component`), and the notebook footer swaps via a +`?reactFooter=true` flag (read into the notebook component's `useReactFooter` +input). Both are query params inside the hash. There is no app-wide "flip this +route to React" flag, and +no cross-framework parity project in this config. Write specs so they survive a +route being reimplemented, but do not build parity infrastructure ahead of need. + +### Write Framework-Neutral Specs + +- Assert observable behavior only: what the user sees, the URL, network effects. + Avoid asserting framework internals (`[ng-version]`, Angular component classes, + `zeppelin-*` custom-element tags) except in a deliberate feature-flag test. +- Keep the locator order from the Locators section (role/label/text first). At a + seam that will flip frameworks, prefer a shared `data-testid` that both + implementations render. +- Never use fixed waits at a fragment seam. Wait on a user-visible post-mount + signal or the specific remote response (`page.waitForResponse` on the fragment + chunk), then assert the rendered result. `react-footer.spec.ts` shows the + fallback pattern (`page.route('**/remoteEntry.js', route => route.abort())`). + +### When a Route Gains a React Flag + +- The flag is a route query param read via `ActivatedRoute.queryParams`, so with + the hash router it goes INSIDE the hash: `/#/notebook//paragraph/?react=true`, + not before the `#`. Popups opened by app code (`window.open`) will not carry a + flag added only to `page.goto`. +- To exercise both frameworks, follow the existing precedent and toggle the flag + in-spec: navigate the same spec with and without the flag across tests, as + `published-paragraph.spec.ts` does. A separate flag-appending Playwright project + is an alternative, but scope it (its own `testMatch`) to routes that read the + flag rather than running the whole suite twice. + +### Coverage + +- Coverage is tracked by `PAGES` key, not source file. The key is the stable + identity; the path behind it is an implementation detail. When a page moves to + React, update its path in `PAGES` rather than deleting the key (deleting drops + it from the coverage denominator). Specs keep the same + `addPageAnnotationBeforeEach(PAGES.KEY)` call across the migration. + +### Suite Shape + +- Keep the composed suite focused on real cross-seam user flows. Behavior that + lives entirely inside one fragment belongs in that fragment's own tests; do not + grow the composed suite into a per-fragment unit suite. diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index b8be01c99a4..83057596471 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -20,15 +20,13 @@ export const NOTEBOOK_PATTERNS = { LINK_SELECTOR: 'a[href*="/notebook/"]' } as const; +// Coverage denominator. Structural/shared components +// (lifecycle hooks, spin, resize-handle, page-header) are intentionally omitted; +// they have no page-level behavior and are exercised transitively. export const PAGES = { // Main App APP: 'src/app/app.component', - // Core - CORE: { - DESTROY_HOOK: 'src/app/core/destroy-hook/destroy-hook.component' - }, - // Pages PAGES: { LOGIN: 'src/app/pages/login/login.component' @@ -81,10 +79,7 @@ export const PAGES = { NOTE_IMPORT: 'src/app/share/note-import/note-import.component', NOTE_RENAME: 'src/app/share/note-rename/note-rename.component', NOTE_TOC: 'src/app/share/note-toc/note-toc.component', - PAGE_HEADER: 'src/app/share/page-header/page-header.component', - RESIZE_HANDLE: 'src/app/share/resize-handle/resize-handle.component', SHORTCUT: 'src/app/share/shortcut/shortcut.component', - SPIN: 'src/app/share/spin/spin.component', THEME_TOGGLE: 'src/app/share/theme-toggle/theme-toggle.component' }, From 864613374344ff8c20b8eb54ef4442e73c283a68 Mon Sep 17 00:00:00 2001 From: Coen90 <81370558+Coen90@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:06:39 +0900 Subject: [PATCH 069/179] [ZEPPELIN-6415] Fix FileSystemNotebookRepo folder move() creating parent of source instead of destination MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The folder `move(String folderPath, String newFolderPath, AuthenticationInfo subject)` method in `FileSystemNotebookRepo` creates the parent directory of the **source** folder instead of the **destination** folder before performing the move. Since the source folder must already exist for the move to succeed, creating its parent is redundant. Meanwhile the destination's parent directory may not exist, causing the subsequent move to fail — e.g. moving `/A/X` to `/B/X` when `/B` does not exist fails because the code creates `/A` (already present) instead of `/B`. This PR changes the `tryMkDir` call to use `newFolderPath` (the destination) instead of `folderPath` (the source), mirroring the existing behavior already present in the note `move()` overload. ```diff - this.fs.tryMkDir(new Path(notebookDir, folderPath.substring(1)).getParent()); + this.fs.tryMkDir(new Path(notebookDir, newFolderPath.substring(1)).getParent()); ``` ### What type of PR is it? Bug Fix ### Todos * [x] - Fix parent directory creation to target the destination folder ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6415 ### How should this be tested? * Existing tests in `FileSystemNotebookRepoTest` cover the folder move flow. * Manual: move a folder into a destination whose parent directory does not yet exist (e.g. `/folder1` → `/folder2/folder3`) and verify the move succeeds and the parent (`/folder2`) is created. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5283 from Coen90/ZEPPELIN-6415. Signed-off-by: Jongyoul Lee --- .../apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java index 9e201a4ded2..08085590df1 100644 --- a/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java +++ b/zeppelin-plugins/notebookrepo/filesystem/src/main/java/org/apache/zeppelin/notebook/repo/FileSystemNotebookRepo.java @@ -106,7 +106,7 @@ public void move(String folderPath, String newFolderPath, AuthenticationInfo sub NotebookPathValidator.rejectTraversalSegments(folderPath); NotebookPathValidator.rejectTraversalSegments(newFolderPath); // [ZEPPELIN-4195] newFolderPath parent path maybe not exist - this.fs.tryMkDir(new Path(notebookDir, folderPath.substring(1)).getParent()); + this.fs.tryMkDir(new Path(notebookDir, newFolderPath.substring(1)).getParent()); this.fs.move(new Path(notebookDir, folderPath.substring(1)), new Path(notebookDir, newFolderPath.substring(1))); } From deb8c158eb5c3c742c903ce4586286935c8f0630 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Mon, 13 Jul 2026 10:07:14 +0900 Subject: [PATCH 070/179] [ZEPPELIN-6506] Return empty list instead of null from completion() in Groovy interpreter ### What is this PR for? Fix `GroovyInterpreter.completion()` to return an empty list instead of null when autocomplete is not supported. This aligns with the collection-returning method contract (Effective Java Item 54), avoids potential NullPointerExceptions in the completion call chain, and provides a safer API for programmatic use. ### What type of PR is it? Bug Fix ### Todos * [x] Fix `GroovyInterpreter.completion()` to return an empty list instead of null ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6506 ### How should this be tested? * Run the existing Groovy interpreter tests to ensure no regressions. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5287 from miinhho/master. Signed-off-by: Jongyoul Lee --- .../main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java index b8eef8c342e..3c6cbed8740 100644 --- a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java +++ b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java @@ -117,7 +117,7 @@ private Job getRunningJob(String paragraphId) { @Override public List completion(String buf, int cursor, InterpreterContext interpreterContext) { - return null; + return Collections.emptyList(); } @SuppressWarnings("unchecked") From 0c4b30f8633f9d2809084d06c168703599aa21ae Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Mon, 13 Jul 2026 23:28:27 +0900 Subject: [PATCH 071/179] [ZEPPELIN-6345] Fire NoteRemove event for each note when deleting a folder ### What is this PR for? Deleting a folder left its notes searchable after removal. `removeFolder(String, AuthenticationInfo)` in `Notebook` called `noteManager.removeFolder` first, which detached the notes from the tree, so the following `removeNote(noteId)` loaded a `null` note and skipped `fireNoteRemoveEvent`. `SearchService.deleteNoteIndex` was therefore never invoked and the Lucene search index kept stale documents for the deleted notes, so they still showed up in search results after emptying the trash or removing a folder. This PR loads the notes non-destructively via a new `NoteManager.getNoteInfoRecursively`, runs the same per-note cleanup as `removeNote(Note, AuthenticationInfo)` (`setRemoved`, `removeNoteAuth`, `fireNoteRemoveEvent`) for each note, and only then deletes the folder. This also removes the pre-existing `NotebookRepo.remove is called twice` TODO, since the repo remove now happens once. ### What type of PR is it? Bug Fix ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6345 ### Screenshots (if appropriate) https://github.com/user-attachments/assets/3bce191f-6f12-443a-bd75-2a0ada28712c ### How should this be tested? * Added `NotebookTest#testRemoveFolderFiresNoteRemoveEventForEachNote`: creates two notes under `/folder1`, registers a `NoteEventListener` counting `onNoteRemove`, calls `removeFolder("/folder1", ...)`, and asserts the event fired once per note. Fails before the change (count `0`), passes after. * Manual: create notes, move them to trash, empty the trash, then search for a deleted note. Before the fix it still appears in results; after the fix it is gone. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5292 from HwangRock/ZEPPELIN-6345-pr. Signed-off-by: ParkGyeongTae --- .../apache/zeppelin/notebook/NoteManager.java | 11 +++++ .../apache/zeppelin/notebook/Notebook.java | 17 ++++++-- .../zeppelin/notebook/NotebookTest.java | 42 +++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java index e0469a825a9..31bb94de327 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java @@ -288,6 +288,17 @@ public void moveFolder(String folderPath, } } + /** + * Returns the NoteInfo of all notes under the given folder, without removing them. + * + * @param folderPath + * @return + * @throws IOException + */ + public List getNoteInfoRecursively(String folderPath) throws IOException { + return getFolder(folderPath).getNoteInfoRecursively(); + } + /** * Remove the folder from the tree and returns the affected NoteInfo under this folder. * diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java index 713cc793223..83f0032822f 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -552,11 +552,22 @@ public void moveFolder(String folderPath, String newFolderPath, AuthenticationIn public void removeFolder(String folderPath, AuthenticationInfo subject) throws IOException { LOGGER.info("Remove folder {}", folderPath); - // TODO(zjffdu) NotebookRepo.remove is called twice here - List noteInfos = noteManager.removeFolder(folderPath, subject); + // Notes must be loaded and their remove listeners fired before the folder (and its + // underlying repo storage) is deleted, otherwise the note content is no longer + // available to run the same per-note cleanup as removeNote(String, AuthenticationInfo). + List noteInfos = noteManager.getNoteInfoRecursively(folderPath); for (NoteInfo noteInfo : noteInfos) { - removeNote(noteInfo.getId(), subject); + processNote(noteInfo.getId(), + note -> { + if (note != null) { + note.setRemoved(true); + authorizationService.removeNoteAuth(note.getId()); + fireNoteRemoveEvent(note, subject); + } + return null; + }); } + noteManager.removeFolder(folderPath, subject); } public void emptyTrash(AuthenticationInfo subject) throws IOException { diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java index c0bdcc116de..39e6ec70e38 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NotebookTest.java @@ -1701,6 +1701,48 @@ public void onParagraphStatusChange(Paragraph p, Status status) { assertEquals(1, onParagraphRemove.get()); } + @Test + void testRemoveFolderFiresNoteRemoveEventForEachNote() throws IOException { + final AtomicInteger onNoteRemove = new AtomicInteger(0); + notebook.addNotebookEventListener(new NoteEventListener() { + @Override + public void onNoteRemove(Note note, AuthenticationInfo subject) { + onNoteRemove.incrementAndGet(); + } + + @Override + public void onNoteCreate(Note note, AuthenticationInfo subject) { + } + + @Override + public void onNoteUpdate(Note note, AuthenticationInfo subject) { + } + + @Override + public void onParagraphRemove(Paragraph p) { + } + + @Override + public void onParagraphCreate(Paragraph p) { + } + + @Override + public void onParagraphUpdate(Paragraph p) { + } + + @Override + public void onParagraphStatusChange(Paragraph p, Status status) { + } + }); + + notebook.createNote("/folder1/note1", anonymous); + notebook.createNote("/folder1/note2", anonymous); + + notebook.removeFolder("/folder1", anonymous); + + assertEquals(2, onNoteRemove.get()); + } + @Test void testGetAllNotes() throws Exception { String note1Id = notebook.createNote("note1", anonymous); From 0b8559a23799be0bd77d239f8be0c4c3f8b4dfee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Tue, 14 Jul 2026 09:32:08 +0900 Subject: [PATCH 072/179] [ZEPPELIN-6495] Use URLSearchParams in terminal getParams helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The `%sh.terminal` frontend helper `getParams(key)` in `shell/src/main/resources/html/js/index.js` parsed the query string by hand: it built a `RegExp` over `location.search`, sliced it with `substr(1)`, and decoded matches with the deprecated global `unescape(...)`. This is harder to read than the platform API and can diverge from standard URL parsing for encoded/repeated/special characters. This PR replaces that logic with the standard `URLSearchParams` API. `URLSearchParams.get(key)` returns `null` for missing keys, so the existing behavior for the `noteId`/`paragraphId` parameters consumed by the terminal page is preserved, while relying on standard URL decoding instead of the deprecated `unescape`. ```js function getParams(key) { var params = new URLSearchParams(location.search); return params.get(key); } ``` The `noteId`/`paragraphId`/`t` values the server generates (see `TerminalInterpreter#createTerminalDashboard`) are plain alphanumeric IDs and a numeric timestamp, so decoded values are identical to the previous implementation for all real inputs. ### What type of PR is it? Refactoring ### Todos * [x] - Replace `substr(...)`/`unescape(...)` in `getParams` with `URLSearchParams` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6495 ### How should this be tested? * The changed file is a static, vendored frontend resource (`index.js`); the `shell` module has no JavaScript test harness (no `package.json`, and the existing `TerminalInterpreterTest` covers the Java interpreter, not this script), so no automated JS test is added. * Behavior was verified equivalent to the previous implementation: * encoded value (e.g. `%2F`) → decoded (`/`) * missing key → `null` * empty value (`key=`) → `""` * Optional manual check: open a `%sh.terminal` paragraph so the terminal dashboard loads `...?noteId=¶graphId=&t=`, and confirm the terminal connects and `TERMINAL_READY` carries the correct `noteId`/`paragraphId`. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No — the file already carries the Apache License 2.0 header and no new file is added. * Is there breaking changes for older versions? No. * Does this needs documentation? No. Closes #5294 from kimyenac/ZEPPELIN-6495. Signed-off-by: ParkGyeongTae --- shell/src/main/resources/html/js/index.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/shell/src/main/resources/html/js/index.js b/shell/src/main/resources/html/js/index.js index f9cc7b7c785..a1a96b8ad78 100644 --- a/shell/src/main/resources/html/js/index.js +++ b/shell/src/main/resources/html/js/index.js @@ -113,12 +113,8 @@ function setupHterm() { } function getParams(key) { - var reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)"); - var r = location.search.substr(1).match(reg); - if (r != null) { - return unescape(r[2]); - } - return null; + var params = new URLSearchParams(location.search); + return params.get(key); }; // This will be whatever normal entry/initialization point your project uses. From 8b0bf9c343f0a69da19fcba61204e8493408a65c Mon Sep 17 00:00:00 2001 From: YeonKyung Ryu <80758099+celinayk@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:45:05 +0900 Subject: [PATCH 073/179] [ZEPPELIN-6496] Replace BigQuery polling stdout output with SLF4J logging ### What is this PR for? `BigQueryInterpreter.pollJob(...)` printed job polling status directly to standard output via `System.out.println(...)`, bypassing Zeppelin's SLF4J/Log4j2 logging configuration, log levels, and appenders. This made diagnostics noisy and hard to route in server/interpreter deployments. This PR replaces the direct stdout call with a structured SLF4J logger call. ### What type of PR is it? Improvement ### Todos * [x] Replace `System.out.println(...)` in `pollJob(...)` with `LOGGER.info(...)` * [x] Preserve job state and wait interval information in the log message * [x] No behavior changes to polling, sleeping, or returned job handling ### What is the Jira issue? [ZEPPELIN-6496](https://issues.apache.org/jira/browse/ZEPPELIN-6496) ### How should this be tested? * `rg -n "System\.out\.println|System\.err\.println" bigquery/src/main/java/org/apache/zeppelin/bigquery` returns no results * `./mvnw test -pl bigquery` compiles/builds successfully * Manually trigger a BigQuery job poll and confirm the state/interval now appears via the configured logger instead of raw stdout ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5298 from celinayk/ZEPPELIN-6496. Signed-off-by: Jongyoul Lee --- .../org/apache/zeppelin/bigquery/BigQueryInterpreter.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bigquery/src/main/java/org/apache/zeppelin/bigquery/BigQueryInterpreter.java b/bigquery/src/main/java/org/apache/zeppelin/bigquery/BigQueryInterpreter.java index a7446e6035d..1daee871d08 100644 --- a/bigquery/src/main/java/org/apache/zeppelin/bigquery/BigQueryInterpreter.java +++ b/bigquery/src/main/java/org/apache/zeppelin/bigquery/BigQueryInterpreter.java @@ -174,9 +174,7 @@ public static Job pollJob(final Bigquery.Jobs.Get request, final long interval) throws IOException, InterruptedException { Job job = request.execute(); while (!job.getStatus().getState().equals("DONE")) { - System.out.println("Job is " - + job.getStatus().getState() - + " waiting " + interval + " milliseconds..."); + LOGGER.info("Job is {} waiting {} milliseconds...", job.getStatus().getState(), interval); Thread.sleep(interval); job = request.execute(); } From cea34d9f7d459530c3b8c44eb634796cbb1e6694 Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Tue, 14 Jul 2026 11:45:35 +0900 Subject: [PATCH 074/179] [ZEPPELIN-6529] Evict note cache entries when removing a folder ### What is this PR for? `NoteManager.removeFolder` removed the deleted notes from `notesInfo` and the in-memory folder tree, but never evicted them from the `NoteCache`. `removeNote(String, AuthenticationInfo)` already calls `noteCache.removeNote(noteId)`, so the single-note path is clean; the folder path was not. As a result the `Note` objects for deleted notes stayed on the heap until the LRU threshold naturally evicted them, and they kept occupying cache slots that live notes could otherwise use. This is most wasteful for large folder deletions such as emptying the trash. This PR evicts each removed note from `noteCache` in the same loop that clears `notesInfo`, mirroring the single-note removal path. There is no functional/correctness change (`processNote` already gates on `notesInfo.containsKey`), only immediate reclamation of the cache slots and heap held by deleted notes. This was found by ParkGyeongTae while reviewing #5288 / #5292 (ZEPPELIN-6345). ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6529 ### How should this be tested? * Added `NoteManagerTest#testRemoveFolderEvictsNoteCache`: adds two notes under `/folder1`, asserts `getCacheSize() == 2`, calls `removeFolder("/folder1", ...)`, and asserts `getCacheSize() == 0`. Fails before the change (cache size stays `2`), passes after. * Full `NoteManagerTest` passes (6 tests), including `testLruCache` and `testNoteOperations`. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5296 from HwangRock/ZEPPELIN-6529-pr. Signed-off-by: Jongyoul Lee --- .../org/apache/zeppelin/notebook/NoteManager.java | 3 ++- .../apache/zeppelin/notebook/NoteManagerTest.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java index 31bb94de327..fffb49d8ca6 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java @@ -316,9 +316,10 @@ public List removeFolder(String folderPath, AuthenticationInfo subject Folder folder = getFolder(folderPath); List noteInfos = folder.getParent().removeFolder(folder.getName(), subject); - // update notesInfo + // update notesInfo and evict the deleted notes from the cache, mirroring removeNote for (NoteInfo noteInfo : noteInfos) { this.notesInfo.remove(noteInfo.getId()); + this.noteCache.removeNote(noteInfo.getId()); } return noteInfos; diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java index 4c5235dd2d7..cb23ea8f167 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java @@ -174,6 +174,20 @@ void testLruCache() throws IOException { assertTrue(noteManager.containsNote(noteNew3.getPath())); } + @Test + void testRemoveFolderEvictsNoteCache() throws IOException { + // add 2 notes under the same folder + Note note1 = createNote("/folder1/note1"); + Note note2 = createNote("/folder1/note2"); + noteManager.addNote(note1, AuthenticationInfo.ANONYMOUS); + noteManager.addNote(note2, AuthenticationInfo.ANONYMOUS); + assertEquals(2, noteManager.getCacheSize()); + + // remove folder should evict its notes from the cache as well + noteManager.removeFolder("/folder1", AuthenticationInfo.ANONYMOUS); + assertEquals(0, noteManager.getCacheSize()); + } + @Test void testConcurrentOperation() throws Exception { int threshold = 10, noteNum = 150; From 933da6862c18240002c8e930b9148a8ab96402bb Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Tue, 14 Jul 2026 22:43:41 +0900 Subject: [PATCH 075/179] [ZEPPELIN-6531] Fail fast when ZeppelinWebSocketClient cannot connect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `ZeppelinWebSocketClient.connect()` blocks forever when the websocket handshake fails. It waits on `connectLatch.await()` with no timeout, and the latch is only counted down in the success callback (`onConnect`). Pre-handshake failures — connection refused, TLS error, rejected upgrade — are not delivered through the annotated callbacks at all; Jetty completes the `CompletableFuture` returned by `WebSocketClient.connect()` exceptionally instead. The original code discards that future, so the failure never reaches the waiting thread and `connect()` hangs. This affects any `zeppelin-client` (`ZSession`) user that passes a `MessageHandler` to `start()`/`reconnect()`: if the target Zeppelin server is down or unreachable, the calling thread blocks indefinitely. Fix: wait on the future with a bounded timeout and surface handshake failures as `IOException`. On failure, stop the Jetty client so its threads are not leaked. `connectLatch` is unused after this change, so it is removed together with its unused `getConnectLatch()` getter. Note on approach: adding `connectLatch.countDown()` to `onError` does not fix this. Against jetty-websocket 11, pre-handshake failures reach only the future, never `OnWebSocketError`, so the latch would still never be released. The future is the only path that carries the failure. ### What type of PR is it? Bug Fix ### Todos * [ ] - Follow-up: make the connect timeout configurable via `ClientConfig` (currently a 30s constant) ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6531 ### How should this be tested? Added `ZeppelinWebSocketClientTest` (the first unit test in `zeppelin-client`): connecting to a closed port must fail within a bounded time instead of hanging. Also verified end-to-end against a docker-exposed port. Ran `nginx` on a port, which accepts the TCP connection but rejects the websocket upgrade (HTTP 404 on `/ws`), and pointed the client at both that port and a closed port. Before (original code, same docker port): ``` [INFO] Running org.apache.zeppelin.client.websocket.ManualE2EVerifyTest ``` Hangs here — no result line. The forked surefire JVM stayed alive past 45s and had to be killed. After (this PR): ``` [E2E] closed-port(1) failed-fast in 295ms -> IOException: Failed to establish websocket connection to ws://127.0.0.1:1/ws [E2E] open-port-non-ws(18080) failed-fast in 45ms -> IOException: Failed to establish websocket connection to ws://127.0.0.1:18080/ws ``` The docker probe was a throwaway check and is not part of the PR; the committed test uses a closed port and needs no docker. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? `getConnectLatch()` is removed. It is public but has no callers in the repo, and it only exposed `connect()`'s internal latch, which no longer exists. * Does this needs documentation? No. Closes #5300 from HwangRock/ZEPPELIN-6531. Signed-off-by: ChanHo Lee --- .../websocket/ZeppelinWebSocketClient.java | 35 +++++++++++++----- .../ZeppelinWebSocketClientTest.java | 37 +++++++++++++++++++ 2 files changed, 62 insertions(+), 10 deletions(-) create mode 100644 zeppelin-client/src/test/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClientTest.java diff --git a/zeppelin-client/src/main/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClient.java b/zeppelin-client/src/main/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClient.java index a3e700398a8..c09fb845ad8 100644 --- a/zeppelin-client/src/main/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClient.java +++ b/zeppelin-client/src/main/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClient.java @@ -33,8 +33,11 @@ import java.io.IOException; import java.net.URI; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** @@ -45,8 +48,8 @@ public class ZeppelinWebSocketClient { private static final Logger LOGGER = LoggerFactory.getLogger(ZeppelinWebSocketClient.class); private static final Gson GSON = new Gson(); + private static final long DEFAULT_CONNECT_TIMEOUT_MS = 30_000; - private CountDownLatch connectLatch = new CountDownLatch(1); private CountDownLatch closeLatch = new CountDownLatch(1); private Session session; @@ -63,8 +66,18 @@ public void connect(String url) throws Exception { URI echoUri = new URI(url); ClientUpgradeRequest request = new ClientUpgradeRequest(); request.setHeader("Origin", "*"); - wsClient.connect(this, echoUri, request); - connectLatch.await(); + CompletableFuture future = wsClient.connect(this, echoUri, request); + try { + future.get(DEFAULT_CONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + stopQuietly(); + throw new IOException("Timeout(" + DEFAULT_CONNECT_TIMEOUT_MS + + "ms) establishing websocket connection to " + url, e); + } catch (ExecutionException e) { + stopQuietly(); + throw new IOException("Failed to establish websocket connection to " + url, + e.getCause()); + } LOGGER.info("WebSocket connect established"); } @@ -93,7 +106,6 @@ public void onClose(int statusCode, String reason) { public void onConnect(Session session) { LOGGER.info("Got connect: {}", session.getRemote()); this.session = session; - connectLatch.countDown(); } @OnWebSocketMessage @@ -103,22 +115,25 @@ public void onText(Session session, String message) throws IOException { @OnWebSocketError public void onError(Throwable cause) { - LOGGER.info("WebSocket Error: " + cause.getMessage()); - cause.printStackTrace(System.out); + LOGGER.error("WebSocket error", cause); } public void send(Message message) throws IOException { session.getRemote().sendString(GSON.toJson(message)); } - public CountDownLatch getConnectLatch() { - return connectLatch; - } - public void stop() throws Exception { if (this.wsClient != null) { this.wsClient.stop(); } } + private void stopQuietly() { + try { + stop(); + } catch (Exception e) { + LOGGER.warn("Failed to stop websocket client after connection failure", e); + } + } + } diff --git a/zeppelin-client/src/test/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClientTest.java b/zeppelin-client/src/test/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClientTest.java new file mode 100644 index 00000000000..7f6cabd1e2d --- /dev/null +++ b/zeppelin-client/src/test/java/org/apache/zeppelin/client/websocket/ZeppelinWebSocketClientTest.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.client.websocket; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +import org.junit.jupiter.api.Test; + +import java.time.Duration; + +class ZeppelinWebSocketClientTest { + + @Test + void connectFailsFastWhenPortClosed() { + ZeppelinWebSocketClient client = new ZeppelinWebSocketClient(msg -> { }); + + assertTimeoutPreemptively(Duration.ofSeconds(20), () -> + assertThrows(Exception.class, () -> client.connect("ws://127.0.0.1:1/ws"))); + } + +} From be438e1396320a6ee244d19757115569d8f2ab8e Mon Sep 17 00:00:00 2001 From: YeonKyung Ryu <80758099+celinayk@users.noreply.github.com> Date: Wed, 15 Jul 2026 10:44:39 +0900 Subject: [PATCH 076/179] [ZEPPELIN-6509] Add error handling and safety guards to genthrift.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `genthrift.sh` (the Thrift code generation script) had no error handling. If the `thrift` compiler was missing or failed, or if the script was run from the wrong directory, it could silently overwrite valid generated Java sources with empty/partial output. This PR adds basic safety guards so the script fails fast instead of corrupting the source tree ### What type of PR is it? Bug Fix ### Todos * [x] Add `set -euo pipefail` so any failing command aborts the script * [x] Add `cd "$(dirname "${BASH_SOURCE[0]}")"` so the script always runs relative to its own location, regardless of the caller's working directory * [x] Check that `java_license_header.txt` exists before proceeding, and exit with a clear error message if it's missing ### What is the Jira issue? [ZEPPELIN-6509](https://issues.apache.org/jira/browse/ZEPPELIN-6509) ### How should this be tested? * This is a developer-only shell script (not covered by the build/test suite), so testing is manual: 1. `bash -n zeppelin-interpreter/src/main/thrift/genthrift.sh` — verify syntax 2. Run the script from the correct directory with `thrift` installed — confirm it still regenerates sources as before 3. Temporarily rename/remove `java_license_header.txt` and run the script — confirm it exits with an error instead of silently producing malformed output 4. Run the script from a different working directory (e.g. repo root) — confirm it still operates on the correct paths instead of deleting an unintended directory ### Screenshots (if appropriate) N/A (shell script change, no UI) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5297 from celinayk/ZEPPELIN-6509. Signed-off-by: ChanHo Lee --- zeppelin-interpreter/src/main/thrift/genthrift.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/zeppelin-interpreter/src/main/thrift/genthrift.sh b/zeppelin-interpreter/src/main/thrift/genthrift.sh index 23a295a1257..cbbb156f4fd 100755 --- a/zeppelin-interpreter/src/main/thrift/genthrift.sh +++ b/zeppelin-interpreter/src/main/thrift/genthrift.sh @@ -17,6 +17,15 @@ # * limitations under the License. # */ +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")" + +if [[ ! -f java_license_header.txt ]]; then + echo "java_license_header.txt not found in $(pwd)" >&2 + exit 1 +fi + rm -rf gen-java rm -rf ../java/org/apache/zeppelin/interpreter/thrift thrift --gen java RemoteInterpreterService.thrift From 9b6691232357bbbea81adcacbd1333afa184a6fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Wed, 15 Jul 2026 23:27:17 +0900 Subject: [PATCH 077/179] [ZEPPELIN-6494] Use HTTPS for zeppelin.apache.org links in UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Zeppelin UI still contained several direct `http://zeppelin.apache.org` links. The public Zeppelin site is served over HTTPS, and newer links in the codebase already use HTTPS. This PR switches the UI-facing website links from `http://` to `https://` and updates the focused E2E expectation that pinned the old scheme. Changes (5 files, 7 links): - `zeppelin-web-angular/src/app/pages/workspace/home/home.component.html` — documentation & community links - `zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html` — "Get involved!" link - `zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts` — community-link expectation - `zeppelin-web/src/app/home/home.html` — documentation & community links (classic UI) - `zeppelin-web/src/components/navbar/navbar.html` — "Get involved!" link (classic UI) Non-Zeppelin links (e.g. `www.apache.org/licenses/LICENSE-2.0`), version placeholders, and unrelated docs are intentionally left unchanged. ### What type of PR is it? Improvement ### What is the Jira issue? [ZEPPELIN-6494](https://issues.apache.org/jira/browse/ZEPPELIN-6494) ### How should this be tested? - Search the touched UI files and confirm no `http://zeppelin.apache.org` remains: ``` rg -n "http://zeppelin.apache.org" zeppelin-web-angular/src/app/pages/workspace/home/home.component.html zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts zeppelin-web/src/app/home/home.html zeppelin-web/src/components/navbar/navbar.html ``` - `cd zeppelin-web-angular && npm run lint` — passes with no errors. ### Questions: - Does the license apply to the code changes? Yes Closes #5299 from kimyenac/ZEPPELIN-6494. Signed-off-by: ParkGyeongTae --- .../e2e/tests/home/home-page-external-links.spec.ts | 2 +- .../src/app/pages/workspace/home/home.component.html | 4 ++-- .../app/share/about-zeppelin/about-zeppelin.component.html | 2 +- zeppelin-web/src/app/home/home.html | 4 ++-- zeppelin-web/src/components/navbar/navbar.html | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts index 09cf4ea563c..77aa47d2e9c 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-external-links.spec.ts @@ -51,7 +51,7 @@ test.describe('Home Page - External Links', () => { await test.step('Then it should have the correct href', async () => { const href = await homePage.externalLinks.mailingList.getAttribute('href'); - expect(href).toBe('http://zeppelin.apache.org/community.html'); + expect(href).toBe('https://zeppelin.apache.org/community.html'); }); await test.step('And it should open in a new tab', async () => { diff --git a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html index 32bdcc60f1d..ac1fb78785c 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/home/home.component.html @@ -34,7 +34,7 @@

    Help

    Zeppelin documentation @@ -46,7 +46,7 @@

    Community

    Any contribution are welcome!

    - + Mailing list diff --git a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html index b27f4ac6fb5..71b269fc263 100644 --- a/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html +++ b/zeppelin-web-angular/src/app/share/about-zeppelin/about-zeppelin.component.html @@ -21,7 +21,7 @@

    Apache Zeppelin

    {{ ticketService.version }}

    - Get involved! + Get involved!
    Licensed under the Apache License, Version 2.0 diff --git a/zeppelin-web/src/app/home/home.html b/zeppelin-web/src/app/home/home.html index ff950b2fe71..0ae02501eac 100644 --- a/zeppelin-web/src/app/home/home.html +++ b/zeppelin-web/src/app/home/home.html @@ -58,12 +58,12 @@

    Help

    Get started with
    Zeppelin documentation
    + href="https://zeppelin.apache.org/docs/{{zeppelinVersion}}/index.html">Zeppelin documentation

    Community

    Please feel free to help us to improve Zeppelin,
    Any contribution are welcome!

    - Mailing list
    Issues tracking
    diff --git a/zeppelin-web/src/components/navbar/navbar.html b/zeppelin-web/src/components/navbar/navbar.html index cfda971f713..8da547bb1a3 100644 --- a/zeppelin-web/src/components/navbar/navbar.html +++ b/zeppelin-web/src/components/navbar/navbar.html @@ -142,7 +142,7 @@

    Apache Zeppelin

    {{zeppelinVersion}}

    - Get involved! + Get involved!
    Licensed under the Apache License, Version 2.0
    From 9489ce8c79e77aa27a3bc6ff0d1bd96331dd4207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Wed, 15 Jul 2026 23:49:30 +0900 Subject: [PATCH 078/179] [ZEPPELIN-6538] Resolve CI runtime warnings and zeppelin-react audit issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? 스크린샷 2026-07-14 오후 11 00 55 This PR resolves CI/tooling issues tracked in ZEPPELIN-6538. First, GitHub Actions now warns that Node.js 20 action runtimes are deprecated and are being forced to run on Node.js 24. This PR updates the affected workflow actions in `core.yml`, `frontend.yml`, and `quick.yml` to Node 24 runtime versions. Second, `zeppelin-web-angular/projects/zeppelin-react` still reported npm audit findings from the `webpack-dev-server5.x` dependency tree. This PR updates `webpack-dev-server` from `5.2.4` to `6.0.0`, which removes the vulnerable `sockjs` / `uuid` transitive path and updates the dev-server dependency tree so `zeppelin-react` full `npm audit` reports zero vulnerabilities. It also makes the existing Spark Angular display implicit conversions explicit with `scala.language.implicitConversions`, avoiding Scala feature warnings in CI without changing the conversion behavior. ### What type of PR is it? Improvement ### Todos * [x] Update GitHub Actions to Node 24 runtime versions * [x] Update `zeppelin-react` `webpack-dev-server` to `6.0.0` * [x] Verify `zeppelin-react` full `npm audit` reports zero vulnerabilities * [x] Make Spark Angular display implicit conversions explicit ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6538 ### How should this be tested? Verified locally: ```bash cd zeppelin-web-angular/projects/zeppelin-react npm ci --ignore-scripts npm audit npm test -- --run npx webpack --config webpack.config.js --mode development --stats=errors-only ``` Results: * `npm audit`: 0 vulnerabilities * `npm test -- --run`: 2 files / 13 tests passed * webpack development build: exit 0 Also verified: ```bash cd zeppelin-web-angular npm ci --ignore-scripts npm run build:react cd .. git diff --check go run github.com/rhysd/actionlint/cmd/actionlintlatest -shellcheck= .github/workflows/core.yml .github/workflows/frontend.yml .github/workflows/quick.yml ``` Notes: * Spark compile verification was blocked locally by a linked-worktree `git-commit-id-plugin` issue before reaching Spark compilation. CI should verify the Spark paths that reported the feature warning. * Live `npm run dev` HTTP smoke was not run locally because the local session hook blocks starting dev servers. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No runtime behavior change is intended. `webpack-dev-server6.0.0` requires Node.js `>=22.15.0`, and `zeppelin-web-angular/.nvmrc` already uses Node `22.21.1`. * Does this needs documentation? No. Closes #5303 from voidmatcha/fix/github-actions-node24-runtime. Signed-off-by: ParkGyeongTae --- .github/workflows/core.yml | 76 +- .github/workflows/frontend.yml | 30 +- .github/workflows/quick.yml | 8 +- .../angular/notebookscope/AngularElem.scala | 4 +- .../angular/paragraphscope/AngularElem.scala | 4 +- .../projects/zeppelin-react/package-lock.json | 1339 ++++++----------- .../projects/zeppelin-react/package.json | 2 +- 7 files changed, 564 insertions(+), 899 deletions(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 28b8777261d..0051ce98844 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -43,16 +43,16 @@ jobs: java: [ 11 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -68,7 +68,7 @@ jobs: - name: install and test plugins run: ./mvnw package -pl zeppelin-plugins -amd ${MAVEN_ARGS} - name: Setup conda environment with python 3.9 - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_3.9.yml @@ -95,16 +95,16 @@ jobs: INTERPRETERS: 'hbase,jdbc,file,flink-cmd,cassandra,elasticsearch,bigquery,livy,groovy,java,neo4j,sparql,mongodb,influxdb,shell' steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -117,7 +117,7 @@ jobs: - name: install environment run: ./mvnw install -DskipTests -am -pl ${INTERPRETERS} ${MAVEN_ARGS} - name: Setup conda environment with python 3.9 - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3_with_tensorflow environment-file: testing/env_python_3_with_tensorflow.yml @@ -139,16 +139,16 @@ jobs: java: [ 11 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -159,7 +159,7 @@ jobs: restore-keys: | ${{ runner.os }}-zeppelin- - name: Setup conda environment with python ${{ matrix.python }} - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_${{ matrix.python }}.yml @@ -187,16 +187,16 @@ jobs: - name: Start mysql run: sudo systemctl start mysql.service - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -211,7 +211,7 @@ jobs: ./mvnw install -DskipTests -Pintegration -pl zeppelin-interpreter-integration,zeppelin-web,spark-submit,spark/scala-2.12,spark/scala-2.13,markdown,flink-cmd,flink/flink-scala-2.12,jdbc,shell -am -Pweb-classic -Pflink-1.20 ${MAVEN_ARGS} ./mvnw package -pl zeppelin-plugins -amd -DskipTests ${MAVEN_ARGS} - name: Setup conda environment with python 3.9 - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_3.yml @@ -240,16 +240,16 @@ jobs: flink-profile: "1.20" steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK 8 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -264,7 +264,7 @@ jobs: ./mvnw install -DskipTests -am -pl flink/flink-scala-2.12,flink-cmd,zeppelin-interpreter-integration -Pflink-${{ matrix.flink-profile }} -Pintegration ${MAVEN_ARGS} ./mvnw clean package -pl zeppelin-plugins -amd -DskipTests ${MAVEN_ARGS} - name: Setup conda environment with python ${{ matrix.python }} - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3_with_flink environment-file: testing/env_python_3_with_flink_${{ matrix.flink }}.yml @@ -288,16 +288,16 @@ jobs: java: [ 11 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -312,7 +312,7 @@ jobs: ./mvnw install -DskipTests -pl zeppelin-interpreter-integration,zeppelin-web,spark-submit,spark/scala-2.12,spark/scala-2.13,markdown -am -Pweb-classic -Pintegration ${MAVEN_ARGS} ./mvnw clean package -pl zeppelin-plugins -amd -DskipTests ${MAVEN_ARGS} - name: Setup conda environment with python 3.9 - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_3.yml @@ -334,16 +334,16 @@ jobs: java: [ 11, 17 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -356,7 +356,7 @@ jobs: - name: install environment run: ./mvnw install -DskipTests -pl spark-submit,spark/scala-2.12,spark/scala-2.13 -am ${MAVEN_ARGS} - name: Setup conda environment with python ${{ matrix.python }} - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_${{ matrix.python }}.yml @@ -397,16 +397,16 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -422,7 +422,7 @@ jobs: ./testing/downloadSpark.sh "3.2.4" "3.2" ./testing/downloadLivy.sh "0.8.0-incubating" "2.12" - name: Setup conda environment with python 3.9 - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_3.9.yml @@ -445,16 +445,16 @@ jobs: java: [ 11 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -475,14 +475,14 @@ jobs: java: [ 11 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~\.m2\repository diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 68ce1c63a66..efdda51a3db 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -34,9 +34,9 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version-file: 'zeppelin-web-angular/.nvmrc' # TODO: Add zeppelin-web-angular root audit after Angular version upgrade and stabilization @@ -48,16 +48,16 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -86,23 +86,23 @@ jobs: python: [ 3.9 ] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 - name: Cache Playwright browsers - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~/.cache/ms-playwright key: ${{ runner.os }}-playwright-${{ hashFiles('zeppelin-web-angular/package-lock.json') }} restore-keys: | ${{ runner.os }}-playwright- - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -113,7 +113,7 @@ jobs: restore-keys: | ${{ runner.os }}-zeppelin- - name: Setup conda environment with python ${{ matrix.python }} - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_only python-version: ${{ matrix.python }} @@ -138,7 +138,7 @@ jobs: - name: Run headless E2E test with Maven run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw verify -pl zeppelin-web-angular -Pweb-e2e ${MAVEN_ARGS} - name: Upload Playwright Report - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 if: always() with: name: playwright-report-${{ matrix.mode }} @@ -165,16 +165,16 @@ jobs: shell: bash -l {0} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - name: Set up JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 - name: Cache local Maven repository - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | ~/.m2/repository @@ -185,7 +185,7 @@ jobs: restore-keys: | ${{ runner.os }}-zeppelin- - name: Setup conda environment with python 3.9 - uses: conda-incubator/setup-miniconda@v3 + uses: conda-incubator/setup-miniconda@v4 with: activate-environment: python_3 environment-file: testing/env_python_3.yml diff --git a/.github/workflows/quick.yml b/.github/workflows/quick.yml index 27c9493daff..6e2f7029b75 100644 --- a/.github/workflows/quick.yml +++ b/.github/workflows/quick.yml @@ -28,9 +28,9 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 @@ -42,9 +42,9 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up JDK 11 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: 11 diff --git a/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/notebookscope/AngularElem.scala b/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/notebookscope/AngularElem.scala index 8fd3164720a..2409ab7d7ec 100644 --- a/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/notebookscope/AngularElem.scala +++ b/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/notebookscope/AngularElem.scala @@ -64,6 +64,8 @@ class AngularElem(override val interpreterContext: InterpreterContext, } object AngularElem { + import scala.language.implicitConversions + implicit def Elem2AngularDisplayElem(elem: Elem): AbstractAngularElem = { new AngularElem(InterpreterContext.get(), null, Map[String, AngularObject[Any]](), @@ -81,4 +83,4 @@ object AngularElem { registry.remove(ao.getName, ao.getNoteId, null) ) } -} \ No newline at end of file +} diff --git a/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/paragraphscope/AngularElem.scala b/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/paragraphscope/AngularElem.scala index e424202a5c6..7ffec206f1c 100644 --- a/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/paragraphscope/AngularElem.scala +++ b/spark/interpreter/src/main/scala/org/apache/zeppelin/display/angular/paragraphscope/AngularElem.scala @@ -66,6 +66,8 @@ class AngularElem(override val interpreterContext: InterpreterContext, } object AngularElem { + import scala.language.implicitConversions + implicit def Elem2AngularDisplayElem(elem: Elem): AbstractAngularElem = { new AngularElem(InterpreterContext.get(), null, Map[String, AngularObject[Any]](), @@ -83,4 +85,4 @@ object AngularElem { registry.remove(ao.getName, ao.getNoteId, ao.getParagraphId) ) } -} \ No newline at end of file +} diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index e8b9719d447..6a209e61829 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -43,7 +43,7 @@ "vitest": "4.1.8", "webpack": "5.105.4", "webpack-cli": "5.1.4", - "webpack-dev-server": "5.2.4" + "webpack-dev-server": "6.0.0" } }, "../zeppelin-sdk": { @@ -859,14 +859,14 @@ } }, "node_modules/@jsonjoy.com/fs-core": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.57.6.tgz", - "integrity": "sha512-uI++Wx6VkBJqVmkb4ZeExwAVpZiA2Do5NrEtXoDk0Pdvce3ytFXJoviT1sLOj16+qDIMnD5nWPfOhVpnDmRJKg==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-core/-/fs-core-4.64.0.tgz", + "integrity": "sha512-zs2TAq7Six5jgMuoMNjpspAvOP3mhtgq/k1UyQodEzCtQi/N83y2/y+zcvnZSGp/Rxq96DBN+bValOBQAyn/ew==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.57.6", - "@jsonjoy.com/fs-node-utils": "4.57.6", + "@jsonjoy.com/fs-node-builtins": "4.64.0", + "@jsonjoy.com/fs-node-utils": "4.64.0", "thingies": "^2.5.0" }, "engines": { @@ -881,15 +881,15 @@ } }, "node_modules/@jsonjoy.com/fs-fsa": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.57.6.tgz", - "integrity": "sha512-pKkw/yC5CzSZKhIIUIsH1przOa+K5jGmZIg1sWaSF24JojyrUFbjcQv7QrcGAudriei6HQ6R0BFj+V8NbQinJw==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-fsa/-/fs-fsa-4.64.0.tgz", + "integrity": "sha512-nMWOVbkLFyEgmXZih3wyvxA9XpgyyqyfrINMHvEFqhi7uqfRl7c9ERJt6yX7vgMPrB9Uo+OJO+Spa0cFzPD01w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-core": "4.57.6", - "@jsonjoy.com/fs-node-builtins": "4.57.6", - "@jsonjoy.com/fs-node-utils": "4.57.6", + "@jsonjoy.com/fs-core": "4.64.0", + "@jsonjoy.com/fs-node-builtins": "4.64.0", + "@jsonjoy.com/fs-node-utils": "4.64.0", "thingies": "^2.5.0" }, "engines": { @@ -904,17 +904,17 @@ } }, "node_modules/@jsonjoy.com/fs-node": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.57.6.tgz", - "integrity": "sha512-Kbn1jdkvDN4F2+BhoB6mMu7NCbhP0bgA5NcI1aJj/Q5UcU+I1JLLW+dEQean33iV4tXv35AzBVKPICnDltBpxw==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node/-/fs-node-4.64.0.tgz", + "integrity": "sha512-dO+NNkODbUli4uV42bcNrrLvq5rE7SNpdZ5TNd0dtbLsAaNK3MDiIC9lUi+brboGoIjW6vd2fB1qao60nrk5xA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-core": "4.57.6", - "@jsonjoy.com/fs-node-builtins": "4.57.6", - "@jsonjoy.com/fs-node-utils": "4.57.6", - "@jsonjoy.com/fs-print": "4.57.6", - "@jsonjoy.com/fs-snapshot": "4.57.6", + "@jsonjoy.com/fs-core": "4.64.0", + "@jsonjoy.com/fs-node-builtins": "4.64.0", + "@jsonjoy.com/fs-node-utils": "4.64.0", + "@jsonjoy.com/fs-print": "4.64.0", + "@jsonjoy.com/fs-snapshot": "4.64.0", "glob-to-regex.js": "^1.0.0", "thingies": "^2.5.0" }, @@ -930,9 +930,9 @@ } }, "node_modules/@jsonjoy.com/fs-node-builtins": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.57.6.tgz", - "integrity": "sha512-V4DgEFT3Cg5S9fCMOZSCVdTxdJWWLBO0WnAazV7hnCM96u5zXHyW/ubDAfcSVwqjkMJ50W1Y44IXtxRoIwaCVg==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-builtins/-/fs-node-builtins-4.64.0.tgz", + "integrity": "sha512-/o7WRFhUWaM/fOrslwLZGnzn4RmRILykn+lAL+mNObqqRNw+CQSiij6hpCeZ+C7buhdoVo7go/OYqzaSUfDYmA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -947,15 +947,15 @@ } }, "node_modules/@jsonjoy.com/fs-node-to-fsa": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.57.6.tgz", - "integrity": "sha512-+JptNw3iifihxH2rEXrninDzX4FFVW8JD/wPR8GbJPAeL9CQUSblrlumOPB5gZuS7tYRX+PJPLtT7XzKoRhv/Q==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-to-fsa/-/fs-node-to-fsa-4.64.0.tgz", + "integrity": "sha512-WDD9WVs0hb7UAEKTgZW2f66WDrbj7gIIWwpP3spbLyXa0rghtUaFTB8L4gdR3ZCWwiKIsj38/CNijpVmpnuPUw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-fsa": "4.57.6", - "@jsonjoy.com/fs-node-builtins": "4.57.6", - "@jsonjoy.com/fs-node-utils": "4.57.6" + "@jsonjoy.com/fs-fsa": "4.64.0", + "@jsonjoy.com/fs-node-builtins": "4.64.0", + "@jsonjoy.com/fs-node-utils": "4.64.0" }, "engines": { "node": ">=10.0" @@ -969,13 +969,14 @@ } }, "node_modules/@jsonjoy.com/fs-node-utils": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.57.6.tgz", - "integrity": "sha512-foyUrfS7WmYEUzqYXSNxmJBcSj04TABrkpFabwO9SCDCpVCfJ+qG+2sk5FjfiflG2n0SDFZDCJ6vYlJAEpxJFg==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-node-utils/-/fs-node-utils-4.64.0.tgz", + "integrity": "sha512-k5Indsx9hWW9xSF7Y6oSKKwtCUNhzZxadub3owhIlitc+iMRVlPPdX2duTKQWBL3qNWpXya8jykgaaWpheeS4w==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-node-builtins": "4.57.6" + "@jsonjoy.com/fs-node-builtins": "4.64.0", + "glob-to-regex.js": "^1.0.1" }, "engines": { "node": ">=10.0" @@ -989,13 +990,13 @@ } }, "node_modules/@jsonjoy.com/fs-print": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.57.6.tgz", - "integrity": "sha512-96eAn4Dudtt67LTeuU47yUD+pg9/G/oKpI10zei9ljk3X3WK4lYKc+n3cpaPCAbKPzoyfxl0mXm8f8Y7BOSFXw==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-print/-/fs-print-4.64.0.tgz", + "integrity": "sha512-PHZFccchvkhWrwPWHjmVAhbC3vSHCtyZvlZfJJ3ho2bnzl450hXri6/8e6pbkWdH+SkmLXNml0sV8e5HDAfxKw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-node-utils": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.64.0", "tree-dump": "^1.1.0" }, "engines": { @@ -1010,14 +1011,14 @@ } }, "node_modules/@jsonjoy.com/fs-snapshot": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.57.6.tgz", - "integrity": "sha512-V57CMzbOgTzUWGOWQ8GzHQdpJP6JnrYVNCtTBNxVYEnlVRvo4uEJqHhtAT8vhDFrIuJOXLrTL1Fki4h5oI7xxg==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/@jsonjoy.com/fs-snapshot/-/fs-snapshot-4.64.0.tgz", + "integrity": "sha512-oM7UDeL83q6NBzzsfKAsYKXKVXlykKFqqOLh4xZZKAzzROTlInkPbc6LTDGThEOnPiFiUzA7tYziHG9xavd76Q==", "dev": true, "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/buffers": "^17.65.0", - "@jsonjoy.com/fs-node-utils": "4.57.6", + "@jsonjoy.com/fs-node-utils": "4.64.0", "@jsonjoy.com/json-pack": "^17.65.0", "@jsonjoy.com/util": "^17.65.0" }, @@ -2041,22 +2042,21 @@ "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.8", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", - "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.2.tgz", + "integrity": "sha512-d3KvEXBSo/lOAMc2u6fkyDHBvetBHeqD7wm/AcXfLpSOQwlmG9D/aQ0SFswVjv05p7ullQS7Mjohj6/VdbZuTg==", "dev": true, "license": "MIT", "dependencies": { @@ -2087,16 +2087,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/http-proxy": { - "version": "1.17.17", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", - "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -2104,13 +2094,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { "version": "22.19.19", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", @@ -2163,13 +2146,6 @@ "@types/react": "^18.0.0" } }, - "node_modules/@types/retry": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", - "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/send": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", @@ -2191,35 +2167,13 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", "dev": true, "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@types/sockjs": { - "version": "0.3.36", - "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", - "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", - "dev": true, - "license": "MIT", - "dependencies": { "@types/node": "*" } }, @@ -3081,33 +3035,6 @@ "react-dom": ">=16.0.0" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3142,13 +3069,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" - }, "node_modules/array-includes": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", @@ -3367,61 +3287,45 @@ "require-from-string": "^2.0.2" } }, - "node_modules/binary-extensions": { + "node_modules/body-parser": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "dev": true, "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/body-parser": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", - "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", "dev": true, "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.15.1", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, "node_modules/bonjour-service": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", @@ -3697,41 +3601,19 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/chrome-trace-event": { @@ -3910,16 +3792,17 @@ } }, "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "dev": true, "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/content-type": { @@ -3950,11 +3833,14 @@ } }, "node_modules/cookie-signature": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", - "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } }, "node_modules/copy-to-clipboard": { "version": "3.3.3", @@ -3965,13 +3851,6 @@ "toggle-selection": "^1.0.6" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", @@ -4304,17 +4183,6 @@ "node": ">=6" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -4325,13 +4193,6 @@ "node": ">=8" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "license": "MIT" - }, "node_modules/dns-packet": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", @@ -5082,13 +4943,6 @@ "node": ">= 0.6" } }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "dev": true, - "license": "MIT" - }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -5119,68 +4973,99 @@ } }, "node_modules/express": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", - "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "~1.20.5", - "content-disposition": "~0.5.4", - "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", - "merge-descriptors": "1.0.3", - "methods": "~1.1.2", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", - "proxy-addr": "~2.0.7", - "qs": "~6.15.1", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", - "setprototypeof": "1.2.0", - "statuses": "~2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 18" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/express" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/express/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -5230,19 +5115,6 @@ "node": ">= 4.9.1" } }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -5300,41 +5172,27 @@ } }, "node_modules/finalhandler": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", - "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "on-finished": "~2.4.1", - "parseurl": "~1.3.3", - "statuses": "~2.0.2", - "unpipe": "~1.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -5383,27 +5241,6 @@ "dev": true, "license": "ISC" }, - "node_modules/follow-redirects": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", - "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -5440,13 +5277,13 @@ } }, "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/fsevents": { @@ -5659,13 +5496,6 @@ "dev": true, "license": "ISC" }, - "node_modules/handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" - }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -5770,59 +5600,6 @@ "he": "bin/he" } }, - "node_modules/hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "node_modules/hpack.js/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/hpack.js/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/hpack.js/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/html-encoding-sniffer": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", @@ -5912,13 +5689,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" - }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -5940,52 +5710,29 @@ "url": "https://opencollective.com/express" } }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-proxy": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", - "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "node_modules/http-proxy-middleware": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-4.2.0.tgz", + "integrity": "sha512-ZA+oNOoM+GLoFTIzhkJptVQov73Srep2LBqhF8hG8CIPKO3nam1jonXVQ/QUH8RbwsmaaVz2SOJdzBNBHNtKbw==", "dev": true, "license": "MIT", "dependencies": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "debug": "^4.4.3", + "httpxy": "^0.5.4", + "is-glob": "^4.0.3", + "is-plain-obj": "^4.1.0", + "micromatch": "^4.0.8" }, "engines": { - "node": ">=8.0.0" + "node": "^22.15.0 || ^24.0.0 || >=26.0.0" } }, - "node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "node_modules/httpxy": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.5.5.tgz", + "integrity": "sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "@types/express": "^4.17.13" - }, - "peerDependenciesMeta": { - "@types/express": { - "optional": true - } - } + "license": "MIT" }, "node_modules/hyperdyperid": { "version": "1.2.0", @@ -5998,16 +5745,20 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/icss-utils": { @@ -6176,19 +5927,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -6345,6 +6083,19 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-inside-container": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", @@ -6431,13 +6182,13 @@ } }, "node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6463,6 +6214,13 @@ "dev": true, "license": "MIT" }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -7271,30 +7029,30 @@ "license": "CC0-1.0" }, "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/memfs": { - "version": "4.57.6", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.57.6.tgz", - "integrity": "sha512-WQK+DGjKCnPdpSyJUXphz+COF2uEhhsxQ3VIWBSbzpbbXuch3h4FePMqXrXGdLjsTgo4JFzBFsP6AWd9pVazGw==", + "version": "4.64.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.64.0.tgz", + "integrity": "sha512-Kw72fgY7Wn+sD8KmtNWSafl1dz0UvAsE/PHs3YVfLiaZuA3HxNm9sRLqAu0ATiBGJvME1PxZXbBZPv5GycDeAw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@jsonjoy.com/fs-core": "4.57.6", - "@jsonjoy.com/fs-fsa": "4.57.6", - "@jsonjoy.com/fs-node": "4.57.6", - "@jsonjoy.com/fs-node-builtins": "4.57.6", - "@jsonjoy.com/fs-node-to-fsa": "4.57.6", - "@jsonjoy.com/fs-node-utils": "4.57.6", - "@jsonjoy.com/fs-print": "4.57.6", - "@jsonjoy.com/fs-snapshot": "4.57.6", + "@jsonjoy.com/fs-core": "4.64.0", + "@jsonjoy.com/fs-fsa": "4.64.0", + "@jsonjoy.com/fs-node": "4.64.0", + "@jsonjoy.com/fs-node-builtins": "4.64.0", + "@jsonjoy.com/fs-node-to-fsa": "4.64.0", + "@jsonjoy.com/fs-node-utils": "4.64.0", + "@jsonjoy.com/fs-print": "4.64.0", + "@jsonjoy.com/fs-snapshot": "4.64.0", "@jsonjoy.com/json-pack": "^1.11.0", "@jsonjoy.com/util": "^1.9.0", "glob-to-regex.js": "^1.0.1", @@ -7311,11 +7069,14 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, "license": "MIT", + "engines": { + "node": ">=18" + }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -7327,16 +7088,6 @@ "dev": true, "license": "MIT" }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -7364,19 +7115,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -7400,13 +7138,6 @@ "node": ">= 0.6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, - "license": "ISC" - }, "node_modules/minimatch": { "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", @@ -7537,16 +7268,6 @@ "node": ">=18" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -7668,13 +7389,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" - }, "node_modules/obug": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", @@ -7709,20 +7423,32 @@ "node": ">= 0.8" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/open": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", - "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", "dev": true, "license": "MIT", "dependencies": { - "default-browser": "^5.2.1", + "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", - "wsl-utils": "^0.1.0" + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7797,18 +7523,16 @@ } }, "node_modules/p-retry": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", - "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-8.0.0.tgz", + "integrity": "sha512-kFVqH1HxOHp8LupNsOys7bSV09VYTRLxarH/mokO4Rqhk6wGi70E0jh4VzvVGXfEVNggHoHLAMWsQqHyU1Ey9A==", "dev": true, "license": "MIT", "dependencies": { - "@types/retry": "0.12.2", - "is-network-error": "^1.0.0", - "retry": "^0.13.1" + "is-network-error": "^1.3.0" }, "engines": { - "node": ">=16.17" + "node": ">=22" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7910,11 +7634,15 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", - "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "dev": true, - "license": "MIT" + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/pathe": { "version": "2.0.3", @@ -8166,6 +7894,19 @@ "dev": true, "license": "MIT" }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8227,13 +7968,6 @@ "node": ">=0.8" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -8308,13 +8042,14 @@ } }, "node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -8324,29 +8059,33 @@ } }, "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", + "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.10" } }, "node_modules/rc-cascader": { @@ -8993,45 +8732,18 @@ "dev": true, "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/rechoir": { @@ -9154,13 +8866,6 @@ "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true, - "license": "MIT" - }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", @@ -9224,16 +8929,6 @@ "node": ">=4" } }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/rolldown": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.3.tgz", @@ -9268,6 +8963,23 @@ "@rolldown/binding-win32-x64-msvc": "1.0.3" } }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -9452,13 +9164,6 @@ "compute-scroll-into-view": "^3.0.2" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" - }, "node_modules/selfsigned": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", @@ -9487,46 +9192,58 @@ } }, "node_modules/send": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", - "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.1", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "~2.4.1", - "range-parser": "~1.2.1", - "statuses": "~2.0.2" + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "node_modules/send/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } }, "node_modules/serve-index": { "version": "1.9.2", @@ -9606,19 +9323,23 @@ } }, "node_modules/serve-static": { - "version": "1.16.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", - "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~2.0.0", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "~0.19.1" + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/set-function-length": { @@ -9727,15 +9448,15 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -9809,18 +9530,6 @@ "dev": true, "license": "ISC" }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" - } - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9852,38 +9561,6 @@ "source-map": "^0.6.0" } }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" - } - }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", @@ -9934,16 +9611,6 @@ "node": ">= 0.4" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-convert": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz", @@ -10485,19 +10152,65 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "dev": true, "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -10721,27 +10434,6 @@ "dev": true, "license": "MIT" }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "dev": true, - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -10947,16 +10639,6 @@ "node": ">=10.13.0" } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, "node_modules/webidl-conversions": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", @@ -11073,28 +10755,27 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", - "integrity": "sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-8.0.3.tgz", + "integrity": "sha512-zWrde9VZDiRaFuWsjHO40wm9LxxtXEk8DdzFXdU7eU5ZpiANnZZDBbZgN3guxbEoKqUHd9YupBmynyioz42nkA==", "dev": true, "license": "MIT", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^4.43.1", - "mime-types": "^3.0.1", + "memfs": "^4.56.10", + "mime-types": "^3.0.2", "on-finished": "^2.4.1", "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "schema-utils": "^4.3.3" }, "engines": { - "node": ">= 18.12.0" + "node": ">= 20.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "webpack": "^5.101.0" }, "peerDependenciesMeta": { "webpack": { @@ -11130,53 +10811,50 @@ } }, "node_modules/webpack-dev-server": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.4.tgz", - "integrity": "sha512-GqDPGZN9bRqKBTkp4aWkobDDHMsrXKoGSdOH56smIri8qR0JG8gfL8/v/f/OZR3/OKXjG8uwJbFVhKm/FNU/UA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-6.0.0.tgz", + "integrity": "sha512-q9SD4ItOGhZLeU6EGT10caDZdHjF50Pz1DtkRZZOPsfluMXOkacWKKOtSBSLVkPqKiF67eFUC0rI88U/tSFPEw==", "dev": true, "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", - "@types/express": "^4.17.25", - "@types/express-serve-static-core": "^4.17.21", + "@types/express": "^5.0.6", + "@types/express-serve-static-core": "^5.1.1", "@types/serve-index": "^1.9.4", - "@types/serve-static": "^1.15.5", - "@types/sockjs": "^0.3.36", - "@types/ws": "^8.5.10", + "@types/serve-static": "^2.2.0", + "@types/ws": "^8.18.1", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.2.1", - "chokidar": "^3.6.0", - "colorette": "^2.0.10", + "bonjour-service": "^1.3.0", + "chokidar": "^5.0.0", "compression": "^1.8.1", "connect-history-api-fallback": "^2.0.0", - "express": "^4.22.1", - "graceful-fs": "^4.2.6", - "http-proxy-middleware": "^2.0.9", - "ipaddr.js": "^2.1.0", - "launch-editor": "^2.6.1", - "open": "^10.0.3", - "p-retry": "^6.2.0", - "schema-utils": "^4.2.0", + "express": "^5.2.1", + "graceful-fs": "^4.2.11", + "http-proxy-middleware": "^4.1.1", + "ipaddr.js": "^2.3.0", + "launch-editor": "^2.14.1", + "open": "^11.0.0", + "p-retry": "^8.0.0", + "schema-utils": "^4.3.3", "selfsigned": "^5.5.0", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^7.4.2", - "ws": "^8.18.0" + "serve-index": "^1.9.2", + "tinyglobby": "^0.2.15", + "webpack-dev-middleware": "^8.0.3", + "ws": "^8.20.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 18.12.0" + "node": ">= 22.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^5.0.0" + "webpack": "^5.101.0" }, "peerDependenciesMeta": { "webpack": { @@ -11236,31 +10914,6 @@ "node": ">=4.0" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/whatwg-mimetype": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", @@ -11443,6 +11096,13 @@ "node": ">=0.10.0" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, "node_modules/ws": { "version": "8.21.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", @@ -11466,16 +11126,17 @@ } }, "node_modules/wsl-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", - "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", "dev": true, "license": "MIT", "dependencies": { - "is-wsl": "^3.1.0" + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" diff --git a/zeppelin-web-angular/projects/zeppelin-react/package.json b/zeppelin-web-angular/projects/zeppelin-react/package.json index a17a90e6b6c..18afbc004e6 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package.json @@ -49,7 +49,7 @@ "vitest": "4.1.8", "webpack": "5.105.4", "webpack-cli": "5.1.4", - "webpack-dev-server": "5.2.4" + "webpack-dev-server": "6.0.0" }, "overrides": { "linkify-it": "^5.0.2" From a46096fe501b3d300d582d355bb36d680b9d4d1e Mon Sep 17 00:00:00 2001 From: gyowoo1113 <58352333+gyowoo1113@users.noreply.github.com> Date: Thu, 16 Jul 2026 23:46:27 +0900 Subject: [PATCH 079/179] [ZEPPELIN-6475] Throw clear error for missing InfluxDB token ### What is this PR for? `InfluxDBInterpreter.open()` read the `influxdb.token` property and immediately called `toCharArray()` on the returned value. When the token was not configured, `getProperty(...)` returned `null`, causing a `NullPointerException` without explaining that the authentication token was missing. This PR validates the token before building the InfluxDB client. Missing, empty, and blank token values now throw an `InterpreterException` with a clear configuration message instead of a `NullPointerException`. Unit tests were added for absent, empty, and whitespace-only token values. Other InfluxDB properties and client creation behavior are unchanged. ### What type of PR is it? Bug Fix ### Todos * [x] Validate missing, empty, and blank `influxdb.token` values * [x] Throw `InterpreterException` with a clear error message * [x] Add unit tests for each invalid token case ### What is the Jira issue? [ZEPPELIN-6475](https://issues.apache.org/jira/browse/ZEPPELIN-6475) ### How should this be tested? `./mvnw test -pl influxdb` passes successfully. To run only the interpreter test: `./mvnw test -pl influxdb -Dtest=InfluxDBInterpeterTest` passes successfully. Missing, empty, and blank `influxdb.token` values throw `InterpreterException` instead of `NullPointerException`. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5301 from gyowoo1113/ZEPPELIN-6475-handle-missing-influxdb-token. Signed-off-by: ParkGyeongTae --- .../influxdb/InfluxDBInterpreter.java | 9 ++++- .../influxdb/InfluxDBInterpeterTest.java | 38 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/influxdb/src/main/java/org/apache/zeppelin/influxdb/InfluxDBInterpreter.java b/influxdb/src/main/java/org/apache/zeppelin/influxdb/InfluxDBInterpreter.java index 3f718fabdaa..7fedf448fe2 100644 --- a/influxdb/src/main/java/org/apache/zeppelin/influxdb/InfluxDBInterpreter.java +++ b/influxdb/src/main/java/org/apache/zeppelin/influxdb/InfluxDBInterpreter.java @@ -169,12 +169,17 @@ private QueryApi getQueryApi() { @Override - public void open() { + public void open() throws InterpreterException { if (this.client == null) { + String token = getProperty(INFLUXDB_TOKEN_PROPERTY); + if (token == null || token.isBlank()) { + throw new InterpreterException("influxdb.token property is not set. Please configure the InfluxDB auth token."); + } + InfluxDBClientOptions opt = InfluxDBClientOptions.builder() .url(getProperty(INFLUXDB_API_URL_PROPERTY)) - .authenticateToken(getProperty(INFLUXDB_TOKEN_PROPERTY).toCharArray()) + .authenticateToken(token.toCharArray()) .logLevel(LogLevel.valueOf( getProperty(INFLUXDB_LOGLEVEL_PROPERTY, LogLevel.NONE.toString()))) .org(getProperty(INFLUXDB_ORG_PROPERTY)) diff --git a/influxdb/src/test/java/org/apache/zeppelin/influxdb/InfluxDBInterpeterTest.java b/influxdb/src/test/java/org/apache/zeppelin/influxdb/InfluxDBInterpeterTest.java index 5896be8dd9e..2ee0e478df3 100644 --- a/influxdb/src/test/java/org/apache/zeppelin/influxdb/InfluxDBInterpeterTest.java +++ b/influxdb/src/test/java/org/apache/zeppelin/influxdb/InfluxDBInterpeterTest.java @@ -16,6 +16,8 @@ package org.apache.zeppelin.influxdb; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; @@ -216,6 +218,42 @@ public void after() throws IOException { } } + @Test + void testOpenWithoutToken() { + properties.remove("influxdb.token"); + + InfluxDBInterpreter interpreter = new InfluxDBInterpreter(properties); + + InterpreterException exception = assertThrows(InterpreterException.class, interpreter::open); + + assertTrue(exception.getMessage().contains("influxdb.token")); + assertTrue(exception.getMessage().contains("not set")); + } + + @Test + void testOpenWithEmptyToken() { + properties.setProperty("influxdb.token",""); + + InfluxDBInterpreter interpreter = new InfluxDBInterpreter(properties); + + InterpreterException exception = assertThrows(InterpreterException.class, interpreter::open); + + assertTrue(exception.getMessage().contains("influxdb.token")); + assertTrue(exception.getMessage().contains("not set")); + } + + @Test + void testOpenWithBlankToken() { + properties.setProperty("influxdb.token"," "); + + InfluxDBInterpreter interpreter = new InfluxDBInterpreter(properties); + + InterpreterException exception = assertThrows(InterpreterException.class, interpreter::open); + + assertTrue(exception.getMessage().contains("influxdb.token")); + assertTrue(exception.getMessage().contains("not set")); + } + @Test void testSigleTable() throws InterpreterException { From 79a6530ec0529f007f99b8f20f473dde3ca94704 Mon Sep 17 00:00:00 2001 From: HyeonUk Kang <43662405+hyunw9@users.noreply.github.com> Date: Thu, 16 Jul 2026 23:52:02 +0900 Subject: [PATCH 080/179] [ZEPPELIN-6539] Fix DockerClient / container resource leaks on interpreter failure paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Docker interpreter launcher (DockerInterpreterProcess) can leak resources on error paths when interpreters are started/stopped repeatedly by notebook workloads. 1. stop() may leak the DockerClient. docker.close() was called after the try/catch that kills/removes the container. If killContainer/removeContainer throws an unexpected (unchecked) exception, it is not caught and docker.close() is skipped, leaking the underlying HTTP socket / file descriptors. 2. start() may leave an orphaned container. start() runs pull → create → start → copy files → exec → wait-for-register. If preparation fails after the container is started (e.g. copyRunFileToContainer / execInContainer), the running container is not cleaned up ### What type of PR is it? Bug Fix ### Todos - [x] Fix stop() to always close the DockerClient - [x] Fix start() to clean up a started container on preparation failure - [x] Add unit tests (Mockito interaction tests) ### What is the Jira issue? * [[ZEPPELIN-6539]](https://issues.apache.org/jira/browse/ZEPPELIN-6539) ### How should this be tested? Automated unit tests added in DockerInterpreterProcessTest (DockerClient is mocked): - stop_alwaysClosesDockerClient_evenWhenKillContainerFails - start_removesContainer_whenContainerPreparationFails ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? - No * Is there breaking changes for older versions? - No * Does this needs documentation? - No Closes #5302 from hyunw9/ZEPPELIN-6539. Signed-off-by: ParkGyeongTae --- .../launcher/DockerInterpreterProcess.java | 50 ++++++++++- .../DockerInterpreterProcessTest.java | 90 +++++++++++++++++++ 2 files changed, 136 insertions(+), 4 deletions(-) diff --git a/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java b/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java index 643afb2061b..3004ae13f79 100644 --- a/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java +++ b/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java @@ -79,7 +79,8 @@ public class DockerInterpreterProcess extends RemoteInterpreterProcess { private AtomicBoolean dockerStarted = new AtomicBoolean(false); - private DockerClient docker = null; + @VisibleForTesting + DockerClient docker; private final String containerName; private String containerHost = ""; private int containerPort = 0; @@ -154,9 +155,15 @@ public String getInterpreterSettingName() { return interpreterSettingName; } + // allows a mock DockerClient to be injected in unit tests. + @VisibleForTesting + DockerClient createDockerClient(String dockerHost) { + return DefaultDockerClient.builder().uri(URI.create(dockerHost)).build(); + } + @Override public void start(String userName) throws IOException { - docker = DefaultDockerClient.builder().uri(URI.create(dockerHost)).build(); + docker = createDockerClient(dockerHost); removeExistContainer(containerName); @@ -220,7 +227,17 @@ public void progress(ProgressMessage message) throws DockerException { } } }); + } catch (DockerException e) { + throw new IOException(e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IOException("Docker preparations were interrupted.", e); + } + // Create, start and prepare the container. If anything fails after the + // container has been created/started, roll it back so we don't leak an + // orphaned container holding resources until the next launch reuses the name. + try { final ContainerCreation containerCreation = docker.createContainer(containerConfig, containerName); String containerId = containerCreation.id(); @@ -232,10 +249,15 @@ public void progress(ProgressMessage message) throws DockerException { execInContainer(containerId, dockerCommand, false); } catch (DockerException e) { + cleanupContainerQuietly(); throw new IOException(e); + } catch (IOException e) { + cleanupContainerQuietly(); + throw e; } catch (InterruptedException e) { // Restore interrupted state... Thread.currentThread().interrupt(); + cleanupContainerQuietly(); throw new IOException("Docker preparations were interrupted.", e); } @@ -363,10 +385,30 @@ public void stop() { Thread.currentThread().interrupt(); } catch (DockerException e) { LOGGER.error(e.getMessage(), e); + } finally { + docker.close(); } + } - // Close the docker client - docker.close(); + // Best-effort removal of a container that was (partially) created during start(). + private void cleanupContainerQuietly() { + try { + docker.killContainer(containerName); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while killing container {} during cleanup", containerName, e); + Thread.currentThread().interrupt(); + } catch (DockerException e) { + LOGGER.warn("Failed to kill container {} during cleanup", containerName, e); + } + + try { + docker.removeContainer(containerName); + } catch (InterruptedException e) { + LOGGER.warn("Interrupted while removing container {} during cleanup", containerName, e); + Thread.currentThread().interrupt(); + } catch (DockerException e) { + LOGGER.warn("Failed to remove container {} during cleanup", containerName, e); + } } // Because docker can't create a container with the same name, it will cause the creation to fail. diff --git a/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java b/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java index 1e9ad7d0bd9..ea5b5bd84ac 100644 --- a/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java +++ b/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java @@ -16,11 +16,16 @@ */ package org.apache.zeppelin.interpreter.launcher; +import com.spotify.docker.client.DockerClient; +import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.ContainerConfig; +import com.spotify.docker.client.messages.ContainerCreation; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; import org.apache.zeppelin.interpreter.InterpreterOption; import org.junit.jupiter.api.Test; import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,14 +35,99 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class DockerInterpreterProcessTest { protected static ZeppelinConfiguration zConf = spy(ZeppelinConfiguration.load()); + private DockerInterpreterProcess newProcess() { + ZeppelinConfiguration conf = spy(ZeppelinConfiguration.load()); + Properties properties = new Properties(); + properties.setProperty( + ConfVars.ZEPPELIN_INTERPRETER_CONNECT_TIMEOUT.getVarName(), "5000"); + return new DockerInterpreterProcess( + conf, + "interpreter-container:1.0", + "test_intp_group", + "sh", + "shell", + properties, + new HashMap<>(), + "zeppelin.server.hostname", + 12320, + 5000, 10); + } + + // stop() must always close the DockerClient, even when killing the container + // fails, so the underlying HTTP socket / file descriptors are never leaked. + @Test + void stop_alwaysClosesDockerClient_evenWhenKillContainerFails() throws Exception { + DockerInterpreterProcess intp = newProcess(); + DockerClient mockDocker = mock(DockerClient.class); + intp.docker = mockDocker; + doThrow(new RuntimeException("unexpected")).when(mockDocker).killContainer(anyString()); + + assertThrows(RuntimeException.class, intp::stop); + + verify(mockDocker, times(1)).close(); + } + + // When start() fails after the container has been started (e.g. file copy / exec + // fails), the container must be cleaned up instead of being left orphaned. + @Test + void start_removesContainer_whenContainerPreparationFails() throws Exception { + DockerInterpreterProcess intp = spy(newProcess()); + DockerClient mockDocker = mock(DockerClient.class); + doReturn(mockDocker).when(intp).createDockerClient(anyString()); + + // No pre-existing container to remove. + when(mockDocker.listContainers(any())).thenReturn(Collections.emptyList()); + // Container is created and started successfully... + when(mockDocker.createContainer(any(ContainerConfig.class), anyString())) + .thenReturn(ContainerCreation.builder().id("test-container-id").build()); + // ...but preparing it (the first exec inside the container) fails. + doThrow(new DockerException("exec failed")) + .when(mockDocker).execCreate(anyString(), any(String[].class), any()); + + assertThrows(IOException.class, () -> intp.start("user1")); + + // The container was started, so start() must roll it back before returning. + verify(mockDocker).startContainer("test-container-id"); + verify(mockDocker).killContainer(anyString()); + verify(mockDocker).removeContainer(anyString()); + } + + @Test + void start_removesContainer_evenWhenKillFailsDuringCleanup() throws Exception { + DockerInterpreterProcess intp = spy(newProcess()); + DockerClient mockDocker = mock(DockerClient.class); + doReturn(mockDocker).when(intp).createDockerClient(anyString()); + + when(mockDocker.listContainers(any())).thenReturn(Collections.emptyList()); + // Container is created... + when(mockDocker.createContainer(any(ContainerConfig.class), anyString())) + .thenReturn(ContainerCreation.builder().id("test-container-id").build()); + // ...but fails to start, so it is created-but-not-running. + doThrow(new DockerException("start failed")).when(mockDocker).startContainer(anyString()); + // Killing a non-running container fails, but removeContainer must still fire. + doThrow(new DockerException("not running")).when(mockDocker).killContainer(anyString()); + + assertThrows(IOException.class, () -> intp.start("user1")); + + verify(mockDocker).removeContainer(anyString()); + } + @Test void testCreateIntpProcess() throws IOException { DockerInterpreterLauncher launcher From 7715ef6ed7287ac30ce6732c2e7a6e9712c7a40a Mon Sep 17 00:00:00 2001 From: gyowoo1113 <58352333+gyowoo1113@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:52:45 +0900 Subject: [PATCH 081/179] Propagate serialization failures in Resource.serializeObject() instead of swallowing them ### What is this PR for? `Resource.serializeObject(Object)` caught serialization exceptions, printed the stack trace, and still returned a `ByteBuffer` from the partially written output. When serialization failed, callers could receive truncated or empty data instead of the original `IOException`. This PR removes the exception-swallowing catch block and uses try-with-resources for `ObjectOutputStream`. Serialization failures now propagate as the already-declared `IOException`, allowing the existing caller-side error handling to run and preventing invalid buffers from being returned. A unit test was added with a `Serializable` object that throws `IOException` during serialization. The method signature and behavior for valid serializable objects are unchanged. ### What type of PR is it? Bug Fix ### Todos * [x] Remove the exception-swallowing catch block * [x] Remove `printStackTrace()` * [x] Propagate serialization failures as `IOException` * [x] Use try-with-resources for `ObjectOutputStream` * [x] Add a regression test for serialization failure ### What is the Jira issue? [ZEPPELIN-6467](https://issues.apache.org/jira/browse/ZEPPELIN-6467) ### How should this be tested? `./mvnw test -pl zeppelin-interpreter -Dtest=ResourceTest` passes successfully. To verify that the shaded interpreter JAR includes the change: `./mvnw clean package -pl zeppelin-interpreter,zeppelin-interpreter-shaded -DskipTests` passes successfully. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5312 from gyowoo1113/ZEPPELIN-6467-propagate-serialization-failure. Signed-off-by: ChanHo Lee --- .../org/apache/zeppelin/resource/Resource.java | 10 ++-------- .../apache/zeppelin/resource/ResourceTest.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/resource/Resource.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/resource/Resource.java index c9d9395451c..f0e7c6709ef 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/resource/Resource.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/resource/Resource.java @@ -390,17 +390,11 @@ public static ByteBuffer serializeObject(Object o) throws IOException { if (o == null || !(o instanceof Serializable)) { return null; } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - ObjectOutputStream oos; - oos = new ObjectOutputStream(out); + try (ObjectOutputStream oos = new ObjectOutputStream(out)) { oos.writeObject(o); - oos.close(); - out.close(); - } catch (Exception e) { - e.printStackTrace(); } + return ByteBuffer.wrap(out.toByteArray()); } diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/resource/ResourceTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/resource/ResourceTest.java index 965f6f9bb63..9e3b76c21d4 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/resource/ResourceTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/resource/ResourceTest.java @@ -26,6 +26,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.nio.ByteBuffer; /** @@ -90,4 +92,18 @@ void testInvokeMethod_shouldAbleToInvokeMethodWithClass() throws ClassNotFoundEx Resource r = new Resource(null, new ResourceId("pool1", "name1"), "object"); assertEquals(true, r.invokeMethod("startsWith", new Class[]{ java.lang.String.class }, new Object[]{"obj"})); } + + @Test + void testSerializeObject_shouldPropagateIOException() { + IOException exception = assertThrows(IOException.class, () -> Resource.serializeObject(new FailingSerializable())); + assertEquals("Serialization failed", exception.getMessage()); + } + private static class FailingSerializable implements Serializable { + private static final long serialVersionUID = 1L; + + private void writeObject(ObjectOutputStream oos) throws IOException { + throw new IOException("Serialization failed"); + } + } + } From 044e120fbf9ce5902ea544760a47a145fcbddf05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:06:03 +0900 Subject: [PATCH 082/179] [ZEPPELIN-6472] Replace deprecated toPromise() with firstValueFrom in CompletionService ### What is this PR for? `CompletionService` (`zeppelin-web-angular/src/app/services/completion.service.ts`) powers Monaco editor code completion for the New UI. In `bindMonacoCompletion()`, the `provideCompletionItems` return path converts a one-shot completion Observable into a Promise using `.toPromise()`, which is **deprecated in RxJS 7 and scheduled for removal in RxJS 8**. The RxJS-recommended replacement is `firstValueFrom`/`lastValueFrom`. This PR: - Replaces the trailing `.toPromise()` with `firstValueFrom(...)`, wrapping the **unchanged** `completionItem$.pipe(filter(...), take(1), map(...))` expression. Because the pipeline already ends with `take(1)`, it emits a single value, so `firstValueFrom` is semantically equivalent and Monaco's `provideCompletionItems` accepts a `Promise` return. - Imports `firstValueFrom` from the `rxjs` root (merged into the existing `Subject` import line; the `rxjs/operators` import is unchanged). - Removes a leftover unconditional `console.log('on receive!', data.id)` debug statement in `onCompletion()` that printed on every `COMPLETION_LIST` message. No other behavioral changes. ### What type of PR is it? Improvement ### Todos * [x] - Replace `.toPromise()` with `firstValueFrom` over the unchanged filter/take(1)/map pipeline * [x] - Import `firstValueFrom` from `rxjs` * [x] - Remove leftover debug `console.log` in `onCompletion()` ### What is the Jira issue? [ZEPPELIN-6472](https://issues.apache.org/jira/browse/ZEPPELIN-6472) ### How should this be tested? This repository's frontend has no unit-test infrastructure, so verification is via lint plus a production build: ``` cd zeppelin-web-angular npm run lint && npm run build:angular ``` Both pass. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No. Edge case worth noting: with no completion match, the old `.toPromise()` resolved `undefined` on completion while `firstValueFrom` rejects with `EmptyError`. In the happy path behavior is identical because the `Subject` is never explicitly completed; the empty-stream difference is a theoretical edge case. A `defaultValue` could be added if reviewers prefer. * Does this needs documentation? No Closes #5309 from kimyenac/ZEPPELIN-6472. Signed-off-by: ChanHo Lee --- .../src/app/services/completion.service.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/zeppelin-web-angular/src/app/services/completion.service.ts b/zeppelin-web-angular/src/app/services/completion.service.ts index 7af1ec8be1f..c1a10f1cc21 100644 --- a/zeppelin-web-angular/src/app/services/completion.service.ts +++ b/zeppelin-web-angular/src/app/services/completion.service.ts @@ -12,7 +12,7 @@ import { Injectable } from '@angular/core'; import { editor, languages, Position } from 'monaco-editor'; -import { Subject } from 'rxjs'; +import { firstValueFrom, Subject } from 'rxjs'; import { filter, map, take } from 'rxjs/operators'; import { MessageListener, MessageListenersManager } from '@zeppelin/core'; @@ -35,7 +35,6 @@ export class CompletionService extends MessageListenersManager { @MessageListener(OP.COMPLETION_LIST) onCompletion(data: CompletionReceived): void { - console.log('on receive!', data.id); this.completionItem$.next(data); } @@ -72,8 +71,8 @@ export class CompletionService extends MessageListenersManager { that.messageService.completion(id, model.getValue(), model.getOffsetAt(position)); - return that.completionItem$ - .pipe( + return firstValueFrom( + that.completionItem$.pipe( filter(d => d.id === id), take(1), map(d => ({ @@ -92,7 +91,7 @@ export class CompletionService extends MessageListenersManager { ) })) ) - .toPromise(); + ); } }); }); From 09355ef9da3120e3550758eb46e80ec99303c790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:33:29 +0900 Subject: [PATCH 083/179] [ZEPPELIN-6473] Replace deprecated substr() with slice() in note-create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The New UI note-create dialog generates note names using `String.prototype.substr()`, an Annex B (legacy) API the language spec recommends against and flags for eventual removal. This PR migrates the three `substr()` calls in `note-create.component.ts` to the recommended `slice()`. The two methods are not blindly interchangeable — `substr(start, length)` takes a length, while `slice(start, end)` takes an end index — so each call site was checked individually to confirm behavior is preserved: - `newNoteName()`: `substr(15)` → `slice(15)` — single-arg, runs to end of string (equivalent). - `cloneNoteName()`: `substr(0, lastIndex)` → `slice(0, lastIndex)` — equivalent specifically because the start is `0`, so `length` and the end index coincide. - `cloneNoteName()`: `substr(lastIndex)` → `slice(lastIndex)` — single-arg, runs to end of string (equivalent). Generated names for both new notes (`Untitled Note N`) and cloned notes are unchanged from current behavior. ### What type of PR is it? Improvement ### Todos * [x] - Replace all three `substr()` calls with `slice()` * [x] - Confirm no remaining `substr()` usage in the file ### What is the Jira issue? [ZEPPELIN-6473](https://issues.apache.org/jira/browse/ZEPPELIN-6473) ### How should this be tested? This repository's frontend has no unit-test infrastructure, so verification is via lint plus a production build: ``` cd zeppelin-web-angular npm run lint && npm run build:angular ``` Both pass. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5305 from kimyenac/ZEPPELIN-6473. Signed-off-by: YONGJAE LEE --- .../src/app/services/angular-drag-drop.service.ts | 4 ++-- .../src/app/share/note-create/note-create.component.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/zeppelin-web-angular/src/app/services/angular-drag-drop.service.ts b/zeppelin-web-angular/src/app/services/angular-drag-drop.service.ts index e67d9f626d4..4683997d891 100644 --- a/zeppelin-web-angular/src/app/services/angular-drag-drop.service.ts +++ b/zeppelin-web-angular/src/app/services/angular-drag-drop.service.ts @@ -74,8 +74,8 @@ export class AngularDragDropService { const identifierTokens = argsString ? argsString.split(',') : []; const args = identifierTokens.map(item => $parse(item.trim())(scope)); - const constructorName = - _callbackStr.indexOf('.') !== -1 ? _callbackStr.substr(0, _callbackStr.indexOf('.')) : null; + const dotIndex = _callbackStr.indexOf('.'); + const constructorName = dotIndex !== -1 ? _callbackStr.slice(0, dotIndex) : null; // @ts-ignore const constructorCandid = constructorName && scope[constructorName]; const constructor = diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts index 30a2cf87971..ff0dbae759b 100644 --- a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts @@ -49,7 +49,7 @@ export class NoteCreateComponent extends MessageListenersManager implements OnIn this.noteListService.notes.flatList.forEach(note => { const noteName = note.path; if (noteName.match(/^\/Untitled Note [0-9]*$/)) { - const lastCount = +noteName.substr(15); + const lastCount = +noteName.slice(15); if (newCount <= lastCount) { newCount = lastCount + 1; } @@ -63,13 +63,13 @@ export class NoteCreateComponent extends MessageListenersManager implements OnIn let newCloneName = ''; const lastIndex = cloneNote.name.lastIndexOf(' '); const endsWithNumber = !!cloneNote.name.match('^.+?\\s\\d$'); - const noteNamePrefix = endsWithNumber ? cloneNote.name.substr(0, lastIndex) : cloneNote.name; + const noteNamePrefix = endsWithNumber ? cloneNote.name.slice(0, lastIndex) : cloneNote.name; const regexp = new RegExp(`^${noteNamePrefix}.+`); this.noteListService.notes.flatList.forEach(note => { const noteName = note.path; if (noteName.match(regexp)) { - const lastCopyCount = parseInt(noteName.substr(lastIndex).trim(), 10); + const lastCopyCount = parseInt(noteName.slice(lastIndex).trim(), 10); newCloneName = noteNamePrefix; if (copyCount <= lastCopyCount) { copyCount = lastCopyCount + 1; From 0fe444ec82673ed3741db387512b0c2afdb3c8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Sat, 18 Jul 2026 00:19:45 +0900 Subject: [PATCH 084/179] [ZEPPELIN-6536] Stabilize notebook keyboard shortcut e2e editor seeding ### What is this PR for? This PR stabilizes the notebook keyboard-shortcut e2e suite by avoiding keyboard-driven fixture seeding in the Monaco editor. In the Firefox Playwright job, setup could trigger Monaco suggestions while typing fixture content. That let Enter accept a suggestion before the shortcut assertion ran, corrupting expected text, for example `line` becoming `license`. The helper now seeds fixture text through the editor textarea without shortcut-style key events. The shortcut assertions still use real keyboard events. This also re-enables the clone-content shortcut coverage now that https://github.com/apache/zeppelin/pull/5254 has been merged. The skip is no longer needed, and keeping it would leave that shortcut path without regression coverage. ### What type of PR is it? Bug Fix ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6536 ### How should this be tested? ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5304 from voidmatcha/fix/stabilize-keyboard-shortcut-e2e. Signed-off-by: YONGJAE LEE --- .../e2e/models/notebook-keyboard-page.ts | 152 +++++------- .../notebook-keyboard-shortcuts.spec.ts | 232 +++++++----------- zeppelin-web-angular/e2e/utils.ts | 7 +- 3 files changed, 165 insertions(+), 226 deletions(-) diff --git a/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts b/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts index 7c2d8b875c7..44e5c3118c8 100644 --- a/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts @@ -58,7 +58,7 @@ export class NotebookKeyboardPage extends BasePage { this.settingsButton = page.locator('a[nz-dropdown]'); this.clearOutputOption = page.locator('li.list-item:has-text("Clear output")'); this.deleteButton = page.locator('button:has-text("Delete"), .delete-paragraph-button'); - this.addParagraphComponent = page.locator('zeppelin-notebook-add-paragraph').last(); // last() — the add-paragraph strip at the bottom of the notebook; the first() is the top strip and is less reliable for insertions + this.addParagraphComponent = page.locator('zeppelin-notebook-add-paragraph').last(); // last() — bottom add-paragraph strip; first() is the top strip this.searchDialog = page.locator( '.dropdown-menu.search-code, .search-widget, .find-widget, [role="dialog"]:has-text("Find")' ); @@ -100,15 +100,34 @@ export class NotebookKeyboardPage extends BasePage { // Wait for any loading/rendering to complete await this.page.waitForLoadState('domcontentloaded'); - const browserName = this.page.context().browser()?.browserType().name(); - if (browserName === 'firefox' || browserName === 'chromium') { - // Additional wait for Firefox to ensure editor is fully ready - await this.page.waitForTimeout(200); // JUSTIFIED: Monaco editor requires extra settle time in Firefox before focus dispatch - } - await this.focusEditorElement(paragraph, paragraphIndex); } + // Focus the paragraph host: it carries the shortcut bindings (tabindex=-1) and works even when the editor is hidden (a %md paragraph collapses its editor after running). + async focusParagraphHost(paragraphIndex: number = 0): Promise { + const paragraph = this.getParagraphByIndex(paragraphIndex); + // Retry: toggling output re-renders the paragraph, so a single focus() can miss. + await expect(async () => { + await paragraph.evaluate((el: HTMLElement) => el.focus()); + await expect(paragraph).toBeFocused({ timeout: 1000 }); + }).toPass({ timeout: 10000 }); + } + + // Dispatch a paragraph-scoped shortcut and retry only until its effect is observed. + async pressShortcutFromHostUntil( + paragraphIndex: number, + press: () => Promise, + isSettled: () => Promise + ): Promise { + await expect(async () => { + if (!(await isSettled())) { + await this.focusParagraphHost(paragraphIndex); + await press(); + } + expect(await isSettled()).toBe(true); + }).toPass({ timeout: 15000 }); + } + async typeInEditor(text: string): Promise { await this.page.keyboard.type(text); } @@ -209,7 +228,7 @@ export class NotebookKeyboardPage extends BasePage { // Wait for paragraph count to increase await this.page.waitForFunction( - expectedCount => document.querySelectorAll('zeppelin-notebook-paragraph').length > expectedCount, // JUSTIFIED: waitForFunction polls DOM count — Playwright toHaveCount() requires exact match, not minimum + expectedCount => document.querySelectorAll('zeppelin-notebook-paragraph').length > expectedCount, // JUSTIFIED: waitForFunction polls DOM count; Playwright toHaveCount() requires exact match, not minimum currentCount, { timeout: 10000 } ); @@ -347,40 +366,29 @@ export class NotebookKeyboardPage extends BasePage { } async getCodeEditorContent(): Promise { - // Fallback to Angular scope - const angularContent = await this.page.evaluate(() => { - const paragraphElement = document.querySelector('zeppelin-notebook-paragraph'); // JUSTIFIED: accesses AngularJS $scope via window.angular — not accessible via Playwright locator API - if (paragraphElement) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const angular = (window as any).angular; - if (angular) { - const scope = angular.element(paragraphElement).scope(); - if (scope && scope.$ctrl && scope.$ctrl.paragraph) { - return scope.$ctrl.paragraph.text || ''; - } - } + return this.readEditorText(this.paragraphContainer.first()); + } + + // Reconstruct editor text from Monaco's absolutely-positioned `.view-line` divs sorted by top (DOM order need not match line order), via textContent; innerText is "" for off-layout lines in headless Chromium. + private async readEditorText(paragraph: Locator): Promise { + const monaco = paragraph.locator('.monaco-editor').first(); + if ((await monaco.count()) > 0) { + const text = await monaco.evaluate((el: Element) => { + const lines = Array.from(el.querySelectorAll('.view-line')) as HTMLElement[]; + lines.sort((a, b) => parseInt(a.style.top || '0', 10) - parseInt(b.style.top || '0', 10)); + return lines.map(l => (l.textContent || '').replace(/\u00a0/g, ' ')).join('\n'); + }); + if (text.trim().length > 0) { + return text; } - return null; - }); - - if (angularContent !== null) { - return angularContent; } - - // Fallback to DOM-based approaches - const selectors = ['.monaco-editor .view-lines', '.CodeMirror-line', '.ace_line', 'textarea']; - - for (const selector of selectors) { - const element = this.page.locator(selector).first(); - if (await element.isVisible({ timeout: 1000 })) { - if (selector === 'textarea') { - return await element.inputValue(); - } else { - return (await element.textContent()) || ''; - } + const textarea = paragraph.locator('.monaco-editor textarea').first(); + if ((await textarea.count()) > 0) { + const value = await textarea.inputValue().catch(() => ''); + if (value) { + return value; } } - return ''; } @@ -419,19 +427,26 @@ export class NotebookKeyboardPage extends BasePage { for (let i = 0; i < contentLength; i++) { await this.page.keyboard.press('Backspace'); } - await this.page.waitForTimeout(100); // JUSTIFIED: Monaco content state settle between backspaces and new input - - await this.page.keyboard.type(content); - await this.page.waitForTimeout(300); // JUSTIFIED: Monaco content state settle after keystroke sequence + // JUSTIFIED: Monaco textarea can be covered by editor overlays during fixture setup. + await editorInput.fill(content, { force: true }); } else { // Standard clearing for other browsers await this.pressSelectAll(); await this.page.keyboard.press('Delete'); - await editorInput.fill(content, { force: true }); // JUSTIFIED: Monaco textarea may be overlaid by editor decorations after select+delete; force required for programmatic fill + // JUSTIFIED: Monaco textarea can be overlaid after select+delete during fixture setup. + await editorInput.fill(content, { force: true }); } - await this.page.waitForTimeout(200); // JUSTIFIED: Monaco content state settle after fill completes + // Wait for the full normalized editor content to avoid stale Monaco renders. + const expected = content.replace(/\s+/g, ''); + if (expected.length === 0) { + await expect.poll(async () => (await this.readEditorText(paragraph)).trim(), { timeout: 10000 }).toBe(''); + } else { + await expect + .poll(async () => (await this.readEditorText(paragraph)).replace(/\s+/g, ''), { timeout: 10000 }) + .toContain(expected); + } } // Helper methods for verifying shortcut effects @@ -496,41 +511,7 @@ export class NotebookKeyboardPage extends BasePage { } async getCodeEditorContentByIndex(paragraphIndex: number): Promise { - const paragraph = this.getParagraphByIndex(paragraphIndex); - - const editorTextarea = paragraph.locator('.monaco-editor textarea'); - if (await editorTextarea.isVisible()) { - const textContent = await editorTextarea.inputValue(); - if (textContent) { - return textContent; - } - } - - const viewLines = paragraph.locator('.monaco-editor .view-lines'); - if (await viewLines.isVisible()) { - const text = await viewLines.evaluate((el: Element) => (el as HTMLElement).innerText || ''); - if (text && text.trim().length > 0) { - return text; - } - } - - const scopeContent = await paragraph.evaluate(el => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const angular = (window as any).angular; - if (angular) { - const scope = angular.element(el).scope(); - if (scope && scope.$ctrl && scope.$ctrl.paragraph) { - return scope.$ctrl.paragraph.text || ''; - } - } - return ''; - }); - - if (scopeContent) { - return scopeContent; - } - - return ''; + return this.readEditorText(this.getParagraphByIndex(paragraphIndex)); } async waitForParagraphCountChange(expectedCount: number, timeout: number = 30000): Promise { @@ -650,9 +631,9 @@ export class NotebookKeyboardPage extends BasePage { const editor = paragraph.locator('.monaco-editor, .CodeMirror, .ace_editor, textarea').first(); - await editor.waitFor({ state: 'visible', timeout: 5000 }).catch(() => {}); // JUSTIFIED: UI stabilization — editor may not be visible yet; click attempt follows - await editor.click({ force: true, trial: true }).catch(async () => { - // JUSTIFIED: UI stabilization — falls back to textarea focus if click fails + await editor.waitFor({ state: 'visible', timeout: 5000 }).catch(() => {}); // editor may not be visible yet; the click/focus below retries + // A `trial` click only runs actionability checks and never focuses; do a real click, falling back to focusing the textarea if it is intercepted. + await editor.click({ force: true }).catch(async () => { const textArea = editor.locator('textarea').first(); if ((await textArea.count()) > 0) { await textArea.focus({ timeout: 1000 }); @@ -669,6 +650,8 @@ export class NotebookKeyboardPage extends BasePage { if (hasTextArea) { await textArea.focus(); await expect(textArea).toBeFocused({ timeout: 3000 }); + // Monaco sets the `focused` class only after processing the focus event; activeElement can be set earlier, dropping the shortcut. Gate on the class so focus is real. + await expect(editor).toHaveClass(/\bfocused\b/, { timeout: 10000 }); } else { await expect(editor).toHaveClass(/focused|focus|active/, { timeout: 30000 }); } @@ -676,9 +659,8 @@ export class NotebookKeyboardPage extends BasePage { private async executePlatformShortcut(shortcut: string | string[]): Promise { const shortcuts = Array.isArray(shortcut) ? shortcut : [shortcut]; - const isMac = process.platform === 'darwin'; - const selected = isMac && shortcuts.length > 1 ? shortcuts[1] : shortcuts[0]; - await this.page.keyboard.press(this.formatKey(selected)); + // Playwright presses by physical key code, so the primary variant works on every platform; the macOS special-character variant (e.g. control.alt.∂) is unpressable via keyboard.press. + await this.page.keyboard.press(this.formatKey(shortcuts[0])); } private formatKey(shortcut: string): string { diff --git a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts index b0818c9f02b..2f43bb6f33f 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts @@ -22,14 +22,10 @@ import { /** * Comprehensive keyboard shortcuts test suite based on ShortcutsMap - * Tests all keyboard shortcuts defined in src/app/key-binding/shortcuts-map.ts - * - * Note: This spec uses waitForTimeout in several places because Monaco editor cursor - * state and editor focus are not observable via DOM events that Playwright can detect. - * These are justified timing gaps to allow Monaco's internal state to settle between - * keystroke sequences. See: https://github.com/microsoft/monaco-editor/issues/2688 + * (src/app/key-binding/shortcuts-map.ts). The page object gates on Monaco's `focused` + * class before dispatching shortcuts; effects are asserted with web-first expectations. */ -// JUSTIFIED: Monaco editor focus state is not observable via DOM events; serial ordering prevents cross-test editor state corruption +// Serial ordering prevents cross-test editor state corruption within the shared notebook. test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); addPageAnnotationBeforeEach(PAGES.SHARE.SHORTCUT); @@ -76,14 +72,13 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.tryFocusCodeEditor(); await keyboardPage.setCodeEditorContent('%md\n# Test Heading\n\nThis is **bold** text.'); - // Verify content was set - const content = await keyboardPage.getCodeEditorContent(); - expect(content.replace(/\s+/g, '')).toContain('#TestHeading'); + // Verify content was set (setCodeEditorContent already gated on the rendered text) + await expect(keyboardPage.editorLines.first()).toContainText('Test Heading'); // When: User presses Shift+Enter await keyboardPage.pressRunParagraph(); - // Then: Paragraph should execute (reach a terminal state — interpreter availability varies by env) + // Then: Paragraph should execute (reach a terminal state; interpreter availability varies by env) await keyboardPage.waitForParagraphExecution(0); // JUSTIFIED: single-paragraph test notebook; first() is deterministic const statusEl = keyboardPage.paragraphContainer.first().locator('.status'); @@ -161,7 +156,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { test.describe('ParagraphActions.Cancel: Control+Alt+C', () => { test('should cancel running paragraph with Control+Alt+C', async () => { - test.skip(!!process.env.CI, 'Requires Python interpreter with running indicator — not available in CI'); + test.skip(!!process.env.CI, 'Requires Python interpreter with running indicator; not available in CI'); // Given: A long-running paragraph await keyboardPage.tryFocusCodeEditor(); await keyboardPage.setCodeEditorContent('%python\nimport time;time.sleep(3)\nprint("Should be cancelled")'); @@ -197,21 +192,17 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Position cursor at end of last line using more reliable cross-browser method await keyboardPage.pressSelectAll(); // Select all content await keyboardPage.pressKey('ArrowRight'); // Move to end - await keyboardPage.page.waitForTimeout(500); // Wait for cursor to position // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // When: User presses Control+P (should move cursor up one line) await keyboardPage.pressMoveCursorUp(); - await keyboardPage.page.waitForTimeout(500); // Wait for cursor movement // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // Then: Verify cursor movement by checking if we can type at the current position // Type a marker and check where it appears in the content await keyboardPage.pressKey('End'); // Move to end of current line await keyboardPage.page.keyboard.type('MARKER'); - const content = await keyboardPage.getCodeEditorContent(); - // If cursor moved up correctly, marker should be on line2 - expect(content).toContain('line2MARKER'); - expect(content).not.toContain('line3MARKER'); + await expect.poll(() => keyboardPage.getCodeEditorContent()).toContain('line2MARKER'); + expect(await keyboardPage.getCodeEditorContent()).not.toContain('line3MARKER'); }); }); @@ -225,20 +216,16 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.pressSelectAll(); // Select all content await keyboardPage.pressKey('ArrowLeft'); // Move to beginning await keyboardPage.pressKey('ArrowDown'); // Move to line1 - await keyboardPage.page.waitForTimeout(500); // Wait for cursor to position // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // When: User presses Control+N (should move cursor down one line) await keyboardPage.pressMoveCursorDown(); - await keyboardPage.page.waitForTimeout(500); // Wait for cursor movement // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // Then: Verify cursor movement by checking if we can type at the current position // Type a marker and check where it appears in the content await keyboardPage.page.keyboard.type('MARKER'); - const content = await keyboardPage.getCodeEditorContent(); - // If cursor moved down correctly, marker should be on line2 - expect(content).toContain('MARKERline2'); - expect(content).not.toContain('MARKERline1'); + await expect.poll(() => keyboardPage.getCodeEditorContent()).toContain('MARKERline2'); + expect(await keyboardPage.getCodeEditorContent()).not.toContain('MARKERline1'); }); }); @@ -265,7 +252,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Focus first paragraph await firstParagraph.click(); await keyboardPage.tryFocusCodeEditor(0); - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor requires time to register focus before keyboard shortcut dispatch // When: User presses Control+Alt+D await keyboardPage.pressDeleteParagraph(); @@ -285,7 +271,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { expect(initialCount).toBe(1); await keyboardPage.tryFocusCodeEditor(0); - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor requires time to register focus before keyboard shortcut dispatch // When: User presses Control+Alt+D on the only paragraph await keyboardPage.pressDeleteParagraph(); @@ -324,17 +309,14 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const finalCount = await keyboardPage.getParagraphCount(); expect(finalCount).toBe(initialCount + 1); - // And: The new paragraph should be at index 0 (above the original) - const newParagraphContent = await keyboardPage.getCodeEditorContentByIndex(0); - const originalParagraphContent = await keyboardPage.getCodeEditorContentByIndex(1); + // And: the new paragraph at index 0 holds no user content; empty or just an interpreter directive (poll so the async insert/render settles). + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0).then(c => c.trim())).toMatch(/^(%\w+)?$/); - // New paragraph may have default interpreter (%python) or be empty - expect(newParagraphContent === '' || newParagraphContent === '%python').toBe(true); - - // Normalize whitespace for comparison since Monaco editor may format differently + // And the original content moved to index 1 (normalize whitespace; Monaco reflows). const normalizedOriginalContent = originalContent.replace(/\s+/g, ' ').trim(); - const normalizedReceivedContent = originalParagraphContent.replace(/\s+/g, ' ').trim(); - expect(normalizedReceivedContent).toContain(normalizedOriginalContent); // Original content should be at index 1 + await expect + .poll(() => keyboardPage.getCodeEditorContentByIndex(1).then(c => c.replace(/\s+/g, ' ').trim())) + .toContain(normalizedOriginalContent); }); }); @@ -355,49 +337,33 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const finalCount = await keyboardPage.getParagraphCount(); expect(finalCount).toBe(initialCount + 1); - // And: The new paragraph should be at index 1 (below the original) + // And: the original content stays at index 0 (poll so the async insert/render settles). + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toMatch(/Original\s+Paragraph/); const originalParagraphContent = await keyboardPage.getCodeEditorContentByIndex(0); - const newParagraphContent = await keyboardPage.getCodeEditorContentByIndex(1); - - // Compare content - use regex to handle potential encoding issues - expect(originalParagraphContent).toMatch(/Original\s+Paragraph/); expect(originalParagraphContent).toMatch(/Content\s+for\s+insert\s+below\s+test/); - expect(newParagraphContent).toBeDefined(); // New paragraph just needs to exist + + // And: a new paragraph exists at index 1 holding no user content. + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1).then(c => c.trim())).toMatch(/^(%\w+)?$/); }); }); - // Note (ZEPPELIN-6294): - // This test appears to be related to ZEPPELIN-6294. - // A proper fix or verification should be added based on the issue details. - // In the New UI, the cloned paragraph’s text is empty on PARAGRAPH_ADDED, - // while the Classic UI receives the correct text. This discrepancy should be addressed - // when applying the proper fix for the issue. test.describe('ParagraphActions.InsertCopyOfParagraphBelow: Control+Shift+C', () => { test('should insert copy of paragraph below with Control+Shift+C', async () => { - test.skip(); // Given: A paragraph with content await keyboardPage.tryFocusCodeEditor(); await keyboardPage.setCodeEditorContent('%md\n# Copy Test\nContent to be copied below'); const initialCount = await keyboardPage.getParagraphCount(); - - // Capture the original paragraph content to verify the copy const originalContent = await keyboardPage.getCodeEditorContentByIndex(0); // When: User presses Control+Shift+C await keyboardPage.pressInsertCopy(); - // Then: A copy of the paragraph should be inserted below + // Then: a copy is inserted below carrying the same text, and the original is unchanged await keyboardPage.waitForParagraphCountChange(initialCount + 1); - const finalCount = await keyboardPage.getParagraphCount(); - expect(finalCount).toBe(initialCount + 1); - - // And: The copied content should be identical to the original - const originalParagraphContent = await keyboardPage.getCodeEditorContentByIndex(0); - const copiedParagraphContent = await keyboardPage.getCodeEditorContentByIndex(1); - - expect(originalParagraphContent).toBe(originalContent); // Original should remain unchanged - expect(copiedParagraphContent).toBe(originalContent); // Copied content should match original exactly + expect(await keyboardPage.getParagraphCount()).toBe(initialCount + 1); + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toBe(originalContent); + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1)).toBe(originalContent); }); }); @@ -407,10 +373,9 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const firstContent = '%python\nprint("First Paragraph - Content for move up test")'; const secondContent = '%python\nprint("Second Paragraph - This should move up")'; - // Set first paragraph content + // Set first paragraph content (setCodeEditorContent gates on the rendered text) await keyboardPage.tryFocusCodeEditor(0); await keyboardPage.setCodeEditorContent(firstContent, 0); - await keyboardPage.page.waitForTimeout(300); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // Create second paragraph using InsertBelow shortcut (Control+Alt+B) await keyboardPage.pressInsertBelow(); @@ -419,7 +384,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Set second paragraph content await keyboardPage.tryFocusCodeEditor(1); await keyboardPage.setCodeEditorContent(secondContent, 1); - await keyboardPage.page.waitForTimeout(300); // JUSTIFIED: Monaco content state settle before read // Verify we have 2 paragraphs const paragraphCount = await keyboardPage.getParagraphCount(); @@ -431,24 +395,17 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Focus on second paragraph for move operation await keyboardPage.tryFocusCodeEditor(1); - await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // When: User presses Control+Alt+K from second paragraph await keyboardPage.pressMoveParagraphUp(); - // Wait for move operation to complete - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM - // Then: Paragraph count should remain the same const finalParagraphCount = await keyboardPage.getParagraphCount(); expect(finalParagraphCount).toBe(2); - // And: Paragraph positions should be swapped - const newFirstParagraph = await keyboardPage.getCodeEditorContentByIndex(0); - const newSecondParagraph = await keyboardPage.getCodeEditorContentByIndex(1); - - expect(newFirstParagraph).toBe(initialSecond); // Second paragraph moved to first position - expect(newSecondParagraph).toBe(initialFirst); // First paragraph moved to second position + // And: Paragraph positions should be swapped (poll until the move lands in the DOM) + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toBe(initialSecond); + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1)).toBe(initialFirst); }); }); @@ -458,10 +415,9 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const firstContent = '%python\nprint("First Paragraph - This should move down")'; const secondContent = '%python\nprint("Second Paragraph - Content for second paragraph")'; - // Set first paragraph content + // Set first paragraph content (setCodeEditorContent gates on the rendered text) await keyboardPage.tryFocusCodeEditor(0); await keyboardPage.setCodeEditorContent(firstContent, 0); - await keyboardPage.page.waitForTimeout(300); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // Create second paragraph using InsertBelow shortcut (Control+Alt+B) await keyboardPage.pressInsertBelow(); @@ -470,7 +426,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Set second paragraph content await keyboardPage.tryFocusCodeEditor(1); await keyboardPage.setCodeEditorContent(secondContent, 1); - await keyboardPage.page.waitForTimeout(300); // JUSTIFIED: Monaco content state settle before read // Verify we have 2 paragraphs const paragraphCount = await keyboardPage.getParagraphCount(); @@ -482,24 +437,17 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Focus first paragraph for move operation await keyboardPage.tryFocusCodeEditor(0); - await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM // When: User presses Control+Alt+J from first paragraph await keyboardPage.pressMoveParagraphDown(); - // Wait for move operation to complete - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM - // Then: Paragraph count should remain the same const finalParagraphCount = await keyboardPage.getParagraphCount(); expect(finalParagraphCount).toBe(2); - // And: Paragraph positions should be swapped - const newFirstParagraph = await keyboardPage.getCodeEditorContentByIndex(0); - const newSecondParagraph = await keyboardPage.getCodeEditorContentByIndex(1); - - expect(newFirstParagraph).toBe(initialSecond); // Second paragraph moved to first position - expect(newSecondParagraph).toBe(initialFirst); // First paragraph moved to second position + // And: Paragraph positions should be swapped (poll until the move lands in the DOM) + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toBe(initialSecond); + await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1)).toBe(initialFirst); }); }); @@ -516,10 +464,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Alt+E await keyboardPage.pressSwitchEditor(); - // Then: Editor visibility should toggle - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM - const finalEditorVisibility = await keyboardPage.isEditorVisible(0); - expect(finalEditorVisibility).not.toBe(initialEditorVisibility); + // Then: editor visibility toggles + await expect.poll(() => keyboardPage.isEditorVisible(0), { timeout: 10000 }).toBe(!initialEditorVisibility); }); }); @@ -534,10 +480,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Alt+R await keyboardPage.pressSwitchEnable(); - // Then: Paragraph enabled state should toggle - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM - const finalEnabledState = await keyboardPage.isParagraphEnabled(0); - expect(finalEnabledState).not.toBe(initialEnabledState); + // Then: paragraph enabled state toggles + await expect.poll(() => keyboardPage.isParagraphEnabled(0), { timeout: 10000 }).toBe(!initialEnabledState); }); }); @@ -552,14 +496,19 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const resultLocator = keyboardPage.getParagraphByIndex(0).locator('[data-testid="paragraph-result"]'); await expect(resultLocator).toBeVisible(); - const initialOutputVisibility = await keyboardPage.isOutputVisible(0); + // When: User presses Control+Alt+O from the paragraph host + await keyboardPage.pressShortcutFromHostUntil( + 0, + () => keyboardPage.pressSwitchOutputShow(), + () => resultLocator.isHidden() + ); - // When: User presses Control+Alt+O - await keyboardPage.tryFocusCodeEditor(0); - await keyboardPage.pressSwitchOutputShow(); - - const finalOutputVisibility = await keyboardPage.isOutputVisible(0); - expect(finalOutputVisibility).not.toBe(initialOutputVisibility); + // And toggling again restores it + await keyboardPage.pressShortcutFromHostUntil( + 0, + () => keyboardPage.pressSwitchOutputShow(), + () => resultLocator.isVisible() + ); }); }); @@ -574,10 +523,10 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Alt+M await keyboardPage.pressSwitchLineNumber(); - // Then: Line numbers visibility should toggle - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM - const finalLineNumbersVisibility = await keyboardPage.areLineNumbersVisible(0); - expect(finalLineNumbersVisibility).not.toBe(initialLineNumbersVisibility); + // Then: line numbers visibility toggles + await expect + .poll(() => keyboardPage.areLineNumbersVisible(0), { timeout: 10000 }) + .toBe(!initialLineNumbersVisibility); }); }); @@ -592,9 +541,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Alt+T await keyboardPage.pressSwitchTitleShow(); - // Then: Title visibility should toggle - const finalTitleVisibility = await keyboardPage.isTitleVisible(0); - expect(finalTitleVisibility).not.toBe(initialTitleVisibility); + // Then: title visibility toggles (poll; the DOM updates asynchronously) + await expect.poll(() => keyboardPage.isTitleVisible(0), { timeout: 10000 }).toBe(!initialTitleVisibility); }); }); @@ -611,12 +559,15 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const statusElBefore = keyboardPage.paragraphContainer.first().locator('.status'); await expect(statusElBefore).toHaveText(/FINISHED|ERROR|PENDING|RUNNING/); - // When: User presses Control+Alt+L - await keyboardPage.tryFocusCodeEditor(0); - await keyboardPage.pressClearOutput(); + // When: User presses Control+Alt+L (editor hidden after %md run; dispatch from the host) + const resultLocator = keyboardPage.getParagraphByIndex(0).locator('[data-testid="paragraph-result"]'); + await keyboardPage.pressShortcutFromHostUntil( + 0, + () => keyboardPage.pressClearOutput(), + () => resultLocator.isHidden() + ); // Then: Output should be cleared - const resultLocator = keyboardPage.getParagraphByIndex(0).locator('[data-testid="paragraph-result"]'); await expect(resultLocator).not.toBeVisible(); }); }); @@ -666,9 +617,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Shift+- await keyboardPage.pressReduceWidth(); - // Then: Paragraph width should be reduced - const finalWidth = await keyboardPage.getParagraphWidth(0); - expect(finalWidth).toBeLessThan(initialWidth); + // Then: paragraph width reduces (poll; the layout updates asynchronously) + await expect.poll(() => keyboardPage.getParagraphWidth(0), { timeout: 10000 }).toBeLessThan(initialWidth); }); }); @@ -679,17 +629,18 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%python\nprint("Test width increase")'); // First, reduce width to ensure there's room to increase + const fullWidth = await keyboardPage.getParagraphWidth(0); await keyboardPage.pressReduceWidth(); - await keyboardPage.page.waitForTimeout(500); // Give UI a moment to update after reduction // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // Poll until the reduction is reflected in the layout instead of a fixed settle + await expect.poll(() => keyboardPage.getParagraphWidth(0), { timeout: 10000 }).toBeLessThan(fullWidth); const initialWidth = await keyboardPage.getParagraphWidth(0); // When: User presses Control+Shift+= await keyboardPage.pressIncreaseWidth(); - // Then: Paragraph width should be increased - const finalWidth = await keyboardPage.getParagraphWidth(0); - expect(finalWidth).toBeGreaterThan(initialWidth); + // Then: paragraph width increases (poll; the layout updates asynchronously) + await expect.poll(() => keyboardPage.getParagraphWidth(0), { timeout: 10000 }).toBeGreaterThan(initialWidth); }); }); @@ -709,20 +660,23 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Additional wait and focus for Firefox compatibility const browserName = test.info().project.name; if (browserName === 'firefox') { - await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM // Ensure Monaco editor is properly focused // JUSTIFIED: single Monaco editor per paragraph; first() picks the active textarea const editorTextarea = keyboardPage.page.locator('.monaco-editor textarea').first(); await editorTextarea.click(); await editorTextarea.focus(); - await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM } // When: User presses Control+K (cut to end of line) await keyboardPage.pressCutLine(); // Then: First line content should be cut (cut from cursor position to end of line) - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM const finalContent = await keyboardPage.getCodeEditorContent(); expect(finalContent).toBeDefined(); expect(typeof finalContent).toBe('string'); @@ -744,13 +698,15 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent(originalContent); // Wait for content to be properly set and verify it - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM const initialContent = await keyboardPage.getCodeEditorContent(); expect(initialContent.replace(/\s+/g, ' ').trim()).toContain(originalContent); // When: User presses Control+K to cut the line await keyboardPage.pressCutLine(); - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM // Then: Content should be reduced (line was cut) const afterCutContent = await keyboardPage.getCodeEditorContent(); @@ -758,13 +714,15 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Clear the editor to verify paste works from clipboard await keyboardPage.setCodeEditorContent(''); - await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(200); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM const emptyContent = await keyboardPage.getCodeEditorContent(); expect(emptyContent.trim()).toBe(''); // When: User presses Control+Y to paste await keyboardPage.pressPasteLine(); - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // JUSTIFIED: wait for Monaco focus/cursor state after editor shortcut + await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle; cursor/focus state not observable via DOM // Then: Original content should be restored from clipboard const finalContent = await keyboardPage.getCodeEditorContent(); @@ -797,8 +755,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Alt+F await keyboardPage.pressFindInCode(); - // Then: Find functionality should be triggered - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + // Then: Find functionality should be triggered (toBeVisible auto-retries) await expect(keyboardPage.searchDialog).toBeVisible(); // Close search dialog @@ -817,9 +774,9 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Space to trigger autocomplete await keyboardPage.pressControlSpace(); - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + await keyboardPage.autocompletePopup.waitFor({ state: 'visible', timeout: 3000 }).catch(() => {}); - // Then: Editor must remain functional after shortcut (baseline — always asserts) + // Then: Editor must remain functional after shortcut (baseline; always asserts) // JUSTIFIED: single-paragraph test notebook; first() is deterministic await expect(keyboardPage.codeEditor.first()).toBeVisible(); @@ -844,7 +801,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User triggers autocomplete and selects an option await keyboardPage.pressControlSpace(); - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + await keyboardPage.autocompletePopup.waitFor({ state: 'visible', timeout: 3000 }).catch(() => {}); const isAutocompleteVisible = await keyboardPage.isAutocompleteVisible(); if (isAutocompleteVisible) { @@ -882,7 +839,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Tab for indentation await keyboardPage.pressTab(); - // Then: Content should be longer (indentation added) — poll until CodeMirror processes the Tab asynchronously + // Then: Content should be longer (indentation added); poll until CodeMirror processes the Tab asynchronously let contentAfterTab = ''; await expect(async () => { contentAfterTab = await keyboardPage.getCodeEditorContent(); @@ -988,8 +945,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%md\n# Recovery Test\nShortcuts work after error', newParagraphIndex); await keyboardPage.pressRunParagraph(); - // Then: New paragraph should execute (FINISHED or ERROR is acceptable — the key assertion is - // that execution completed, proving shortcuts are functional after an error occurred) + // Then: Shortcut execution still reaches a terminal state await keyboardPage.waitForParagraphExecution(newParagraphIndex); // JUSTIFIED: newParagraphIndex is dynamically computed from getParagraphCount(); nth() is the only way to address this specific paragraph const statusElNew = keyboardPage.paragraphContainer.nth(newParagraphIndex).locator('.status'); @@ -1001,23 +957,22 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.tryFocusCodeEditor(); await keyboardPage.setCodeEditorContent('%md\n# Test paragraph'); - // Remove focus by clicking on empty area + // Remove focus by clicking on empty area, then confirm no editor holds focus await keyboardPage.page.locator('body').click(); - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM + await expect(keyboardPage.page.locator('.monaco-editor.focused')).toHaveCount(0, { timeout: 5000 }); const initialCount = await keyboardPage.getParagraphCount(); // When: User tries keyboard shortcuts that require paragraph focus // These should either not work or gracefully handle the lack of focus await keyboardPage.pressInsertBelow(); // This may not work without focus - await keyboardPage.page.waitForTimeout(1000); // JUSTIFIED: Monaco editor internal state settle — cursor/focus state not observable via DOM const afterShortcut = await keyboardPage.getParagraphCount(); // Then: Either the shortcut works (creates new paragraph) or is gracefully ignored expect(afterShortcut === initialCount || afterShortcut === initialCount + 1).toBe(true); - // System must remain stable — editor still accessible + // Editor remains usable after error recovery. // JUSTIFIED: single-paragraph test notebook; first() is deterministic await expect(keyboardPage.codeEditor.first()).toBeVisible(); }); @@ -1032,7 +987,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.waitForParagraphExecution(0, 60000); // JUSTIFIED: single-paragraph test notebook; first() is deterministic await expect(keyboardPage.paragraphResult.first()).toBeVisible({ timeout: 60000 }); - await keyboardPage.page.waitForTimeout(500); // JUSTIFIED: brief gap between rapid sequential runs to prevent WebSocket message overlap } // Then: System should remain stable diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index 83057596471..93aaf67f70a 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -363,7 +363,7 @@ export const navigateToNotebookWithFallback = async ( // Strategy 1: Direct navigation await page.goto(`/#/notebook/${noteId}`, { waitUntil: 'networkidle', timeout: 30000 }); navigationSuccessful = true; - } catch (error) { + } catch { // Strategy 2: Wait for loading completion and check URL await page.waitForFunction( () => { @@ -485,7 +485,10 @@ export const createTestNotebookWithName = async ( options: CreateTestNotebookWithNameOptions = {} ): Promise<{ noteId: string; paragraphId: string; notebookName: string; notebookPath: string }> => { const isRetryableError = (message: string): boolean => - /REST request failed: (404|409|500)\b/.test(message) || message.includes('Fetch notebook REST request failed'); + /REST request failed: (404|409|500)\b/.test(message) || + message.includes('Fetch notebook REST request failed') || + // TODO: transient WebKit-on-Linux crash (microsoft/playwright#34450); drop once fixed upstream. + /WebKit encountered an internal error|Target crashed/.test(message); const tryCreate = async () => { const prefix = options.namePrefix ?? 'TestNotebook'; From 9245bbb6bf4b74d36959b0335ee2958b0542b984 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Sat, 18 Jul 2026 01:26:12 +0900 Subject: [PATCH 085/179] [ZEPPELIN-6527] Fix flaky run-e2e-tests-in-zeppelin-web CI job (searchBlock Protractor timing) ### What is this PR for? This PR removes the flaky classic `zeppelin-web` Protractor e2e job by moving its remaining active coverage to the existing Playwright e2e workflow. The old `run-e2e-tests-in-zeppelin-web` job depended on Protractor, webdriver-manager, and a pinned ChromeDriver 2.35, and had been failing intermittently in the classic search/replace tests due to AngularJS/Ace synchronization timing. Since that stack is end-of-life and cannot be reasonably modernized in place, this PR ports the 10 active checks from `home.spec.js` and `searchBlock.spec.js` to Playwright, pointed at the classic `/classic` UI. The migrated tests keep the existing classic UI coverage for the home page, interpreter permission save flow, search shortcut, match counters, replace, and replace-all behavior. After that coverage is available in Playwright, the obsolete Protractor config, scripts, dependencies, and CI job are removed. ### What type of PR is it? Improvement ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6527 ### How should this be tested? ```bash cd zeppelin-web-angular npx playwright test e2e/tests/classic --project=classic --reporter=line ``` For the Maven/CI path: ```bash ./mvnw clean install -DskipTests -am -pl python,zeppelin-jupyter-interpreter,zeppelin-web,zeppelin-web-angular -Pweb-classic xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw verify -pl zeppelin-web-angular -Pweb-e2e ``` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? Edit `zeppelin-web/README.md` to reflect migrated classic web e2e test Closes #5295 from miinhho/fix/flaky-e2e-in-zeppelin-web. Signed-off-by: YONGJAE LEE --- .github/workflows/frontend.yml | 39 +- pom.xml | 1 - zeppelin-web-angular/e2e/AGENTS.md | 30 + zeppelin-web-angular/e2e/cleanup-util.ts | 8 +- .../classic-collaborative-mode.spec.ts | 20 + .../e2e/tests/classic/classic-home.spec.ts | 40 + .../tests/classic/classic-interpreter.spec.ts | 72 + .../classic/classic-search-block.spec.ts | 164 +++ zeppelin-web-angular/package.json | 1 + zeppelin-web-angular/playwright.config.js | 44 +- zeppelin-web/README.md | 9 +- zeppelin-web/e2e/collaborativeMode.spec.js | 72 - zeppelin-web/e2e/home.spec.js | 66 - zeppelin-web/e2e/searchBlock.spec.js | 207 --- zeppelin-web/package-lock.json | 1229 +---------------- zeppelin-web/package.json | 3 - zeppelin-web/pom.xml | 70 +- zeppelin-web/protractor.conf.js | 44 - 18 files changed, 403 insertions(+), 1716 deletions(-) create mode 100644 zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts delete mode 100644 zeppelin-web/e2e/collaborativeMode.spec.js delete mode 100644 zeppelin-web/e2e/home.spec.js delete mode 100644 zeppelin-web/e2e/searchBlock.spec.js delete mode 100644 zeppelin-web/protractor.conf.js diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index efdda51a3db..872bfe6133b 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -44,37 +44,6 @@ jobs: working-directory: zeppelin-web-angular/projects/zeppelin-react run: npm ci --ignore-scripts && npm audit --audit-level=high - run-e2e-tests-in-zeppelin-web: - runs-on: ubuntu-24.04 - steps: - - name: Checkout - uses: actions/checkout@v5 - - name: Tune Runner VM - uses: ./.github/actions/tune-runner-vm - - name: Set up JDK 11 - uses: actions/setup-java@v5 - with: - distribution: 'temurin' - java-version: 11 - - name: Cache local Maven repository - uses: actions/cache@v5 - with: - path: | - ~/.m2/repository - !~/.m2/repository/org/apache/zeppelin/ - ~/.spark-dist - ~/.cache - key: ${{ runner.os }}-zeppelin-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-zeppelin- - - name: Install application - run: ./mvnw clean install -DskipTests -am -pl zeppelin-web,zeppelin-web-angular -Pweb-classic -Pspark-scala-2.12 -Pspark-3.4 -Pweb-dist ${MAVEN_ARGS} - - name: Run headless test - run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw verify -pl zeppelin-web -Pweb-classic -Pspark-scala-2.12 -Pspark-3.4 -Pweb-dist -Pweb-e2e ${MAVEN_ARGS} - - name: Print zeppelin logs - if: always() - run: if [ -d "logs" ]; then cat logs/*; fi - run-playwright-e2e-tests: runs-on: ubuntu-24.04 env: @@ -122,7 +91,11 @@ jobs: channels: conda-forge,defaults channel-priority: strict - name: Install application - run: ./mvnw clean install -DskipTests -am -pl python,zeppelin-jupyter-interpreter,zeppelin-web-angular ${MAVEN_ARGS} + run: ./mvnw clean install -DskipTests -am -pl python,zeppelin-jupyter-interpreter,zeppelin-web,zeppelin-web-angular -Pweb-classic ${MAVEN_ARGS} + # Keeps the Karma coverage previously run by the removed zeppelin-web e2e job + - name: Run zeppelin-web unit tests + if: matrix.mode == 'anonymous' + run: ./mvnw test -pl zeppelin-web -Pweb-classic,web-unit-test ${MAVEN_ARGS} - name: Setup Zeppelin Server (Shiro.ini) run: | export ZEPPELIN_CONF_DIR=./conf @@ -136,6 +109,8 @@ jobs: mkdir -p $ZEPPELIN_E2E_TEST_NOTEBOOK_DIR echo "Created test notebook directory: $ZEPPELIN_E2E_TEST_NOTEBOOK_DIR" - name: Run headless E2E test with Maven + env: + E2E_MODE: ${{ matrix.mode }} run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw verify -pl zeppelin-web-angular -Pweb-e2e ${MAVEN_ARGS} - name: Upload Playwright Report uses: actions/upload-artifact@v6 diff --git a/pom.xml b/pom.xml index 0b3a1803014..62fe3a5b2d0 100644 --- a/pom.xml +++ b/pom.xml @@ -998,7 +998,6 @@ **/.bowerrc .editorconfig **/.eslintrc - **/protractor.conf.js **/.tmp/** **/target/** **/node/** diff --git a/zeppelin-web-angular/e2e/AGENTS.md b/zeppelin-web-angular/e2e/AGENTS.md index 3a65bff2a31..1fe1c62acff 100644 --- a/zeppelin-web-angular/e2e/AGENTS.md +++ b/zeppelin-web-angular/e2e/AGENTS.md @@ -117,6 +117,7 @@ exercised transitively and are not counted. | --- | --- | | `npm run e2e` | Full suite | | `npm run e2e:fast` | Chromium only (fast) | +| `npm run e2e:classic` | Classic `/classic` UI suite against `:8080` (needs `-Pweb-classic`) | | `npm run e2e:ui` | Playwright Test UI | | `npm run e2e:headed` | Headed run | | `npm run e2e:debug` | Step-by-step debugger | @@ -184,3 +185,32 @@ route being reimplemented, but do not build parity infrastructure ahead of need. - Keep the composed suite focused on real cross-seam user flows. Behavior that lives entirely inside one fragment belongs in that fragment's own tests; do not grow the composed suite into a per-fragment unit suite. + +## Classic UI Tests (`e2e/tests/classic/`) + +`e2e/tests/classic/` runs Playwright against the legacy AngularJS app served at +`/classic`, ported from the retired `zeppelin-web` Protractor suite. Treat it as +a frozen legacy surface: keep it at parity coverage and test new features only in +the Angular/React suites. + +- **Locators (classic exception):** the classic templates predate roles and + `data-testid`, so the role/label/text-first rule cannot apply. Sanctioned here: + element ids (`#findInput`), `ng-click="..."` / `ng-controller="..."` attribute + selectors, class selectors the legacy templates already expose (`.username`, + `.interpreterHead`), and Ace/Select2 internals. Do not add `data-testid` to the + frozen `zeppelin-web` sources. +- **Readiness:** `waitForZeppelinReady` is Angular-specific (`[ng-version]`) and + does not resolve on `/classic`; gate on a classic-visible signal instead (e.g. + the first `ParagraphCtrl` paragraph, or `.ace_text-input` attached). +- **Coverage:** `PAGES` is the Angular coverage denominator; classic pages are + intentionally outside it, so `addPageAnnotationBeforeEach` is not used here. +- **Running:** the `classic` project targets `http://localhost:8080` (Desktop + Chrome only) and needs a Zeppelin server built with `-Pweb-classic` — the + `:4200` dev server does not serve `/classic`. Run it with `npm run e2e:classic` + (sets `E2E_CLASSIC=1`); running a `tests/classic/*` file path directly is also + detected. In CI the classic project runs only in the anonymous matrix leg + (`E2E_MODE`), matching the anonymous-only legacy Protractor suite. +- **POM:** inlining locators/helpers is acceptable while the suite is this small; + if it grows, move them behind `models/classic-*.ts` / `*.util.ts`. +- The React-migration / framework-neutral-spec guidance does not apply to + `tests/classic/`. diff --git a/zeppelin-web-angular/e2e/cleanup-util.ts b/zeppelin-web-angular/e2e/cleanup-util.ts index a00678dedd8..48a0deefd5c 100644 --- a/zeppelin-web-angular/e2e/cleanup-util.ts +++ b/zeppelin-web-angular/e2e/cleanup-util.ts @@ -12,12 +12,14 @@ import { BASE_URL, E2E_TEST_FOLDER } from './models/base-page'; +const cleanupBaseUrl = process.env.PLAYWRIGHT_BASE_URL || BASE_URL; + export const cleanupTestNotebooks = async () => { try { console.log('Cleaning up test folder via API...'); // Get all notebooks and folders - const response = await fetch(`${BASE_URL}/api/notebook`); + const response = await fetch(`${cleanupBaseUrl}/api/notebook`); const data = await response.json(); if (!data.body || !Array.isArray(data.body)) { console.log('No notebooks found or invalid response format'); @@ -47,7 +49,7 @@ export const cleanupTestNotebooks = async () => { try { console.log(`Deleting test folder: ${testFolder.id} (${testFolder.path})`); - const deleteResponse = await fetch(`${BASE_URL}/api/notebook/${testFolder.id}`, { + const deleteResponse = await fetch(`${cleanupBaseUrl}/api/notebook/${testFolder.id}`, { method: 'DELETE' }); @@ -70,7 +72,7 @@ export const cleanupTestNotebooks = async () => { if (error instanceof Error && error.message.includes('ECONNREFUSED')) { console.error('Failed to connect to local server. Please start the frontend server first:'); console.error(' npm start'); - console.error(` or make sure ${BASE_URL} is running`); + console.error(` or make sure ${cleanupBaseUrl} is running`); } else { console.warn('Failed to cleanup test folder:', error); } diff --git a/zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts b/zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts new file mode 100644 index 00000000000..afc9935d0f3 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/classic/classic-collaborative-mode.spec.ts @@ -0,0 +1,20 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test } from '@playwright/test'; + +test.describe('Classic collaborative mode', () => { + // TODO: Port the disabled Protractor collaborative editing scenario from + // zeppelin-web/e2e/collaborativeMode.spec.js when collaborative mode coverage is restored. + // See https://issues.apache.org/jira/browse/ZEPPELIN-5674. + test.fixme('propagates edits across browser sessions', async () => {}); +}); diff --git a/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts b/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts new file mode 100644 index 00000000000..c20d5ebfe15 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/classic/classic-home.spec.ts @@ -0,0 +1,40 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page, test } from '@playwright/test'; + +const CLASSIC_HOME = '/classic'; + +const waitForClassicHomeReady = async (page: Page) => { + await page.goto(CLASSIC_HOME, { waitUntil: 'domcontentloaded' }); + await expect(page.locator('#welcome')).toHaveText('Welcome to Zeppelin!', { timeout: 30000 }); + await expect(page.getByRole('link', { name: /Import note/ })).toBeVisible(); + await expect(page.getByRole('link', { name: /Create new note/ })).toBeVisible(); +}; + +test.describe('Classic home', () => { + test.beforeEach(async ({ page }) => { + await waitForClassicHomeReady(page); + }); + + test('should have a welcome message', async ({ page }) => { + await expect(page.locator('#welcome')).toHaveText('Welcome to Zeppelin!'); + }); + + test('should have the button for importing notebook', async ({ page }) => { + await expect(page.getByRole('link', { name: /Import note/ })).toBeVisible(); + }); + + test('should have the button for creating notebook', async ({ page }) => { + await expect(page.getByRole('link', { name: /Create new note/ })).toBeVisible(); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts b/zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts new file mode 100644 index 00000000000..f0453a8fcd3 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/classic/classic-interpreter.spec.ts @@ -0,0 +1,72 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page, test } from '@playwright/test'; + +const CLASSIC_HOME = '/classic'; + +const waitForClassicHomeReady = async (page: Page) => { + await page.goto(CLASSIC_HOME, { waitUntil: 'domcontentloaded' }); + await expect(page.locator('#welcome')).toHaveText('Welcome to Zeppelin!', { timeout: 30000 }); + await expect(page.getByRole('link', { name: /Import note/ })).toBeVisible(); + await expect(page.getByRole('link', { name: /Create new note/ })).toBeVisible(); +}; + +test.describe('Classic interpreter', () => { + test.beforeEach(async ({ page }) => { + await waitForClassicHomeReady(page); + }); + + test('correct save permission in interpreter', async ({ page }) => { + const ownerName = 'admin'; + const interpreterName = `interpreter_e2e_test_${Date.now()}`; + + await page.locator('.username').click(); + await page.locator('a[href="#/interpreter"]').click(); + await expect(page.locator('.interpreterHead')).toBeVisible({ timeout: 30000 }); + + await page.locator('button[ng-click="showAddNewSetting = !showAddNewSetting"]').click(); + const createForm = page.locator('.interpreterSettingAdd'); + await expect(createForm).toBeVisible(); + await createForm.locator('#newInterpreterSettingName').fill(interpreterName); + await createForm.locator('select[ng-model="newInterpreterSetting.group"]').selectOption({ label: 'angular' }); + await createForm.locator('#idShowPermission').check(); + + const ownerInput = createForm.locator('input.select2-search__field'); + await ownerInput.fill(ownerName); + // JUSTIFIED: Select2 can render grouped AJAX/tag candidates; the final visible option is the concrete typed owner. + const ownerOption = page.locator('.select2-results__option').filter({ hasText: ownerName }).last(); + await expect(ownerOption).toBeVisible({ timeout: 30000 }); + await ownerInput.press('Enter'); + await expect(createForm.locator('.select2-selection__choice', { hasText: ownerName })).toBeVisible(); + + await createForm.locator('span[ng-click="addNewInterpreterSetting()"]').click(); + + let setting = page.locator(`#${interpreterName}`); + await expect(setting).toBeVisible({ timeout: 30000 }); + + await setting.locator('span.fa-pencil').click(); + await setting.locator('button[type="submit"]').click(); + await page.locator('.bootstrap-dialog-footer-buttons button', { hasText: 'OK' }).click(); + + await page.goto('/classic/#/interpreter', { waitUntil: 'domcontentloaded' }); + await expect(page.locator('.interpreterHead')).toBeVisible({ timeout: 30000 }); + setting = page.locator(`#${interpreterName}`); + await expect(setting.locator(`select[id="${interpreterName}Owners"] option`)).toHaveText(ownerName, { + timeout: 30000 + }); + + await setting.locator('span.fa-trash').click(); + await page.locator('.bootstrap-dialog-footer-buttons button', { hasText: 'OK' }).click(); + await expect(setting).toBeHidden({ timeout: 30000 }); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts b/zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts new file mode 100644 index 00000000000..72d36f09b6b --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/classic/classic-search-block.spec.ts @@ -0,0 +1,164 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page, test } from '@playwright/test'; +import { createTestNotebookWithName } from '../../utils'; + +const testData = { + textInFirstP: 'text word text', + textInSecondP: 'text tete tt' +}; + +const countSubstringOccurrence = (text: string, substring: string): number => + substring ? text.split(substring).length - 1 : 0; + +const expectedMatchCount = (substring: string): number => + countSubstringOccurrence(testData.textInFirstP, substring) + + countSubstringOccurrence(testData.textInSecondP, substring); + +const waitForClassicNotebookReady = async (page: Page, noteId: string) => { + await page.goto(`/classic/#/notebook/${noteId}`, { waitUntil: 'domcontentloaded' }); + // JUSTIFIED: Classic note setup creates a single first paragraph; this is the render gate for that paragraph. + await expect(page.locator('div[ng-controller="ParagraphCtrl"]').first()).toBeVisible({ timeout: 30000 }); + // JUSTIFIED: The first Ace textarea belongs to the first paragraph created with the note. + await expect(page.locator('.ace_text-input').first()).toBeAttached({ timeout: 30000 }); +}; + +const fillAceEditor = async (page: Page, index: number, text: string) => { + // JUSTIFIED: The tests intentionally fill paragraph editors by creation order: first paragraph, then inserted second paragraph. + const editor = page.locator('.ace_editor').nth(index); + await editor.click(); + await page.keyboard.type(text); + await expect(editor.locator('.ace_line', { hasText: text })).toBeVisible({ timeout: 15000 }); +}; + +const makeTestParagraphs = async (page: Page) => { + await fillAceEditor(page, 0, testData.textInFirstP); + + await page.locator('.new-paragraph.last-paragraph').click(); + await expect(page.locator('.ace_editor')).toHaveCount(2, { timeout: 15000 }); + await fillAceEditor(page, 1, testData.textInSecondP); +}; + +const openSearchBoxByShortcut = async (page: Page) => { + await page.keyboard.press('Control+Alt+F'); + await expect(page.locator('.search-dropdown')).toBeVisible({ timeout: 10000 }); +}; + +const findInput = (page: Page) => page.locator('#findInput'); +const replaceInput = (page: Page) => page.locator('.search-group', { hasText: 'Replace' }).locator('input'); +const matchesElement = (page: Page) => page.locator('.search-group .after-input'); +const nextOccurrenceButton = (page: Page) => page.locator('.search-group button[ng-click="nextOccurrence()"]'); +const prevOccurrenceButton = (page: Page) => page.locator('.search-group button[ng-click="prevOccurrence()"]'); +const replaceButton = (page: Page) => page.locator('.search-group button[ng-click="replace()"]'); +const replaceAllButton = (page: Page) => page.locator('.search-group button[ng-click="replaceAll()"]'); + +const setFindText = async (page: Page, text: string) => { + await findInput(page).fill(text); +}; + +const waitForMatches = async (page: Page, current: number, amount: number) => { + await expect(matchesElement(page)).toHaveText(`${current} of ${amount}`, { timeout: 15000 }); +}; + +const markerCount = async (page: Page): Promise => + page.locator('.ace_marker-layer div.ace_selected-word, .ace_marker-layer div.ace_selection').count(); + +test.describe('Classic search block', () => { + test.beforeEach(async ({ page }) => { + const { noteId } = await createTestNotebookWithName(page, { + namePrefix: 'ClassicSearchBlock' + }); + await waitForClassicNotebookReady(page, noteId); + }); + + test('shortcut works', async ({ page }) => { + // JUSTIFIED: The keyboard shortcut is scoped to the currently focused first paragraph editor. + await page.locator('.ace_editor').first().click(); + await openSearchBoxByShortcut(page); + }); + + test('correct count of selections', async ({ page }) => { + await makeTestParagraphs(page); + await openSearchBoxByShortcut(page); + + const textToFind = 'te'; + const matchesCount = expectedMatchCount(textToFind); + await setFindText(page, textToFind); + + await waitForMatches(page, 1, matchesCount); + await expect.poll(() => markerCount(page), { timeout: 15000 }).toBe(matchesCount + 1); + }); + + test('correct matches count number', async ({ page }) => { + await makeTestParagraphs(page); + await openSearchBoxByShortcut(page); + + let textToFind = 't'; + await setFindText(page, textToFind); + await waitForMatches(page, 1, expectedMatchCount(textToFind)); + + textToFind = 'te'; + await setFindText(page, textToFind); + await waitForMatches(page, 1, expectedMatchCount(textToFind)); + }); + + test('counter increase and decrease correctly', async ({ page }) => { + await makeTestParagraphs(page); + await openSearchBoxByShortcut(page); + + const textToFind = 'te'; + const matchesCount = expectedMatchCount(textToFind); + await setFindText(page, textToFind); + await waitForMatches(page, 1, matchesCount); + + await nextOccurrenceButton(page).click(); + await waitForMatches(page, matchesCount > 1 ? 2 : 1, matchesCount); + + await prevOccurrenceButton(page).click(); + await waitForMatches(page, 1, matchesCount); + + await prevOccurrenceButton(page).click(); + await waitForMatches(page, matchesCount, matchesCount); + }); + + test('matches count changes correctly after replace', async ({ page }) => { + await makeTestParagraphs(page); + await openSearchBoxByShortcut(page); + + const textToFind = 'te'; + const matchesCount = expectedMatchCount(textToFind); + await setFindText(page, textToFind); + await waitForMatches(page, 1, matchesCount); + await replaceInput(page).fill('ABC'); + + await replaceButton(page).click(); + await waitForMatches(page, 1, matchesCount - 1); + + await prevOccurrenceButton(page).click(); + await replaceButton(page).click(); + await waitForMatches(page, 1, matchesCount - 2); + }); + + test('replace all works correctly', async ({ page }) => { + await makeTestParagraphs(page); + await openSearchBoxByShortcut(page); + + const textToFind = 'te'; + await setFindText(page, textToFind); + await waitForMatches(page, 1, expectedMatchCount(textToFind)); + await replaceInput(page).fill('ABC'); + + await replaceAllButton(page).click(); + await waitForMatches(page, 0, 0); + }); +}); diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 5e84360608e..441c4cb5eab 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -21,6 +21,7 @@ "test:eslint-rules": "node --test eslint-rules/", "e2e": "playwright test", "e2e:fast": "playwright test --project=chromium", + "e2e:classic": "cross-env E2E_CLASSIC=1 playwright test --project=classic", "e2e:ui": "playwright test --ui", "e2e:headed": "playwright test --headed", "e2e:debug": "playwright test --debug", diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index bc1bd46ebd5..4e019e8fd52 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -12,6 +12,11 @@ const { defineConfig, devices } = require('@playwright/test'); +const classicTests = /tests\/classic\/.*\.spec\.ts/; +const isClassicOnlyRun = process.env.E2E_CLASSIC === '1' || process.argv.some(arg => arg.includes('tests/classic')); +const defaultBaseURL = process.env.CI || isClassicOnlyRun ? 'http://localhost:8080' : 'http://localhost:4200'; +process.env.PLAYWRIGHT_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || defaultBaseURL; + // https://playwright.dev/docs/test-configuration module.exports = defineConfig({ testDir: './e2e', @@ -31,7 +36,7 @@ module.exports = defineConfig({ ['./e2e/reporter.coverage.ts'] ], use: { - baseURL: process.env.CI ? 'http://localhost:8080' : 'http://localhost:4200', + baseURL: process.env.PLAYWRIGHT_BASE_URL, trace: 'on-first-retry', // https://playwright.dev/docs/trace-viewer screenshot: process.env.CI ? 'off' : 'only-on-failure', video: process.env.CI ? 'off' : 'retain-on-failure', @@ -50,8 +55,24 @@ module.exports = defineConfig({ name: 'setup', testMatch: /global\.setup\.ts/ }, + // skip classic in the auth CI leg (its Protractor predecessor was anonymous-only) + ...(process.env.E2E_MODE === 'auth' + ? [] + : [ + { + name: 'classic', + testMatch: classicTests, + use: { + ...devices['Desktop Chrome'], + baseURL: 'http://localhost:8080', + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] + } + ]), { name: 'chromium', + testIgnore: classicTests, use: { ...devices['Desktop Chrome'], permissions: ['clipboard-read', 'clipboard-write'], @@ -61,6 +82,7 @@ module.exports = defineConfig({ }, { name: 'Google Chrome', + testIgnore: classicTests, use: { ...devices['Desktop Chrome'], channel: 'chrome', @@ -71,6 +93,7 @@ module.exports = defineConfig({ }, { name: 'firefox', + testIgnore: classicTests, use: { ...devices['Desktop Firefox'], storageState: 'playwright/.auth/user.json' @@ -79,6 +102,7 @@ module.exports = defineConfig({ }, { name: 'webkit', + testIgnore: classicTests, use: { ...devices['Desktop Safari'], launchOptions: { @@ -90,6 +114,7 @@ module.exports = defineConfig({ }, { name: 'Microsoft Edge', + testIgnore: classicTests, use: { ...devices['Desktop Edge'], channel: 'msedge', @@ -99,12 +124,13 @@ module.exports = defineConfig({ dependencies: ['setup'] } ], - webServer: process.env.CI - ? undefined - : { - command: 'npm run start', - url: 'http://localhost:4200', - reuseExistingServer: true, - timeout: 2 * 60 * 1000 - } + webServer: + process.env.CI || isClassicOnlyRun + ? undefined + : { + command: 'npm run start', + url: 'http://localhost:4200', + reuseExistingServer: true, + timeout: 2 * 60 * 1000 + } }); diff --git a/zeppelin-web/README.md b/zeppelin-web/README.md index a7ab7117004..4023f14d873 100644 --- a/zeppelin-web/README.md +++ b/zeppelin-web/README.md @@ -40,12 +40,15 @@ $ WEB_PORT=YOUR_WEB_DEV_PORT npm run dev # running unit tests $ npm run karma-test -# running e2e tests: make sure that zeppelin instance started (localhost:8080) -$ npm run e2e +# running unit tests through Maven (requires node_modules from a prior build) +$ (cd .. && ./mvnw test -pl zeppelin-web -Pweb-classic,web-unit-test) + +# running classic UI e2e tests: make sure that a Zeppelin instance started (localhost:8080) +$ cd ../zeppelin-web-angular && npm run e2e:classic ``` - to write unit tests, please refer [Angular Test Patterns](https://github.com/daniellmb/angular-test-patterns) -- to write e2e tests, please refer [Protractor Tutorial](http://www.protractortest.org/#/tutorial#step-1-interacting-with-elements) +- to write e2e tests, please refer to the Playwright tests under `zeppelin-web-angular/e2e` ### Packaging diff --git a/zeppelin-web/e2e/collaborativeMode.spec.js b/zeppelin-web/e2e/collaborativeMode.spec.js deleted file mode 100644 index 2c3dc1196ee..00000000000 --- a/zeppelin-web/e2e/collaborativeMode.spec.js +++ /dev/null @@ -1,72 +0,0 @@ -// Disable this test temporarily, See https://issues.apache.org/jira/browse/ZEPPELIN-5674 -// describe('Collaborative mode tests', function () { -// -// let clickOn = function(elem) { -// browser.actions().mouseMove(elem).click().perform() -// }; -// -// let waitVisibility = function(elem) { -// browser.wait(protractor.ExpectedConditions.visibilityOf(elem)) -// }; -// -// let test_text_1 = "_one_more_text_for_tests"; // without space!!! -// let test_text_2 = "Collaborative_mode_test_text"; // without space!!! -// -// browser.get('http://localhost:8080/classic'); -// clickOn(element(by.linkText('Create new note'))); -// waitVisibility(element(by.id('noteCreateModal'))); -// clickOn(element(by.id('createNoteButton'))); -// let user1Browser = browser.forkNewDriverInstance(); -// let user2Browser = browser.forkNewDriverInstance(); -// browser.getCurrentUrl().then(function (url) { -// user1Browser.get(url); -// user2Browser.get(url); -// }); -// waitVisibility(element(by.xpath('//*[@uib-tooltip="Users who watch this note: anonymous"]'))); -// browser.sleep(500); -// -// it('user 1 received the first patch', function () { -// browser.switchTo().activeElement().sendKeys(test_text_1); -// browser.sleep(500); -// user1Browser.isElementPresent(by.xpath('//span[contains(text(), \'' + test_text_1 + '\')]')) -// .then(function (isPresent) { -// expect(isPresent).toBe(true); -// }); -// }); -// -// it('user 2 received the first patch', function () { -// user2Browser.isElementPresent(by.xpath('//span[contains(text(), \'' + test_text_1 + '\')]')) -// .then(function (isPresent) { -// expect(isPresent).toBe(true); -// }); -// }); -// -// it('user root received a first patch', function () { -// user1Browser.switchTo().activeElement().sendKeys(test_text_2); -// user1Browser.sleep(500); -// browser.isElementPresent(by.xpath('//span[contains(text(), \'' + test_text_2 + -// test_text_1 + '\')]')).then(function (isPresent) { -// expect(isPresent).toBe(true); -// }); -// }); -// -// it('user 2 received the second patch', function () { -// user2Browser.isElementPresent(by.xpath('//span[contains(text(), \'' + test_text_2 + -// test_text_1 + '\')]')).then(function (isPresent) { -// expect(isPresent).toBe(true); -// }); -// }); -// -// it('finish', function () { -// user1Browser.close(); -// user2Browser.close(); -// clickOn(element(by.xpath('//*[@id="main"]//button[@ng-click="moveNoteToTrash(note.id)"]'))); -// let moveToTrashDialogPath = -// '//div[@class="modal-dialog"][contains(.,"This note will be moved to trash")]'; -// waitVisibility(element(by.xpath(moveToTrashDialogPath))); -// let okButton = element( -// by.xpath(moveToTrashDialogPath + '//div[@class="modal-footer"]//button[contains(.,"OK")]')); -// clickOn(okButton); -// }); -// -// }); diff --git a/zeppelin-web/e2e/home.spec.js b/zeppelin-web/e2e/home.spec.js deleted file mode 100644 index 7a9dde07593..00000000000 --- a/zeppelin-web/e2e/home.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -describe('Home e2e Test', function() { - /*Common methods for interact with elements*/ - let clickOn = function(elem) { - browser.actions().mouseMove(elem).click().perform() - } - - let sendKeysToInput = function(input, keys) { - cleanInput(input) - input.sendKeys(keys) - } - - let cleanInput = function(inputElem) { - inputElem.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, "a")) - inputElem.sendKeys(protractor.Key.BACK_SPACE) - } - - let scrollToElementAndClick = function(elem) { - browser.executeScript("arguments[0].scrollIntoView(false);", elem.getWebElement()) - browser.sleep(300) - clickOn(elem) - } - - //tests - it('should have a welcome message', function() { - browser.get('http://localhost:8080/classic'); - browser.sleep(500); - var welcomeElem = element(by.id('welcome')) - - expect(welcomeElem.getText()).toEqual('Welcome to Zeppelin!') - }) - - it('should have the button for importing notebook', function() { - var btn = element(by.cssContainingText('a', 'Import note')) - expect(btn.isPresent()).toBe(true) - }) - - it('should have the button for creating notebook', function() { - var btn = element(by.cssContainingText('a', 'Create new note')) - expect(btn.isPresent()).toBe(true) - }) - - it('correct save permission in interpreter', function() { - var ownerName = 'admin' - var interpreterName = 'interpreter_e2e_test' - clickOn(element(by.xpath('//span[@class="username ng-binding"]'))) - clickOn(element(by.xpath('//a[@href="#/interpreter"]'))) - clickOn(element(by.xpath('//button[@ng-click="showAddNewSetting = !showAddNewSetting"]'))) - sendKeysToInput(element(by.xpath('//input[@id="newInterpreterSettingName"]')), interpreterName) - clickOn(element(by.xpath('//select[@ng-model="newInterpreterSetting.group"]'))) - browser.sleep(500) - browser.actions().sendKeys('angular').perform() - clickOn(element(by.xpath('//div[@ng-show="showAddNewSetting"]//input[@id="idShowPermission"]'))) - sendKeysToInput(element(by.xpath('//div[@ng-show="showAddNewSetting"]//input[@class="select2-search__field"]')), ownerName) - browser.sleep(500) - browser.actions().sendKeys(protractor.Key.ENTER).perform() - scrollToElementAndClick(element(by.xpath('//span[@ng-click="addNewInterpreterSetting()"]'))) - scrollToElementAndClick(element(by.xpath('//*[@id="' + interpreterName + '"]//span[@class="fa fa-pencil"]'))) - scrollToElementAndClick(element(by.xpath('//*[@id="' + interpreterName + '"]//button[@type="submit"]'))) - clickOn(element(by.xpath('//div[@class="bootstrap-dialog-footer-buttons"]//button[contains(text(), \'OK\')]'))) - browser.get('http://localhost:8080/classic/#/interpreter'); - var text = element(by.xpath('//*[@id="' + interpreterName + '"]//li[contains(text(), \'admin\')]')).getText() - scrollToElementAndClick(element(by.xpath('//*[@id="' + interpreterName + '"]//span//span[@class="fa fa-trash"]'))) - clickOn(element(by.xpath('//div[@class="bootstrap-dialog-footer-buttons"]//button[contains(text(), \'OK\')]'))) - expect(text).toEqual(ownerName); - }) -}) diff --git a/zeppelin-web/e2e/searchBlock.spec.js b/zeppelin-web/e2e/searchBlock.spec.js deleted file mode 100644 index af59f42c0dc..00000000000 --- a/zeppelin-web/e2e/searchBlock.spec.js +++ /dev/null @@ -1,207 +0,0 @@ -describe('Search block e2e Test', function() { - let testData = { - textInFirstP: 'text word text', - textInSecondP: 'text tete tt' - } - - /*Common methods for interact with elements*/ - let clickOn = function(elem) { - browser.actions().mouseMove(elem).click().perform() - } - - let clickAndWait = function(elem){ - clickOn(elem) - browser.sleep(60); - } - - let waitVisibility = function(elem) { - browser.wait(protractor.ExpectedConditions.visibilityOf(elem)) - } - - beforeEach(function() { - browser.get('http://localhost:8080/classic') - browser.sleep(500); - waitVisibility(element(by.linkText('Create new note'))) - clickOn(element(by.linkText('Create new note'))) - waitVisibility(element(by.id('noteCreateModal'))) - clickAndWait(element(by.id('createNoteButton'))) - }) - - afterEach(function() { - clickOn(element(by.xpath('//*[@id="main"]//button[@ng-click="moveNoteToTrash(note.id)"]'))) - let moveToTrashDialogPath = - '//div[@class="modal-dialog"][contains(.,"This note will be moved to trash")]' - waitVisibility(element(by.xpath(moveToTrashDialogPath))) - let okButton = element( - by.xpath(moveToTrashDialogPath + '//div[@class="modal-footer"]//button[contains(.,"OK")]')) - clickOn(okButton) - }) - - /*Getting elements*/ - let getFindInput = function() { - return element(by.id('findInput')) - } - - let getReplaceInput = function() { - return element( - by.xpath('//div[contains(@class, "search-group")]//span[text()="Replace"]//..//input')) - } - - let getNextOccurrenceButton = function() { - return element(by.xpath('//div[contains(@class, "search-group")]' + - '/div/button[@ng-click="nextOccurrence()"]')) - } - - let getPrevOccurrenceButton = function() { - return element(by.xpath('//div[contains(@class, "search-group")]' + - '/div/button[@ng-click="prevOccurrence()"]')) - } - - let getReplaceButton = function() { - return element(by.xpath('//div[contains(@class, "search-group")]//button[@ng-click="replace()"]')) - } - - let getReplaceAllButton = function() { - return element( - by.xpath('//div[contains(@class, "search-group")]//button[@ng-click="replaceAll()"]')) - } - - let getMatchesElement = function() { - return element(by.xpath('//div[contains(@class, "search-group")]' + - '//span[contains(@class, "after-input")]')) - } - - /*Require: focus on any paragraph editor*/ - let openSearchBoxByShortcut = function() { - browser.switchTo().activeElement().sendKeys(protractor.Key.chord(protractor.Key.CONTROL, - protractor.Key.ALT, "f")) - } - - let countSubstringOccurrence = function(s, subs) { - return (s.match(new RegExp(subs,"g")) || []).length - } - - let cleanInput = function(inputElem) { - inputElem.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, "a")) - inputElem.sendKeys(protractor.Key.BACK_SPACE) - } - - let checkFind = function(findInput, text, expectedMatchesCount) { - cleanInput(findInput) - findInput.sendKeys(text) - let matchesCount = element(by.xpath('//div[contains(@class, "search-group")]' + - '//span[contains(@class, "after-input")]')) - matchesCount.getText().then(function(text) { - expect(text.indexOf((expectedMatchesCount === 0 ? 0 : 1) + ' of ' + - expectedMatchesCount) !== -1).toBe(true) - }) - } - - let makeTestParagraphs = function() { - waitVisibility(element(by.repeater('currentParagraph in note.paragraphs'))) - browser.switchTo().activeElement().sendKeys(testData.textInFirstP) - let addBelow = element( - by.xpath('//div[@class="new-paragraph last-paragraph" and @ng-click="insertNew(\'below\');"]')) - clickAndWait(addBelow) - browser.switchTo().activeElement().sendKeys(testData.textInSecondP) - } - - let checkMatchesElement = function(elem, current, amount) { - elem.getText().then(function(text) { - expect(text.indexOf(current + ' of ' + amount) !== -1).toBe(true)}) - } - - let sendKeysToInput = function(input, keys) { - cleanInput(input) - input.sendKeys(keys) - } - - let sendKeysToFindInput = function(keys) { - sendKeysToInput(getFindInput(), keys) - } - - let sendKeysToReplaceInput = function(keys) { - sendKeysToInput(getReplaceInput(), keys) - } - - /*Tests*/ - it('shortcut works', function() { - waitVisibility(element(by.repeater('currentParagraph in note.paragraphs'))) - openSearchBoxByShortcut() - expect(element(by.xpath('//ul[contains(@class,"search-dropdown")]')).isDisplayed()).toBeTruthy() - }) - - it('correct count of selections', function() { - makeTestParagraphs() - openSearchBoxByShortcut() - let subs = 'te' - sendKeysToFindInput(subs) - var markers = element.all(by.xpath('//code-editor/div/div[@class="ace_scroller"]' + - '/div[@class="ace_content"]/div[@class="ace_layer ace_marker-layer"]/div')) - expect(markers.count()).toEqual(countSubstringOccurrence(testData.textInFirstP, subs) + - countSubstringOccurrence(testData.textInSecondP, subs) + 1) - }) - - it('correct matches count number', function() { - makeTestParagraphs() - openSearchBoxByShortcut() - let findInput = getFindInput() - clickAndWait(findInput) - let subs = 't'; - checkFind(findInput, subs, countSubstringOccurrence(testData.textInFirstP, subs) + - countSubstringOccurrence(testData.textInSecondP, subs)) - subs = 'te'; - checkFind(findInput, subs, countSubstringOccurrence(testData.textInFirstP, subs) + - countSubstringOccurrence(testData.textInSecondP, subs)) - }) - - it('counter increase and decrease correctly', function() { - makeTestParagraphs() - openSearchBoxByShortcut() - let subs = 'te' - sendKeysToFindInput(subs) - let matchesElement = getMatchesElement() - let matchesCount = countSubstringOccurrence(testData.textInFirstP, subs) + - countSubstringOccurrence(testData.textInSecondP, subs) - checkMatchesElement(matchesElement, matchesCount > 0 ? 1 : 0, matchesCount) - let nextOccurrenceButton = getNextOccurrenceButton() - let prevOccurrenceButton = getPrevOccurrenceButton() - clickOn(nextOccurrenceButton) - checkMatchesElement(matchesElement, matchesCount > 1 ? 2 : 1, matchesCount) - clickOn(prevOccurrenceButton) - checkMatchesElement(matchesElement, 1, matchesCount) - clickOn(prevOccurrenceButton) - checkMatchesElement(matchesElement, matchesCount, matchesCount) - }) - - it('matches count changes correctly after replace', function() { - makeTestParagraphs() - openSearchBoxByShortcut() - let textToFind = 'te' - sendKeysToFindInput(textToFind) - let matchesElement = getMatchesElement() - let matchesCount = countSubstringOccurrence(testData.textInFirstP, textToFind) + - countSubstringOccurrence(testData.textInSecondP, textToFind) - sendKeysToReplaceInput('ABC') - let replaceButton = getReplaceButton() - clickOn(replaceButton) - checkMatchesElement(matchesElement, 1, matchesCount - 1) - clickOn(getPrevOccurrenceButton()) - clickOn(replaceButton) - checkMatchesElement(matchesElement, 1, matchesCount - 2) - }) - - it('replace all works correctly', function() { - makeTestParagraphs() - openSearchBoxByShortcut() - let textToFind = 'te' - sendKeysToFindInput(textToFind) - let matchesElement = getMatchesElement() - let matchesCount = countSubstringOccurrence(testData.textInFirstP, textToFind) + - countSubstringOccurrence(testData.textInSecondP, textToFind) - sendKeysToReplaceInput('ABC') - let replaceAllButton = getReplaceAllButton() - clickOn(replaceAllButton) - checkMatchesElement(matchesElement, 0, 0) - }) -}) diff --git a/zeppelin-web/package-lock.json b/zeppelin-web/package-lock.json index 5c97c383095..19a8f4b58b6 100644 --- a/zeppelin-web/package-lock.json +++ b/zeppelin-web/package-lock.json @@ -115,7 +115,6 @@ "ng-annotate-loader": "^0.2.0", "npm-run-all": "^4.1.5", "postcss-loader": "^3.0.0", - "protractor": "^5.4.1", "raw-loader": "^0.5.1", "rimraf": "^3.0.2", "string-replace-webpack-plugin": "^0.1.3", @@ -258,12 +257,6 @@ "@types/node": "*" } }, - "node_modules/@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -282,12 +275,6 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.26", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", - "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -615,33 +602,12 @@ "node": ">=0.4.0" } }, - "node_modules/adm-zip": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", - "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", - "dev": true, - "engines": { - "node": ">=12.0" - } - }, "node_modules/after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==", "dev": true }, - "node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1243,24 +1209,6 @@ "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, "node_modules/asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", @@ -1288,15 +1236,6 @@ "util": "^0.10.4" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/assert/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", @@ -1347,12 +1286,6 @@ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", "dev": true }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, "node_modules/atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -1394,21 +1327,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", - "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==", - "dev": true - }, "node_modules/babel-cli": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", @@ -2263,15 +2181,6 @@ "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/better-assert": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", @@ -2318,21 +2227,6 @@ "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" - }, - "engines": { - "node": ">=6.9.x" - } - }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2516,15 +2410,6 @@ "browserslist": "cli.js" } }, - "node_modules/browserstack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - } - }, "node_modules/buffer": { "version": "4.9.2", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", @@ -2741,15 +2626,6 @@ "upper-case": "^1.1.1" } }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", @@ -2810,12 +2686,6 @@ } ] }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, "node_modules/center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -3072,60 +2942,6 @@ "tiny-emitter": "^1.0.0" } }, - "node_modules/cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "dependencies": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -3292,18 +3108,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -3943,18 +3747,6 @@ "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==" }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -4280,72 +4072,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", - "dev": true, - "dependencies": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", - "dev": true, - "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/delegate": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", @@ -4592,16 +4318,6 @@ "node": ">=0.10.0" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -5047,21 +4763,6 @@ "event-emitter": "~0.3.5" } }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dev": true, - "dependencies": { - "es6-promise": "^4.0.3" - } - }, - "node_modules/es6-promisify/node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, "node_modules/es6-set": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.6.tgz", @@ -6037,24 +5738,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha512-9mDDwqVIma6OZX79ZlDACZl8sBm0TEnkf99zV3iMA4GzkIT/9hiqP5mY0HoT1iNLCrKc/R1HByV+yJfRWVJryQ==" }, - "node_modules/execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "dependencies": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -6194,15 +5877,6 @@ "node": ">=0.10.0" } }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6577,29 +6251,6 @@ "node": ">=0.10.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -6755,12 +6406,6 @@ "is-property": "^1.0.0" } }, - "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -6789,28 +6434,6 @@ "node": ">=0.10.0" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/get-stream/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", @@ -6845,15 +6468,6 @@ "node": ">= 0.8.0" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/github-markdown-css": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-2.6.0.tgz", @@ -8062,36 +7676,13 @@ "node": ">=0.8.0" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "dev": true, "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" + "node": ">= 0.4.0" } }, "node_modules/has-ansi": { @@ -8928,55 +8519,12 @@ "node": ">=8.0" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, "node_modules/https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", "dev": true }, - "node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -9036,12 +8584,6 @@ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", "dev": true }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true - }, "node_modules/import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -9257,12 +8799,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "node_modules/inquirer": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", @@ -9322,15 +8858,6 @@ "loose-envify": "^1.0.0" } }, - "node_modules/invert-kv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", - "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -9674,39 +9201,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", - "dev": true, - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -9791,15 +9285,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-string": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", @@ -9857,12 +9342,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, "node_modules/is-upper-case": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", @@ -9943,12 +9422,6 @@ "node": ">=0.10.0" } }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, "node_modules/istanbul": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", @@ -10093,20 +9566,6 @@ "which": "bin/which" } }, - "node_modules/jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", - "dev": true, - "dependencies": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" - }, - "bin": { - "jasmine": "bin/jasmine.js" - } - }, "node_modules/jasmine-core": { "version": "3.99.1", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", @@ -10131,21 +9590,6 @@ "node": ">=0.1.90" } }, - "node_modules/jasmine/node_modules/jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true - }, - "node_modules/jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", - "dev": true, - "engines": { - "node": ">= 6.9.x" - } - }, "node_modules/jquery": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", @@ -10205,12 +9649,6 @@ "node": ">=4" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, "node_modules/jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", @@ -10387,12 +9825,6 @@ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -10417,12 +9849,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, "node_modules/json3": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", @@ -10455,21 +9881,6 @@ "node": ">=0.10.0" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/jszip": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.6.1.tgz", @@ -11004,18 +10415,6 @@ "node": ">=0.10.0" } }, - "node_modules/lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "dev": true, - "dependencies": { - "invert-kv": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -11029,15 +10428,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/load-grunt-tasks": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-0.4.0.tgz", @@ -11339,18 +10729,6 @@ "node": ">=4" } }, - "node_modules/map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "dev": true, - "dependencies": { - "p-defer": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -11469,20 +10847,6 @@ "node": ">= 0.6" } }, - "node_modules/mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "dev": true, - "dependencies": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/memfs": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", @@ -12284,11 +11648,10 @@ } }, "node_modules/node-gyp-build": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", - "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "dev": true, - "license": "MIT", "optional": true, "peer": true, "bin": { @@ -12472,18 +11835,6 @@ "node": ">=4" } }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -12518,15 +11869,6 @@ "d3": "^3.4.4" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -12857,20 +12199,6 @@ "node": ">=0.10.0" } }, - "node_modules/os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "dev": true, - "dependencies": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -12891,33 +12219,6 @@ "object-assign": "^4.1.0" } }, - "node_modules/p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -13197,12 +12498,6 @@ "node": ">= 0.8.0" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, "node_modules/picocolors": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", @@ -14128,48 +13423,6 @@ "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", "dev": true }, - "node_modules/protractor": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.4.4.tgz", - "integrity": "sha512-BaL4vePgu3Vfa/whvTUAlgaCAId4uNSGxIFSCXMgj7LMYENPWLp85h5RBi9pdpX/bWQ8SF6flP7afmi2TC4eHw==", - "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", - "dev": true, - "dependencies": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.0.6", - "yargs": "^12.0.5" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/protractor/node_modules/q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -14195,12 +13448,6 @@ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, "node_modules/public-encrypt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", @@ -15078,56 +14325,6 @@ "node": ">=0.10.0" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -15137,12 +14334,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", - "dev": true - }, "node_modules/require-uncached": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", @@ -15415,18 +14606,6 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/sax": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", @@ -15468,58 +14647,6 @@ "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz", "integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==" }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", - "dev": true, - "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "engines": { - "node": ">= 6.9.0" - } - }, - "node_modules/selenium-webdriver/node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "dev": true, - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/selfsigned": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", @@ -15685,12 +14812,6 @@ "node": ">= 0.8.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -16312,31 +15433,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ssri": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", @@ -16695,15 +15791,6 @@ "node": ">=4" } }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -17572,28 +16659,6 @@ "integrity": "sha512-FclLrw8b9bMWf4QlCJuHBEVhSRsqDj6u3nIjAzPeJvgl//1hBlffdlk0MALceL14+koWEdU4ofRAXofbODxQzg==", "dev": true }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tough-cookie/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", @@ -17648,24 +16713,6 @@ "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==", "dev": true }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, "node_modules/type": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz", @@ -18237,26 +17284,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, "node_modules/vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -18785,57 +17812,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/webdriver-js-extender": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", - "dev": true, - "dependencies": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", - "dev": true, - "dependencies": { - "adm-zip": "^0.5.2", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/webpack": { "version": "4.47.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.47.0.tgz", @@ -19165,12 +18141,11 @@ } }, "node_modules/webpack-dev-server/node_modules/bufferutil": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", - "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -19352,12 +18327,11 @@ } }, "node_modules/webpack-dev-server/node_modules/utf-8-validate": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.4.tgz", - "integrity": "sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz", + "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "peer": true, "dependencies": { @@ -19719,12 +18693,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, "node_modules/which-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", @@ -19782,19 +18750,6 @@ "errno": "~0.1.7" } }, - "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -19833,28 +18788,6 @@ "integrity": "sha512-NpTtJIGjrofxyTNuc497ZTI/LfhWMSTWbCnAQ8w7DZLgIwn7pWjHNcOhghCEPgzdrwXSZJNxh/dHjunId2jhNQ==", "dev": true }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", @@ -19885,140 +18818,6 @@ "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", "dev": true }, - "node_modules/yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", - "dev": true, - "dependencies": { - "cliui": "^4.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" - } - }, - "node_modules/yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", - "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yargs/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/zeppelin-web/package.json b/zeppelin-web/package.json index 1b5cf1fc607..484fe4a4318 100644 --- a/zeppelin-web/package.json +++ b/zeppelin-web/package.json @@ -19,8 +19,6 @@ "dev:watch": "grunt watch-webpack-dev", "dev": "npm-run-all --parallel dev:server lint:watch dev:watch", "test:watch": "karma start karma.conf.js --single-run=false", - "pree2e": "webdriver-manager update --gecko false --versions.chrome=2.35", - "e2e": "protractor protractor.conf.js", "karma-test": "karma start karma.conf.js" }, "dependencies": { @@ -130,7 +128,6 @@ "ng-annotate-loader": "^0.2.0", "npm-run-all": "^4.1.5", "postcss-loader": "^3.0.0", - "protractor": "^5.4.1", "raw-loader": "^0.5.1", "rimraf": "^3.0.2", "string-replace-webpack-plugin": "^0.1.3", diff --git a/zeppelin-web/pom.xml b/zeppelin-web/pom.xml index 3dfb3a9da83..b9295680462 100644 --- a/zeppelin-web/pom.xml +++ b/zeppelin-web/pom.xml @@ -31,9 +31,8 @@ Zeppelin: web Application - true - false - ../bin + true + false UTF-8 @@ -122,7 +121,7 @@ npm - ${web.e2e.enabled} + ${web.unit.test.enabled} ci @@ -133,7 +132,7 @@ npm - ${web.e2e.enabled} + ${web.unit.test.enabled} ${web.build.command} @@ -145,61 +144,10 @@ test - ${web.e2e.disabled} + ${web.unit.test.disabled} run karma-test - - - npm e2e - - npm - - integration-test - - ${web.e2e.disabled} - run e2e - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - - - start-zeppelin - pre-integration-test - - ${web.e2e.disabled} - - - - - - - - run - - - - - stop-zeppelin - post-integration-test - - ${web.e2e.disabled} - - - - - - - - run - - @@ -274,14 +222,14 @@ run build:ci - - web-e2e + web-unit-test - false - true + false + true + spark-scala-2.13 diff --git a/zeppelin-web/protractor.conf.js b/zeppelin-web/protractor.conf.js deleted file mode 100644 index 6d55ab74063..00000000000 --- a/zeppelin-web/protractor.conf.js +++ /dev/null @@ -1,44 +0,0 @@ -var baseConfig = { - baseUrl: 'http://localhost:8080/classic', - directConnect: true, - capabilities: { - browserName: 'chrome', - }, - allScriptsTimeout: 300000, // 5 min - - framework: 'jasmine', - specs: ['e2e/**/*.js'], - jasmineNodeOpts: { - showTiming: true, - showColors: true, - isVerbose: true, - includeStackTrace: false, - defaultTimeoutInterval: 300000, // 5 min - print: function() {}, // remove protractor dot reporter, we are using jasmine-spec-reporter - }, - - onPrepare: function() { - // should be false for angular apps - // browser.ignoreSynchronization = true; - - browser.manage().timeouts().pageLoadTimeout(300000); - // with the implicitlyWait() this will even though you expect the element not to be there - browser.manage().timeouts().implicitlyWait(30000); - - // add reporter to display executed tests in console - var SpecReporter = require('jasmine-spec-reporter').SpecReporter; - jasmine.getEnv().addReporter(new SpecReporter({ - spec: { - displayStacktrace: true - } - })); - }, -}; - -var chromeOptions = { - args: ['--disable-gpu', '--no-sandbox', 'window-size=1920, 1080', '--disable-browser-side-navigation'] -} - -baseConfig.capabilities.chromeOptions = chromeOptions; - -exports.config = baseConfig; From adea3b955148eb9c7f990e682309261fec660099 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Sat, 18 Jul 2026 11:03:34 +0900 Subject: [PATCH 086/179] [ZEPPELIN-6545] Move the classic-suite gating to a dedicated Playwright config ### What is this PR for? This PR separates the classic UI Playwright e2e suite from the main Playwright config. After ZEPPELIN-6527, classic specs under `e2e/tests/classic/` were wired into the shared config and gated with `E2E_CLASSIC` plus argv sniffing. That made plain `npm run e2e` depend on a `-Pweb-classic` server, allowed false positives from arguments like `--grep tests/classic`, and caused the coverage reporter to run for classic pages that are outside the coverage denominator. This change moves classic execution to a dedicated `playwright.classic.config.js`, updates `e2e:classic` and CI wiring to use it, removes the env/argv detection from the main config, and keeps the coverage reporter on the main suite only. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6545 ### How should this be tested? - `cd zeppelin-web-angular && npm run e2e -- tests/classic --list --reporter=list` - Verifies the main Playwright config no longer selects classic specs. - `cd zeppelin-web-angular && npm run e2e:classic -- --list --reporter=list` - Verifies classic specs are selected only through the dedicated classic config. - `rg "E2E_CLASSIC|process\\.argv|isClassicOnlyRun|E2E_MODE" zeppelin-web-angular .github/workflows/frontend.yml` - Verifies the old env/argv gating was removed. - `rg "reporter\\.coverage" zeppelin-web-angular/playwright.config.js zeppelin-web-angular/playwright.classic.config.js` - Verifies the coverage reporter is only configured for the main suite. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? Edit AGENTS.md about modified classic suite config Closes #5317 from miinhho/test/move-classic-suite-gate. Signed-off-by: YONGJAE LEE --- .github/workflows/frontend.yml | 9 +-- zeppelin-web-angular/.gitignore | 2 + zeppelin-web-angular/e2e/AGENTS.md | 23 ++++--- zeppelin-web-angular/package.json | 5 +- .../playwright.classic.config.js | 47 +++++++++++++ zeppelin-web-angular/playwright.config.js | 68 ++++--------------- zeppelin-web-angular/playwright.shared.js | 39 +++++++++++ zeppelin-web-angular/pom.xml | 14 ++++ 8 files changed, 139 insertions(+), 68 deletions(-) create mode 100644 zeppelin-web-angular/playwright.classic.config.js create mode 100644 zeppelin-web-angular/playwright.shared.js diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 872bfe6133b..1998142a41d 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -109,15 +109,16 @@ jobs: mkdir -p $ZEPPELIN_E2E_TEST_NOTEBOOK_DIR echo "Created test notebook directory: $ZEPPELIN_E2E_TEST_NOTEBOOK_DIR" - name: Run headless E2E test with Maven - env: - E2E_MODE: ${{ matrix.mode }} - run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw verify -pl zeppelin-web-angular -Pweb-e2e ${MAVEN_ARGS} + # Classic UI e2e runs only on the anonymous leg, like the legacy Protractor suite + run: xvfb-run --auto-servernum --server-args="-screen 0 1024x768x24" ./mvnw verify -pl zeppelin-web-angular -Pweb-e2e -Dweb.e2e.classic.disabled=${{ matrix.mode != 'anonymous' }} ${MAVEN_ARGS} - name: Upload Playwright Report uses: actions/upload-artifact@v6 if: always() with: name: playwright-report-${{ matrix.mode }} - path: zeppelin-web-angular/playwright-report/ + path: | + zeppelin-web-angular/playwright-report/ + zeppelin-web-angular/playwright-report-classic/ retention-days: 3 - name: Print Zeppelin logs if: always() diff --git a/zeppelin-web-angular/.gitignore b/zeppelin-web-angular/.gitignore index 42b640c2fdd..d0a457873a3 100644 --- a/zeppelin-web-angular/.gitignore +++ b/zeppelin-web-angular/.gitignore @@ -45,8 +45,10 @@ Thumbs.db # Playwright /playwright-report/ +/playwright-report-classic/ /playwright-coverage/ /test-results/ +/test-results-classic/ /playwright/.cache/ /playwright/.auth/ diff --git a/zeppelin-web-angular/e2e/AGENTS.md b/zeppelin-web-angular/e2e/AGENTS.md index 1fe1c62acff..900756358ac 100644 --- a/zeppelin-web-angular/e2e/AGENTS.md +++ b/zeppelin-web-angular/e2e/AGENTS.md @@ -21,8 +21,10 @@ limitations under the License. > to the repository-root AGENTS.md, loaded only when working under `e2e/`. > See [AGENTS.md specification](https://github.com/agentsmd/agents.md). -Config: `zeppelin-web-angular/playwright.config.js`. This file is the shared source -of truth for E2E conventions; Codex and agents.md-native tools read it directly. +Config: `zeppelin-web-angular/playwright.config.js` (Angular UI) and +`playwright.classic.config.js` (legacy classic UI), sharing `playwright.shared.js`. +This document is the shared source of truth for E2E conventions; Codex and +agents.md-native tools read it directly. Claude Code / Gemini users can symlink `CLAUDE.md` / `GEMINI.md` to it locally (both gitignored, personal, not committed). @@ -122,7 +124,8 @@ exercised transitively and are not counted. | `npm run e2e:headed` | Headed run | | `npm run e2e:debug` | Step-by-step debugger | | `npm run e2e:report` | Open last HTML report | -| `npm run e2e:ci` | CI mode (`CI=true`, baseURL `:8080`) | +| `npm run e2e:report:classic` | Open last classic HTML report | +| `npm run e2e:ci` | CI mode (`CI=true`, baseURL `:8080`), main then classic suite | | `npm run e2e:codegen` | Record against `:4200` | | `npm run e2e:cleanup` | Delete leftover test notebooks (`e2e/cleanup-util.ts`) | @@ -204,12 +207,14 @@ the Angular/React suites. the first `ParagraphCtrl` paragraph, or `.ace_text-input` attached). - **Coverage:** `PAGES` is the Angular coverage denominator; classic pages are intentionally outside it, so `addPageAnnotationBeforeEach` is not used here. -- **Running:** the `classic` project targets `http://localhost:8080` (Desktop - Chrome only) and needs a Zeppelin server built with `-Pweb-classic` — the - `:4200` dev server does not serve `/classic`. Run it with `npm run e2e:classic` - (sets `E2E_CLASSIC=1`); running a `tests/classic/*` file path directly is also - detected. In CI the classic project runs only in the anonymous matrix leg - (`E2E_MODE`), matching the anonymous-only legacy Protractor suite. +- **Running:** the classic suite has its own config, `playwright.classic.config.js` + (Desktop Chrome only, targets `http://localhost:8080`), and needs a Zeppelin + server built with `-Pweb-classic` — the `:4200` dev server does not serve + `/classic`, so a plain `npm run e2e` never includes it. Run it with + `npm run e2e:classic` (single spec: `npm run e2e:classic -- tests/classic/`). + In CI the workflow enables it on the anonymous matrix leg only + (`-Dweb.e2e.classic.disabled=false`), matching the anonymous-only legacy + Protractor suite. - **POM:** inlining locators/helpers is acceptable while the suite is this small; if it grows, move them behind `models/classic-*.ts` / `*.util.ts`. - The React-migration / framework-neutral-spec guidance does not apply to diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 441c4cb5eab..55ae7ab835e 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -21,12 +21,13 @@ "test:eslint-rules": "node --test eslint-rules/", "e2e": "playwright test", "e2e:fast": "playwright test --project=chromium", - "e2e:classic": "cross-env E2E_CLASSIC=1 playwright test --project=classic", + "e2e:classic": "playwright test --config playwright.classic.config.js", "e2e:ui": "playwright test --ui", "e2e:headed": "playwright test --headed", "e2e:debug": "playwright test --debug", "e2e:report": "playwright show-report", - "e2e:ci": "export CI=true && playwright test", + "e2e:report:classic": "playwright show-report playwright-report-classic", + "e2e:ci": "export CI=true && playwright test && playwright test --config playwright.classic.config.js", "e2e:codegen": "playwright codegen http://localhost:4200", "e2e:cleanup": "npx tsx e2e/cleanup-util.ts" }, diff --git a/zeppelin-web-angular/playwright.classic.config.js b/zeppelin-web-angular/playwright.classic.config.js new file mode 100644 index 00000000000..e7a3fc63647 --- /dev/null +++ b/zeppelin-web-angular/playwright.classic.config.js @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const { defineConfig, devices } = require('@playwright/test'); +const { baseConfig } = require('./playwright.shared'); + +// Classic UI suite (e2e/tests/classic/): needs a Zeppelin server built with -Pweb-classic +// (:4200 does not serve /classic, hence no webServer). Run with: npm run e2e:classic +process.env.PLAYWRIGHT_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:8080'; + +module.exports = defineConfig({ + ...baseConfig, + testMatch: /tests\/classic\/.*\.spec\.ts/, + outputDir: 'test-results-classic', + // Classic pages are outside the PAGES coverage denominator, so no coverage reporter. + reporter: [ + [!!process.env.CI ? 'github' : 'list'], + ['html', { outputFolder: 'playwright-report-classic', open: !!process.env.CI ? 'never' : 'always' }] + ], + use: { + ...baseConfig.use, + baseURL: process.env.PLAYWRIGHT_BASE_URL + }, + projects: [ + { + name: 'setup', + testMatch: /global\.setup\.ts/ + }, + { + name: 'classic', + use: { + ...devices['Desktop Chrome'], + storageState: 'playwright/.auth/user.json' + }, + dependencies: ['setup'] + } + ] +}); diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index 4e019e8fd52..617d5776edb 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -11,41 +11,24 @@ */ const { defineConfig, devices } = require('@playwright/test'); +const { baseConfig } = require('./playwright.shared'); -const classicTests = /tests\/classic\/.*\.spec\.ts/; -const isClassicOnlyRun = process.env.E2E_CLASSIC === '1' || process.argv.some(arg => arg.includes('tests/classic')); -const defaultBaseURL = process.env.CI || isClassicOnlyRun ? 'http://localhost:8080' : 'http://localhost:4200'; +const defaultBaseURL = process.env.CI ? 'http://localhost:8080' : 'http://localhost:4200'; process.env.PLAYWRIGHT_BASE_URL = process.env.PLAYWRIGHT_BASE_URL || defaultBaseURL; // https://playwright.dev/docs/test-configuration module.exports = defineConfig({ - testDir: './e2e', - globalSetup: require.resolve('./e2e/global-setup'), - globalTeardown: require.resolve('./e2e/global-teardown'), - fullyParallel: true, - forbidOnly: !!process.env.CI, - retries: process.env.CI ? 2 : 1, - workers: 5, - timeout: 300000, - expect: { - timeout: 60000 - }, + ...baseConfig, + // The legacy classic UI suite runs separately via playwright.classic.config.js. + testIgnore: /tests\/classic\/.*\.spec\.ts/, reporter: [ [!!process.env.CI ? 'github' : 'list'], ['html', { open: !!process.env.CI ? 'never' : 'always' }], ['./e2e/reporter.coverage.ts'] ], use: { - baseURL: process.env.PLAYWRIGHT_BASE_URL, - trace: 'on-first-retry', // https://playwright.dev/docs/trace-viewer - screenshot: process.env.CI ? 'off' : 'only-on-failure', - video: process.env.CI ? 'off' : 'retain-on-failure', - launchOptions: { - args: ['--disable-dev-shm-usage'] - }, - headless: true, - actionTimeout: 60000, - navigationTimeout: 180000 + ...baseConfig.use, + baseURL: process.env.PLAYWRIGHT_BASE_URL }, projects: [ // Auth setup runs once and writes playwright/.auth/user.json, which the browser @@ -55,24 +38,8 @@ module.exports = defineConfig({ name: 'setup', testMatch: /global\.setup\.ts/ }, - // skip classic in the auth CI leg (its Protractor predecessor was anonymous-only) - ...(process.env.E2E_MODE === 'auth' - ? [] - : [ - { - name: 'classic', - testMatch: classicTests, - use: { - ...devices['Desktop Chrome'], - baseURL: 'http://localhost:8080', - storageState: 'playwright/.auth/user.json' - }, - dependencies: ['setup'] - } - ]), { name: 'chromium', - testIgnore: classicTests, use: { ...devices['Desktop Chrome'], permissions: ['clipboard-read', 'clipboard-write'], @@ -82,7 +49,6 @@ module.exports = defineConfig({ }, { name: 'Google Chrome', - testIgnore: classicTests, use: { ...devices['Desktop Chrome'], channel: 'chrome', @@ -93,7 +59,6 @@ module.exports = defineConfig({ }, { name: 'firefox', - testIgnore: classicTests, use: { ...devices['Desktop Firefox'], storageState: 'playwright/.auth/user.json' @@ -102,7 +67,6 @@ module.exports = defineConfig({ }, { name: 'webkit', - testIgnore: classicTests, use: { ...devices['Desktop Safari'], launchOptions: { @@ -114,7 +78,6 @@ module.exports = defineConfig({ }, { name: 'Microsoft Edge', - testIgnore: classicTests, use: { ...devices['Desktop Edge'], channel: 'msedge', @@ -124,13 +87,12 @@ module.exports = defineConfig({ dependencies: ['setup'] } ], - webServer: - process.env.CI || isClassicOnlyRun - ? undefined - : { - command: 'npm run start', - url: 'http://localhost:4200', - reuseExistingServer: true, - timeout: 2 * 60 * 1000 - } + webServer: process.env.CI + ? undefined + : { + command: 'npm run start', + url: 'http://localhost:4200', + reuseExistingServer: true, + timeout: 2 * 60 * 1000 + } }); diff --git a/zeppelin-web-angular/playwright.shared.js b/zeppelin-web-angular/playwright.shared.js new file mode 100644 index 00000000000..cb3c254f46c --- /dev/null +++ b/zeppelin-web-angular/playwright.shared.js @@ -0,0 +1,39 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Settings shared by playwright.config.js and playwright.classic.config.js. +const baseConfig = { + testDir: './e2e', + globalSetup: require.resolve('./e2e/global-setup'), + globalTeardown: require.resolve('./e2e/global-teardown'), + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 1, + workers: 5, + timeout: 300000, + expect: { + timeout: 60000 + }, + use: { + trace: 'on-first-retry', // https://playwright.dev/docs/trace-viewer + screenshot: process.env.CI ? 'off' : 'only-on-failure', + video: process.env.CI ? 'off' : 'retain-on-failure', + launchOptions: { + args: ['--disable-dev-shm-usage'] + }, + headless: true, + actionTimeout: 60000, + navigationTimeout: 180000 + } +}; + +module.exports = { baseConfig }; diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml index 113bb69e792..6c9a164688e 100644 --- a/zeppelin-web-angular/pom.xml +++ b/zeppelin-web-angular/pom.xml @@ -33,6 +33,8 @@ true false + + true ../bin UTF-8 @@ -128,6 +130,18 @@ + + npm e2e classic + + npm + + integration-test + + ${web.e2e.classic.disabled} + run e2e:classic + + + From 108536f4e0eef785ba855927a94701627d333d98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Sun, 19 Jul 2026 02:06:59 +0900 Subject: [PATCH 087/179] [ZEPPELIN-6534] Escape note name before building clone-name RegExp ### What is this PR for? Cloning a note whose name contains a regular-expression metacharacter (for example `[`, `(`, or a trailing backslash) threw an uncaught `SyntaxError` when the clone dialog opened, so the suggested clone name was never generated and the dialog was broken for that note. `cloneNoteName()` interpolated the note name directly into a `RegExp` source without escaping it. This PR escapes the note name before building the `RegExp`, so any note name is matched literally. While verifying the fix in the running UI, a second, pre-existing defect surfaced in the same note view: opening **any** note logged an uncaught `TypeError: Cannot read properties of undefined (reading 'forEach')`. In `ngOnInit`, the `queryParamMap` subscription runs synchronously via `startWith()` and calls `onParagraphSearch()` before the `ViewChildren` `QueryList` (`listOfNotebookParagraphComponent`) is populated (it is only available after `ngAfterViewInit`). This PR guards that call with optional chaining, consistent with the existing null handling elsewhere in the same component. It is included here as a small drive-by fix, in its own commit so it can be split out if preferred. ### What type of PR is it? Bug Fix ### Todos * [x] Escape note name before building the clone-name `RegExp` * [x] Guard `onParagraphSearch()` against an uninitialized `ViewChildren` `QueryList` ### What is the Jira issue? [ZEPPELIN-6534](https://issues.apache.org/jira/browse/ZEPPELIN-6534) ### How should this be tested? * `cd zeppelin-web-angular && npm run lint` * Create a note named `report[2024` (or `foo(bar`) and click **Clone**: before the fix the dialog throws `SyntaxError` and no name is suggested; after the fix it suggests `report[2024 1` and clones normally. Clone-name numbering for ordinary names is unchanged (escaping is a no-op when there are no metacharacters). * Open any note with the browser devtools console open: before the fix a `forEach` `TypeError` is logged on load; after the fix the console is clean. ### Questions: * Does the license files need to be updated? No * Are there breaking changes for older versions? No * Does this need documentation? No Closes #5318 from kimyenac/ZEPPELIN-6534. Signed-off-by: ChanHo Lee --- .../src/app/pages/workspace/notebook/notebook.component.ts | 2 +- .../src/app/share/note-create/note-create.component.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index d76bca003e4..408ca1af281 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -272,7 +272,7 @@ export class NotebookComponent extends MessageListenersManager implements OnInit } onParagraphSearch(term: string) { - this.listOfNotebookParagraphComponent.forEach(comp => comp.highlightMatches(term || '')); + this.listOfNotebookParagraphComponent?.forEach(comp => comp.highlightMatches(term || '')); } saveParagraph(id: string) { diff --git a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts index ff0dbae759b..96f510ffd43 100644 --- a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts +++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts @@ -64,7 +64,8 @@ export class NoteCreateComponent extends MessageListenersManager implements OnIn const lastIndex = cloneNote.name.lastIndexOf(' '); const endsWithNumber = !!cloneNote.name.match('^.+?\\s\\d$'); const noteNamePrefix = endsWithNumber ? cloneNote.name.slice(0, lastIndex) : cloneNote.name; - const regexp = new RegExp(`^${noteNamePrefix}.+`); + const escapedNoteNamePrefix = noteNamePrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const regexp = new RegExp(`^${escapedNoteNamePrefix}.+`); this.noteListService.notes.flatList.forEach(note => { const noteName = note.path; From 386d110c089fb26bbbe6d61b30dd395c6c181037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Sun, 19 Jul 2026 02:24:53 +0900 Subject: [PATCH 088/179] [ZEPPELIN-6544] Harden keyboard-shortcut e2e helpers against silent passes ### What is this PR for? Follow-up to ZEPPELIN-6536 (#5304). A cross-review of the merged keyboard-shortcut suite found four silent-pass risks in the helpers; this PR closes them: - `pressShortcutFromHostUntil` now polls for the press's effect before retrying, so a slow toggle is not double-pressed and the loop cannot return on the transient state between two in-flight effects. - The clear-output test asserts the result is visible before pressing; previously a no-output run let the helper skip the press entirely. - InsertAbove/InsertBelow emptiness assertions now gate on the editor being rendered (`waitForEditorRendered`); an unrendered editor reads as `''` and matched vacuously. - `setCodeEditorContent` compares normalized equality instead of containment, so stale fixture text fails at seeding time. Test-only change; no product code touched. ### What type of PR is it? Improvement ### What is the Jira issue? ZEPPELIN-6544 ### How should this be tested? ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5315 from voidmatcha/fix/harden-keyboard-e2e-helpers. Signed-off-by: ChanHo Lee --- .../e2e/models/notebook-keyboard-page.ts | 138 ++++++++++-------- .../notebook-keyboard-shortcuts.spec.ts | 61 +++++--- 2 files changed, 121 insertions(+), 78 deletions(-) diff --git a/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts b/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts index 44e5c3118c8..fb4a24a3a6f 100644 --- a/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts @@ -10,7 +10,7 @@ * limitations under the License. */ -import test, { expect, Locator, Page } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import { navigateToNotebookWithFallback } from '../utils'; import { ShortcutsMap } from '../../src/app/key-binding/shortcuts-map'; import { ParagraphActions } from '../../src/app/key-binding/paragraph-actions'; @@ -123,6 +123,8 @@ export class NotebookKeyboardPage extends BasePage { if (!(await isSettled())) { await this.focusParagraphHost(paragraphIndex); await press(); + // Wait for this press's effect before retrying — an immediate recheck would double-press a slow toggle. The wait must comfortably exceed legitimate settle latency so only a genuinely dropped press is retried. + await expect.poll(isSettled, { timeout: 10000 }).toBe(true); } expect(await isSettled()).toBe(true); }).toPass({ timeout: 15000 }); @@ -369,27 +371,30 @@ export class NotebookKeyboardPage extends BasePage { return this.readEditorText(this.paragraphContainer.first()); } + // Gate for emptiness assertions — an empty Monaco model still renders one (empty) .view-line. + async waitForEditorRendered(paragraphIndex: number): Promise { + const paragraph = this.getParagraphByIndex(paragraphIndex); + await expect(paragraph.locator('.monaco-editor .view-line').first()).toBeAttached({ timeout: 10000 }); + } + // Reconstruct editor text from Monaco's absolutely-positioned `.view-line` divs sorted by top (DOM order need not match line order), via textContent; innerText is "" for off-layout lines in headless Chromium. + // Constraints: Monaco virtualizes lines (keep fixtures short); returns '' for both an empty and a not-yet-rendered editor. private async readEditorText(paragraph: Locator): Promise { const monaco = paragraph.locator('.monaco-editor').first(); - if ((await monaco.count()) > 0) { - const text = await monaco.evaluate((el: Element) => { - const lines = Array.from(el.querySelectorAll('.view-line')) as HTMLElement[]; - lines.sort((a, b) => parseInt(a.style.top || '0', 10) - parseInt(b.style.top || '0', 10)); - return lines.map(l => (l.textContent || '').replace(/\u00a0/g, ' ')).join('\n'); - }); - if (text.trim().length > 0) { - return text; - } + if ((await monaco.count()) === 0) { + return ''; } - const textarea = paragraph.locator('.monaco-editor textarea').first(); - if ((await textarea.count()) > 0) { - const value = await textarea.inputValue().catch(() => ''); - if (value) { - return value; - } - } - return ''; + // Reconstruct from view-lines only. The hidden textarea holds Monaco's IME buffer + // (a fragment, not the full model), so falling back to it returns partial text and + // makes reads non-deterministic. Callers poll, so '' while lines render is fine. + return monaco.evaluate((el: Element) => { + const lines = Array.from(el.querySelectorAll('.view-line')) as HTMLElement[]; + lines.sort((a, b) => parseInt(a.style.top || '0', 10) - parseInt(b.style.top || '0', 10)); + // Normalize all Unicode space separators (NBSP etc. that Monaco renders for + // whitespace) to a plain space, but keep line structure so exact-match assertions + // still verify it. + return lines.map(l => (l.textContent || '').replace(/\p{Zs}/gu, ' ')).join('\n'); + }); } async setCodeEditorContent(content: string, paragraphIndex: number = 0): Promise { @@ -398,55 +403,74 @@ export class NotebookKeyboardPage extends BasePage { return; } - await this.tryFocusCodeEditor(paragraphIndex); - if (this.page.isClosed()) { - console.warn('Cannot set code editor content: page closed after focusing'); - return; - } + // Seed via REST, not the editor: per-keystroke seeding fights the collaborative + // patch loop, merging a fresh note's "%python" prefix into the content on Firefox. + await this.seedParagraphViaRest(paragraphIndex, content); - const paragraph = this.getParagraphByIndex(paragraphIndex); - const editorInput = paragraph.locator('.monaco-editor .inputarea, .monaco-editor textarea').first(); + await this.tryFocusCodeEditor(paragraphIndex); - const browserName = test.info().project.name; - if (browserName !== 'firefox') { - await editorInput.waitFor({ state: 'visible', timeout: 30000 }); - await editorInput.click(); - await editorInput.clear(); + // The REST flush resets the cursor to (1,1); restore end-of-content so tests that + // seed then press End/Enter start from the right line. Keymap-independent. + if (content) { + await this.pressSelectAll(); + await this.page.keyboard.press('ArrowRight'); } + } - // Clear existing content with keyboard shortcuts for better reliability - await editorInput.focus(); + private noteIdFromUrl(): string { + const match = /\/notebook\/([^/?#]+)/.exec(this.page.url()); + if (!match) { + throw new Error(`No noteId in URL ${this.page.url()}`); + } + return match[1]; + } - if (browserName === 'firefox') { - // Clear by backspacing existing content length - const currentContent = await editorInput.inputValue(); - const contentLength = currentContent.length; + // Read a paragraph's persisted text from the server. Use this instead of the editor + // DOM when asserting content equality: Monaco reconstructs the same text with + // different whitespace codepoints across reads, which breaks byte-exact matches. + async getParagraphTextByIndex(paragraphIndex: number): Promise { + const noteId = this.noteIdFromUrl(); + const response = await this.page.request.get(`/api/notebook/${noteId}`, { failOnStatusCode: false }); + if (!response.ok()) { + throw new Error(`Fetch notebook REST request failed: ${response.status()} ${await response.text()}`); + } + const json = (await response.json()) as { body?: { paragraphs?: Array<{ text?: string }> } }; + return json.body?.paragraphs?.[paragraphIndex]?.text ?? ''; + } - // Position cursor at end and backspace all content - await this.page.keyboard.press('End'); - for (let i = 0; i < contentLength; i++) { - await this.page.keyboard.press('Backspace'); - } + private async seedParagraphViaRest(paragraphIndex: number, content: string): Promise { + const noteId = this.noteIdFromUrl(); + const paragraph = this.getParagraphByIndex(paragraphIndex); - // JUSTIFIED: Monaco textarea can be covered by editor overlays during fixture setup. - await editorInput.fill(content, { force: true }); - } else { - // Standard clearing for other browsers - await this.pressSelectAll(); - await this.page.keyboard.press('Delete'); - // JUSTIFIED: Monaco textarea can be overlaid after select+delete during fixture setup. - await editorInput.fill(content, { force: true }); + const paragraphId = await this.resolveParagraphId(noteId, paragraphIndex); + const response = await this.page.request.put(`/api/notebook/${noteId}/paragraph/${paragraphId}`, { + data: { text: content }, + failOnStatusCode: false + }); + if (!response.ok()) { + throw new Error(`Seed paragraph REST request failed: ${response.status()} ${await response.text()}`); } - // Wait for the full normalized editor content to avoid stale Monaco renders. + // The PUT broadcasts the paragraph; wait for the flush to render the exact content. const expected = content.replace(/\s+/g, ''); - if (expected.length === 0) { - await expect.poll(async () => (await this.readEditorText(paragraph)).trim(), { timeout: 10000 }).toBe(''); - } else { - await expect - .poll(async () => (await this.readEditorText(paragraph)).replace(/\s+/g, ''), { timeout: 10000 }) - .toContain(expected); - } + await expect + .poll(async () => (await this.readEditorText(paragraph)).replace(/\s+/g, ''), { timeout: 15000 }) + .toBe(expected); + } + + private async resolveParagraphId(noteId: string, paragraphIndex: number): Promise { + // Retry: a paragraph just inserted through the UI may not be persisted server-side yet. + let id: string | undefined; + await expect(async () => { + const response = await this.page.request.get(`/api/notebook/${noteId}`, { failOnStatusCode: false }); + if (!response.ok()) { + throw new Error(`Fetch notebook REST request failed: ${response.status()} ${await response.text()}`); + } + const json = (await response.json()) as { body?: { paragraphs?: Array<{ id?: string }> } }; + id = json.body?.paragraphs?.[paragraphIndex]?.id; + expect(id, `No paragraph at index ${paragraphIndex} in note ${noteId}`).toBeTruthy(); + }).toPass({ timeout: 10000, intervals: [200, 400, 800] }); + return id!; } // Helper methods for verifying shortcut effects diff --git a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts index 2f43bb6f33f..6f3029fa51e 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts @@ -309,7 +309,9 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const finalCount = await keyboardPage.getParagraphCount(); expect(finalCount).toBe(initialCount + 1); - // And: the new paragraph at index 0 holds no user content; empty or just an interpreter directive (poll so the async insert/render settles). + // And: the new paragraph at index 0 holds no user content; empty or just an interpreter directive. + // Render gate: an unrendered editor reads as '' and would vacuously match. + await keyboardPage.waitForEditorRendered(0); await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0).then(c => c.trim())).toMatch(/^(%\w+)?$/); // And the original content moved to index 1 (normalize whitespace; Monaco reflows). @@ -343,6 +345,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { expect(originalParagraphContent).toMatch(/Content\s+for\s+insert\s+below\s+test/); // And: a new paragraph exists at index 1 holding no user content. + // Render gate: an unrendered editor reads as '' and would vacuously match. + await keyboardPage.waitForEditorRendered(1); await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1).then(c => c.trim())).toMatch(/^(%\w+)?$/); }); }); @@ -354,7 +358,10 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%md\n# Copy Test\nContent to be copied below'); const initialCount = await keyboardPage.getParagraphCount(); - const originalContent = await keyboardPage.getCodeEditorContentByIndex(0); + // Compare persisted server text, not the editor DOM: the clone's correctness is + // that the copied paragraph is stored identically, and reading from the server + // avoids Monaco's non-deterministic whitespace rendering. + const originalContent = await keyboardPage.getParagraphTextByIndex(0); // When: User presses Control+Shift+C await keyboardPage.pressInsertCopy(); @@ -362,8 +369,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Then: a copy is inserted below carrying the same text, and the original is unchanged await keyboardPage.waitForParagraphCountChange(initialCount + 1); expect(await keyboardPage.getParagraphCount()).toBe(initialCount + 1); - await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toBe(originalContent); - await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1)).toBe(originalContent); + await expect.poll(() => keyboardPage.getParagraphTextByIndex(0)).toBe(originalContent); + await expect.poll(() => keyboardPage.getParagraphTextByIndex(1)).toBe(originalContent); }); }); @@ -389,9 +396,9 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const paragraphCount = await keyboardPage.getParagraphCount(); expect(paragraphCount).toBe(2); - // Verify initial content before move - const initialFirst = await keyboardPage.getCodeEditorContentByIndex(0); - const initialSecond = await keyboardPage.getCodeEditorContentByIndex(1); + // Capture server-persisted text (avoids Monaco DOM whitespace non-determinism) + const initialFirst = await keyboardPage.getParagraphTextByIndex(0); + const initialSecond = await keyboardPage.getParagraphTextByIndex(1); // Focus on second paragraph for move operation await keyboardPage.tryFocusCodeEditor(1); @@ -403,9 +410,13 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const finalParagraphCount = await keyboardPage.getParagraphCount(); expect(finalParagraphCount).toBe(2); - // And: Paragraph positions should be swapped (poll until the move lands in the DOM) - await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toBe(initialSecond); - await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1)).toBe(initialFirst); + // And: positions are swapped (poll the server until the move persists) + await expect.poll(() => keyboardPage.getParagraphTextByIndex(0)).toBe(initialSecond); + await expect.poll(() => keyboardPage.getParagraphTextByIndex(1)).toBe(initialFirst); + // And the visible order reflects the swap. Containment on a distinctive marker + // proves the user-visible reorder without an exact Monaco whitespace match. + await expect(keyboardPage.getParagraphByIndex(0).locator('.view-lines')).toContainText('Second Paragraph'); + await expect(keyboardPage.getParagraphByIndex(1).locator('.view-lines')).toContainText('First Paragraph'); }); }); @@ -431,9 +442,9 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const paragraphCount = await keyboardPage.getParagraphCount(); expect(paragraphCount).toBe(2); - // Verify initial content before move - const initialFirst = await keyboardPage.getCodeEditorContentByIndex(0); - const initialSecond = await keyboardPage.getCodeEditorContentByIndex(1); + // Capture server-persisted text (avoids Monaco DOM whitespace non-determinism) + const initialFirst = await keyboardPage.getParagraphTextByIndex(0); + const initialSecond = await keyboardPage.getParagraphTextByIndex(1); // Focus first paragraph for move operation await keyboardPage.tryFocusCodeEditor(0); @@ -445,9 +456,13 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const finalParagraphCount = await keyboardPage.getParagraphCount(); expect(finalParagraphCount).toBe(2); - // And: Paragraph positions should be swapped (poll until the move lands in the DOM) - await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(0)).toBe(initialSecond); - await expect.poll(() => keyboardPage.getCodeEditorContentByIndex(1)).toBe(initialFirst); + // And: positions are swapped (poll the server until the move persists) + await expect.poll(() => keyboardPage.getParagraphTextByIndex(0)).toBe(initialSecond); + await expect.poll(() => keyboardPage.getParagraphTextByIndex(1)).toBe(initialFirst); + // And the visible order reflects the swap. Containment on a distinctive marker + // proves the user-visible reorder without an exact Monaco whitespace match. + await expect(keyboardPage.getParagraphByIndex(0).locator('.view-lines')).toContainText('Second Paragraph'); + await expect(keyboardPage.getParagraphByIndex(1).locator('.view-lines')).toContainText('First Paragraph'); }); }); @@ -559,8 +574,11 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { const statusElBefore = keyboardPage.paragraphContainer.first().locator('.status'); await expect(statusElBefore).toHaveText(/FINISHED|ERROR|PENDING|RUNNING/); - // When: User presses Control+Alt+L (editor hidden after %md run; dispatch from the host) + // Gate: without visible output, isSettled starts true and the helper would skip the press entirely. const resultLocator = keyboardPage.getParagraphByIndex(0).locator('[data-testid="paragraph-result"]'); + await expect(resultLocator).toBeVisible(); + + // When: User presses Control+Alt+L (editor hidden after %md run; dispatch from the host) await keyboardPage.pressShortcutFromHostUntil( 0, () => keyboardPage.pressClearOutput(), @@ -932,7 +950,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Verify error result exists (invalid syntax produces a final ERROR or FINISHED with error output) // JUSTIFIED: single-paragraph test notebook; first() is deterministic const statusElError = keyboardPage.paragraphContainer.first().locator('.status'); - await expect(statusElError).toHaveText(/FINISHED|ERROR/, { timeout: 30000 }); + await expect(statusElError).toHaveText(/FINISHED|ERROR/, { timeout: 60000 }); // When: User continues with shortcuts (insert new paragraph) const initialCount = await keyboardPage.getParagraphCount(); @@ -945,11 +963,12 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%md\n# Recovery Test\nShortcuts work after error', newParagraphIndex); await keyboardPage.pressRunParagraph(); - // Then: Shortcut execution still reaches a terminal state - await keyboardPage.waitForParagraphExecution(newParagraphIndex); + // Then: Shortcut execution still reaches a terminal state (real interpreter run; + // allow extra time as a cold interpreter under CI load can stay RUNNING past 30s) + await keyboardPage.waitForParagraphExecution(newParagraphIndex, 60000); // JUSTIFIED: newParagraphIndex is dynamically computed from getParagraphCount(); nth() is the only way to address this specific paragraph const statusElNew = keyboardPage.paragraphContainer.nth(newParagraphIndex).locator('.status'); - await expect(statusElNew).toHaveText(/FINISHED|ERROR/, { timeout: 30000 }); + await expect(statusElNew).toHaveText(/FINISHED|ERROR/, { timeout: 60000 }); }); test('should gracefully handle shortcuts when no paragraph is focused', async () => { From 156cd548968d90b62e7cf262b369abd96f0c042d Mon Sep 17 00:00:00 2001 From: Gyeongtae Park Date: Sun, 19 Jul 2026 02:49:09 +0900 Subject: [PATCH 089/179] [ZEPPELIN-6541] Pin maven-checkstyle-plugin version so it is actually applied MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The root `pom.xml` declares a `plugin.checkstyle.version` property (`2.17`) intended to pin the `maven-checkstyle-plugin` version used across all modules, but the plugin's `` declaration never referenced it via a `` tag. As a result Maven silently resolved a different, non-deterministic plugin version regardless of what the property said — confirmed locally: the property said `2.17`, but the build actually ran `checkstyle:3.4.0:check`. This PR adds the missing `${plugin.checkstyle.version}` tag and bumps the property to `3.6.0` (the current latest release) so the pinned version is the one that actually runs. ### What type of PR is it? Improvement ### Todos * [x] Add `${plugin.checkstyle.version}` to the `maven-checkstyle-plugin` block in `` * [x] Bump `plugin.checkstyle.version` from `2.17` to `3.6.0` ### What is the Jira issue? [ZEPPELIN-6541](https://issues.apache.org/jira/projects/ZEPPELIN/issues/ZEPPELIN-6541) ### How should this be tested? ```bash ./mvnw -pl shell verify -DskipTests ``` Confirm the log shows checkstyle:3.6.0:check (not an arbitrary/older version) and the build completes with BUILD SUCCESS. No module overrides the plugin version locally, so all modules using maven-checkstyle-plugin inherit the pinned version consistently. Screenshots (if appropriate) N/A Questions: - Does the license files need to update? No. - Is there breaking changes for older versions? No — build-time only change, no runtime behavior affected. - Does this needs documentation? No. Closes #5308 from ParkGyeongTae/ZEPPELIN-6541. Signed-off-by: ChanHo Lee --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 62fe3a5b2d0..8ddaa73ec78 100644 --- a/pom.xml +++ b/pom.xml @@ -158,7 +158,6 @@ 1.7.7 1.7 1.4 - 2.17 2.7 1.6.0 1.6.0 From 2e804101dfe9a3a12da1919bc08c16d190fe82ed Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Sun, 19 Jul 2026 03:03:32 +0900 Subject: [PATCH 090/179] [ZEPPELIN-6546] Restore Math.max accumulation for NoteJobInfo.unixTimeLastRun MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Job Manager reports a wrong "last run" time for any note whose most recently executed paragraph is not the last paragraph in the note. `NoteJobInfo(Note)` in `JobManagerService` overwrites `lastRunningUnixTime` on every loop iteration, so the last paragraph always wins: ```java lastRunningUnixTime = getUnixTimeLastRunParagraph(paragraph); ``` Consequences: - Both UIs render and sort by `unixTimeLastRun` (`jobmanager.filter.js` in zeppelin-web, `job-manager.component.ts` in zeppelin-web-angular), so the displayed relative time and the Recently-Update sort order are wrong. - The incremental path `getNoteJobInfoByUnixTime()` filters with `unixTimeLastRun > lastUpdateServerUnixTime`, so a note that just ran can be silently dropped from `LIST_UPDATE_NOTE_JOBS` pushes when an older paragraph sits at the bottom. This is a regression of ZEPPELIN-2860, which fixed exactly this in 2017 with `Math.max` (#2543). The ZEPPELIN-3737 refactor moved the logic from NotebookServer into JobManagerService and dropped the `Math.max` (001c621c7). This PR restores it. Verified on a live server: a two-paragraph note whose first paragraph finished today and whose second paragraph was created 8 days ago and never ran showed "8 days ago" in Job Manager before the fix and the correct run time after. ### Screenshots (if appropriate) https://github.com/user-attachments/assets/4508d689-2d6a-4998-bbbc-326a6006a9d9 ### What type of PR is it? Bug Fix ### Todos * [x] Restore `Math.max` accumulation in `NoteJobInfo` * [x] Regression tests ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6546 ### How should this be tested? `mvn test -pl zeppelin-server -Dtest=JobManagerServiceTest` — the two new tests pin `unixTimeLastRun` to the max paragraph timestamp via the `getNoteJobInfoByUnixTime` filter boundary and fail without the fix. Manually: create a note with two paragraphs, run only the first one, open the Job Manager page. Before the fix the note shows the second paragraph's creation date as its last run and sorts accordingly; after the fix it shows the actual run time. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5319 from HwangRock/ZEPPELIN-6546. Signed-off-by: ChanHo Lee --- .../zeppelin/service/JobManagerService.java | 2 +- .../service/JobManagerServiceTest.java | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/service/JobManagerService.java b/zeppelin-server/src/main/java/org/apache/zeppelin/service/JobManagerService.java index 6b65ef58d65..e699d58f490 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/service/JobManagerService.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/service/JobManagerService.java @@ -194,7 +194,7 @@ public NoteJobInfo(Note note) { } // get data for the job manager. ParagraphJobInfo paragraphItem = new ParagraphJobInfo(paragraph); - lastRunningUnixTime = getUnixTimeLastRunParagraph(paragraph); + lastRunningUnixTime = Math.max(lastRunningUnixTime, getUnixTimeLastRunParagraph(paragraph)); paragraphs.add(paragraphItem); } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/service/JobManagerServiceTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/service/JobManagerServiceTest.java index e8d69d604b0..b56c8473081 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/service/JobManagerServiceTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/service/JobManagerServiceTest.java @@ -18,6 +18,7 @@ package org.apache.zeppelin.service; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -28,10 +29,16 @@ import static org.mockito.Mockito.when; import java.io.IOException; +import java.util.Collections; +import java.util.Date; import java.util.List; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.notebook.AuthorizationService; +import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.notebook.NoteInfo; import org.apache.zeppelin.notebook.Notebook; +import org.apache.zeppelin.notebook.Paragraph; +import org.apache.zeppelin.scheduler.Job; import org.apache.zeppelin.service.JobManagerService.NoteJobInfo; import org.apache.zeppelin.service.exception.JobManagerForbiddenException; import org.apache.zeppelin.user.AuthenticationInfo; @@ -111,4 +118,80 @@ void removeNoteJobInfo_doesNothing() { } } + @Nested + class WhenJobManagerIsEnabled { + + private static final long LAST_RUN_TIME = 200_000L; + private static final long NEVER_RUN_CREATED_TIME = 100_000L; + + private Note mockNote; + + @BeforeEach + void enableJobManager() throws IOException { + when(zConf.isJobManagerEnabled()).thenReturn(true); + + mockNote = mock(Note.class); + when(mockNote.getId()).thenReturn("note1"); + when(mockNote.getName()).thenReturn("note1"); + when(mockNote.getConfig()).thenReturn(Collections.emptyMap()); + when(mockNote.getDefaultInterpreterGroup()).thenReturn("spark"); + + Paragraph lastRunParagraph = mock(Paragraph.class); + when(lastRunParagraph.isTerminated()).thenReturn(true); + when(lastRunParagraph.getDateFinished()).thenReturn(new Date(LAST_RUN_TIME)); + when(lastRunParagraph.getStatus()).thenReturn(Job.Status.FINISHED); + when(lastRunParagraph.getId()).thenReturn("p1"); + when(lastRunParagraph.getTitle()).thenReturn(null); + + Paragraph neverRunParagraph = mock(Paragraph.class); + when(neverRunParagraph.isTerminated()).thenReturn(false); + when(neverRunParagraph.isRunning()).thenReturn(false); + when(neverRunParagraph.getDateCreated()).thenReturn(new Date(NEVER_RUN_CREATED_TIME)); + when(neverRunParagraph.getStatus()).thenReturn(Job.Status.READY); + when(neverRunParagraph.getId()).thenReturn("p2"); + when(neverRunParagraph.getTitle()).thenReturn(null); + + when(mockNote.getParagraphs()).thenReturn(List.of(lastRunParagraph, neverRunParagraph)); + + when(mockNotebook.getNotesInfo()).thenReturn(List.of(new NoteInfo("note1", "note1.zpln"))); + when(mockAuthorizationService.isOwner(any(), eq("note1"))).thenReturn(true); + when(mockNotebook.processNote(eq("note1"), any())).thenAnswer(invocation -> { + Notebook.NoteProcessor noteProcessor = invocation.getArgument(1); + return noteProcessor.process(mockNote); + }); + } + + @Test + void getNoteJobInfoByUnixTime_usesMaxParagraphTimestamp_notLastParagraph() throws IOException { + ServiceCallback> callback = new SimpleServiceCallback<>(); + + List result = jobManagerService.getNoteJobInfoByUnixTime( + (NEVER_RUN_CREATED_TIME + LAST_RUN_TIME) / 2, + serviceContext, + callback + ); + + assertEquals(1, result.size()); + } + + @Test + void getNoteJobInfoByUnixTime_boundaryIsExactlyMaxTimestamp() throws IOException { + ServiceCallback> callback = new SimpleServiceCallback<>(); + + List includedResult = jobManagerService.getNoteJobInfoByUnixTime( + LAST_RUN_TIME - 1, + serviceContext, + callback + ); + List excludedResult = jobManagerService.getNoteJobInfoByUnixTime( + LAST_RUN_TIME, + serviceContext, + callback + ); + + assertEquals(1, includedResult.size()); + assertTrue(excludedResult.isEmpty()); + } + } + } From c50b1dcad3643516d0b521e25ceec9fa730098b6 Mon Sep 17 00:00:00 2001 From: Manhua Date: Sun, 19 Jul 2026 02:06:02 +0800 Subject: [PATCH 091/179] [ZEPPELIN-6542] Fix missing "Run" menu for first paragraph in Zeppelin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The "Run" menu item for the first paragraph was not showing due to an incorrect show condition (!this.first). This change sets show: true unconditionally for the "Run" button, ensuring it is always visible for the first paragraph — which is expected behavior in Zeppelin. ### What type of PR is it? Bug Fix ### Todos * [ ] - Task ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6542 ### How should this be tested? * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? * Is there breaking changes for older versions? * Does this needs documentation? Closes #5307 from kevinjmh/patch-3. Signed-off-by: ChanHo Lee --- .../workspace/notebook/paragraph/control/control.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts index c54da56058d..8a13b3309e6 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/control/control.component.ts @@ -98,7 +98,7 @@ export class NotebookParagraphControlComponent implements OnInit, OnChanges { this.listOfMenu = [ { label: 'Run', - show: !this.first, + show: true, disabled: this.isEntireNoteRunning, icon: 'play-circle', trigger: () => this.trigger(this.runParagraph), From 63e32d74c960d138531f79487fc4bb88b56606a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:37:11 +0900 Subject: [PATCH 092/179] [ZEPPELIN-6471] Share a single aggregation-type constant between table and pivot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Angular frontend hardcoded the same aggregation-type set (count, sum, min, max, avg) in two independent places — the table visualization and the pivot setting UI — with no single source of truth. The table component declared a local, unexported `AggregationType` union plus a value array; the pivot component had only an untyped `string[]` with the same values in a different order. Duplication meant the two could silently drift, and type safety was inconsistent. This PR extracts a single shared **type** and has both components consume it, while each component keeps its own display-order array. ### What changes were proposed in this PR? - Add `common/util/aggregation-type.ts` exporting `AggregationType` as the single shared type for the aggregation-type set. - `table-visualization.component.ts`: remove the local, unexported `AggregationType` type and import the shared one. `aggregations` keeps its existing order and is now typed `readonly AggregationType[]`. - `pivot-setting.component.ts`: replace the untyped `string[]` with `readonly AggregationType[]` from the shared type, keeping its existing order. Both usages are read-only iteration/display (`for`), so `readonly` is safe. The table's `switch (opt.aggregation)` stays exhaustive against the shared type. #### Why share the type only (not a shared value array) Both arrays drive an aggregation dropdown in the UI: - pivot: `pivot-setting.component.html` `for (aggregate of aggregates; ...)` - table: `table-visualization.component.html:112` `for (aggregation of aggregations; ...)` rendered via `{{ aggregation | titlecase }}` The two arrays use different orders. Collapsing them onto one canonical array would reorder the table column's Aggregation dropdown (Count, Sum, Min, Max, Avg → Sum, Count, Avg, Min, Max) — cosmetic, but a visible change the issue did not intend. Sharing only the type removes the duplicated/untyped definition and guarantees the two sets stay in sync, while leaving **both dropdowns exactly as they are today** — no user-visible change. ### How should this be tested? There is no frontend unit-test infrastructure in this project, so regression is confirmed via lint + build: ``` cd zeppelin-web-angular && npm run lint && npm run build:angular ``` Both pass (0 lint errors, successful production build). Manually verified that both aggregation dropdowns are unchanged: - pivot setting dropdown still shows `Sum, Count, Avg, Min, Max` - table column Aggregation dropdown still shows `Count, Sum, Min, Max, Avg` ### Questions - Does the license files need to update? No - Is there breaking change for older versions? No - Does this needs documentation? No Closes #5313 from kimyenac/ZEPPELIN-6471. Signed-off-by: ChanHo Lee --- .../pivot-setting/pivot-setting.component.ts | 4 +++- .../common/util/aggregation-type.ts | 17 +++++++++++++++++ .../table/table-visualization.component.ts | 5 +++-- 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 zeppelin-web-angular/src/app/visualizations/common/util/aggregation-type.ts diff --git a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts index e3995298d31..59a480b934a 100644 --- a/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts +++ b/zeppelin-web-angular/src/app/visualizations/common/pivot-setting/pivot-setting.component.ts @@ -16,6 +16,8 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } import { GraphConfig } from '@zeppelin/sdk'; import { TableData, Visualization } from '@zeppelin/visualization'; +import { AggregationType } from '../util/aggregation-type'; + @Component({ selector: 'zeppelin-visualization-pivot-setting', templateUrl: './pivot-setting.component.html', @@ -28,7 +30,7 @@ export class VisualizationPivotSettingComponent implements OnInit { config!: GraphConfig; columns: Array<{ name: string; index: number; aggr: string }> = []; - aggregates = ['sum', 'count', 'avg', 'min', 'max']; + aggregates: readonly AggregationType[] = ['sum', 'count', 'avg', 'min', 'max']; // eslint-disable-next-line drop(event: CdkDragDrop) { diff --git a/zeppelin-web-angular/src/app/visualizations/common/util/aggregation-type.ts b/zeppelin-web-angular/src/app/visualizations/common/util/aggregation-type.ts new file mode 100644 index 00000000000..dfc8b3e23a1 --- /dev/null +++ b/zeppelin-web-angular/src/app/visualizations/common/util/aggregation-type.ts @@ -0,0 +1,17 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Single source of truth for the aggregation-type set shared by the table +// visualization and the pivot setting UI. Only the type is shared; each +// component keeps its own display-order array (typed readonly AggregationType[]) +// so that neither aggregation dropdown changes its visible order. +export type AggregationType = 'count' | 'sum' | 'min' | 'max' | 'avg'; diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts index 0eefb93ce73..482900644d4 100644 --- a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts @@ -18,8 +18,9 @@ import { utils, writeFile, WorkSheet } from 'xlsx'; import { TableData, Visualization, VISUALIZATION } from '@zeppelin/visualization'; +import { AggregationType } from '../common/util/aggregation-type'; + type ColType = 'string' | 'date' | 'number'; -type AggregationType = 'count' | 'sum' | 'min' | 'max' | 'avg'; class FilterOption { sort: 'desc' | 'asc' | '' = ''; @@ -59,7 +60,7 @@ export class TableVisualizationComponent implements OnInit { columns: string[] = []; colOptions = new Map(); types: ColType[] = ['string', 'number', 'date']; - aggregations: AggregationType[] = ['count', 'sum', 'min', 'max', 'avg']; + aggregations: readonly AggregationType[] = ['count', 'sum', 'min', 'max', 'avg']; // eslint-disable-next-line @typescript-eslint/no-explicit-any @ViewChild(NzTableComponent, { static: false }) nzTable!: NzTableComponent; From 03c9d16c10ef76d36c4749ad5d246961ca766c80 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:40:36 +0900 Subject: [PATCH 093/179] [ZEPPELIN-6498] Fix broken interpreter binding mode link in interpreter overview docs ### What is this PR for? This PR fixes a broken relative link in the ConfInterpreter section of the interpreter overview documentation. The page previously linked to `../usage/interpreter/interpreter_bindings_mode.html`, but the actual interpreter binding mode document is `interpreter_binding_mode.md` and is published as `interpreter_binding_mode.html`. This updates the link to the correct relative target ### What type of PR is it? Documentation ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6498 ### How should this be tested? * Search the file for the broken target: ``` rg -n "interpreter_bindings_mode|\.\./usage/interpreter/interpreter_binding" docs/usage/interpreter/overview.md ``` * Confirm `docs/usage/interpreter/interpreter_binding_mode.md` exists. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5321 from miinhho/docs/fix-broken-interpreter-binding-link. Signed-off-by: ChanHo Lee --- docs/usage/interpreter/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index 5186b9ed5f8..fe5cf3bd0b9 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -123,7 +123,7 @@ This approach works, but is not convenient. Inline generic configuration can pro `ConfInterpreter` is a generic interpreter that can be used by any interpreter. You can use it just like defining a java property file. It can be used to make custom settings for any interpreter. However, `ConfInterpreter` needs to run before that interpreter process is launched. When that interpreter process is launched is determined by the interpreter binding mode setting. -So users need to understand the [interpreter binding mode setting](../usage/interpreter/interpreter_bindings_mode.html) of Zeppelin and be aware of when the interpreter process is launched. E.g., if we set the Spark interpreter setting as isolated per note, then under this setting, each note will launch one interpreter process. +So users need to understand the [interpreter binding mode setting](./interpreter_binding_mode.html) of Zeppelin and be aware of when the interpreter process is launched. E.g., if we set the Spark interpreter setting as isolated per note, then under this setting, each note will launch one interpreter process. In this scenario, users need to put `ConfInterpreter` as the first paragraph as in the below example. Otherwise, the customized setting cannot be applied (actually it would report `ERROR`). From 1355de15de9247a55e3bcf6f76a11a42d21bad8d Mon Sep 17 00:00:00 2001 From: gyowoo1113 <58352333+gyowoo1113@users.noreply.github.com> Date: Sun, 19 Jul 2026 17:10:01 +0900 Subject: [PATCH 094/179] [ZEPPELIN-6435] Remove frontend build dependency from IndexHtmlServletTest ### What is this PR for? `IndexHtmlServletTest` included a disabled Angular HTML addon test because it depended on the generated file at `zeppelin-web-angular/dist/zeppelin/index.html`. That artifact is not built during normal `zeppelin-server` tests, so the test could not run independently. This PR replaces the frontend build dependency with a temporary, test-owned `index.html` file and re-enables `testZeppelinWebAngularHtmlAddon`. The `zeppelin-web` index and the Angular-style index exercise different branches in `IndexHtmlServlet`. The `zeppelin-web` index does not contain explicit `` and `` closing tags, so the servlet falls back to inserting the head addon before `` and the body addon before ``. The Angular-style index contains both closing tags, so the re-enabled test verifies that the configured head and body addons are inserted immediately before `` and ``. ### What type of PR is it? Improvement ### Todos - [x] Remove the dependency on `zeppelin-web-angular/dist/zeppelin/index.html` - [x] Create a temporary, test-owned Angular-style `index.html` - [x] Re-enable `testZeppelinWebAngularHtmlAddon` - [x] Verify addon insertion before `` and `` ### What is the Jira issue? [[ZEPPELIN-6435]](https://issues.apache.org/jira/browse/ZEPPELIN-6435) ### How should this be tested? `./mvnw test -pl zeppelin-server -Dtest=IndexHtmlServletTest` passes successfully. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5314 from gyowoo1113/ZEPPELIN-6435-index-html-servlet-test-frontend-independence. Signed-off-by: ChanHo Lee --- .../zeppelin/server/IndexHtmlServletTest.java | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java index 22af77db147..70e75adef21 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/server/IndexHtmlServletTest.java @@ -17,6 +17,7 @@ package org.apache.zeppelin.server; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.endsWith; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.hamcrest.MatcherAssert.assertThat; @@ -24,12 +25,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.net.URL; - +import java.nio.file.Files; +import java.nio.file.Path; import org.apache.zeppelin.conf.ZeppelinConfiguration; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import jakarta.servlet.ServletConfig; import jakarta.servlet.ServletContext; @@ -42,9 +43,8 @@ class IndexHtmlServletTest { private final static String TEST_BODY_ADDON = ""; private final static String TEST_HEAD_ADDON = ""; - private final static String FILE_PATH_INDEX_HTML_ZEPPELIN_WEB = "../zeppelin-web/dist/index.html"; - private final static String FILE_PATH_INDEX_HTML_ZEPPELIN_WEB_ANGULAR = "../zeppelin-web-angular/dist/zeppelin/index.html"; - + @TempDir + Path tempDir; @Test void testZeppelinWebHtmlAddon() throws IOException, ServletException { @@ -52,10 +52,18 @@ void testZeppelinWebHtmlAddon() throws IOException, ServletException { when(zConf.getHtmlBodyAddon()).thenReturn(TEST_BODY_ADDON); when(zConf.getHtmlHeadAddon()).thenReturn(TEST_HEAD_ADDON); + Path indexHtml = tempDir.resolve("index.html"); + Files.writeString( + indexHtml, + "\n" + + "\n" + + " Zeppelin\n" + + " \n"); + ServletConfig sc = mock(ServletConfig.class); ServletContext ctx = mock(ServletContext.class); when(ctx.getResource("/index.html")) - .thenReturn(new URL("file:" + FILE_PATH_INDEX_HTML_ZEPPELIN_WEB)); + .thenReturn(indexHtml.toUri().toURL()); when(sc.getServletContext()).thenReturn(ctx); IndexHtmlServlet servlet = new IndexHtmlServlet(zConf, null); @@ -74,22 +82,30 @@ void testZeppelinWebHtmlAddon() throws IOException, ServletException { // Get Content String content = new String(out.toString()); - assertThat(content, containsString(TEST_BODY_ADDON)); - assertThat(content, containsString(TEST_HEAD_ADDON)); + assertThat(content, containsString(TEST_HEAD_ADDON + "")); + assertThat(content, endsWith(TEST_BODY_ADDON)); } @Test - @Disabled("ignored due to zeppelin-web-angular not build for core tests") void testZeppelinWebAngularHtmlAddon() throws IOException, ServletException { ZeppelinConfiguration zConf = mock(ZeppelinConfiguration.class); when(zConf.getHtmlBodyAddon()).thenReturn(TEST_BODY_ADDON); when(zConf.getHtmlHeadAddon()).thenReturn(TEST_HEAD_ADDON); + Path indexHtml = tempDir.resolve("index.html"); + Files.writeString( + indexHtml, + "\n" + + "\n" + + " Zeppelin\n" + + " \n" + + "\n"); + ServletConfig sc = mock(ServletConfig.class); ServletContext ctx = mock(ServletContext.class); when(ctx.getResource("/index.html")) - .thenReturn(new URL("file:" + FILE_PATH_INDEX_HTML_ZEPPELIN_WEB_ANGULAR)); + .thenReturn(indexHtml.toUri().toURL()); when(sc.getServletContext()).thenReturn(ctx); IndexHtmlServlet servlet = new IndexHtmlServlet(zConf, null); @@ -106,8 +122,7 @@ void testZeppelinWebAngularHtmlAddon() throws IOException, ServletException { // Get Content String content = new String(out.toString()); - assertThat(content, containsString(TEST_BODY_ADDON)); - assertThat(content, containsString(TEST_HEAD_ADDON)); - + assertThat(content, containsString(TEST_HEAD_ADDON + "")); + assertThat(content, containsString(TEST_BODY_ADDON + "")); } } From 09ba0e0139a58b75cbace12129182b8c7d2ccf90 Mon Sep 17 00:00:00 2001 From: JangAyeon <67853616+JangAyeon@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:01:32 +0900 Subject: [PATCH 095/179] [ZEPPELIN-6535] Match table column filter terms literally instead of as regex MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Typing a regular-expression metacharacter (for example `[`, `(`, `*`) into a Table visualization's per-column search box threw an uncaught SyntaxError and silently broke the column filter, because the term was compiled as a regular expression. In `filterRows()`, each column's filter predicate called `String(row[key]).search(value.term)`, and `String.prototype.search()` coerces its argument to a RegExp, so the raw user-typed term became a pattern; benign metacharacters such as `.` or `*` also silently changed the match semantics instead of throwing an error. This PR replaces `.search()` with `String.prototype.includes()`, so the term is always matched as a literal substring instead of being compiled as a regex. The term is also trimmed before matching, so leading/trailing whitespace typed into the search box doesn't affect the result. ### What type of PR is it? Bug Fix ### Todos - [x] Match table column filter terms literally instead of compiling them as a RegExp ### What is the Jira issue? [ZEPPELIN-6535](https://issues.apache.org/jira/browse/ZEPPELIN-6535) ### How should this be tested? - `cd zeppelin-web-angular && npm run lint` - Produce a Table result (e.g. run `print("%table Name\tValue\nAlice\t10\nBob\t20")` in a `%python` paragraph), open a column's filter dropdown (▼ icon) and type `[` into the search box: before the fix, filtering breaks with an `Invalid regular expression` error in the console and stops updating; after the fix it filters literally with no error. - Type an ordinary substring (e.g. `Ali`): matching behavior is unchanged from before the fix. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5320 from JangAyeon/ZEPPELIN-6535. Signed-off-by: ChanHo Lee --- .../app/visualizations/table/table-visualization.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts index 482900644d4..63cf65d9438 100644 --- a/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts +++ b/zeppelin-web-angular/src/app/visualizations/table/table-visualization.component.ts @@ -209,8 +209,9 @@ export class TableVisualizationComponent implements OnInit { sortKeys.push((row: any) => typeCoercion(row[key], value.type)); sortTypes.push(value.sort); } + const term = value.term.trim(); // eslint-disable-next-line @typescript-eslint/no-explicit-any - terms.push((row: any) => String(row[key]).search(value.term) !== -1); + terms.push((row: any) => String(row[key]).includes(term)); }); this.rows = filter(this.tableData.rows, row => terms.every(term => term(row))); this.rows = orderBy(this.rows, sortKeys, sortTypes); From b572a07156324c6ae9c08da6ac82c9215877741f Mon Sep 17 00:00:00 2001 From: HyeonUk Kang <43662405+hyunw9@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:03:00 +0900 Subject: [PATCH 096/179] [ZEPPELIN-5876] Implement DockerInterpreterProcess.isAlive() using container state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Docker launcher's isAlive() isn't really implemented. It just calls isRunning(), which only checks whether the interpreter's Thrift port accepts a connection (checkIfRemoteEndpointAccessible). That tells you the port is open, not that the process behind it is alive. A container can be OOMKilled or already gone and still look alive if the port happens to answer for a moment. It also doesn't match the InterpreterClient contract, which says isAlive should reflect process status and stay separate from running. The method still had //TODO(ZEPPELIN-5876): Implement it more accurately sitting on it. While I was there I filled in getErrorMessage(), which always returned null. When the container isn't running it now says why: OOMKilled, or a non-zero exit code. That logic lives in a small describeContainerFailure() helper to keep getErrorMessage() short. One change is test-only: the docker field is now 'VisibleForTesting', so tests can inject a mock DockerClient and skip needing a real daemon. ### What type of PR is it? Feature ### Todos - [x] Implement isAlive() from the container's actual state (running/paused) - [x] Implement getErrorMessage() (OOMKilled / exit code) - [x] Unit tests with a mocked DockerClient ### What is the Jira issue? [[ZEPPELIN-5876]](https://issues.apache.org/jira/browse/ZEPPELIN-5876) ### How should this be tested? Automated unit tests in DockerInterpreterProcessTest : - isAlive_trueWhenContainerRunning - running == true → alive - isAlive_falseWhenContainerExitedOrOomKilled — running == false → not alive - getErrorMessage_reportsOomKilled - oomKilled == true → message contains the reason ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? - no * Is there breaking changes for older versions? - no * Does this needs documentation? - no Closes #5316 from hyunw9/ZEPPELIN-5876. Signed-off-by: ChanHo Lee --- .../launcher/DockerInterpreterProcess.java | 47 +++++++++++- .../DockerInterpreterProcessTest.java | 71 +++++++++++++++---- 2 files changed, 104 insertions(+), 14 deletions(-) diff --git a/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java b/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java index 3004ae13f79..9c86a676083 100644 --- a/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java +++ b/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java @@ -46,6 +46,7 @@ import com.spotify.docker.client.messages.Container; import com.spotify.docker.client.messages.ContainerConfig; import com.spotify.docker.client.messages.ContainerCreation; +import com.spotify.docker.client.messages.ContainerState; import com.spotify.docker.client.messages.ExecCreation; import com.spotify.docker.client.messages.HostConfig; import com.spotify.docker.client.messages.PortBinding; @@ -466,8 +467,20 @@ public int getPort() { @Override public boolean isAlive() { - //TODO(ZEPPELIN-5876): Implement it more accurately - return isRunning(); + DockerClient client = docker; + if (client == null) { + return false; + } + try { + ContainerState state = client.inspectContainer(containerName).state(); + return Boolean.TRUE.equals(state.running()) || Boolean.TRUE.equals(state.paused()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } catch (Exception e) { + LOGGER.warn("Failed to inspect container {} for liveness", containerName, e); + return false; + } } @Override @@ -480,6 +493,36 @@ public boolean isRunning() { @Override public String getErrorMessage() { + DockerClient client = docker; + if (client == null) { + return null; + } + try { + ContainerState state = client.inspectContainer(containerName).state(); + return describeContainerFailure(state); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } catch (Exception e) { + LOGGER.warn("Failed to inspect container {} for error message", containerName, e); + return null; + } + } + + // Returns null when the container is still running or exited cleanly, + // otherwise a human-readable reason for the failure. + private String describeContainerFailure(ContainerState state) { + if (Boolean.TRUE.equals(state.running())) { + return null; + } + if (Boolean.TRUE.equals(state.oomKilled())) { + return "Interpreter container " + containerName + + " was OOMKilled (exitCode=" + state.exitCode() + ")"; + } + Long exitCode = state.exitCode(); + if (exitCode != null && exitCode != 0) { + return "Interpreter container " + containerName + " exited with code " + exitCode; + } return null; } diff --git a/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java b/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java index ea5b5bd84ac..a4b0b4910bd 100644 --- a/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java +++ b/zeppelin-plugins/launcher/docker/src/test/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcessTest.java @@ -20,6 +20,8 @@ import com.spotify.docker.client.exceptions.DockerException; import com.spotify.docker.client.messages.ContainerConfig; import com.spotify.docker.client.messages.ContainerCreation; +import com.spotify.docker.client.messages.ContainerInfo; +import com.spotify.docker.client.messages.ContainerState; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; import org.apache.zeppelin.interpreter.InterpreterOption; @@ -69,7 +71,17 @@ private DockerInterpreterProcess newProcess() { 5000, 10); } - // stop() must always close the DockerClient, even when killing the container + // Stubs docker.inspectContainer(...).state() and returns the ContainerState mock + // so each test can set running/paused/oomKilled/exitCode as needed. + private ContainerState stubContainerState(DockerClient mockDocker) throws Exception { + ContainerInfo info = mock(ContainerInfo.class); + ContainerState state = mock(ContainerState.class); + when(mockDocker.inspectContainer(anyString())).thenReturn(info); + when(info.state()).thenReturn(state); + return state; + } + + // #1: stop() must always close the DockerClient, even when killing the container // fails, so the underlying HTTP socket / file descriptors are never leaked. @Test void stop_alwaysClosesDockerClient_evenWhenKillContainerFails() throws Exception { @@ -83,26 +95,23 @@ void stop_alwaysClosesDockerClient_evenWhenKillContainerFails() throws Exception verify(mockDocker, times(1)).close(); } - // When start() fails after the container has been started (e.g. file copy / exec - // fails), the container must be cleaned up instead of being left orphaned. + // #2: when start() fails after the container has been started, it must be rolled + // back (kill + remove) instead of being left orphaned. @Test void start_removesContainer_whenContainerPreparationFails() throws Exception { DockerInterpreterProcess intp = spy(newProcess()); DockerClient mockDocker = mock(DockerClient.class); doReturn(mockDocker).when(intp).createDockerClient(anyString()); - // No pre-existing container to remove. when(mockDocker.listContainers(any())).thenReturn(Collections.emptyList()); - // Container is created and started successfully... when(mockDocker.createContainer(any(ContainerConfig.class), anyString())) .thenReturn(ContainerCreation.builder().id("test-container-id").build()); - // ...but preparing it (the first exec inside the container) fails. + // Container is created and started, then preparation (the first exec) fails. doThrow(new DockerException("exec failed")) .when(mockDocker).execCreate(anyString(), any(String[].class), any()); assertThrows(IOException.class, () -> intp.start("user1")); - // The container was started, so start() must roll it back before returning. verify(mockDocker).startContainer("test-container-id"); verify(mockDocker).killContainer(anyString()); verify(mockDocker).removeContainer(anyString()); @@ -115,19 +124,57 @@ void start_removesContainer_evenWhenKillFailsDuringCleanup() throws Exception { doReturn(mockDocker).when(intp).createDockerClient(anyString()); when(mockDocker.listContainers(any())).thenReturn(Collections.emptyList()); - // Container is created... when(mockDocker.createContainer(any(ContainerConfig.class), anyString())) .thenReturn(ContainerCreation.builder().id("test-container-id").build()); - // ...but fails to start, so it is created-but-not-running. - doThrow(new DockerException("start failed")).when(mockDocker).startContainer(anyString()); - // Killing a non-running container fails, but removeContainer must still fire. - doThrow(new DockerException("not running")).when(mockDocker).killContainer(anyString()); + // Container is created and started, then preparation (the first exec) fails. + doThrow(new DockerException("exec failed")) + .when(mockDocker).execCreate(anyString(), any(String[].class), any()); + // ...and killing the container during cleanup fails too. + doThrow(new DockerException("kill failed")).when(mockDocker).killContainer(anyString()); assertThrows(IOException.class, () -> intp.start("user1")); + // removeContainer must still fire despite the kill failure. + verify(mockDocker).killContainer(anyString()); verify(mockDocker).removeContainer(anyString()); } + // isAlive() reflects the container's actual state from the Docker daemon, + // not just whether the Thrift port is reachable. + @Test + void isAlive_trueWhenContainerRunning() throws Exception { + DockerInterpreterProcess intp = newProcess(); + DockerClient mockDocker = mock(DockerClient.class); + intp.docker = mockDocker; + ContainerState state = stubContainerState(mockDocker); + when(state.running()).thenReturn(true); + + assertTrue(intp.isAlive()); + } + + @Test + void isAlive_falseWhenContainerNotRunning() throws Exception { + DockerInterpreterProcess intp = newProcess(); + DockerClient mockDocker = mock(DockerClient.class); + intp.docker = mockDocker; + ContainerState state = stubContainerState(mockDocker); + when(state.running()).thenReturn(false); + + assertFalse(intp.isAlive()); + } + + @Test + void getErrorMessage_reportsOomKilled() throws Exception { + DockerInterpreterProcess intp = newProcess(); + DockerClient mockDocker = mock(DockerClient.class); + intp.docker = mockDocker; + ContainerState state = stubContainerState(mockDocker); + when(state.oomKilled()).thenReturn(true); + when(state.exitCode()).thenReturn(137L); + + assertTrue(intp.getErrorMessage().contains("OOMKilled")); + } + @Test void testCreateIntpProcess() throws IOException { DockerInterpreterLauncher launcher From 8c199a29cb7f03c164509ea2ba04f8c336e68cfb Mon Sep 17 00:00:00 2001 From: JangAyeon <67853616+JangAyeon@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:25:37 +0900 Subject: [PATCH 097/179] [ZEPPELIN-6532] Complete destroy$ in paragraph ngOnDestroy to stop leaking subscriptions ### What is this PR for? Destroying a notebook paragraph did not tear down its own long-lived subscriptions or the shortcut key listeners it registered. ngOnDestroy() only called super.ngOnDestroy(), which (via MessageListenersManager) unsubscribes the MessageListener subscriptions but never touches destroy$. Subscriptions gated on takeUntil(this.destroy$) - keyBinderService.keyEvent(), angularContextManager.runParagraphAction(), and .contextChanged() - are on singleton services, so a destroyed paragraph instance stayed reachable and kept receiving callbacks after being removed from the DOM. The shortcut keydown listeners registered by KeyBinder via shortcutService.bindShortcut() were also never released. This PR emits and completes destroy$ in ngOnDestroy, after super.ngOnDestroy(), matching the pattern already used in result.component.ts and dynamic-forms.component.ts. ### What type of PR is it? Bug Fix ### Todos - [x] Emit and complete destroy$ in paragraph ngOnDestroy ### What is the Jira issue? [ZEPPELIN-6532](https://issues.apache.org/jira/browse/ZEPPELIN-6532) ### How should this be tested? * `cd zeppelin-web-angular && npm run lint` * At runtime, subscribe to a paragraph component's destroy$, then remove it (or navigate away): before the fix destroy$ never completes even though the paragraph is removed from the DOM; after the fix it completes on destroy, and the keyEvent/runParagraphAction/contextChanged subscriptions stop firing along with the shortcut keydown listeners. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5322 from JangAyeon/ZEPPELIN-6532. Signed-off-by: ChanHo Lee --- .../pages/workspace/notebook/paragraph/paragraph.component.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index 67d1f787de4..8f72c2bbf3d 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -775,5 +775,7 @@ export class NotebookParagraphComponent ngOnDestroy(): void { super.ngOnDestroy(); + this.destroy$.next(); + this.destroy$.complete(); } } From 226b0a6b3b26a158b460af79d44176d318c80011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:26:40 +0900 Subject: [PATCH 098/179] [ZEPPELIN-6441] Replace outdated type assertions with satisfies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Angular UI now uses TypeScript ~5.9.3, so the pre-4.9 workaround TODOs that asked to replace broad type assertions with `satisfies` are obsolete. This replaces those outdated assertions with `satisfies`, which improves compile-time checking without changing runtime behavior. - `app.module.ts`: `as JoinedEditorOptions` → `satisfies JoinedEditorOptions`, so unsupported editor options are caught at compile time. - `create-repository-modal.component.ts`: `as Record<...>` → `satisfies Record<...>`, so every form control key is validated against `CreateInterpreterRepositoryForm`. - `notebook-paragraph-keyboard-event-handler.ts`: `as const` → `as const satisfies ...` for both the action→handler map and the Monaco-handled action list. `as const` is intentionally kept so the downstream `typeof`-based literal indexing still narrows correctly, while `satisfies` now validates keys/values (e.g. invalid handler names are rejected). All three changes are compile-time-only annotations; runtime behavior is unchanged. ### What type of PR is it? Improvement ### What is the Jira issue? [ZEPPELIN-6441](https://issues.apache.org/jira/browse/ZEPPELIN-6441) ### How should this be tested? - `cd zeppelin-web-angular && npm run lint` passes (0 errors). - Verified the `satisfies` checks are active: injecting an unsupported editor option is caught as TS2353, and an invalid handler name is caught as TS2418. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this need documentation? No 🤖 Generated with [Claude Code](https://claude.com/claude-code) Closes #5323 from kimyenac/ZEPPELIN-6441. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/src/app/app.module.ts | 3 +-- .../notebook-paragraph-keyboard-event-handler.ts | 12 ++---------- .../create-repository-modal.component.ts | 3 +-- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/zeppelin-web-angular/src/app/app.module.ts b/zeppelin-web-angular/src/app/app.module.ts index af099ac17e5..a630b2d9be5 100644 --- a/zeppelin-web-angular/src/app/app.module.ts +++ b/zeppelin-web-angular/src/app/app.module.ts @@ -60,8 +60,7 @@ registerLocaleData(en); useValue: { defaultEditorOption: { scrollBeyondLastLine: false - // TODO: Change 'as' to 'satisfies' when typescript version is over 4.9 to detect unsupported editor options at compile time. - } as JoinedEditorOptions, + } satisfies JoinedEditorOptions, onLoad: loadMonaco } }, diff --git a/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts b/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts index 5ebffd8fedf..3c6e8508c83 100644 --- a/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts +++ b/zeppelin-web-angular/src/app/key-binding/notebook-paragraph-keyboard-event-handler.ts @@ -69,12 +69,7 @@ export const ParagraphActionToHandlerName = { [ParagraphActions.PasteLine]: 'handlePasteLine', [ParagraphActions.SearchInsideCode]: 'handleSearchInsideCode', [ParagraphActions.FindInCode]: 'handleFindInCode' -} as const; -// TODO: Replace `as const` with -// `satisfies Record` -// when typescript version is over 4.9. -// This allows checking both keys and values at the type level, -// while preserving the binding between them. +} as const satisfies Record; // Referenced only via `typeof` below to derive a type; the runtime binding is intentionally unused. // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -85,10 +80,7 @@ const MonacoHandledParagraphActions = [ ParagraphActions.CutLine, ParagraphActions.PasteLine, ParagraphActions.SearchInsideCode -] as const; -// TODO: Replace `as const` with `satisfies ParagraphActions[]` when typescript version is over 4.9. -// This ensures that the array contains only valid ParagraphActions, -// while preserving the literal value of the each element. +] as const satisfies ParagraphActions[]; type MonacoHandledParagraphAction = (typeof MonacoHandledParagraphActions)[number]; diff --git a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts index e254d6870dc..0813facdcd6 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/interpreter/create-repository-modal/create-repository-modal.component.ts @@ -73,7 +73,6 @@ export class InterpreterCreateRepositoryModalComponent extends DestroyHookCompon ], proxyLogin: '', proxyPassword: '' - // TODO: Change 'as' to 'satisfies' when typescript version is over 4.9 to detect unsupported editor options at compile time. - } as Record); + } satisfies Record); } } From aad361148cdab6348c47f187909f88f30a83dd41 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:27:32 +0900 Subject: [PATCH 099/179] [ZEPPELIN-6497] Refresh stale Cassandra interpreter embedded help links ### What is this PR for? The Cassandra interpreter help menu was linked to old Zeppelin `0.6.0-SNAPSHOT` documentation pages for dynamic forms and interpreter binding mode. Those links used outdated paths and HTTP URLs, which could send users to stale documentation. This PR updates those embedded help links to the current Zeppelin documentation URLs under `https://zeppelin.apache.org/docs/latest/usage/...`. ### What type of PR is it? Documentation ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6497 ### How should this be tested? * Search for stale links: ``` rg -n "0\.6\.0-SNAPSHOT|manual/dynamicform|manual/interpreters" cassandra/src/main/resources/scalate/helpMenu.ssp ``` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5324 from miinhho/docs/refresh-stale-cassandra-help-link. Signed-off-by: ChanHo Lee --- cassandra/src/main/resources/scalate/helpMenu.ssp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cassandra/src/main/resources/scalate/helpMenu.ssp b/cassandra/src/main/resources/scalate/helpMenu.ssp index 80fc99413a4..7139cb512da 100644 --- a/cassandra/src/main/resources/scalate/helpMenu.ssp +++ b/cassandra/src/main/resources/scalate/helpMenu.ssp @@ -834,7 +834,7 @@ select id, double, float, text, date, time, timestamp from zep.test_format;

    Instead of hard-coding your CQL queries, it is possible to use - Zeppelin dynamic form + Zeppelin dynamic form syntax to inject simple value or multiple choices forms. The legacy mustache syntax ( {{ }} ) to bind input text and select form is still supported but is deprecated and will be removed in future releases. @@ -1050,7 +1050,7 @@ select id, double, float, text, date, time, timestamp from zep.test_format;Asynchronous execution is only possible when it is possible to return a Future value in the InterpreterResult. It may be an interesting proposal for the Zeppelin project.

    Recently, Zeppelin allows you to choose the level of isolation for your interpreters (see - Interpreter Binding Mode ). + Interpreter Binding Mode ).

    Long story short, you have 3 available bindings: From 12399c7acfbf81b86dbbb122c9ac415fdd380e83 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:28:20 +0900 Subject: [PATCH 100/179] [ZEPPELIN-6464] Throw IllegalArgumentException for an unsupported Scala version in SparkInterpreterLauncher ### What is this PR for? This PR updates `SparkInterpreterLauncher` to throw `IllegalArgumentException` when the Scala version parsed from `spark-submit --version` is outside the supported range. Unsupported Scala versions are invalid input values for this validation path, so `IllegalArgumentException` better describes the failure than a generic `Exception`. The exception message is intentionally unchanged, and the `detectSparkScalaVersion(...)` method signature still declares `throws Exception` because the method can still raise checked exceptions from process execution, stream reading, and fallback Scala version detection. This is behavior-preserving for callers: the existing caller catches `Exception` and wraps it in an `IOException`, so the surfaced behavior and public API remain unchanged. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6464 ### How should this be tested? * Build and run the module tests: ``` ./mvnw test -pl zeppelin-server --am ``` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5326 from miinhho/refactor/throw-illegal-exception-in-unsupported-scala. Signed-off-by: ChanHo Lee --- .../zeppelin/interpreter/launcher/SparkInterpreterLauncher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java index 7b66b821dfb..98e0e5e0b82 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java @@ -285,7 +285,7 @@ private String detectSparkScalaVersion(String sparkHome, Map env } else if (scalaVersion.startsWith("2.13")) { return "2.13"; } else { - throw new Exception("Unsupported scala version: " + scalaVersion); + throw new IllegalArgumentException("Unsupported scala version: " + scalaVersion); } } else { return detectSparkScalaVersionByReplClass(sparkHome); From 0bd5b0329ad4dd50ed006a2fac904e67e072dd04 Mon Sep 17 00:00:00 2001 From: YeonKyung Ryu <80758099+celinayk@users.noreply.github.com> Date: Tue, 21 Jul 2026 00:18:21 +0900 Subject: [PATCH 101/179] [ZEPPELIN-6322] Filter download messages in ProcessData error stream ### What is this PR for? This PR improves error stream output filtering in the `ProcessData` class to exclude download-related messages. Currently, Maven/npm download progress information clutters the error stream during integration tests, making it difficult to identify actual errors. This change filters out download messages (e.g., "Downloading:", "Progress: 45%", "1024/2048 KB") while preserving real error messages. ### What type of PR is it? Improvement ### Todos * [x] - Add DOWNLOAD_PATTERNS array with 6 regex patterns * [x] - Implement isDownloadMessage() method * [x] - Apply filtering logic in buildOutputAndErrorStreamData() ### What is the Jira issue? [ZEPPELIN-6322](https://issues.apache.org/jira/browse/ZEPPELIN-6322) ### How should this be tested? ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5104 from celinayk/ZEPPELIN-6322. Signed-off-by: ChanHo Lee --- .../java/org/apache/zeppelin/ProcessData.java | 91 +++++++++++++++++-- .../org/apache/zeppelin/ProcessDataTest.java | 63 +++++++++++++ 2 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessDataTest.java diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java index f4a578a32b8..a7ad3fc3d9d 100644 --- a/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessData.java @@ -25,6 +25,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +40,19 @@ public enum Types_Of_Data { private static final Logger LOGGER = LoggerFactory.getLogger(ProcessData.class); + // Patterns to identify download-related messages in the error stream. + // Anchored to the start of a (single, already-split) line to avoid matching + // error messages that merely mention a size or percentage figure. + private static final Pattern[] DOWNLOAD_PATTERNS = { + Pattern.compile("^\\[INFO\\]\\s+(Downloading|Downloaded):.*"), // Maven download messages + Pattern.compile("^Downloading\\s+.*"), // Generic downloading messages + Pattern.compile("^Downloaded\\s+.*"), // Generic downloaded messages + Pattern.compile("^Progress\\s*(\\(\\d+\\))?:?\\s*\\d+%.*", + Pattern.CASE_INSENSITIVE), // Progress indicators, e.g. "Progress (1): 45%" + Pattern.compile("^[\\d.]+/[\\d.]+\\s*(KB|MB|GB|bytes|kB)\\b.*", + Pattern.CASE_INSENSITIVE) // Size progress (e.g., "1024/2048 KB") + }; + private Process checked_process; private boolean printToConsole = false; @@ -149,6 +163,51 @@ public String getErrorStream() { return this.errorStream; } + /** + * Checks whether a single (already trimmed) line looks like a download-related + * message (Maven downloads, progress indicators, size information, etc.). + * + *

    This is only used to decide the console log level for a line - a line that + * matches is still logged (at TRACE), never dropped, so a misclassified line is + * merely quieter rather than lost. Callers must check for "error"/"failed" content + * before calling this, since that check always takes precedence. + * + * @param line The single line to check + * @return true if the line looks like a download message, false otherwise + */ + boolean isDownloadMessage(String line) { + if (line == null || line.isEmpty()) { + return false; + } + + for (Pattern pattern : DOWNLOAD_PATTERNS) { + if (pattern.matcher(line).matches()) { + return true; + } + } + return false; + } + + /** + * Classifies and logs a single, complete line of error-stream output to the console. + * A line is never dropped: real error/failed lines always win at WARN, and only lines + * that look like download noise are downgraded to TRACE instead of being discarded. + */ + private void logErrorLine(String line) { + String trimmedLine = line.trim(); + if (trimmedLine.isEmpty()) { + return; + } + String lowerLine = trimmedLine.toLowerCase(); + if (lowerLine.contains("error") || lowerLine.contains("failed")) { + LOGGER.warn(trimmedLine); + } else if (isDownloadMessage(trimmedLine)) { + LOGGER.trace(trimmedLine); + } else { + LOGGER.debug(trimmedLine); + } + } + @Override public String toString() { StringBuilder result = new StringBuilder(); @@ -161,6 +220,10 @@ public String toString() { private void buildOutputAndErrorStreamData() throws IOException { StringBuilder sbInStream = new StringBuilder(); StringBuilder sbErrorStream = new StringBuilder(); + // Carries an incomplete trailing line across chunk reads, since a single line of + // output can be split across two BUFFER_LEN-sized reads (or even two outer-loop + // iterations). Only complete lines are ever classified/logged from this buffer. + StringBuilder pendingErrorLine = new StringBuilder(); try { InputStream in = this.checked_process.getInputStream(); @@ -203,19 +266,25 @@ private void buildOutputAndErrorStreamData() throws IOException { break; } tempSB.append(charBuffer, 0, readCount); + // The full, unfiltered chunk is always kept here, so getErrorStream() always + // returns the complete error output. Download-message filtering below only + // affects the verbosity of the console log, not the returned stream content. sbErrorStream.append(tempSB); if (tempSB.length() > 0) { outputProduced = true; String temp = new String(tempSB); temp = temp.replaceAll("Pseudo-terminal will not be allocated because stdin is not a terminal.", ""); - //TODO : error stream output need to be improved, because it outputs downloading information. if (printToConsole) { - if (!temp.trim().equals("")) { - if (temp.toLowerCase().contains("error") || temp.toLowerCase().contains("failed")) { - LOGGER.warn(temp.trim()); - } else { - LOGGER.debug(temp.trim()); - } + // Buffer chunks can hold several lines, and a line can itself be split + // across chunks/iterations, so accumulate into pendingErrorLine and only + // classify/log complete lines. The trailing remainder (no newline yet) + // stays buffered until more data (or stream close) completes it. + pendingErrorLine.append(temp); + int newlineIndex; + while ((newlineIndex = pendingErrorLine.indexOf("\n")) >= 0) { + String line = pendingErrorLine.substring(0, newlineIndex); + pendingErrorLine.delete(0, newlineIndex + 1); + logErrorLine(line); } } } @@ -246,6 +315,14 @@ private void buildOutputAndErrorStreamData() throws IOException { } } + // Stream ended (or we gave up waiting) - the process will send no more data, so + // whatever is left in pendingErrorLine is a final, unterminated line. Flush it + // rather than silently dropping it. + if (printToConsole && pendingErrorLine.length() > 0) { + logErrorLine(pendingErrorLine.toString()); + pendingErrorLine.setLength(0); + } + in.close(); inErrors.close(); } finally { diff --git a/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessDataTest.java b/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessDataTest.java new file mode 100644 index 00000000000..a7df1dca30f --- /dev/null +++ b/zeppelin-integration/src/test/java/org/apache/zeppelin/ProcessDataTest.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class ProcessDataTest { + + private final ProcessData processData = new ProcessData(null, false); + + @Test + public void detectsMavenDownloadMessages() { + assertTrue(processData.isDownloadMessage( + "[INFO] Downloading: https://repo1.maven.org/maven2/foo/foo.jar")); + assertTrue(processData.isDownloadMessage( + "[INFO] Downloaded: https://repo1.maven.org/maven2/foo/foo.jar (12 kB at 45 kB/s)")); + assertTrue(processData.isDownloadMessage("Downloading from central: https://example.com/foo.jar")); + assertTrue(processData.isDownloadMessage("Downloaded from central: https://example.com/foo.jar")); + } + + @Test + public void detectsProgressAndSizeMessages() { + assertTrue(processData.isDownloadMessage("Progress (1): 45%")); + assertTrue(processData.isDownloadMessage("progress: 45%")); + assertTrue(processData.isDownloadMessage("1024/2048 KB")); + assertTrue(processData.isDownloadMessage("1.5/12 kB")); + } + + @Test + public void doesNotFilterOutRealErrorLines() { + // These lines contain download-shaped figures but are genuine failures and must + // never be classified as a download message, otherwise they would only ever be + // reachable via the download-noise path instead of being surfaced as warnings. + assertFalse(processData.isDownloadMessage("Task failed after writing 1024/2048 MB")); + assertFalse(processData.isDownloadMessage("Build failed at progress: 50%")); + assertFalse(processData.isDownloadMessage("ERROR: could not resolve dependency foo:bar:1.0")); + assertFalse(processData.isDownloadMessage("Compilation error in Main.java")); + } + + @Test + public void ignoresBlankOrNullInput() { + assertFalse(processData.isDownloadMessage("")); + assertFalse(processData.isDownloadMessage(null)); + } +} \ No newline at end of file From 9521f7cb8a49656d844882257f318358588b8320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=ED=99=98?= <66408194+dev-donghwan@users.noreply.github.com> Date: Tue, 21 Jul 2026 00:21:15 +0900 Subject: [PATCH 102/179] [ZEPPELIN-6479] Harden Hive version parsing against missing-dot and qualifier-suffix versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `HiveUtils.isProgressBarSupported(String)` decides whether to show the Hive query progress bar by parsing the version returned by `HiveVersionInfo.getVersion()`. The previous implementation split the version on `.` and parsed the first two tokens with `Integer.parseInt` with no validation, so it threw for two version shapes that real Hive builds can produce: - **Missing dot** (e.g. `"2"`): the split yields a single-element array, so reading `tokens[1]` throws `ArrayIndexOutOfBoundsException`. - **Qualifier suffix** (e.g. `"3-cdh"`, `"2.3-dev"`): a numeric segment carries a trailing qualifier, so `Integer.parseInt` throws `NumberFormatException`. Either exception propagates into `startHiveMonitorThread()` and can break Hive job monitoring setup. This PR makes the parser return a boolean for any input without throwing: - strips any qualifier after the numeric version (`"3-cdh"` -> `"3"`, `"2.3-dev"` -> `"2.3"`), - treats a missing minor segment as absent (`"3"` -> major 3 = supported, `"2"` -> major 2 with no minor = not supported), - returns `false` for null / blank / otherwise unparsable versions. The support rule is unchanged (progress bar is supported from Hive 2.3, HIVE-16045); it is only made robust and expressed as explicit tiers: major >= 3 always supported, major <= 1 unsupported, major == 2 depends on minor >= 3. ### What type of PR is it? Bug Fix ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6479 ### How should this be tested? `./mvnw test -pl jdbc -Dtest=HiveUtilsTest` The new `testIsProgressBarSupported` calls `HiveUtils.isProgressBarSupported` directly — the method is made package-private to match its sibling helpers in the same class (`extractMRJobURL`, `extractTezAppId`), which are already package-private and unit-tested the same way (no reflection). Testing through the only caller (`startHiveMonitorThread`) is not practical because the version is obtained internally from `HiveVersionInfo.getVersion()` and the method needs a live `HiveStatement`, so the edge-case versions cannot be injected. Cases cover the 2.3 boundary, both failure modes, null/blank input, and recent Maven Central releases (Hive 4.2.0 and 4.0.0-beta-1). ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5328 from dev-donghwan/ZEPPELIN-6479. Signed-off-by: ChanHo Lee --- .../apache/zeppelin/jdbc/hive/HiveUtils.java | 24 +++++++++++++++---- .../zeppelin/jdbc/hive/HiveUtilsTest.java | 20 ++++++++++++++++ 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/hive/HiveUtils.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/hive/HiveUtils.java index f2c683faef6..bc141986ff6 100644 --- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/hive/HiveUtils.java +++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/hive/HiveUtils.java @@ -219,11 +219,25 @@ private static boolean isHadoopJarAvailable() { } // Hive progress bar is supported from hive 2.3 (HIVE-16045) - private static boolean isProgressBarSupported(String hiveVersion) { - String[] tokens = hiveVersion.split("\\."); - int majorVersion = Integer.parseInt(tokens[0]); - int minorVersion = Integer.parseInt(tokens[1]); - return majorVersion > 2 || ((majorVersion == 2) && minorVersion >= 3); + static boolean isProgressBarSupported(String hiveVersion) { + if (StringUtils.isBlank(hiveVersion)) { + return false; // null / blank -> unsupported + } + // Drop any qualifier after the numeric version: "3-cdh" -> "3", "2.3-dev" -> "2.3" + String[] tokens = hiveVersion.replaceAll("[^0-9.].*$", "").split("\\."); + try { + int majorVersion = Integer.parseInt(tokens[0]); + if (majorVersion >= 3) { + return true; // 3.x and above -> always supported + } + if (majorVersion <= 1) { + return false; // 1.x and below -> unsupported + } + // major == 2 -> supported from 2.3 onward + return tokens.length > 1 && Integer.parseInt(tokens[1]) >= 3; + } catch (NumberFormatException e) { + return false; // unparsable version -> unsupported + } } // extract hive job url from logs, it only works for MR engine. diff --git a/jdbc/src/test/java/org/apache/zeppelin/jdbc/hive/HiveUtilsTest.java b/jdbc/src/test/java/org/apache/zeppelin/jdbc/hive/HiveUtilsTest.java index 11e940f09fc..1e7ab944793 100644 --- a/jdbc/src/test/java/org/apache/zeppelin/jdbc/hive/HiveUtilsTest.java +++ b/jdbc/src/test/java/org/apache/zeppelin/jdbc/hive/HiveUtilsTest.java @@ -22,6 +22,7 @@ import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -51,4 +52,23 @@ public void testTezAppId() { assertTrue(appId.isPresent()); assertEquals("application_1612885840821_260263", appId.get()); } + + @Test + public void testIsProgressBarSupported() { + // null / blank versions + assertFalse(HiveUtils.isProgressBarSupported(null)); + assertFalse(HiveUtils.isProgressBarSupported("")); + // supported only from Hive 2.3 (HIVE-16045) + assertFalse(HiveUtils.isProgressBarSupported("2")); + assertFalse(HiveUtils.isProgressBarSupported("2.2")); + assertTrue(HiveUtils.isProgressBarSupported("2.3")); + assertTrue(HiveUtils.isProgressBarSupported("3.1.3")); + assertFalse(HiveUtils.isProgressBarSupported("1.2.1")); + // versions with a trailing qualifier or a missing minor segment + assertTrue(HiveUtils.isProgressBarSupported("2.3-dev")); + assertTrue(HiveUtils.isProgressBarSupported("3-cdh")); + // real-world releases up to 2026 (both on Maven Central) + assertTrue(HiveUtils.isProgressBarSupported("4.2.0")); // latest Apache Hive + assertTrue(HiveUtils.isProgressBarSupported("4.0.0-beta-1")); // Hive 4 pre-release + } } From fb7f9dc86f2966395610cf8fa7942f6a56abf274 Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:48:54 +0900 Subject: [PATCH 103/179] [ZEPPELIN-6540] Make ConnectionManager.userSocketMap thread-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `ConnectionManager.userSocketMap` (`user -> Queue`) is a plain `HashMap`, but every access to it is unsynchronized: `addUserConnection`/`removeUserConnection` (writes) and `multicastToUser`/`unicastParagraph`/`forAllUsers`/`broadcastNoteListExcept` (reads and `keySet()` iteration). The sibling field `noteSocketMap` is guarded by `synchronized (noteSocketMap)` at every access — only `userSocketMap` was left unprotected. These paths run on different Jetty WebSocket threads (login `onMessage`, disconnect `onClose`, note-list broadcast `broadcastNoteListUpdate`). Under concurrent connect/disconnect — e.g. a burst of client reconnects after a server restart — this leads to: - `ConcurrentModificationException` while iterating `keySet()`, aborting the note-list broadcast so some users stop receiving updates - possible CPU spin / lost entries during `HashMap` resize - `NullPointerException` from the `containsKey` + `get` TOCTOU in `multicastToUser`/`unicastParagraph` The map value is already a `ConcurrentLinkedQueue`, so only the map itself was unprotected. Fix: switch `userSocketMap` to `ConcurrentHashMap` and make the compound operations atomic: - `addUserConnection`: `compute(...)` so the queue create-or-reuse and the `add` happen in one atomic map operation (closing the add-after-remove window that a bare `computeIfAbsent(...).add(...)` would leave open) - `removeUserConnection`: `computeIfPresent(...)`, removing the key when the queue becomes empty - `multicastToUser` / `unicastParagraph`: a single `get()` + null check, removing the TOCTOU/NPE - `forAllUsers` / `broadcastNoteListExcept`: unchanged — `keySet()` iteration is safe under `ConcurrentHashMap`'s weakly-consistent iterator `noteSocketMap` intentionally keeps `synchronized`: it needs multi-entry atomic operations (`removeConnectionFromAllNote`, `checkCollaborativeStatus`) that a per-key `ConcurrentHashMap` guarantee does not cover, so a single-strategy migration would not be correct there. ### What type of PR is it? Bug Fix ### Todos * [ ] - none ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6540 ### How should this be tested? Added two unit tests in `ConnectionManagerTest`: - `userSocketMapConcurrentAccessTest`: 8 writer threads add/remove connections while 2 reader threads iterate via `forAllUsers`. On the old `HashMap` this reproduces `ConcurrentModificationException` / `NullPointerException`; with the fix it passes with no thrown exception. - `userSocketMapConcurrentAddPreservesAllConnectionsTest`: 16 threads concurrently add unique sockets for the same user, then assert every socket is present and the final queue size matches — validates the atomic publish `compute()` guarantees. Ran the full `ConnectionManagerTest` 5× consecutively — stable, no intermittent failures. Note on the add-after-remove window: it is extremely narrow and did not reproduce as a deterministic failing test even under heavy contention (16 churn threads, 16×5000 iterations). The `compute()` fix closes it by construction (atomic per-key create-and-add under `ConcurrentHashMap`); the correctness rests on that plus the concurrent-add invariant test rather than a RED→GREEN of the exact interleaving. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No — public method signatures are unchanged. * Does this needs documentation? No. Closes #5306 from HwangRock/ZEPPELIN-6540. Signed-off-by: ParkGyeongTae --- .../zeppelin/socket/ConnectionManager.java | 42 +++--- .../socket/ConnectionManagerTest.java | 142 ++++++++++++++++++ 2 files changed, 166 insertions(+), 18 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java index a348d218afb..6b13613ccec 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/ConnectionManager.java @@ -53,6 +53,7 @@ import java.util.Map.Entry; import java.util.Queue; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; /** @@ -71,7 +72,7 @@ public class ConnectionManager { // noteId -> connection final Map> noteSocketMap = Metrics.gaugeMapSize("zeppelin_note_sockets", Tags.empty(), new HashMap<>()); // user -> connection - final Map> userSocketMap = Metrics.gaugeMapSize("zeppelin_user_sockets", Tags.empty(), new HashMap<>()); + final Map> userSocketMap = Metrics.gaugeMapSize("zeppelin_user_sockets", Tags.empty(), new ConcurrentHashMap<>()); /** * This is a special endpoint in the notebook websocket, Every connection in this Queue @@ -153,24 +154,27 @@ public void removeConnectionFromAllNote(NotebookSocket socket) { public void addUserConnection(String user, NotebookSocket conn) { LOGGER.debug("Add user connection {} for user: {}", conn, user); conn.setUser(user); - if (userSocketMap.containsKey(user)) { - userSocketMap.get(user).add(conn); - } else { - Queue socketQueue = new ConcurrentLinkedQueue<>(); - socketQueue.add(conn); - userSocketMap.put(user, socketQueue); - } + userSocketMap.compute(user, (k, connections) -> { + Queue queue = + (connections == null) ? new ConcurrentLinkedQueue<>() : connections; + queue.add(conn); + return queue; + }); } public void removeUserConnection(String user, NotebookSocket conn) { LOGGER.debug("Remove user connection {} for user: {}", conn, user); - if (userSocketMap.containsKey(user)) { - Queue connections = userSocketMap.get(user); + if (user == null) { + LOGGER.warn("Closing connection for null user"); + return; + } + boolean[] wasPresent = {false}; + userSocketMap.computeIfPresent(user, (k, connections) -> { + wasPresent[0] = true; connections.remove(conn); - if (connections.isEmpty()) { - userSocketMap.remove(user); - } - } else { + return connections.isEmpty() ? null : connections; + }); + if (!wasPresent[0]) { LOGGER.warn("Closing connection that is absent in user connections"); } } @@ -330,12 +334,13 @@ public Set getConnectedUsers() { public void multicastToUser(String user, Message m) { - if (!userSocketMap.containsKey(user)) { + Queue connections = userSocketMap.get(user); + if (connections == null) { LOGGER.warn("Multicasting to user {} that is not in connections map", user); return; } - for (NotebookSocket conn : userSocketMap.get(user)) { + for (NotebookSocket conn : connections) { unicast(m, conn); } } @@ -354,12 +359,13 @@ public void unicastParagraph(Note note, Paragraph p, String user, String msgId) return; } - if (!userSocketMap.containsKey(user)) { + Queue connections = userSocketMap.get(user); + if (connections == null) { LOGGER.warn("Failed to send unicast. user {} that is not in connections map", user); return; } - for (NotebookSocket conn : userSocketMap.get(user)) { + for (NotebookSocket conn : connections) { Message m = new Message(Message.OP.PARAGRAPH).withMsgId(msgId).put("paragraph", p); unicast(m, conn); } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/ConnectionManagerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/ConnectionManagerTest.java index 92adc93c795..562d0658949 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/ConnectionManagerTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/ConnectionManagerTest.java @@ -16,18 +16,25 @@ */ package org.apache.zeppelin.socket; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Queue; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.notebook.AuthorizationService; @@ -142,6 +149,122 @@ void removeWatcherConnectionConcurrentTest() throws InterruptedException { assertEquals(0, manager.watcherSockets.size()); } + @Test + void userSocketMapConcurrentAccessTest() throws InterruptedException { + AuthorizationService authService = mock(AuthorizationService.class); + when(authService.getRoles(anyString())).thenAnswer(invocation -> new HashSet<>()); + ConnectionManager manager = new ConnectionManager(authService, ZeppelinConfiguration.load()); + + int writerCount = 8; + int readerCount = 2; + int iterations = 1000; + + List users = new ArrayList<>(); + List sockets = new ArrayList<>(); + for (int i = 0; i < writerCount; i++) { + users.add("user-" + i); + sockets.add(mock(NotebookSocket.class)); + } + + AtomicReference failure = new AtomicReference<>(); + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(writerCount + readerCount); + ExecutorService executor = Executors.newFixedThreadPool(writerCount + readerCount); + + for (int i = 0; i < writerCount; i++) { + String user = users.get(i); + NotebookSocket socket = sockets.get(i); + executor.submit(() -> { + try { + startLatch.await(); + for (int j = 0; j < iterations; j++) { + manager.addUserConnection(user, socket); + manager.removeUserConnection(user, socket); + } + } catch (Throwable t) { + failure.compareAndSet(null, t); + } finally { + doneLatch.countDown(); + } + }); + } + + for (int i = 0; i < readerCount; i++) { + executor.submit(() -> { + try { + startLatch.await(); + for (int j = 0; j < iterations; j++) { + manager.forAllUsers((user, userAndRoles) -> { }); + } + } catch (Throwable t) { + failure.compareAndSet(null, t); + } finally { + doneLatch.countDown(); + } + }); + } + + startLatch.countDown(); + assertTrue(doneLatch.await(30, TimeUnit.SECONDS)); + executor.shutdown(); + + assertNull(failure.get(), + "Concurrent access to userSocketMap should not throw, but got: " + failure.get()); + } + + @Test + void userSocketMapConcurrentAddPreservesAllConnectionsTest() throws InterruptedException { + AuthorizationService authService = mock(AuthorizationService.class); + ConnectionManager manager = new ConnectionManager(authService, ZeppelinConfiguration.load()); + + String user = "shared-user"; + int threadCount = 16; + int iterationsPerThread = 500; + + AtomicReference failure = new AtomicReference<>(); + List addedSockets = new CopyOnWriteArrayList<>(); + + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + CountDownLatch startLatch = new CountDownLatch(1); + CountDownLatch doneLatch = new CountDownLatch(threadCount); + for (int i = 0; i < threadCount; i++) { + executor.submit(() -> { + try { + startLatch.await(); + for (int j = 0; j < iterationsPerThread; j++) { + NotebookSocket socket = mock(NotebookSocket.class); + manager.addUserConnection(user, socket); + addedSockets.add(socket); + } + } catch (Throwable t) { + failure.compareAndSet(null, t); + } finally { + doneLatch.countDown(); + } + }); + } + + startLatch.countDown(); + assertTrue(doneLatch.await(30, TimeUnit.SECONDS)); + executor.shutdown(); + + assertNull(failure.get(), "Concurrent add should not throw, but got: " + failure.get()); + + Queue finalConnections = manager.userSocketMap.get(user); + assertEquals(threadCount * iterationsPerThread, addedSockets.size()); + List missing = new ArrayList<>(); + for (NotebookSocket socket : addedSockets) { + if (finalConnections == null || !finalConnections.contains(socket)) { + missing.add(socket); + } + } + + assertTrue(missing.isEmpty(), + missing.size() + " of " + addedSockets.size() + + " concurrently added connections were lost from userSocketMap"); + assertEquals(addedSockets.size(), finalConnections.size()); + } + @Test void switchConnectionToWatcherAndRemove() { AuthorizationService authService = mock(AuthorizationService.class); @@ -168,4 +291,23 @@ void switchConnectionToWatcherAndRemove() { // Verify it's completely removed assertFalse(manager.watcherSockets.contains(socket)); } + + @Test + void removeUserConnectionWithNullUserDoesNotThrow() { + AuthorizationService authService = mock(AuthorizationService.class); + ConnectionManager manager = new ConnectionManager(authService, ZeppelinConfiguration.load()); + NotebookSocket socket = mock(NotebookSocket.class); + + assertDoesNotThrow(() -> manager.removeUserConnection(null, socket)); + } + + @Test + void removeUserConnectionBeforeUserAssignment() { + AuthorizationService authService = mock(AuthorizationService.class); + ConnectionManager manager = new ConnectionManager(authService, ZeppelinConfiguration.load()); + NotebookSocket socket = mock(NotebookSocket.class); + + assertDoesNotThrow(() -> manager.removeUserConnection("", socket)); + assertTrue(manager.userSocketMap.isEmpty()); + } } From 52397c8cd585fd821837432ff94c2b49f4ba2fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:02:43 +0900 Subject: [PATCH 104/179] [ZEPPELIN-6443] Avoid misleading elapsed-time footer when a running paragraph has no dateStarted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Angular paragraph footer fell back to `new Date()` when `dateStarted` was undefined for a running paragraph, which rendered a misleading `Started less than a minute ago.` message — implying the run had just started when the real start time was simply unknown (a race where the paragraph is `RUNNING` before `dateStarted` is populated). This PR shows a neutral `Running…` label instead when the start time is unknown, and keeps the existing `Started X ago.` output when `dateStarted` is present. The same bug/fix applies to the React `ParagraphFooter` twin, and a unit test is added there for the missing-`dateStarted` case (the Angular project has no unit-test setup). The pre-existing `TODO(hsuanxyz) dateStarted undefined after start` is resolved. ### What type of PR is it? Bug Fix ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6443 ### How should this be tested? - `cd zeppelin-web-angular && npm run lint` - React unit tests: `cd zeppelin-web-angular/projects/zeppelin-react && npm test` (covers the `Running…` / missing-`dateStarted` case) - Manually: run a paragraph and confirm the running (elapsed-time) and finished (execution-time) footers still render correctly. ### Screenshots (if appropriate) N/A ### Questions: - Does the licenses files need to update? No - Is there breaking changes for older versions? No - Does this needs documentation? No 🤖 Generated with [Claude Code](https://claude.com/claude-code) Closes #5330 from kimyenac/ZEPPELIN-6443. Signed-off-by: YONGJAE LEE --- .../paragraph/ParagraphFooter.spec.tsx | 14 +++++++++++ .../components/paragraph/ParagraphFooter.tsx | 25 ++++++++----------- .../paragraph/footer/footer.component.ts | 9 +++++-- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx index 69d1476b4f6..43e5bec30a6 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.spec.tsx @@ -96,6 +96,20 @@ describe('ParagraphFooter mount contract', () => { } }); + it('renders a neutral "Running…" label while running without a dateStarted', () => { + mountFooter({ + ...baseProps, + dateStarted: undefined, + showExecutionTime: false, + showElapsedTime: true + }); + + // A missing dateStarted must not produce a misleading "Started 0 seconds ago" message. + const elapsedTime = host!.querySelector('.elapsed-time')!; + expect(elapsedTime.textContent).toBe('Running…'); + expect(elapsedTime.textContent).not.toMatch(/Started/); + }); + it('update() re-renders in place with new props', () => { mountFooter(baseProps); expect(host!.querySelector('.execution-time')).not.toBeNull(); diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx index d73f881653b..1adec800f5c 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx +++ b/zeppelin-web-angular/projects/zeppelin-react/src/components/paragraph/ParagraphFooter.tsx @@ -26,11 +26,7 @@ export interface ParagraphFooterProps { } const isOutdated = (dateUpdated?: string, dateStarted?: string): boolean => { - return ( - dateUpdated !== undefined && - dateStarted !== undefined && - Date.parse(dateUpdated) > Date.parse(dateStarted) - ); + return dateUpdated !== undefined && dateStarted !== undefined && Date.parse(dateUpdated) > Date.parse(dateStarted); }; const computeExecutionTime = (props: ParagraphFooterProps): string => { @@ -43,10 +39,7 @@ const computeExecutionTime = (props: ParagraphFooterProps): string => { return isOutdated(dateUpdated, dateStarted) ? 'outdated' : ''; } - const durationFormat = formatDistanceStrict( - new Date(dateStarted), - new Date(dateFinished) - ); + const durationFormat = formatDistanceStrict(new Date(dateStarted), new Date(dateFinished)); const endFormat = format(new Date(dateFinished), 'MMMM dd yyyy, h:mm:ss a'); const userLabel = user === undefined || user === null ? 'anonymous' : user; let desc = `Took ${durationFormat}. Last updated by ${userLabel} at ${endFormat}.`; @@ -57,8 +50,13 @@ const computeExecutionTime = (props: ParagraphFooterProps): string => { }; const computeElapsedTime = (dateStarted?: string): string => { - const base = dateStarted ? new Date(dateStarted) : new Date(); - return `Started ${formatDistanceToNow(base)} ago.`; + // A running paragraph may not have a dateStarted yet (e.g. queued/pending on the + // interpreter). Fall back to a neutral label instead of measuring from "now", which + // would render a misleading "Started less than a minute ago." message. + if (!dateStarted) { + return 'Running…'; + } + return `Started ${formatDistanceToNow(new Date(dateStarted))} ago.`; }; export const ParagraphFooter = (props: ParagraphFooterProps) => { @@ -79,10 +77,7 @@ export interface ParagraphFooterMountHandle { unmount: () => void; } -export const mount = ( - element: HTMLElement, - initialProps: ParagraphFooterProps -): ParagraphFooterMountHandle => { +export const mount = (element: HTMLElement, initialProps: ParagraphFooterProps): ParagraphFooterMountHandle => { if (!element) { throw new Error('Mount element is required'); } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts index 6495742e26d..7441edd2d5f 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/footer/footer.component.ts @@ -67,8 +67,13 @@ export class NotebookParagraphFooterComponent implements OnChanges { } getElapsedTime() { - // TODO(hsuanxyz) dateStarted undefined after start - return `Started ${formatDistanceToNow(this.dateStarted ? new Date(this.dateStarted) : new Date())} ago.`; + // A running paragraph may not have a dateStarted yet (e.g. queued/pending on the + // interpreter). Fall back to a neutral label instead of measuring from "now", which + // would render a misleading "Started less than a minute ago." message. + if (!this.dateStarted) { + return 'Running…'; + } + return `Started ${formatDistanceToNow(new Date(this.dateStarted))} ago.`; } constructor() {} From 7dd659ee633466caec6e36079dc478ef36a2873d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Wed, 22 Jul 2026 00:03:39 +0900 Subject: [PATCH 105/179] [HOTFIX] Fix 3 high-severity npm audit vulnerabilities in zeppelin-react MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The `npm-audit` CI job (`.github/workflows/frontend.yml`) is failing on `master` because `npm audit --audit-level=high` reports 3 high-severity advisories in zeppelin-react's transitive dev-toolchain dependencies: | Package | Advisory | Issue | |---|---|---| | `brace-expansion` | [GHSA-3jxr-9vmj-r5cp](https://github.com/advisories/GHSA-3jxr-9vmj-r5cp) | DoS via exponential-time `{}` expansion | | `js-yaml` | [GHSA-52cp-r559-cp3m](https://github.com/advisories/GHSA-52cp-r559-cp3m) | Quadratic CPU on YAML merge-key chains | | `shell-quote` | [GHSA-395f-4hp3-45gv](https://github.com/advisories/GHSA-395f-4hp3-45gv) | Quadratic-complexity DoS in `parse()` | All three are non-breaking, in-range fixes applied via `npm audit fix` (lockfile-only; `package.json` is untouched). Resolved versions: `brace-expansion` 1.1.16 / 5.0.7, `js-yaml` 4.3.0, `shell-quote` 1.10.0. ### What type of PR is it? Hotfix (CI) ### What is the Jira issue? N/A — CI hotfix, no functional change. ### How should this be tested? Verified locally under CI-matching Node 22.21.1 (`.nvmrc`) / npm 10.9.4: - `cd zeppelin-web-angular/projects/zeppelin-react` - `npm ci --ignore-scripts && npm audit --audit-level=high` → `found 0 vulnerabilities` (exit 0 — the exact npm-audit CI step) - `npm test` → 13 passed - `npm run lint` → no issues ### Screenshots (if appropriate) N/A ### Questions: - Does the licenses files need to update? No - Is there breaking changes for older versions? No - Does this needs documentation? No Closes #5334 from voidmatcha/hotfix/react-npm-audit. Signed-off-by: ChanHo Lee --- .../projects/zeppelin-react/package-lock.json | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index 6a209e61829..00c5813aecf 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -509,9 +509,9 @@ "license": "MIT" }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -590,9 +590,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -3345,9 +3345,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", "dev": true, "license": "MIT", "dependencies": { @@ -4729,9 +4729,9 @@ "license": "MIT" }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4800,9 +4800,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", "dev": true, "license": "MIT", "dependencies": { @@ -6462,9 +6462,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", + "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", "dev": true, "funding": [ { @@ -9435,9 +9435,9 @@ } }, "node_modules/shell-quote": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", - "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", "dev": true, "license": "MIT", "engines": { From 554fffe9d349bb55a23a61ac4559b28edc647268 Mon Sep 17 00:00:00 2001 From: YeonKyung Ryu <80758099+celinayk@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:05:02 +0900 Subject: [PATCH 106/179] [ZEPPELIN-6502] Replace deprecated openjdk Docker image with Eclipse Temurin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The root `Dockerfile` used the `openjdk:11` base image for its build stage, but that image is deprecated on Docker Hub and no longer receives updates. This PR replaces it with `eclipse-temurin:11-jdk`, the community-recommended drop-in successor, and uppercases the `AS` keyword to match modern Dockerfile (BuildKit) convention ### What type of PR is it? Improvement ### Todos * [x] Replace `FROM openjdk:11 as builder` with `FROM eclipse-temurin:11-jdk AS builder` ### What is the Jira issue? [ZEPPELIN-6502](https://issues.apache.org/jira/browse/ZEPPELIN-6502) ### How should this be tested? * `docker build --check -f Dockerfile .` — confirms the image resolves and the Dockerfile has no lint warnings * Optionally run a full `docker build -f Dockerfile .` to confirm the image still builds and produces a working Zeppelin distribution ### Screenshots (if appropriate) N/A (Dockerfile change, no UI ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5331 from celinayk/ZEPPELIN-6502. Signed-off-by: ChanHo Lee --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 982e54ed443..61a7714282c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -FROM openjdk:11 as builder +FROM eclipse-temurin:11-jdk AS builder ADD . /workspace/zeppelin WORKDIR /workspace/zeppelin ENV MAVEN_OPTS="-Xms1024M -Xmx2048M -XX:MaxMetaspaceSize=1024m -XX:-UseGCOverheadLimit -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn" From a454d173e52edfe413fc57341c8d5002ad6659c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Wed, 22 Jul 2026 10:46:37 +0900 Subject: [PATCH 107/179] [ZEPPELIN-6547] Add collaboration-mode and editor-search e2e coverage for the new UI ### What is this PR for? Adds two e2e scenarios missing from the Angular suite and cleans up the action bar's personalized-mode toggle found along the way. - **Collaborative edit sync**: edits in one viewer propagate to a second viewer of the same note (same-principal scope). - **Editor find widget (per-paragraph Monaco)**: open via shortcut, match count and highlights, next/previous navigation, replace-all. The notebook-wide search/replace menu is unimplemented and tracked separately by [ZEPPELIN-6442](https://issues.apache.org/jira/browse/ZEPPELIN-6442), so its scenarios are out of scope here. - **Accessibility**: `aria-label` on the two icon-only personalized-mode toggle buttons (the only `src/` change). - **Test cleanup**: replaces the always-skipped action-bar toggle test (its gate targeted a `ng-container[ngSwitch=...]` that never renders) with a real toggle round-trip test (auth mode; skipped for anonymous, where the button isn't rendered). Page objects follow `e2e/AGENTS.md` (EditorSearchPage, CollaborationPage; shared auth-skip helper in `e2e/utils.ts`). ### What type of PR is it? Improvement ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6547 ### How should this be tested? Ran the collaboration and editor-search specs 10x per mode (anonymous + auth) across all browser projects with `--retries=0`, all green: https://github.com/voidmatcha/zeppelin/actions/runs/29684367065 ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5327 from voidmatcha/fix/new-ui-personalized-toggle-e2e. Signed-off-by: ChanHo Lee --- .../e2e/models/collaboration-page.ts | 62 ++++++++++++ .../e2e/models/editor-search-page.ts | 81 +++++++++++++++ .../e2e/models/notebook-action-bar-page.ts | 14 --- .../action-bar-functionality.spec.ts | 19 +--- .../collaboration/collaborative-mode.spec.ts | 90 +++++++++++++++++ .../notebook/search/editor-search.spec.ts | 98 +++++++++++++++++++ zeppelin-web-angular/e2e/utils.ts | 8 ++ .../action-bar/action-bar.component.html | 2 + 8 files changed, 342 insertions(+), 32 deletions(-) create mode 100644 zeppelin-web-angular/e2e/models/collaboration-page.ts create mode 100644 zeppelin-web-angular/e2e/models/editor-search-page.ts create mode 100644 zeppelin-web-angular/e2e/tests/notebook/collaboration/collaborative-mode.spec.ts create mode 100644 zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts diff --git a/zeppelin-web-angular/e2e/models/collaboration-page.ts b/zeppelin-web-angular/e2e/models/collaboration-page.ts new file mode 100644 index 00000000000..6bab8540d6f --- /dev/null +++ b/zeppelin-web-angular/e2e/models/collaboration-page.ts @@ -0,0 +1,62 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Locator, Page } from '@playwright/test'; +import { waitForZeppelinReady } from '../utils'; +import { BasePage } from './base-page'; + +export class CollaborationPage extends BasePage { + readonly paragraph: Locator; + readonly editor: Locator; + readonly editorText: Locator; + readonly switchToPersonalModeButton: Locator; + readonly switchToCollaborationModeButton: Locator; + + constructor(page: Page) { + super(page); + // JUSTIFIED: CSS chains into Monaco's third-party DOM — it exposes no roles/test ids. + this.paragraph = page.locator('zeppelin-notebook-paragraph').first(); + this.editor = this.paragraph.locator('.monaco-editor').first(); + this.editorText = this.paragraph.locator('.view-lines').first(); + this.switchToPersonalModeButton = page.getByRole('button', { name: 'Switch to personal mode' }); + this.switchToCollaborationModeButton = page.getByRole('button', { name: 'Switch to collaboration mode' }); + } + + async openNotebook(noteId: string): Promise { + await this.page.goto(`/#/notebook/${noteId}`); + await waitForZeppelinReady(this.page); + await expect(this.paragraph).toBeVisible({ timeout: 15000 }); + } + + async getPrincipal(): Promise { + const response = await this.page.request.get('/api/security/ticket', { failOnStatusCode: false }); + if (!response.ok()) { + return ''; + } + const json = (await response.json()) as { body?: { principal?: string } }; + return json.body?.principal ?? ''; + } + + async confirmPersonalizedModeChange(): Promise { + // Scope to this dialog and wait for it to close, so a back-to-back toggle can't race the animation or hit another modal. + const dialog = this.page.locator('.ant-modal-confirm', { hasText: 'Setting the result display' }).first(); + await expect(dialog).toBeVisible({ timeout: 15000 }); + await dialog.locator('button:has-text("OK")').click(); + await expect(dialog).toBeHidden({ timeout: 15000 }); + } + + async typeInEditor(text: string): Promise { + await this.editor.click(); + // insertText avoids per-key events that can trigger Monaco autocomplete (see ZEPPELIN-6536). + await this.page.keyboard.insertText(text); + } +} diff --git a/zeppelin-web-angular/e2e/models/editor-search-page.ts b/zeppelin-web-angular/e2e/models/editor-search-page.ts new file mode 100644 index 00000000000..d47ba32fc47 --- /dev/null +++ b/zeppelin-web-angular/e2e/models/editor-search-page.ts @@ -0,0 +1,81 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Locator, Page } from '@playwright/test'; +import { waitForZeppelinReady } from '../utils'; +import { BasePage } from './base-page'; + +export class EditorSearchPage extends BasePage { + readonly editor: Locator; + readonly editorText: Locator; + readonly findWidget: Locator; + readonly findInput: Locator; + readonly replaceInput: Locator; + readonly matchesCount: Locator; + readonly matchHighlights: Locator; + readonly nextMatchButton: Locator; + readonly previousMatchButton: Locator; + readonly toggleReplaceButton: Locator; + readonly replaceAllButton: Locator; + + constructor(page: Page) { + super(page); + // JUSTIFIED: Monaco's find-widget DOM exposes no roles/test ids; aria-label/title alternates used where available. + this.editor = page.locator('zeppelin-notebook-paragraph .monaco-editor').first(); + this.editorText = this.editor.locator('.view-lines').first(); + this.findWidget = this.editor.locator('.find-widget').first(); + this.findInput = this.findWidget + .locator('.monaco-findInput .input, input[aria-label="Find"], textarea[aria-label="Find"]') + .first(); + this.replaceInput = this.findWidget + .locator('.replace-input .input, input[aria-label="Replace"], textarea[aria-label="Replace"]') + .first(); + this.matchesCount = this.findWidget.locator('.matchesCount').first(); + // Monaco decorates every match with .findMatch and the active one with .currentFindMatch. + this.matchHighlights = this.editor.locator('.findMatch, .currentFindMatch'); + this.nextMatchButton = this.findWidget.locator('.button.next, [title^="Next Match"]').first(); + this.previousMatchButton = this.findWidget.locator('.button.previous, [title^="Previous Match"]').first(); + this.toggleReplaceButton = this.findWidget.locator('.button.toggle, [title^="Toggle Replace"]').first(); + this.replaceAllButton = this.findWidget.locator('.button.replace-all, [title^="Replace All"]').first(); + } + + async openNotebook(noteId: string): Promise { + await this.page.goto(`/#/notebook/${noteId}`); + await waitForZeppelinReady(this.page); + await expect(this.editor).toBeVisible({ timeout: 15000 }); + } + + async setEditorContent(content: string): Promise { + await this.editor.click(); + // Key off the browser, not the host: Monaco follows the browser UA's keymap, and + // webkit emulates macOS (Meta) even on a Linux CI host. + const isWebkit = this.page.context().browser()?.browserType().name() === 'webkit'; + await this.page.keyboard.press(isWebkit ? 'Meta+A' : 'ControlOrMeta+A'); + await this.page.keyboard.insertText(content); + await expect(this.editorText).toContainText(content.split('\n')[0], { timeout: 15000 }); + } + + async openFindWidget(): Promise { + await this.editor.click(); + // 'Home' anchors the find widget on the first match (cursor sits at end after seeding); + // keymap-independent, and single-line content means line start == document start. + await this.page.keyboard.press('Home'); + // Control+S is Zeppelin's SearchInsideCode binding (shortcuts-map.ts), not a typo of Control+F. + await this.page.keyboard.press('Control+S'); + await expect(this.findWidget).toBeVisible({ timeout: 15000 }); + } + + async searchFor(text: string): Promise { + await this.findInput.fill(text); + await expect(this.matchesCount).toBeVisible({ timeout: 15000 }); + } +} diff --git a/zeppelin-web-angular/e2e/models/notebook-action-bar-page.ts b/zeppelin-web-angular/e2e/models/notebook-action-bar-page.ts index d73b268c2dd..1ecc33bd2c1 100644 --- a/zeppelin-web-angular/e2e/models/notebook-action-bar-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-action-bar-page.ts @@ -22,9 +22,6 @@ export class NotebookActionBarPage extends BasePage { readonly cloneButton: Locator; readonly exportButton: Locator; readonly reloadButton: Locator; - readonly collaborationModeToggle: Locator; - readonly personalModeButton: Locator; - readonly collaborationModeButton: Locator; readonly commitButton: Locator; readonly setRevisionButton: Locator; readonly compareRevisionsButton: Locator; @@ -49,9 +46,6 @@ export class NotebookActionBarPage extends BasePage { this.cloneButton = page.locator('button[nzTooltipTitle="Clone this note"]'); this.exportButton = page.locator('button[nzTooltipTitle="Export this note"]'); this.reloadButton = page.locator('button[nzTooltipTitle="Reload from note file"]'); - this.collaborationModeToggle = page.locator('ng-container[ngSwitch="note.config.personalizedMode"]'); - this.personalModeButton = page.getByRole('button', { name: 'Personal' }); - this.collaborationModeButton = page.getByRole('button', { name: 'Collaboration' }); this.commitButton = page.getByRole('button', { name: 'Commit' }); this.setRevisionButton = page.getByRole('button', { name: 'Set as default revision' }); this.compareRevisionsButton = page.getByRole('button', { name: 'Compare with current revision' }); @@ -83,14 +77,6 @@ export class NotebookActionBarPage extends BasePage { await this.clearOutputButton.click(); } - async switchToPersonalMode(): Promise { - await this.personalModeButton.click(); - } - - async switchToCollaborationMode(): Promise { - await this.collaborationModeButton.click(); - } - async openRevisionDropdown(): Promise { await this.revisionDropdown.click(); } diff --git a/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts index 358e77c65dc..f8d158838b4 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts @@ -140,24 +140,7 @@ test.describe('Notebook Action Bar Functionality', () => { await expect(actionBarPage.reloadButton).toBeEnabled(); }); - test('should handle collaboration mode toggle when available', async () => { - test.skip( - !(await actionBarPage.collaborationModeToggle.isVisible()), - 'Collaboration mode not available in this environment' - ); - - const personalVisible = await actionBarPage.personalModeButton.isVisible(); - const collaborationVisible = await actionBarPage.collaborationModeButton.isVisible(); - expect(personalVisible || collaborationVisible).toBe(true); - - if (personalVisible) { - await actionBarPage.switchToPersonalMode(); - await expect(actionBarPage.collaborationModeButton).toBeVisible({ timeout: 5000 }); - } else if (collaborationVisible) { - await actionBarPage.switchToCollaborationMode(); - await expect(actionBarPage.personalModeButton).toBeVisible({ timeout: 5000 }); - } - }); + // Toggle coverage lives in collaboration/collaborative-mode.spec.ts. test('should handle revision controls when supported', async () => { test.skip(!(await actionBarPage.commitButton.isVisible()), 'Revision controls not supported in this environment'); diff --git a/zeppelin-web-angular/e2e/tests/notebook/collaboration/collaborative-mode.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/collaboration/collaborative-mode.spec.ts new file mode 100644 index 00000000000..7d463b7fb15 --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/notebook/collaboration/collaborative-mode.spec.ts @@ -0,0 +1,90 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, Page, test } from '@playwright/test'; +import { CollaborationPage } from 'e2e/models/collaboration-page'; +import { + addPageAnnotationBeforeEach, + createTestNotebook, + PAGES, + performLoginIfRequired, + skipWhenAuthenticationIsStillRequired, + waitForNotebookLinks, + waitForZeppelinReady +} from '../../../utils'; + +const prepareWorkspace = async (page: Page): Promise => { + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + await skipWhenAuthenticationIsStillRequired(page); + await waitForNotebookLinks(page); +}; + +test.describe('Collaborative mode', () => { + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); + + // Both viewers share one principal (same storageState); cross-principal routing/permissions are out of scope here. + test('syncs paragraph editor changes between two notebook viewers', async ({ page, browser }) => { + const syncText = `collaborative_mode_text_${Date.now()}`; + const collaborationPage = new CollaborationPage(page); + + await prepareWorkspace(page); + + const { noteId } = await createTestNotebook(page); + await collaborationPage.openNotebook(noteId); + + const collaboratorContext = await browser.newContext({ storageState: await page.context().storageState() }); + const collaboratorPage = await collaboratorContext.newPage(); + const collaboratorView = new CollaborationPage(collaboratorPage); + + try { + await collaboratorPage.goto('/#/'); + await waitForZeppelinReady(collaboratorPage); + await performLoginIfRequired(collaboratorPage); + await skipWhenAuthenticationIsStillRequired(collaboratorPage); + await collaboratorView.openNotebook(noteId); + + await expect(collaborationPage.editor).toBeVisible({ timeout: 15000 }); + await expect(collaboratorView.editor).toBeVisible({ timeout: 15000 }); + + await collaborationPage.typeInEditor(syncText); + + await expect(collaborationPage.editorText).toContainText(syncText, { timeout: 15000 }); + await expect(collaboratorView.editorText).toContainText(syncText, { timeout: 30000 }); + } finally { + await collaboratorContext.close(); + } + }); + + test('toggles between personal and collaboration mode from the action bar', async ({ page }) => { + const collaborationPage = new CollaborationPage(page); + + await prepareWorkspace(page); + + const principal = await collaborationPage.getPrincipal(); + test.skip(!principal || principal === 'anonymous', 'The mode toggle is not rendered for anonymous principals'); + + const { noteId } = await createTestNotebook(page); + await collaborationPage.openNotebook(noteId); + + await expect(collaborationPage.switchToPersonalModeButton).toBeVisible({ timeout: 15000 }); + + await collaborationPage.switchToPersonalModeButton.click(); + await collaborationPage.confirmPersonalizedModeChange(); + await expect(collaborationPage.switchToCollaborationModeButton).toBeVisible({ timeout: 15000 }); + + await collaborationPage.switchToCollaborationModeButton.click(); + await collaborationPage.confirmPersonalizedModeChange(); + await expect(collaborationPage.switchToPersonalModeButton).toBeVisible({ timeout: 15000 }); + }); +}); diff --git a/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts new file mode 100644 index 00000000000..a7420914f1c --- /dev/null +++ b/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts @@ -0,0 +1,98 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, test } from '@playwright/test'; +import { EditorSearchPage } from 'e2e/models/editor-search-page'; +import { + addPageAnnotationBeforeEach, + createTestNotebook, + PAGES, + performLoginIfRequired, + skipWhenAuthenticationIsStillRequired, + waitForNotebookLinks, + waitForZeppelinReady +} from '../../../utils'; + +// Covers the per-paragraph Monaco find widget. The notebook-wide search/replace menu is +// unimplemented and tracked by ZEPPELIN-6442. +test.describe('Notebook editor search', () => { + addPageAnnotationBeforeEach(PAGES.WORKSPACE.NOTEBOOK); + + let editorSearchPage: EditorSearchPage; + + test.beforeEach(async ({ page }) => { + editorSearchPage = new EditorSearchPage(page); + await page.goto('/#/'); + await waitForZeppelinReady(page); + await performLoginIfRequired(page); + await skipWhenAuthenticationIsStillRequired(page); + await waitForNotebookLinks(page); + }); + + test('shows match count and navigates next and previous matches', async ({ page }) => { + const { noteId } = await createTestNotebook(page); + + await editorSearchPage.openNotebook(noteId); + await editorSearchPage.setEditorContent('alpha target beta target gamma target'); + await editorSearchPage.openFindWidget(); + await editorSearchPage.searchFor('target'); + + await expect(editorSearchPage.matchesCount).toContainText(/1 of 3/, { timeout: 15000 }); + + await editorSearchPage.nextMatchButton.click(); + await expect(editorSearchPage.matchesCount).toContainText(/2 of 3/, { timeout: 15000 }); + + await editorSearchPage.previousMatchButton.click(); + await expect(editorSearchPage.matchesCount).toContainText(/1 of 3/, { timeout: 15000 }); + }); + + test('opens the find widget with the search shortcut', async ({ page }) => { + const { noteId } = await createTestNotebook(page); + + await editorSearchPage.openNotebook(noteId); + await editorSearchPage.setEditorContent('find me in this line'); + await editorSearchPage.openFindWidget(); + + await expect(editorSearchPage.findWidget).toBeVisible(); + }); + + test('highlights every match in the editor', async ({ page }) => { + const { noteId } = await createTestNotebook(page); + + await editorSearchPage.openNotebook(noteId); + await editorSearchPage.setEditorContent('alpha target beta target gamma target'); + await editorSearchPage.openFindWidget(); + await editorSearchPage.searchFor('target'); + + await expect(editorSearchPage.matchesCount).toContainText(/1 of 3/, { timeout: 15000 }); + await expect(editorSearchPage.matchHighlights).toHaveCount(3); + }); + + test('replaces all matches in the editor search widget', async ({ page }) => { + const { noteId } = await createTestNotebook(page); + + await editorSearchPage.openNotebook(noteId); + await editorSearchPage.setEditorContent('replace_target one replace_target two replace_target'); + await editorSearchPage.openFindWidget(); + await editorSearchPage.searchFor('replace_target'); + await expect(editorSearchPage.matchesCount).toContainText(/1 of 3/, { timeout: 15000 }); + + await editorSearchPage.toggleReplaceButton.click(); + await editorSearchPage.replaceInput.fill('replacement'); + await editorSearchPage.replaceAllButton.click(); + + await expect(editorSearchPage.editorText).toContainText('replacement one replacement two replacement', { + timeout: 15000 + }); + await expect(editorSearchPage.editorText).not.toContainText('replace_target'); + }); +}); diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index 93aaf67f70a..25e6d4304b7 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -281,6 +281,14 @@ export const performLoginIfRequired = async (page: Page): Promise => { return false; }; +export const skipWhenAuthenticationIsStillRequired = async (page: Page): Promise => { + const loginStillVisible = await page + .locator('zeppelin-login') + .isVisible() + .catch(() => false); + test.skip(loginStillVisible, 'Authentication is enabled but no E2E test credentials are configured'); +}; + export const waitForZeppelinReady = async (page: Page, options: WaitForZeppelinReadyOptions = {}): Promise => { try { // Enhanced wait for network idle with longer timeout for CI environments diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html index b829227fd93..f53f5292dae 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.html @@ -95,6 +95,7 @@ } @else { - } @@ -373,6 +373,7 @@

    Properties

    @@ -471,6 +479,7 @@

    Dependencies

    From b82f14e5e9e7da0d9182af26f41d87aea91e1a98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Tue, 28 Jul 2026 01:09:57 +0900 Subject: [PATCH 119/179] [ZEPPELIN-6559] Drop the faked Windows user agent so Monaco keybindings match the host platform ### What is this PR for? `playwright.config.js` builds the chromium project from `devices['Desktop Chrome']`, whose `userAgent` is a hardcoded `Windows NT 10.0` string regardless of the host. Monaco picks its keybinding platform by sniffing that user agent, while Playwright's key resolution (`ControlOrMeta`) and the browser's native text editing follow the real OS. On a macOS host those disagree, and two things break. 1. Ctrl+P and Ctrl+N are never claimed by Monaco. The keydown reaches the document with `defaultPrevented === false`, so macOS Chromium runs its native Emacs-style caret binding inside Monaco's hidden textarea. The next typed character then lands in the wrong place: pressing `Control+P` and typing `MARKER` yields `M` on its own line and `line2ARKER` below it. 2. `Meta+A` select-all is a silent no-op. `pressSelectAll` resolves `ControlOrMeta+A` to `Meta+A` on macOS, but Windows-mode Monaco only binds `Ctrl+A`. No model event fires, so every select-all in the suite quietly did nothing locally. Linux CI is unaffected because its Chromium build has no native caret bindings, which is why this only ever showed up locally. Real users are not affected either: with a genuine macOS user agent Monaco runs in mac mode and calls `preventDefault`. This is a test-harness defect only. Unsetting the override is what Playwright recommends for this case (https://playwright.dev/docs/emulation#devices): > Pre-configured devices assume a specific platform. For example, "Desktop Chrome" will provide a Windows-specific user agent string. If you would like to use the user agent specific to the platform that is running the tests, we recommend unsetting the user agent property. webkit deliberately keeps its `Desktop Safari` mac user agent, because the page objects' `Meta+A` branch depends on it. Local (macOS) and CI (Linux) no longer share one keybinding platform as a result. That uniformity was not worth keeping: under it, select-all on macOS produced no model event at all, so the suite ran locally without exercising what it claimed to. ### What type of PR is it? Bug Fix ### Todos * [x] Verify `navigator.userAgent` reports the host platform after the change * [x] Run the keyboard spec on macOS * [x] Run the full chromium suite on CI ### What is the Jira issue? ZEPPELIN-6559 ### How should this be tested? CI covers the regression side: the full chromium suite reports 546 passed with no failure attributable to this change. The fix itself is only observable on a macOS host: ```bash cd zeppelin-web-angular npm run start npx playwright test e2e/tests/notebook/keyboard/ --project=chromium ``` Before: 3 passed, 1 failed (`ParagraphActions.MoveCursorUp: Control+P`). Because the suite is `describe.serial`, that first failure blocks every later test in the file. After: 31 passed, 0 failed. To confirm the user agent directly, read `navigator.userAgent` in any spec. It changes from the `Windows NT 10.0` string to `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ...`. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5342 from voidmatcha/fix/e2e-monaco-keybinding-platform. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/playwright.config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zeppelin-web-angular/playwright.config.js b/zeppelin-web-angular/playwright.config.js index 6633e6cd55c..292dbc3cab1 100644 --- a/zeppelin-web-angular/playwright.config.js +++ b/zeppelin-web-angular/playwright.config.js @@ -42,6 +42,10 @@ module.exports = defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'], + // Monaco reads the UA to pick its keybinding platform; the faked Windows string + // breaks Ctrl+P/N and Meta+A on macOS. https://playwright.dev/docs/emulation#devices + // webkit must keep its mac UA — the page objects' Meta+A branch relies on it. + userAgent: undefined, permissions: ['clipboard-read', 'clipboard-write'], storageState: 'playwright/.auth/user.json' }, From dbb58f81446f85524145234acf502574dbeaf848 Mon Sep 17 00:00:00 2001 From: JangAyeon <67853616+JangAyeon@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:04:19 +0900 Subject: [PATCH 120/179] [ZEPPELIN-6522] Guard HTTP interceptor unwrap against null response bodies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `AppHttpInterceptor.intercept` unwraps every `HttpResponse` as `event.body.body`, assuming the Zeppelin REST envelope (`{status, message, body}`). When `event.body` is `null` — a 204 No Content, or any empty 200 response — evaluating `event.body.body` throws `TypeError: Cannot read properties of null (reading 'body')`, which propagates to every subscriber of that request and turns an otherwise-successful empty response into a failure. Non-enveloped JSON and `responseType: 'text'` responses were never affected `event.body.body` is `undefined` for them, and `HttpResponse.clone()` keeps the original body when the update body is `undefined`. The defect was specific to the null-body case. This PR guards the unwrap on `event.body` being a non-null object that actually carries a `body` field; any other response (including null-body) now passes through `event.clone()` unchanged instead of touching `.body` on it. ### What type of PR is it? Bug Fix ### Todos * [x] Guard the unwrap so it only runs on a non-null object carrying a `body` field * [x] Verify enveloped responses still unwrap correctly * [x] Verify null-body responses pass through without throwing ### What is the Jira issue? [ZEPPELIN-6522](https://issues.apache.org/jira/browse/ZEPPELIN-6522) ### How should this be tested? * `cd zeppelin-web-angular && npm run lint` * Feed the four body shapes (enveloped object, non-enveloped object, text string, null) through `event.clone({ body: event.body.body })` using a real `angular/common/http` `HttpResponse`: before the fix, only the null case throws `TypeError: Cannot read properties of null (reading 'body')`; after the fix, all four pass through without throwing and the enveloped case still unwraps correctly. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5344 from JangAyeon/ZEPPELIN-6522. Signed-off-by: YONGJAE LEE --- zeppelin-web-angular/src/app/app-http.interceptor.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/zeppelin-web-angular/src/app/app-http.interceptor.ts b/zeppelin-web-angular/src/app/app-http.interceptor.ts index e3e4f26a4f0..b1e287622ac 100644 --- a/zeppelin-web-angular/src/app/app-http.interceptor.ts +++ b/zeppelin-web-angular/src/app/app-http.interceptor.ts @@ -32,7 +32,12 @@ export class AppHttpInterceptor implements HttpInterceptor { } return next.handle(httpRequestUpdated).pipe( map(event => { - if (event instanceof HttpResponse) { + if ( + event instanceof HttpResponse && + !isNil(event.body) && + typeof event.body === 'object' && + 'body' in event.body + ) { return event.clone({ body: event.body.body }); } else { return event; From cc5c38aafb2aabefc8182ef9139bb48c333329ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YONGJAE=20LEE=20=28=EC=9D=B4=EC=9A=A9=EC=9E=AC=29?= Date: Wed, 29 Jul 2026 23:29:41 +0900 Subject: [PATCH 121/179] [ZEPPELIN-6562] Fix specs that silently pass or flake because they target DOM the new UI no longer renders ### What is this PR for? Several new UI specs target DOM that the previous UI rendered. Those selectors match no element, and the result splits two ways: some checks pass without proving anything, and some waits never resolve and time out. Both symptoms come from the same cause. The silent passes are the heavier half. `waitForParagraphExecution` in `notebook-keyboard-page.ts` waits on `.paragraph-control .fa-spin, .running-indicator, .paragraph-status-running`. None of those classes appear in any new UI template, and `.fa-spin` is only a class definition in the vendored FontAwesome stylesheet that is never applied. The wait resolves immediately, so callers move on while the paragraph still reads `READY`. The keyboard suite uses this helper throughout. The same selector is used as an assertion. `paragraph-functionality.spec.ts:184` is meant to confirm that a cancelled paragraph stopped running, but the locator matches nothing and `not.toBeVisible` passes whether or not execution stopped. This PR asserts that `.status` reaches `ABORT` instead. Asserting that the cancel control disappears is not enough, because that control only renders while the paragraph is `PENDING` or `RUNNING`, so it also disappears on natural completion. For the same reason the cancel has to happen after the run starts: the control is visible during `PENDING` too, so the existing code clicked it while the interpreter was still starting and exercised something other than what the test claims. The flaky half comes from three places. The trash folder's "Empty" anchor collapses when the row loses hover: its bounding box is `{width:0, height:0}` unhovered and `{width:12, height:17}` hovered, so splitting reveal and click clicks empty space. A click that lands while a dialog is still running its open animation is not registered at all. And paragraphs arrive over the WebSocket, so `waitForLoadState('networkidle')` can resolve before any paragraph has rendered. Strict-mode collisions sit on top of that. `getByRole('link', { name: 'Job' })` matches the accessible name as a substring, so it also selects note links whose title contains "Job". The header and user-menu locators now pass `exact: true`, checked against the names in the templates. Fallback selector chains move into the Page Object and narrow to the element that exists. The cancel button was `.cancel-para, [nz-tooltip*="Cancel"], [title*="Cancel"], button:has-text("Cancel"), i[nz-icon="pause-circle"], .anticon-pause-circle`; only `.cancel-para` is in the new UI. The export dropdown is declared without `nzTrigger`, so ng-zorro opens it on hover rather than click, which is now encapsulated as `openExportMenu()`. The clipboard spec produced a TEXT result because `%sh` output has no `%table` marker, so the export control never rendered at all; adding the marker gives it a real TABLE result. ### What type of PR is it? Bug Fix ### Todos * [x] Confirm the removed selectors appear in no Angular template and in no React component * [x] Confirm each replacement exists and means what the test assumes * [x] Check that every changed assertion still fails when the feature is broken * [x] Run the cancel test, measure the status transitions, and set the timeout from the measurement * [x] Lint with the rules added in ZEPPELIN-6560 and confirm no new violations ### What is the Jira issue? ZEPPELIN-6562 ### How should this be tested? ```bash cd zeppelin-web-angular npm run e2e:fast -- tests/notebook/ tests/home/ tests/share/ tests/workspace/ ``` The clipboard spec needs a shell interpreter and skips on CI. The cancel test runs on CI against the Python interpreter; measured locally, the status goes `PENDING` to `RUNNING` and reaches `ABORT` about ten seconds after the click, which is what the assertion timeout is set from. The dead selectors can be confirmed directly: `grep -rn "fa-spin\|running-indicator\|paragraph-status-running" zeppelin-web-angular/src` matches only the vendored FontAwesome stylesheet and no template. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5350 from voidmatcha/fix/e2e-flaky-stabilization. Signed-off-by: ChanHo Lee --- .../e2e/models/header-page.ts | 22 ++++-- .../e2e/models/notebook-keyboard-page.ts | 38 +++++----- .../e2e/models/notebook-paragraph-page.ts | 18 ++++- .../e2e/models/notebook-repos-page.ts | 1 - .../home/home-page-note-operations.spec.ts | 16 ++-- .../home/home-page-notebook-actions.spec.ts | 2 +- .../action-bar-functionality.spec.ts | 1 - .../notebook-keyboard-shortcuts.spec.ts | 53 +++++-------- .../notebook/main/notebook-container.spec.ts | 2 +- .../paragraph/copy-to-clipboard.spec.ts | 74 +++++-------------- .../paragraph/paragraph-functionality.spec.ts | 20 +++-- .../sidebar/sidebar-functionality.spec.ts | 1 - .../note-import/note-import-modal.spec.ts | 4 +- .../e2e/tests/share/note-toc/note-toc.spec.ts | 3 - .../workspace/user-menu-navigation.spec.ts | 3 +- zeppelin-web-angular/e2e/utils.ts | 5 +- 16 files changed, 114 insertions(+), 149 deletions(-) diff --git a/zeppelin-web-angular/e2e/models/header-page.ts b/zeppelin-web-angular/e2e/models/header-page.ts index 0a17045eecb..ae30cb3ed73 100644 --- a/zeppelin-web-angular/e2e/models/header-page.ts +++ b/zeppelin-web-angular/e2e/models/header-page.ts @@ -44,20 +44,26 @@ export class HeaderPage extends BasePage { this.notebookMenuItem = page.locator('[nz-menu-item]').filter({ hasText: 'Notebook' }); this.notebookDropdownTrigger = page.locator('.node-list-trigger'); this.notebookDropdown = page.locator('zeppelin-node-list.ant-dropdown-menu'); - this.jobMenuItem = page.getByRole('link', { name: 'Job' }); + // A global getByRole('link', { name: 'Job' }) matches by substring. + // It also picks up note-list links (e.g. a note named "...Job..."), which is a strict-mode violation. + // Scoping to the menu item and matching exactly selects the single header entry. + this.jobMenuItem = page.locator('[nz-menu-item]').getByRole('link', { name: 'Job', exact: true }); this.userDropdownTrigger = page.locator('.header .user .status'); this.userBadge = page.locator('.header .user nz-badge'); this.searchInput = page.locator('.header .search input[type="text"]'); this.themeToggleButton = page.locator('zeppelin-theme-toggle button'); + // Same substring and strict-mode risk as jobMenuItem above. + // Scope these links to the dropdown overlay and match exactly. + const userMenu = page.locator('.zeppelin-user-menu'); this.userMenuItems = { - aboutZeppelin: page.getByText('About Zeppelin', { exact: true }), - interpreter: page.getByRole('link', { name: 'Interpreter' }), - notebookRepos: page.getByRole('link', { name: 'Notebook Repos' }), - credential: page.getByRole('link', { name: 'Credential' }), - configuration: page.getByRole('link', { name: 'Configuration' }), - logout: page.getByText('Logout', { exact: true }), - switchToClassicUI: page.getByRole('link', { name: 'Switch to Classic UI' }) + aboutZeppelin: userMenu.getByText('About Zeppelin', { exact: true }), + interpreter: userMenu.getByRole('link', { name: 'Interpreter', exact: true }), + notebookRepos: userMenu.getByRole('link', { name: 'Notebook Repos', exact: true }), + credential: userMenu.getByRole('link', { name: 'Credential', exact: true }), + configuration: userMenu.getByRole('link', { name: 'Configuration', exact: true }), + logout: userMenu.getByText('Logout', { exact: true }), + switchToClassicUI: userMenu.getByRole('link', { name: 'Switch to Classic UI', exact: true }) }; } diff --git a/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts b/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts index 2ffedd0b645..1b402b0f03b 100644 --- a/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-keyboard-page.ts @@ -330,6 +330,10 @@ export class NotebookKeyboardPage extends BasePage { return this.paragraphContainer.nth(index); } + getParagraphStatus(index: number): Locator { + return this.getParagraphByIndex(index).locator('.status'); + } + async isAutocompleteVisible(): Promise { return await this.autocompletePopup.isVisible(); } @@ -482,16 +486,14 @@ export class NotebookKeyboardPage extends BasePage { const paragraph = this.getParagraphByIndex(paragraphIndex); - // Step 1: Wait for execution to start await this.waitForExecutionStart(paragraphIndex); - // Step 2: Wait for execution to complete - const runningIndicator = paragraph.locator( - '.paragraph-control .fa-spin, .running-indicator, .paragraph-status-running' - ); - await this.waitForExecutionComplete(runningIndicator, paragraphIndex, timeout); + // The spinner classes this used to wait on are not rendered by the new UI, so the wait + // resolved immediately. The status text is the observable signal. + // On a fast re-run that text can still read the previous terminal state, so tight re-run + // loops get a stability gate here, not proof that this particular run finished. + await expect(paragraph.locator('.status')).toHaveText(/FINISHED|ERROR|ABORT/, { timeout }); - // Step 3: Wait for result to be visible await this.waitForResultVisible(paragraphIndex, timeout); } @@ -562,7 +564,12 @@ export class NotebookKeyboardPage extends BasePage { for (let i = 0; i < count; i++) { const button = this.okButtons.nth(i); await button.waitFor({ state: 'visible', timeout }); - await button.click({ delay: 100 }); + // A click landed during the dialog's open animation can fail to register at all, + // so retry until the button actually goes away. + await expect(async () => { + await button.click({ delay: 100 }); + await expect(button).toBeHidden({ timeout: 2000 }); + }).toPass({ timeout: 15000 }); await this.modal.waitFor({ state: 'hidden', timeout: 2000 }).catch(() => {}); // JUSTIFIED: UI stabilization — next iteration or detach check handles remaining modals } @@ -582,7 +589,8 @@ export class NotebookKeyboardPage extends BasePage { return false; } - const hasRunning = targetParagraph.querySelector('.fa-spin, .running-indicator, .paragraph-status-running'); + const status = targetParagraph.querySelector('.status'); + const hasRunning = !!status && /PENDING|RUNNING/.test(status.textContent || ''); const hasResult = targetParagraph.querySelector(selector); return hasRunning || hasResult; @@ -601,18 +609,6 @@ export class NotebookKeyboardPage extends BasePage { } } - private async waitForExecutionComplete( - runningIndicator: Locator, - paragraphIndex: number, - timeout: number - ): Promise { - if (this.page.isClosed()) { - return; - } - - await runningIndicator.waitFor({ state: 'detached', timeout: timeout / 2 }).catch(() => {}); // JUSTIFIED: UI stabilization — paragraph may have completed before indicator appeared - } - private async waitForResultVisible(paragraphIndex: number, timeout: number): Promise { if (this.page.isClosed()) { return; diff --git a/zeppelin-web-angular/e2e/models/notebook-paragraph-page.ts b/zeppelin-web-angular/e2e/models/notebook-paragraph-page.ts index 674dcffd142..f50359a780e 100644 --- a/zeppelin-web-angular/e2e/models/notebook-paragraph-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-paragraph-page.ts @@ -10,7 +10,7 @@ * limitations under the License. */ -import { Locator, Page } from '@playwright/test'; +import { expect, Locator, Page } from '@playwright/test'; import { BasePage } from './base-page'; export class NotebookParagraphPage extends BasePage { @@ -24,6 +24,10 @@ export class NotebookParagraphPage extends BasePage { readonly footerInfo: Locator; readonly runButton: Locator; readonly settingsDropdown: Locator; + readonly status: Locator; + readonly cancelButton: Locator; + readonly exportDropdownTrigger: Locator; + readonly exportMenu: Locator; constructor(page: Page) { super(page); @@ -47,6 +51,18 @@ export class NotebookParagraphPage extends BasePage { .first() .locator('zeppelin-notebook-paragraph-control a[nz-dropdown]') .first(); + this.status = this.controlPanel.locator('.status'); + // The control renders the cancel icon only while the paragraph is PENDING or RUNNING. + this.cancelButton = this.controlPanel.locator('.cancel-para'); + // The export controls render only for a TABLE result. + this.exportDropdownTrigger = this.resultDisplay.locator('.export-dropdown-icon-btn'); + this.exportMenu = page.locator('.ant-dropdown-menu'); + } + + // The export dropdown is declared without nzTrigger, so ng-zorro opens it on hover, not click. + async openExportMenu(): Promise { + await this.exportDropdownTrigger.hover(); + await expect(this.exportMenu).toBeVisible(); } async doubleClickToEdit(): Promise { diff --git a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts index 76cbf00f7bc..f047b44b2e6 100644 --- a/zeppelin-web-angular/e2e/models/notebook-repos-page.ts +++ b/zeppelin-web-angular/e2e/models/notebook-repos-page.ts @@ -28,7 +28,6 @@ export class NotebookReposPage extends BasePage { await this.navigateToRoute('/notebook-repos', { timeout: 60000 }); await this.page.waitForURL('**/#/notebook-repos', { timeout: 60000 }); await waitForZeppelinReady(this.page); - await this.page.waitForLoadState('networkidle', { timeout: 15000 }); await Promise.race([ this.zeppelinPageHeader.filter({ hasText: 'Notebook Repository' }).waitFor({ state: 'visible' }), this.page.waitForSelector('zeppelin-notebook-repo-item', { state: 'visible' }) diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts index 280ab64a341..7a1cf66ce01 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-note-operations.spec.ts @@ -85,10 +85,14 @@ test.describe('Home Page Note Operations', () => { test.describe('Given rename note functionality', () => { test('When rename button is clicked Then should open rename dialog', async ({ page }) => { const testNote = page.locator('.node .file').filter({ hasText: testNoteName }); + // WebSocket note updates re-render the list and can detach a hovered row mid-interaction. + // Re-confirm the row and re-hover right before revealing the action. + await expect(testNote).toBeVisible({ timeout: 15000 }); await testNote.hover(); const renameButton = testNote.locator('.operation a[nztooltiptitle="Rename note"]'); await expect(renameButton).toBeVisible(); + await testNote.hover(); await renameButton.click(); // JUSTIFIED: compound selector targets rename dialog; first() picks the visible modal instance @@ -240,13 +244,13 @@ test.describe('Home Page Note Operations', () => { test('When empty trash is clicked Then should show permanent deletion warning', async ({ page }) => { const trashFolder = page.locator('.node .folder').filter({ hasText: 'Trash' }); - await trashFolder.hover(); - await trashFolder.locator('.operation').waitFor({ state: 'visible' }); - const emptyButton = trashFolder.locator('.operation a[nztooltiptitle*="Empty all"]'); - await expect(emptyButton).toBeVisible(); - await emptyButton.hover(); - await emptyButton.click(); + + // The anchor collapses to zero size when the row loses hover, so reveal and click must be one step. + await expect(async () => { + await trashFolder.hover(); + await emptyButton.click({ timeout: 5000 }); + }).toPass({ timeout: 30000 }); await expect(page.locator('text=This cannot be undone. Are you sure?')).toBeVisible(); }); diff --git a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts index a92326f32e1..5911232c855 100644 --- a/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts +++ b/zeppelin-web-angular/e2e/tests/home/home-page-notebook-actions.spec.ts @@ -42,7 +42,7 @@ test.describe('Home Page Notebook Actions', () => { test('When filter is used Then should filter notebook list', async ({ page }) => { test.skip(true, 'ZEPPELIN-6386: Notebook search filter in the New UI is too slow — re-enable when fixed'); await homePage.filterNotes('test'); - await page.waitForLoadState('networkidle', { timeout: 15000 }); + await expect(page.locator('nz-tree .node').filter({ hasText: 'test' })).not.toHaveCount(0, { timeout: 15000 }); const filteredResults = await page.locator('nz-tree .node').count(); expect(filteredResults).toBeGreaterThan(0); }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts index f8d158838b4..5825e1d31b1 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/action-bar/action-bar-functionality.spec.ts @@ -117,7 +117,6 @@ test.describe('Notebook Action Bar Functionality', () => { } await expect(actionBarPage.clearOutputButton).toBeEnabled(); - await page.waitForLoadState('networkidle'); const paragraphResults = page.locator('zeppelin-notebook-paragraph-result'); const resultCount = await paragraphResults.count(); diff --git a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts index f4e584d2153..ee2fa5f4812 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/keyboard/notebook-keyboard-shortcuts.spec.ts @@ -78,12 +78,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Shift+Enter await keyboardPage.pressRunParagraph(); - // Then: Paragraph should execute (reach a terminal state; interpreter availability varies by env) + // waitForParagraphExecution gates on the status text, so it is the assertion and throws if the run never settles. await keyboardPage.waitForParagraphExecution(0); - // JUSTIFIED: single-paragraph test notebook; first() is deterministic - const statusEl = keyboardPage.paragraphContainer.first().locator('.status'); - const statusText = (await statusEl.textContent({ timeout: 30000 }))?.trim(); - expect(statusText === 'FINISHED' || statusText === 'ERROR' || statusText === 'ABORT').toBe(true); }); }); @@ -104,10 +100,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%md\n# Second Paragraph\nTest content for second paragraph', 1); await keyboardPage.tryFocusCodeEditor(1); // Ensure focus on the second paragraph - // Add an explicit wait for the page to be completely stable and the notebook UI to be interactive - await keyboardPage.page.waitForLoadState('networkidle', { timeout: 30000 }); // Wait for network to be idle // JUSTIFIED: single-paragraph test notebook; first() is deterministic - await expect(keyboardPage.paragraphContainer.first()).toBeVisible({ timeout: 15000 }); // Ensure a paragraph is visible + await expect(keyboardPage.paragraphContainer.first()).toBeVisible({ timeout: 15000 }); // When: User presses Control+Shift+ArrowUp from second paragraph await keyboardPage.pressRunAbove(); @@ -168,20 +162,14 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Start execution await keyboardPage.pressRunParagraph(); - // Wait for execution to start by checking if paragraph is running - // JUSTIFIED: compound selector; first() picks any visible running indicator - const runningIndicator = keyboardPage.page - .locator('zeppelin-notebook-paragraph .fa-spin, .running-indicator') - .first(); - await expect(runningIndicator).toBeVisible({ timeout: 30000 }); + const paragraphStatus = keyboardPage.getParagraphStatus(0); + await expect(paragraphStatus).toHaveText(/PENDING|RUNNING/, { timeout: 30000 }); // When: User presses Control+Alt+C quickly await keyboardPage.pressCancel(); // Then: The execution should be cancelled or completed - await expect( - keyboardPage.getParagraphByIndex(0).locator('.paragraph-control .fa-spin, .running-indicator') - ).not.toBeVisible(); + await expect(paragraphStatus).toHaveText(/ABORT|FINISHED|ERROR/, { timeout: 30000 }); }); }); @@ -573,11 +561,6 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.pressRunParagraph(); await keyboardPage.waitForParagraphExecution(0); - // Verify there is output to clear - // JUSTIFIED: single-paragraph test notebook; first() is deterministic - const statusElBefore = keyboardPage.paragraphContainer.first().locator('.status'); - await expect(statusElBefore).toHaveText(/FINISHED|ERROR|PENDING|RUNNING/); - // Gate: without visible output, isSettled starts true and the helper would skip the press entirely. const resultLocator = keyboardPage.getParagraphByIndex(0).locator('[data-testid="paragraph-result"]'); await expect(resultLocator).toBeVisible(); @@ -614,7 +597,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // Then: A new tab should be opened with paragraph link const newPage = await newPagePromise; - await newPage.waitForLoadState('networkidle'); + await newPage.waitForURL(/\/paragraph\/paragraph_\d+_\d+/); // Verify the new tab URL contains the notebook ID and paragraph reference const newUrl = newPage.url(); @@ -800,7 +783,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User presses Control+Space to trigger autocomplete await keyboardPage.pressControlSpace(); - await keyboardPage.autocompletePopup.waitFor({ state: 'visible', timeout: 3000 }).catch(() => {}); + await expect(keyboardPage.autocompletePopup).toBeVisible({ timeout: 3000 }); // Then: Editor must remain functional after shortcut (baseline; always asserts) // JUSTIFIED: single-paragraph test notebook; first() is deterministic @@ -827,7 +810,7 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { // When: User triggers autocomplete and selects an option await keyboardPage.pressControlSpace(); - await keyboardPage.autocompletePopup.waitFor({ state: 'visible', timeout: 3000 }).catch(() => {}); + await expect(keyboardPage.autocompletePopup).toBeVisible({ timeout: 3000 }); const isAutocompleteVisible = await keyboardPage.isAutocompleteVisible(); if (isAutocompleteVisible) { @@ -953,7 +936,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.tryFocusCodeEditor(); await keyboardPage.setCodeEditorContent('invalid python syntax here'); await keyboardPage.pressRunParagraph(); - await keyboardPage.waitForParagraphExecution(0); + // Real interpreter run: a cold interpreter under CI load can stay RUNNING past the 30s default. + await keyboardPage.waitForParagraphExecution(0, 60000); // Verify error result exists (invalid syntax produces a final ERROR or FINISHED with error output) // JUSTIFIED: single-paragraph test notebook; first() is deterministic @@ -971,12 +955,8 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.setCodeEditorContent('%md\n# Recovery Test\nShortcuts work after error', newParagraphIndex); await keyboardPage.pressRunParagraph(); - // Then: Shortcut execution still reaches a terminal state (real interpreter run; - // allow extra time as a cold interpreter under CI load can stay RUNNING past 30s) + // Allow extra time; a cold interpreter under CI load can stay RUNNING past the 30s default. await keyboardPage.waitForParagraphExecution(newParagraphIndex, 60000); - // JUSTIFIED: newParagraphIndex is dynamically computed from getParagraphCount(); nth() is the only way to address this specific paragraph - const statusElNew = keyboardPage.paragraphContainer.nth(newParagraphIndex).locator('.status'); - await expect(statusElNew).toHaveText(/FINISHED|ERROR/, { timeout: 60000 }); }); test('should gracefully handle shortcuts when no paragraph is focused', async () => { @@ -1008,17 +988,18 @@ test.describe.serial('Comprehensive Keyboard Shortcuts (ShortcutsMap)', () => { await keyboardPage.tryFocusCodeEditor(); await keyboardPage.setCodeEditorContent('%md\nrapid keyboard test'); - // Rapid Shift+Enter operations + // On a fast re-run the status can still read the previous FINISHED, so this checks stability, not each run. + // The result element re-renders and briefly detaches on every %md re-run, so do not assert on it. for (let i = 0; i < 3; i++) { await keyboardPage.pressRunParagraph(); await keyboardPage.waitForParagraphExecution(0, 60000); - // JUSTIFIED: single-paragraph test notebook; first() is deterministic - await expect(keyboardPage.paragraphResult.first()).toBeVisible({ timeout: 60000 }); } - // Then: System should remain stable + // Running a %md paragraph collapses it to rendered mode and detaches the Monaco editor, + // so assert on the rendered output instead. It survives the re-render and proves the runs + // produced a result, which the container being visible does not. // JUSTIFIED: single-paragraph test notebook; first() is deterministic - await expect(keyboardPage.codeEditor.first()).toBeVisible(); + await expect(keyboardPage.paragraphResult.first()).toContainText('rapid keyboard test', { timeout: 30000 }); }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts index 03b956e77d6..a8656cc8f39 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/main/notebook-container.spec.ts @@ -60,7 +60,7 @@ test.describe('Notebook Container Component', () => { test('should display paragraph container with grid layout', async () => { await expect(notebookPage.paragraphInner).toBeVisible(); - expect(await notebookPage.paragraphInner.getAttribute('class')).toContain('paragraph-inner'); + await expect(notebookPage.paragraphInner).toHaveClass(/paragraph-inner/); await expect(notebookPage.paragraphInner).toHaveAttribute('nz-row'); }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts index 93a9b7029e0..3816c6a5941 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/paragraph/copy-to-clipboard.spec.ts @@ -25,6 +25,7 @@ test.describe('Copy table result to clipboard', () => { addPageAnnotationBeforeEach(PAGES.WORKSPACE.SHARE_RESULT); let paragraphPage: NotebookParagraphPage; + let keyboard: NotebookKeyboardPage; let testNotebook: { noteId: string; paragraphId: string }; test.beforeEach(async ({ page, context }, testInfo) => { @@ -40,34 +41,19 @@ test.describe('Copy table result to clipboard', () => { paragraphPage = new NotebookParagraphPage(page); await page.goto(`/#/notebook/${testNotebook.noteId}`); - await page.waitForLoadState('networkidle'); + await expect(page.locator('zeppelin-notebook-paragraph')).toHaveCount(1, { timeout: 15000 }); - // Type a paragraph that outputs a TABLE result using the %sh interpreter - await paragraphPage.doubleClickToEdit(); - await expect(paragraphPage.codeEditor).toBeVisible(); - - const codeEditor = paragraphPage.codeEditor.locator('textarea, .monaco-editor .input-area').first(); - await expect(codeEditor).toBeAttached({ timeout: 10000 }); - await codeEditor.focus(); - - const keyboard = new NotebookKeyboardPage(page); - await keyboard.pressSelectAll(); - await page.keyboard.type('%sh\nprintf "name\\tcount\\na\\t12\\nb\\t24\\n"'); + // Without the %table marker the output renders as TEXT and no export control exists. + keyboard = new NotebookKeyboardPage(page); + await keyboard.setCodeEditorContent('%sh\nprintf "%%table name\\tcount\\na\\t12\\nb\\t24\\n"'); await paragraphPage.runParagraph(); await expect(paragraphPage.resultDisplay).toBeVisible({ timeout: 30000 }); }); - test('export dropdown should contain Copy as TSV and Copy as CSV options', async ({ page }) => { - // Open the export dropdown (down-arrow button next to the download icon) - const exportDropdownTrigger = page - .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') - .first(); - await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); - await exportDropdownTrigger.click(); - - const menu = page.locator('.ant-dropdown-menu'); - await expect(menu).toBeVisible({ timeout: 5000 }); + test('export dropdown should contain Copy as TSV and Copy as CSV options', async () => { + await paragraphPage.openExportMenu(); + const menu = paragraphPage.exportMenu; await expect(menu.locator('li:has-text("Download as CSV")')).toBeVisible(); await expect(menu.locator('li:has-text("Download as TSV")')).toBeVisible(); @@ -76,14 +62,8 @@ test.describe('Copy table result to clipboard', () => { }); test('Copy as TSV should write tab-delimited data with headers to clipboard', async ({ page }) => { - const exportDropdownTrigger = page - .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') - .first(); - await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); - await exportDropdownTrigger.click(); - - const menu = page.locator('.ant-dropdown-menu'); - await expect(menu).toBeVisible({ timeout: 5000 }); + await paragraphPage.openExportMenu(); + const menu = paragraphPage.exportMenu; await menu.locator('li:has-text("Copy as TSV")').click(); // Read back what was written to the clipboard @@ -98,14 +78,8 @@ test.describe('Copy table result to clipboard', () => { }); test('Copy as CSV should write comma-delimited data with headers to clipboard', async ({ page }) => { - const exportDropdownTrigger = page - .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') - .first(); - await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); - await exportDropdownTrigger.click(); - - const menu = page.locator('.ant-dropdown-menu'); - await expect(menu).toBeVisible({ timeout: 5000 }); + await paragraphPage.openExportMenu(); + const menu = paragraphPage.exportMenu; await menu.locator('li:has-text("Copy as CSV")').click(); const clipboardText = await page.evaluate(() => navigator.clipboard.readText()); @@ -118,22 +92,14 @@ test.describe('Copy table result to clipboard', () => { test('Copy as CSV should quote cell values that contain double quotes', async ({ page }) => { // Re-run the paragraph with a value containing a double quote - const codeEditor = page.locator('.monaco-editor .input-area, textarea').first(); - await codeEditor.focus(); - const keyboard = new NotebookKeyboardPage(page); - await keyboard.pressSelectAll(); - await page.keyboard.type('%sh\nprintf "col1\\tcol2\\nsay \\"hi\\"\\t1\\n"'); - await new NotebookParagraphPage(page).runParagraph(); - await page.waitForLoadState('networkidle'); - - const exportDropdownTrigger = page - .locator('.export-dropdown .export-dropdown-icon-btn, .export-dropdown button:last-child') - .first(); - await expect(exportDropdownTrigger).toBeVisible({ timeout: 10000 }); - await exportDropdownTrigger.click(); - - const menu = page.locator('.ant-dropdown-menu'); - await expect(menu).toBeVisible({ timeout: 5000 }); + await keyboard.setCodeEditorContent('%sh\nprintf "%%table col1\\tcol2\\nsay \\"hi\\"\\t1\\n"'); + await paragraphPage.runParagraph(); + // runParagraph only clicks Run, and the previous table result is still rendered, so wait for + // the new output before exporting or the clipboard reads the stale table. + await expect(paragraphPage.resultDisplay).toContainText('col2', { timeout: 30000 }); + + await paragraphPage.openExportMenu(); + const menu = paragraphPage.exportMenu; await menu.locator('li:has-text("Copy as CSV")').click(); const clipboardText = await page.evaluate(() => navigator.clipboard.readText()); diff --git a/zeppelin-web-angular/e2e/tests/notebook/paragraph/paragraph-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/paragraph/paragraph-functionality.spec.ts index c1d50203091..105c4226202 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/paragraph/paragraph-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/paragraph/paragraph-functionality.spec.ts @@ -37,7 +37,9 @@ test.describe('Notebook Paragraph Functionality', () => { paragraphPage = new NotebookParagraphPage(page); await page.goto(`/#/notebook/${testNotebook.noteId}`); - await page.waitForLoadState('networkidle'); + // Paragraphs arrive over the WebSocket, so 'networkidle' can resolve before they render. + // Wait for the paragraph to mount so tests do not act on a bare page. + await expect(paragraphPage.paragraphContainer).toBeVisible({ timeout: 30000 }); }); test('should display paragraph container with proper structure', async () => { @@ -173,14 +175,16 @@ println("Age: " + z.select("age", Seq(("1","Under 18"), ("2","18-65"), ("3","Ove await paragraphPage.runParagraph(); - const cancelButton = page.locator( - '.cancel-para, [nz-tooltip*="Cancel"], [title*="Cancel"], button:has-text("Cancel"), i[nz-icon="pause-circle"], .anticon-pause-circle' - ); - await expect(cancelButton).toBeVisible({ timeout: 5000 }); + // The control also renders while the paragraph is PENDING, so wait for the run to start + // before cancelling it. + await expect(paragraphPage.cancelButton).toBeVisible({ timeout: 10000 }); + await expect(paragraphPage.status).toHaveText('RUNNING', { timeout: 30000 }); - await cancelButton.click(); + await paragraphPage.cancelButton.click(); - // Then: Execution should stop — running spinner disappears - await expect(page.locator('.paragraph-control .fa-spin')).not.toBeVisible({ timeout: 15000 }); + // Waiting for the button to disappear would also pass on natural completion, since the + // control is hidden once the paragraph leaves PENDING or RUNNING. Only cancelling reaches + // ABORT. The interpreter finishes the statement it is on first, so allow for the sleep. + await expect(paragraphPage.status).toHaveText('ABORT', { timeout: 30000 }); }); }); diff --git a/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts index 996ac0d24ca..348d56004b0 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/sidebar/sidebar-functionality.spec.ts @@ -71,7 +71,6 @@ test.describe('Notebook Sidebar Functionality', () => { }); test('should close sidebar functionality work properly', async ({ page }) => { - await page.waitForLoadState('networkidle', { timeout: 15000 }); await expect(sidebar.sidebarContainer).toBeVisible({ timeout: 10000 }); // Try to open TOC, but accept FILE_TREE if TOC isn't available diff --git a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts index 9fe75cbae34..229967d719b 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts @@ -78,8 +78,8 @@ test.describe('Note Import Modal', () => { }); test('Given JSON File tab is selected, When viewing file size limit, Then limit should be displayed', async () => { - const fileSizeLimit = await noteImportModal.getFileSizeLimit(); - expect(fileSizeLimit).toMatch(/\d+\s*(MB|KB|GB)/i); + // The limit is fetched asynchronously and renders as "-" until it arrives. + await expect(noteImportModal.fileSizeLimit).toHaveText(/\d+\s*(MB|KB|GB)/i); }); test('Given Import Note modal is open, When clicking close button, Then modal should close', async () => { diff --git a/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts index 355bb287708..d56b91941be 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-toc/note-toc.spec.ts @@ -37,9 +37,6 @@ test.describe('Note Table of Contents', () => { // Use the more robust navigation method from parent class await noteTocPage.navigateToNotebook(testNotebook.noteId); - // Wait for notebook to fully load - await page.waitForLoadState('networkidle'); - // Verify we're actually in a notebook with more specific checks await expect(page).toHaveURL(new RegExp(`#/notebook/${testNotebook.noteId}`)); // JUSTIFIED: test notebook always has exactly one paragraph diff --git a/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts b/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts index 656dcd5c619..a58d108ca41 100644 --- a/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts +++ b/zeppelin-web-angular/e2e/tests/workspace/user-menu-navigation.spec.ts @@ -57,8 +57,7 @@ test.describe('Header user menu - full-row navigation', () => { }); await test.step(`Then the app navigates to ${item.route}`, async () => { - await page.waitForURL(url => url.hash.includes(item.route), { timeout: 10000 }); - expect(page.url()).toContain(item.route); + await expect(page).toHaveURL(new RegExp(item.route)); }); }); } diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index 7ccae56156a..cfc3c110e17 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -269,7 +269,6 @@ export const performLoginIfRequired = async (page: Page): Promise => { try { await page.waitForSelector('zeppelin-login', { state: 'hidden', timeout: 30000 }); await page.waitForSelector('text=Welcome to Zeppelin!', { timeout: 30000 }); - await page.waitForLoadState('networkidle'); await page.waitForSelector('zeppelin-node-list', { timeout: 30000 }); await waitForZeppelinReady(page); return true; @@ -369,7 +368,8 @@ export const navigateToNotebookWithFallback = async ( try { // Strategy 1: Direct navigation - await page.goto(`/#/notebook/${noteId}`, { waitUntil: 'networkidle', timeout: 30000 }); + await page.goto(`/#/notebook/${noteId}`, { waitUntil: 'domcontentloaded', timeout: 30000 }); + await page.locator('zeppelin-notebook-paragraph').first().waitFor({ state: 'visible', timeout: 30000 }); navigationSuccessful = true; } catch { // Strategy 2: Wait for loading completion and check URL @@ -389,7 +389,6 @@ export const navigateToNotebookWithFallback = async ( // Strategy 3: Navigate through home page if notebook name is provided if (!navigationSuccessful && notebookName) { await page.goto('/#/'); - await page.waitForLoadState('networkidle', { timeout: 15000 }); await page.waitForSelector('zeppelin-node-list', { timeout: 15000 }); // The link text in the UI is the base name of the note, not the full path. From c11fe272ea01d17e26218453b48a72044b980d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=ED=99=98?= <66408194+dev-donghwan@users.noreply.github.com> Date: Fri, 31 Jul 2026 00:23:32 +0900 Subject: [PATCH 122/179] [ZEPPELIN-6530] Fix operator precedence in SSL store path checks and make isWindowsPath null-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `getKeyStorePath()` and `getTrustStorePath()` in `ZeppelinConfiguration` contain a mis-parenthesized condition: ```java if (path != null && path.startsWith("/") || isWindowsPath(path)) { ``` The condition is meant to answer a single question — "is `path` an absolute path (Unix `/...` or Windows `C:\...`)?" — with `path != null` guarding the whole check. But since `&&` binds tighter than `||`, it actually parses as `(path != null && path.startsWith("/")) || isWindowsPath(path)`, leaving `isWindowsPath(path)` outside the null guard. `isWindowsPath` dereferences its argument, so a null `path` would throw an NPE. Note on reachability: with the current defaults this NPE is latent rather than user-facing. `ZEPPELIN_SSL_KEYSTORE_PATH` has a non-null default (`"keystore"`), so `getKeyStorePath()` never sees a null path, and `getTrustStorePath()` falls back to `getKeyStorePath()` when the truststore path is unset. So this PR is a correctness/hardening fix, not a fix for a currently reproducible crash. This PR: - restores the intended grouping in both methods — `path != null && (path.startsWith("/") || isWindowsPath(path))` — matching the correctly-parenthesized pattern already used in `getAbsoluteDir()` in the same class - makes `isWindowsPath(null)` return `false` instead of throwing, as defense in depth ### What type of PR is it? Bug Fix ### Todos * [x] - Add the missing parentheses in `getKeyStorePath()` / `getTrustStorePath()` * [x] - Make `isWindowsPath` null-safe * [x] - Add a unit test for `isWindowsPath(null)` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6530 ### How should this be tested? * `./mvnw test -pl zeppelin-server -Dtest=ZeppelinConfigurationTest` * The new `isWindowsPathTestNull` asserts `isWindowsPath(null)` returns `false` (it threw an NPE before this change), following the existing `isWindowsPathTestTrue` / `isWindowsPathTestFalse` convention. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No — behavior is unchanged for all reachable inputs; only the (previously unreachable) null case changes from NPE to the intended relative-path fallback * Does this needs documentation? No Closes #5353 from dev-donghwan/ZEPPELIN-6530. Signed-off-by: ChanHo Lee --- .../org/apache/zeppelin/conf/ZeppelinConfiguration.java | 6 +++--- .../apache/zeppelin/conf/ZeppelinConfigurationTest.java | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index 252fd51a9bd..179dcce6e85 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -353,7 +353,7 @@ public String getServerContextPath() { public String getKeyStorePath() { String path = getString(ConfVars.ZEPPELIN_SSL_KEYSTORE_PATH); - if (path != null && path.startsWith("/") || isWindowsPath(path)) { + if (path != null && (path.startsWith("/") || isWindowsPath(path))) { return path; } else { return getAbsoluteDir( @@ -385,7 +385,7 @@ public String getTrustStorePath() { if (path == null) { path = getKeyStorePath(); } - if (path != null && path.startsWith("/") || isWindowsPath(path)) { + if (path != null && (path.startsWith("/") || isWindowsPath(path))) { return path; } else { return getAbsoluteDir( @@ -667,7 +667,7 @@ public String getInterpreterPortRange() { } public boolean isWindowsPath(String path){ - return path.matches("^[A-Za-z]:\\\\.*"); + return path != null && path.matches("^[A-Za-z]:\\\\.*"); } public boolean isPathWithScheme(String path){ diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java index 63fcd0da212..a5cb0037fd0 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java @@ -72,6 +72,14 @@ void isWindowsPathTestFalse() { assertFalse(isIt); } + @Test + void isWindowsPathTestNull() { + + ZeppelinConfiguration zConf = ZeppelinConfiguration.load("zeppelin-test-site.xml"); + Boolean isIt = zConf.isWindowsPath(null); + assertFalse(isIt); + } + @Test void isPathWithSchemeTestTrue() { From f4561394eab37c3238bec8bcb30b870e748801a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=ED=99=98?= <66408194+dev-donghwan@users.noreply.github.com> Date: Fri, 31 Jul 2026 23:09:29 +0900 Subject: [PATCH 123/179] [ZEPPELIN-6483] Format HDFS modification time in GMT to match the printed label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? In the HDFS file interpreter, `listOne()` appends a hard-coded `GMT` label to the modification time, but `listDate()` formats the timestamp using the JVM default time zone. On any server not running in UTC, the displayed value does not match the label (e.g. a file modified at `2015-08-02 20:43` GMT is shown as `2015-08-03 05:43GMT` on a KST server). This PR sets the formatter's time zone to GMT in `listDate()` so the rendered value matches the existing label. Why format in GMT (option A) rather than keep local time and fix the label (option B): - `modificationTime` is an absolute epoch value, so the time zone is only a display choice. Formatting in GMT keeps the output identical regardless of the host/JVM default zone and consistent with the label already printed. - Showing the interpreter JVM's local time would be ambiguous in shared HDFS / remote-interpreter, multi-user setups ("whose local time?"), and the output would vary per deployment, making it harder to reproduce and test. ### What type of PR is it? Bug Fix ### Todos * [x] - Format the modification time in GMT in `listDate()` * [x] - Add a regression test that runs under a non-UTC default zone (`Asia/Seoul`) and asserts the value is rendered in GMT to match the label ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6483 ### How should this be tested? * `./mvnw test -pl file -Dtest=HDFSFileInterpreterTest` * The new test `testListDateFormatsInGmtToMatchLabel` pins a known `modificationTime` (1438548219672 = 2015-08-02 20:43 GMT) under an `Asia/Seoul` default zone and asserts the output contains `2015-08-02 20:43GMT`. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No — display-only change; on non-UTC servers the shown value changes, but it now correctly matches the label * Does this needs documentation? No Closes #5351 from dev-donghwan/ZEPPELIN-6483. Signed-off-by: ChanHo Lee --- .../zeppelin/file/HDFSFileInterpreter.java | 7 +++++- .../file/HDFSFileInterpreterTest.java | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java b/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java index 3429de0b55a..662d02add81 100644 --- a/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java +++ b/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.List; import java.util.Properties; +import java.util.TimeZone; import org.apache.zeppelin.completer.CompletionType; import org.apache.zeppelin.interpreter.InterpreterContext; @@ -173,7 +174,11 @@ private String listPermission(OneFileStatus fs){ } private String listDate(OneFileStatus fs) { - return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(new Date(fs.modificationTime)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + // Format in GMT so the value matches the "GMT" label appended in listOne(), + // regardless of the JVM default time zone. + sdf.setTimeZone(TimeZone.getTimeZone("GMT")); + return sdf.format(new Date(fs.modificationTime)); } private String listOne(String path, OneFileStatus fs) { diff --git a/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java b/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java index 5c9e268e5d4..dc4dcbe5cc8 100644 --- a/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java +++ b/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java @@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.gson.Gson; @@ -30,6 +31,7 @@ import java.util.HashMap; import java.util.List; import java.util.Properties; +import java.util.TimeZone; import org.apache.zeppelin.completer.CompletionType; import org.apache.zeppelin.interpreter.InterpreterResult; @@ -183,6 +185,26 @@ void testNoSuchFile() { t.close(); } + @Test + void testListDateFormatsInGmtToMatchLabel() { + // ZEPPELIN-6483: the timestamp must be formatted in GMT to match the trailing + // "GMT" label, regardless of the JVM default time zone. + TimeZone original = TimeZone.getDefault(); + try { + TimeZone.setDefault(TimeZone.getTimeZone("Asia/Seoul")); + HDFSFileInterpreter t = new MockHDFSFileInterpreter(new Properties()); + t.open(); + InterpreterResult result = t.interpret("ls -l /", null); + String out = result.message().get(0).getData(); + // modificationTime 1438548219672 == 2015-08-02 20:43 GMT (2015-08-03 05:43 in KST) + assertTrue(out.contains("2015-08-02 20:43GMT"), + "modification time should be shown in GMT to match the label, but was:\n" + out); + t.close(); + } finally { + TimeZone.setDefault(original); + } + } + } /** From fafc11347354fdfbbfb6f341b19710a12ea0e3b0 Mon Sep 17 00:00:00 2001 From: Seoyeon Lee <68765200+sylee6529@users.noreply.github.com> Date: Fri, 31 Jul 2026 23:18:21 +0900 Subject: [PATCH 124/179] [ZEPPELIN-6474] Handle NumberFormatException when parsing MongoDB interpreter numeric properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `MongoDbInterpreter.open()` parses two numeric properties, `mongo.shell.command.timeout` and `mongo.interpreter.concurrency.max`, with `Long.parseLong()` / `Integer.parseInt()` outside any `try`/`catch` — the existing try-with-resources in that method covers only the `Scanner` that loads the shell extension. When either value is empty, missing, or non-numeric, a raw `NumberFormatException` escapes `open()`. Because `open()` is triggered lazily by the first paragraph run, this lands in the notebook paragraph as a bare stack trace that never names the property at fault. The MongoDB interpreter has several numeric properties, so the only way to tell which one failed today is to read the line number off the trace and open the source — which is not something a Zeppelin user should have to do. Reproduced on JDK 11: an empty value yields `NumberFormatException: For input string: ""`, a non-numeric value yields `For input string: "60s"`, and a missing property yields a message of just `null`. One note on that last case — the issue describes it as `Cannot parse null string`, but that wording comes from newer JDKs. On the JDK 11 this project builds with, `Long.parseLong(null)` throws `NumberFormatException("null")`, so the message carries even less information than the issue suggests. ### What does this PR do? - Wraps each parse and re-throws the `NumberFormatException` as an `InterpreterException` that names the property and its invalid value, keeping the original exception as the cause: ``` Invalid value for property 'mongo.shell.command.timeout': 60s ``` - Keeps the two parses separate so the message always points at the exact property that failed. - Adds `throws InterpreterException` to the `open()` override. The base `Interpreter.open()` already declares it, so no caller contract changes — at runtime the call goes through `LazyOpenInterpreter.open()`, which already declares it too, and the only direct caller was the test. Per the issue, the scope is deliberately narrow: no range validation, no silent fallback to default values, no unrelated changes. An invalid configuration still fails exactly as before; it just fails understandably. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6474 ### How should this be tested? * `./mvnw test -pl mongodb` * Four tests were added to the existing `MongoDbInterpreterTest`, covering both properties across the three failure modes named in the issue: non-numeric and missing for `mongo.shell.command.timeout`, empty and missing for `mongo.interpreter.concurrency.max`. Each asserts that an `InterpreterException` is thrown, that its message names the offending property, and that the original `NumberFormatException` is preserved as the cause. The two remaining combinations exercise the identical catch block, so they were left out rather than duplicated. * `MongoDbInterpreterTest.init()` now declares `throws InterpreterException`, since it calls `open()` on the concrete type. * To confirm the new tests are meaningful, I reverted the change to `MongoDbInterpreter` and re-ran the suite: exactly the four new tests fail with `expected: but was: `, while the two pre-existing tests still pass. With the change applied, all six pass. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No — a valid configuration behaves exactly as before, and an invalid one already failed. Only the exception type and its message change. * Does this needs documentation? No Closes #5356 from sylee6529/ZEPPELIN-6474-mongodb-numberformat. Signed-off-by: ChanHo Lee --- .../zeppelin/mongodb/MongoDbInterpreter.java | 22 ++++++- .../mongodb/MongoDbInterpreterTest.java | 59 ++++++++++++++++++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/mongodb/src/main/java/org/apache/zeppelin/mongodb/MongoDbInterpreter.java b/mongodb/src/main/java/org/apache/zeppelin/mongodb/MongoDbInterpreter.java index 54c121fcdff..5521135a391 100644 --- a/mongodb/src/main/java/org/apache/zeppelin/mongodb/MongoDbInterpreter.java +++ b/mongodb/src/main/java/org/apache/zeppelin/mongodb/MongoDbInterpreter.java @@ -35,6 +35,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.zeppelin.interpreter.Interpreter; import org.apache.zeppelin.interpreter.InterpreterContext; +import org.apache.zeppelin.interpreter.InterpreterException; import org.apache.zeppelin.interpreter.InterpreterResult; import org.apache.zeppelin.interpreter.InterpreterResult.Code; import org.apache.zeppelin.scheduler.Scheduler; @@ -66,13 +67,28 @@ public MongoDbInterpreter(Properties property) { } @Override - public void open() { + public void open() throws InterpreterException { try (final Scanner scanner = new Scanner(MongoDbInterpreter.class.getResourceAsStream("/shell_extension.js"), "UTF-8").useDelimiter("\\A")) { shellExtension = scanner.next(); } - commandTimeout = Long.parseLong(getProperty("mongo.shell.command.timeout")); - maxConcurrency = Integer.parseInt(getProperty("mongo.interpreter.concurrency.max")); + + final String commandTimeoutValue = getProperty("mongo.shell.command.timeout"); + try { + commandTimeout = Long.parseLong(commandTimeoutValue); + } catch (NumberFormatException e) { + throw new InterpreterException("Invalid value for property " + + "'mongo.shell.command.timeout': " + commandTimeoutValue, e); + } + + final String maxConcurrencyValue = getProperty("mongo.interpreter.concurrency.max"); + try { + maxConcurrency = Integer.parseInt(maxConcurrencyValue); + } catch (NumberFormatException e) { + throw new InterpreterException("Invalid value for property " + + "'mongo.interpreter.concurrency.max': " + maxConcurrencyValue, e); + } + dbAddress = getProperty("mongo.server.host") + ":" + getProperty("mongo.server.port"); prepareShellExtension(); } diff --git a/mongodb/src/test/java/org/apache/zeppelin/mongodb/MongoDbInterpreterTest.java b/mongodb/src/test/java/org/apache/zeppelin/mongodb/MongoDbInterpreterTest.java index 08991c3a844..cd57db0a96a 100644 --- a/mongodb/src/test/java/org/apache/zeppelin/mongodb/MongoDbInterpreterTest.java +++ b/mongodb/src/test/java/org/apache/zeppelin/mongodb/MongoDbInterpreterTest.java @@ -19,6 +19,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; @@ -30,6 +32,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.zeppelin.interpreter.InterpreterContext; +import org.apache.zeppelin.interpreter.InterpreterException; import org.apache.zeppelin.interpreter.InterpreterOutput; import org.apache.zeppelin.interpreter.InterpreterOutputListener; import org.apache.zeppelin.interpreter.InterpreterResult; @@ -80,7 +83,7 @@ public static void setup() { } @BeforeEach - public void init() { + public void init() throws InterpreterException { buffer = ByteBuffer.allocate(10000); props.put("mongo.shell.path", (IS_WINDOWS ? "" : "sh ") + MONGO_SHELL); props.put("mongo.shell.command.table.limit", "10000"); @@ -137,6 +140,60 @@ void testBadConf() { assertSame(Code.ERROR, res.code()); } + @Test + void testInvalidCommandTimeout() { + props.setProperty("mongo.shell.command.timeout", "not-a-number"); + + final InterpreterException e = + assertThrows(InterpreterException.class, () -> interpreter.open()); + + assertTrue(e.getMessage().contains("mongo.shell.command.timeout"), + "The message must name the offending property: " + e.getMessage()); + assertTrue(e.getMessage().contains("not-a-number"), + "The message must show the invalid value: " + e.getMessage()); + assertTrue(e.getCause() instanceof NumberFormatException, + "The original NumberFormatException must be preserved as the cause"); + } + + @Test + void testMissingCommandTimeout() { + props.remove("mongo.shell.command.timeout"); + + final InterpreterException e = + assertThrows(InterpreterException.class, () -> interpreter.open()); + + assertTrue(e.getMessage().contains("mongo.shell.command.timeout"), + "The message must name the offending property: " + e.getMessage()); + assertTrue(e.getCause() instanceof NumberFormatException, + "The original NumberFormatException must be preserved as the cause"); + } + + @Test + void testEmptyMaxConcurrency() { + props.setProperty("mongo.interpreter.concurrency.max", ""); + + final InterpreterException e = + assertThrows(InterpreterException.class, () -> interpreter.open()); + + assertTrue(e.getMessage().contains("mongo.interpreter.concurrency.max"), + "The message must name the offending property: " + e.getMessage()); + assertTrue(e.getCause() instanceof NumberFormatException, + "The original NumberFormatException must be preserved as the cause"); + } + + @Test + void testMissingMaxConcurrency() { + props.remove("mongo.interpreter.concurrency.max"); + + final InterpreterException e = + assertThrows(InterpreterException.class, () -> interpreter.open()); + + assertTrue(e.getMessage().contains("mongo.interpreter.concurrency.max"), + "The message must name the offending property: " + e.getMessage()); + assertTrue(e.getCause() instanceof NumberFormatException, + "The original NumberFormatException must be preserved as the cause"); + } + @Override public void onUpdateAll(InterpreterOutput interpreterOutput) { From d8c43cb1561bddc296f9a158eafe8477c488625f Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Sat, 1 Aug 2026 13:16:51 +0900 Subject: [PATCH 125/179] [ZEPPELIN-6579] Make notebook tree reload safe for concurrent note operations ### What is this PR for? `NoteManager` locates a note through two separate pieces of state: `notesInfo` maps a note id to its path, and `root` holds the folder tree that the path is walked against. A lookup uses both in sequence, so the two have to agree. `reloadNotes()` replaced them one at a time: ```java public void reloadNotes() throws IOException { this.root = new Folder("/", notebookRepo, noteCache, zConf); // (1) tree becomes empty this.trash = this.root.getOrCreateFolder(TRASH_FOLDER); init(); // (2) new mapping, (3) refill tree } ``` Neither field is `volatile` and nothing is held while they are swapped, so a concurrent `processNote()` can observe a mapping and a tree that belong to different generations: | time | reloading thread | note request thread | state | |---|---|---|---| | t1 | installs an empty tree | | mapping: old (complete) / tree: **empty** | | t2 | | `notesInfo.containsKey(noteId)` passes | the id is still in the old mapping | | t3 | | walks the path in the tree, finds nothing | **throws** | | t4 | installs the new mapping | | | | t5 | refills the tree, one note at a time | | notes not inserted yet still fail | The guard in `processNote()` only checks `notesInfo`, so it passes and the failure surfaces one line later in `getNoteNode()`: ``` java.io.IOException: Can not find note: /E2E_TEST_FOLDER/TestNotebook_... at org.apache.zeppelin.notebook.NoteManager.getNoteNode at org.apache.zeppelin.notebook.NoteManager.processNote at org.apache.zeppelin.rest.NotebookRestApi.updateParagraph ``` `IOException` is not mapped to a specific status, so `WebApplicationExceptionMapper` turns it into **HTTP 500** for a note that was never removed. Everything that goes through `processNote()` is affected: reading a note, updating a paragraph, creating, deleting and moving notes, and listing the notebook. This PR holds the tree, the trash folder and the mapping in one immutable `NoteTree` and publishes it with a single `volatile` write. `buildNoteTree()` fills the new tree locally and returns it; only then is it assigned. The tree-walking helpers (`getNoteNode`, `getFolder`, `getOrCreateFolder`, `isNotePathAvailable`) take the tree as a parameter, and callers that need both pieces of state read the reference once, so a lookup resolves the mapping and the tree against the same generation. Those helpers are `static` so that the compiler prevents them from reaching back to the field. ### Scope and related issues **#5325** (`[ZEPPELIN-5858]`) is open against the same class and restructures `removeNote`, `moveNote` and `moveFolder` with `synchronized (this)`. It targets a different race (two mutators duplicating a note) and its monitor does not cover `reloadNotes()`, so neither change subsumes the other. Whichever merges second will need a rebase. ### What type of PR is it? Bug Fix ### Todos * [x] - Build the new tree, trash folder and mapping in `buildNoteTree()` before publishing them * [x] - Hold the three in an immutable `NoteTree` published through a single `volatile` write * [x] - Pass the tree into the tree-walking helpers so one lookup uses one generation * [x] - Add a regression test that reloads while other threads read notes * [x] - Confirm the test fails without the fix and passes with it ### What is the Jira issue? * [ZEPPELIN-6579](https://issues.apache.org/jira/browse/ZEPPELIN-6579) ### How should this be tested? New test `NoteManagerTest#testConcurrentReloadAndProcessNote`: it saves 50 notes, then runs `reloadNotes()` in a loop on one thread while four threads keep calling `processNote()` for every note, and asserts that no lookup fails or returns nothing. ```bash export JAVA_HOME=$(/usr/libexec/java_home -v 11) ./mvnw package -pl zeppelin-server --am -Dtest=NoteManagerTest -DfailIfNoTests=false ``` Result with the fix: `Tests run: 7, Failures: 0, Errors: 0`. Reverting only the production change makes the new test fail on every reader thread with `java.io.IOException: Can not find note: /prod/note_0` thrown from `NoteManager.getNoteNode` via `NoteManager.processNote`, which is the stack from the ticket; with the fix it passes. Also run, to cover the callers of the reload path: ```bash ./mvnw package -pl zeppelin-server --am \ -Dtest='NotebookTest#testReloadAllNotes+testReloadAndSetInterpreter' -DfailIfNoTests=false ``` Result: `Tests run: 2, Failures: 0, Errors: 0`. Not verified locally: the full `NotebookTest` and `NotebookServerTest` classes, which start real remote interpreter processes and time out in my environment, and `NotebookRepoSyncTest`. Those are left to CI. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5357 from big-cir/ZEPPELIN-6579. Signed-off-by: Jongyoul Lee --- .../apache/zeppelin/notebook/NoteManager.java | 155 +++++++++++------- .../zeppelin/notebook/NoteManagerTest.java | 59 +++++++ 2 files changed, 158 insertions(+), 56 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java index fffb49d8ca6..0635fde994c 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java @@ -59,54 +59,62 @@ public class NoteManager { private static final Logger LOGGER = LoggerFactory.getLogger(NoteManager.class); public static final String TRASH_FOLDER = "~Trash"; - private Folder root; - private Folder trash; - private NotebookRepo notebookRepo; private NoteCache noteCache; - // noteId -> notePath - private Map notesInfo; private final ZeppelinConfiguration zConf; + /** + * The folder tree and the noteId -> notePath mapping. They are held together in one + * immutable reference so that a reload publishes both at once and concurrent note + * operations never observe a tree and a mapping that belong to different generations. + */ + private volatile NoteTree noteTree; + @Inject public NoteManager(NotebookRepo notebookRepo, ZeppelinConfiguration zConf) throws IOException { this.zConf = zConf; this.notebookRepo = notebookRepo; this.noteCache = new NoteCache(zConf.getNoteCacheThreshold()); - this.root = new Folder("/", notebookRepo, noteCache, zConf); - this.trash = this.root.getOrCreateFolder(TRASH_FOLDER); - init(); + this.noteTree = buildNoteTree(); } - // build the tree structure of notes - private void init() throws IOException { - this.notesInfo = notebookRepo.list(AuthenticationInfo.ANONYMOUS).values().stream() - .collect(Collectors.toConcurrentMap(NoteInfo::getId, NoteInfo::getPath)); - this.notesInfo.entrySet().stream() - .forEach(entry -> - { - try { - addOrUpdateNoteNode(new NoteInfo(entry.getKey(), entry.getValue())); - } catch (IOException e) { - LOGGER.warn(e.getMessage()); - } - }); + /** + * Build the tree structure of notes from the NotebookRepo. The tree is fully populated + * before it is returned, and it is not reachable by other threads until the caller + * publishes it to {@link #noteTree}. + */ + private NoteTree buildNoteTree() throws IOException { + Folder newRoot = new Folder("/", notebookRepo, noteCache, zConf); + Folder newTrash = newRoot.getOrCreateFolder(TRASH_FOLDER); + Map newNotesInfo = + notebookRepo.list(AuthenticationInfo.ANONYMOUS).values().stream() + .collect(Collectors.toConcurrentMap(NoteInfo::getId, NoteInfo::getPath)); + NoteTree newNoteTree = new NoteTree(newRoot, newTrash, newNotesInfo); + for (Map.Entry entry : newNotesInfo.entrySet()) { + try { + addOrUpdateNoteNode(newNoteTree, new NoteInfo(entry.getKey(), entry.getValue()), false); + } catch (IOException e) { + LOGGER.warn(e.getMessage()); + } + } + return newNoteTree; } public Map getNotesInfo() { - return notesInfo; + return this.noteTree.notesInfo; } /** + * Rebuild the notebook metadata from the NotebookRepo. The new tree is built completely + * before it replaces the current one, so a concurrent note operation sees either the + * previous tree or the new one, never a partially rebuilt tree. * * @throws IOException */ public void reloadNotes() throws IOException { - this.root = new Folder("/", notebookRepo, noteCache, zConf); - this.trash = this.root.getOrCreateFolder(TRASH_FOLDER); - init(); + this.noteTree = buildNoteTree(); } /** @@ -117,15 +125,16 @@ public int getCacheSize() { return this.noteCache.getSize(); } - private void addOrUpdateNoteNode(NoteInfo noteInfo, boolean checkDuplicates) throws IOException { + private void addOrUpdateNoteNode(NoteTree tree, NoteInfo noteInfo, boolean checkDuplicates) + throws IOException { String notePath = noteInfo.getPath(); - if (checkDuplicates && !isNotePathAvailable(notePath)) { + if (checkDuplicates && !isNotePathAvailable(tree, notePath)) { throw new NotePathAlreadyExistsException("Note '" + notePath + "' existed"); } String[] tokens = notePath.split("/"); - Folder curFolder = root; + Folder curFolder = tree.root; for (int i = 0; i < tokens.length - 1; ++i) { if (!StringUtils.isBlank(tokens[i])) { curFolder = curFolder.getOrCreateFolder(tokens[i]); @@ -133,11 +142,7 @@ private void addOrUpdateNoteNode(NoteInfo noteInfo, boolean checkDuplicates) thr } curFolder.addNote(tokens[tokens.length -1], noteInfo); - this.notesInfo.put(noteInfo.getId(), noteInfo.getPath()); - } - - private void addOrUpdateNoteNode(NoteInfo noteInfo) throws IOException { - addOrUpdateNoteNode(noteInfo, false); + tree.notesInfo.put(noteInfo.getId(), noteInfo.getPath()); } /** @@ -182,7 +187,7 @@ public void saveNote(Note note, AuthenticationInfo subject) throws IOException { if (note.isRemoved()) { LOGGER.warn("Try to save note: {} when it is removed", note.getId()); } else { - addOrUpdateNoteNode(new NoteInfo(note)); + addOrUpdateNoteNode(this.noteTree, new NoteInfo(note), false); noteCache.putNote(note); // Make sure to execute `notebookRepo.save()` successfully in concurrent context // Otherwise, the NullPointerException will be thrown when invoking notebookRepo.get() in the following operations. @@ -193,7 +198,7 @@ public void saveNote(Note note, AuthenticationInfo subject) throws IOException { } public void addNote(Note note, AuthenticationInfo subject) throws IOException { - addOrUpdateNoteNode(new NoteInfo(note), true); + addOrUpdateNoteNode(this.noteTree, new NoteInfo(note), true); noteCache.putNote(note); } @@ -215,8 +220,9 @@ public void saveNote(Note note) throws IOException { * @throws IOException */ public void removeNote(String noteId, AuthenticationInfo subject) throws IOException { - String notePath = this.notesInfo.remove(noteId); - Folder folder = getOrCreateFolder(getFolderName(notePath)); + NoteTree tree = this.noteTree; + String notePath = tree.notesInfo.remove(noteId); + Folder folder = getOrCreateFolder(tree, getFolderName(notePath)); folder.removeNote(getNoteName(notePath)); noteCache.removeNote(noteId); this.notebookRepo.remove(noteId, notePath, subject); @@ -229,21 +235,22 @@ public void moveNote(String noteId, throw new IOException("No metadata found for this note: " + noteId); } - if (!isNotePathAvailable(newNotePath)) { + NoteTree tree = this.noteTree; + if (!isNotePathAvailable(tree, newNotePath)) { throw new NotePathAlreadyExistsException("Note '" + newNotePath + "' existed"); } // move the old NoteNode from notePath to newNotePath - String notePath = this.notesInfo.get(noteId); - NoteNode noteNode = getNoteNode(notePath); + String notePath = tree.notesInfo.get(noteId); + NoteNode noteNode = getNoteNode(tree, notePath); noteNode.getParent().removeNote(getNoteName(notePath)); noteNode.setNotePath(newNotePath); String newParent = getFolderName(newNotePath); - Folder newFolder = getOrCreateFolder(newParent); + Folder newFolder = getOrCreateFolder(tree, newParent); newFolder.addNoteNode(noteNode); // update noteInfo mapping - this.notesInfo.put(noteId, newNotePath); + tree.notesInfo.put(noteId, newNotePath); // update notebookrepo this.notebookRepo.move(noteId, notePath, newNotePath, subject); @@ -277,14 +284,15 @@ public void moveFolder(String folderPath, this.notebookRepo.move(folderPath, newFolderPath, subject); // update filesystem tree - Folder folder = getFolder(folderPath); + NoteTree tree = this.noteTree; + Folder folder = getFolder(tree, folderPath); folder.getParent().removeFolder(folder.getName(), subject); - Folder newFolder = getOrCreateFolder(newFolderPath); + Folder newFolder = getOrCreateFolder(tree, newFolderPath); newFolder.getParent().addFolder(newFolder.getName(), folder); // update notesInfo for (NoteInfo noteInfo : folder.getNoteInfoRecursively()) { - notesInfo.put(noteInfo.getId(), noteInfo.getPath()); + tree.notesInfo.put(noteInfo.getId(), noteInfo.getPath()); } } @@ -313,12 +321,13 @@ public List removeFolder(String folderPath, AuthenticationInfo subject this.notebookRepo.remove(folderPath, subject); // update filesystem tree - Folder folder = getFolder(folderPath); + NoteTree tree = this.noteTree; + Folder folder = getFolder(tree, folderPath); List noteInfos = folder.getParent().removeFolder(folder.getName(), subject); // update notesInfo and evict the deleted notes from the cache, mirroring removeNote for (NoteInfo noteInfo : noteInfos) { - this.notesInfo.remove(noteInfo.getId()); + tree.notesInfo.remove(noteInfo.getId()); this.noteCache.removeNote(noteInfo.getId()); } @@ -336,11 +345,14 @@ public List removeFolder(String folderPath, AuthenticationInfo subject */ public T processNote(String noteId, boolean reload, NoteProcessor noteProcessor) throws IOException { - if (this.notesInfo == null || noteId == null || !this.notesInfo.containsKey(noteId)) { + // Read the tree once, so that the mapping lookup below and the tree traversal that + // follows it are both resolved against the same generation of the metadata. + NoteTree tree = this.noteTree; + if (tree == null || noteId == null || !tree.notesInfo.containsKey(noteId)) { return noteProcessor.process(null); } - String notePath = this.notesInfo.get(noteId); - NoteNode noteNode = getNoteNode(notePath); + String notePath = tree.notesInfo.get(noteId); + NoteNode noteNode = getNoteNode(tree, notePath); return noteNode.loadAndProcessNote(reload, noteProcessor); } @@ -362,8 +374,12 @@ public T processNote(String noteId, NoteProcessor noteProcessor) throws I * @return */ public Folder getOrCreateFolder(String folderName) { + return getOrCreateFolder(this.noteTree, folderName); + } + + private static Folder getOrCreateFolder(NoteTree tree, String folderName) { String[] tokens = folderName.split("/"); - Folder curFolder = root; + Folder curFolder = tree.root; for (int i = 0; i < tokens.length; ++i) { if (!StringUtils.isBlank(tokens[i])) { curFolder = curFolder.getOrCreateFolder(tokens[i]); @@ -373,8 +389,12 @@ public Folder getOrCreateFolder(String folderName) { } private NoteNode getNoteNode(String notePath) throws IOException { + return getNoteNode(this.noteTree, notePath); + } + + private static NoteNode getNoteNode(NoteTree tree, String notePath) throws IOException { String[] tokens = notePath.split("/"); - Folder curFolder = root; + Folder curFolder = tree.root; for (int i = 0; i < tokens.length - 1; ++i) { if (!StringUtils.isBlank(tokens[i])) { curFolder = curFolder.getFolder(tokens[i]); @@ -391,8 +411,12 @@ private NoteNode getNoteNode(String notePath) throws IOException { } private Folder getFolder(String folderPath) throws IOException { + return getFolder(this.noteTree, folderPath); + } + + private static Folder getFolder(NoteTree tree, String folderPath) throws IOException { String[] tokens = folderPath.split("/"); - Folder curFolder = root; + Folder curFolder = tree.root; for (int i = 0; i < tokens.length; ++i) { if (!StringUtils.isBlank(tokens[i])) { curFolder = curFolder.getFolder(tokens[i]); @@ -405,7 +429,7 @@ private Folder getFolder(String folderPath) throws IOException { } public Folder getTrashFolder() { - return this.trash; + return this.noteTree.trash; } private String getFolderName(String notePath) { @@ -418,9 +442,9 @@ private String getNoteName(String notePath) { return notePath.substring(pos + 1); } - private boolean isNotePathAvailable(String notePath) { + private static boolean isNotePathAvailable(NoteTree tree, String notePath) { String[] tokens = notePath.split("/"); - Folder curFolder = root; + Folder curFolder = tree.root; for (int i = 0; i < tokens.length - 1; ++i) { if (!StringUtils.isBlank(tokens[i])) { curFolder = curFolder.getFolder(tokens[i]); @@ -441,6 +465,25 @@ public String getNoteIdByPath(String notePath) throws IOException { return noteNode.getNoteId(); } + /** + * The two indexes that together locate a note: the folder tree and the noteId -> notePath + * mapping. A note lookup resolves the id through the mapping and then walks the tree, so + * the two must belong to the same generation. Holding them in one immutable reference lets + * a reload replace both of them in a single assignment. + */ + private static class NoteTree { + private final Folder root; + private final Folder trash; + // noteId -> notePath + private final Map notesInfo; + + NoteTree(Folder root, Folder trash, Map notesInfo) { + this.root = root; + this.trash = trash; + this.notesInfo = notesInfo; + } + } + /** * Represent one folder that could contains sub folders and note files. */ diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java index cb23ea8f167..eaed222f9e3 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerTest.java @@ -25,15 +25,20 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -208,6 +213,60 @@ void testConcurrentOperation() throws Exception { threadPool.shutdown(); } + @Test + void testConcurrentReloadAndProcessNote() throws Exception { + int noteNum = 50, readerNum = 4, reloadRounds = 30; + Map notes = new ConcurrentHashMap<>(); + for (int i = 0; i < noteNum; i++) { + Note note = createNote(String.format("/prod/note_%s", i)); + noteManager.saveNote(note); + notes.put(i, note.getId()); + } + + List failures = Collections.synchronizedList(new ArrayList<>()); + AtomicBoolean reloading = new AtomicBoolean(true); + ExecutorService threadPool = Executors.newFixedThreadPool(readerNum + 1); + CountDownLatch done = new CountDownLatch(readerNum + 1); + + // Reload the whole note tree repeatedly while other threads read the notes + threadPool.execute(() -> { + try { + for (int i = 0; i < reloadRounds; i++) { + noteManager.reloadNotes(); + } + } catch (Throwable t) { + failures.add(t); + } finally { + reloading.set(false); + done.countDown(); + } + }); + + for (int i = 0; i < readerNum; i++) { + threadPool.execute(() -> { + try { + while (reloading.get()) { + for (String noteId : notes.values()) { + assertNotNull(noteManager.processNote(noteId, note -> note), + "processNote() found no note for an existing noteId during reload"); + } + } + } catch (Throwable t) { + failures.add(t); + } finally { + done.countDown(); + } + }); + } + + assertTrue(done.await(60, TimeUnit.SECONDS), "Concurrent reload did not finish in time"); + threadPool.shutdown(); + if (!failures.isEmpty()) { + throw new AssertionError(failures.size() + + " note operation(s) failed while the note tree was being reloaded", failures.get(0)); + } + } + abstract class ConcurrentTask { private ExecutorService threadPool; private int noteNum; From 21b845a01d4d75a32e87dc330760eb60e5a6934b Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Sun, 2 Aug 2026 11:50:28 +0900 Subject: [PATCH 126/179] [ZEPPELIN-6561] Restore default SIGINT handler so python paragraph cancel works under daemon launch ### What is this PR for? Cancelling a running `%python` paragraph has no effect when Zeppelin is started via `zeppelin-daemon.sh`: the user code runs to completion and the result is recorded as SUCCESS while the job status becomes ABORT. The cancel plumbing itself works. `cancel()` in `PythonInterpreter` sends SIGINT to the correct python pid, and the interpreter log shows it. The problem is signal disposition inheritance: `zeppelin-daemon.sh` starts the server with `nohup ... &` from a non-interactive shell, so per POSIX the whole process chain (ZeppelinServer JVM, interpreter JVM, python) inherits SIGINT=SIG_IGN, and CPython keeps SIGINT ignored instead of installing the KeyboardInterrupt handler when it starts with the signal already ignored. The SIGINT sent by `cancel()` is then a no-op. Running `signal.getsignal(signal.SIGINT)` inside an affected interpreter prints `Handlers.SIG_IGN`. This cannot be fixed in the shell scripts, since POSIX forbids a non-interactive shell from resetting a signal that was ignored on entry. The fix restores the default SIGINT handler at the top of `zeppelin_python.py` when the inherited disposition is SIG_IGN. Starting Zeppelin in the foreground with `bin/zeppelin.sh` was never affected, which is why cancellation appears to work in some environments and not in others. ### What type of PR is it? Bug Fix ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6561 ### How should this be tested? * Automated: `testSigintDefaultHandlerRestoredWhenInheritedIgnored` in `PythonInterpreterTest` launches the interpreter through a shell wrapper that ignores SIGINT before exec'ing python, reproducing the disposition of a daemon launch, and asserts the default handler is restored inside the interpreter process. Without the fix the assertion fails with `Handlers.SIG_IGN`. Unlike the disabled `testCancelIntp`, it does not depend on timing. * Manual: start Zeppelin with `bin/zeppelin-daemon.sh start`, run a `%python` paragraph such as `for i in range(1, 50): print(i); time.sleep(0.5)`, and cancel it a few seconds in. Before the fix it runs to 49 and stores SUCCESS. After the fix it stops immediately with a KeyboardInterrupt traceback and ERROR. ### Screenshots (if appropriate) #### Before https://github.com/user-attachments/assets/b9c6f5b4-24f6-4eb9-9019-37dab52526f0 #### After https://github.com/user-attachments/assets/7b35d549-d97e-45cb-9d95-4ae5c543e0c0 ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5346 from HwangRock/ZEPPELIN-6561. Signed-off-by: Jongyoul Lee --- .../main/resources/python/zeppelin_python.py | 9 +++- .../python/PythonInterpreterTest.java | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/python/src/main/resources/python/zeppelin_python.py b/python/src/main/resources/python/zeppelin_python.py index f3f91861c23..83a6137dde0 100644 --- a/python/src/main/resources/python/zeppelin_python.py +++ b/python/src/main/resources/python/zeppelin_python.py @@ -15,13 +15,20 @@ # limitations under the License. # -import os, sys, traceback, json, re +import os, signal, sys, traceback, json, re from py4j.java_gateway import java_import, JavaGateway, GatewayClient from py4j.protocol import Py4JJavaError import ast +# When Zeppelin is started via zeppelin-daemon.sh (nohup ... &), this process +# inherits SIGINT=SIG_IGN and CPython keeps it ignored instead of installing the +# KeyboardInterrupt handler, so PythonInterpreter.cancel()'s SIGINT would be a +# no-op. Restore the default handler to keep paragraph cancellation working. +if signal.getsignal(signal.SIGINT) == signal.SIG_IGN: + signal.signal(signal.SIGINT, signal.default_int_handler) + class Logger(object): def __init__(self): pass diff --git a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java index 28cfadc5b46..7d0ad4f0e2a 100644 --- a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java +++ b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java @@ -24,6 +24,7 @@ import org.apache.zeppelin.interpreter.InterpreterException; import org.apache.zeppelin.interpreter.InterpreterGroup; import org.apache.zeppelin.interpreter.InterpreterResult; +import org.apache.zeppelin.interpreter.InterpreterResultMessage; import org.apache.zeppelin.interpreter.LazyOpenInterpreter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -35,8 +36,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; import java.util.LinkedList; +import java.util.List; import java.util.Properties; import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; @@ -174,4 +179,42 @@ public void testFailtoLaunchPythonProcess() throws InterpreterException { assertTrue(stacktrace.contains("No such file or directory"), stacktrace); } } + + @Test + public void testSigintDefaultHandlerRestoredWhenInheritedIgnored() + throws IOException, InterpreterException { + tearDown(); + + File wrapper = File.createTempFile("python-sigint-wrapper", ".sh"); + wrapper.deleteOnExit(); + Files.write(wrapper.toPath(), Arrays.asList( + "#!/bin/sh", + "trap '' INT", + "exec python \"$@\"")); + wrapper.setExecutable(true); + + intpGroup = new InterpreterGroup(); + + Properties properties = new Properties(); + properties.setProperty("zeppelin.python", wrapper.getAbsolutePath()); + properties.setProperty("zeppelin.python.useIPython", "false"); + properties.setProperty("zeppelin.python.gatewayserver_address", "127.0.0.1"); + + interpreter = new LazyOpenInterpreter(new PythonInterpreter(properties)); + + intpGroup.put("note", new LinkedList()); + intpGroup.get("note").add(interpreter); + interpreter.setInterpreterGroup(intpGroup); + + InterpreterContext.set(getInterpreterContext()); + + InterpreterContext context = getInterpreterContext(); + InterpreterResult result = interpreter.interpret( + "import signal\nprint(signal.getsignal(signal.SIGINT))", context); + assertEquals(InterpreterResult.Code.SUCCESS, result.code()); + List interpreterResultMessages = + context.out.toInterpreterResultMessage(); + String output = interpreterResultMessages.get(0).getData(); + assertTrue(output.contains("default_int_handler"), output); + } } From 7dfc421f686ce89eb5963fb10bd7eb37dfa75717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=B1=ED=98=95=EC=A4=80?= <138356797+vividbaek@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:36:51 +0900 Subject: [PATCH 127/179] [ZEPPELIN-6478] Log Groovy classpath discovery failures with throwable ### What is this PR for? Pass the caught exception to SLF4J when Groovy classpath discovery fails in `GroovyInterpreter.open()`. Previously, only `e.getMessage()` was logged, so the exception stack trace was lost. This change logs a descriptive message together with the throwable while preserving the existing non-fatal fallback behavior. ### What type of PR is it? Improvement ### Todos * [x] Pass the classpath discovery exception to SLF4J * [x] Preserve the existing non-fatal control flow * [x] Run the Groovy module test lifecycle ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6478 ### How should this be tested? The following command completed successfully: * `./mvnw test -pl groovy` * Build succeeded ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5363 from vividbaek/ZEPPELIN-6478-log-groovy-classpath-failure. Signed-off-by: ChanHo Lee --- .../main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java index 3c6cbed8740..f2a88ccf39d 100644 --- a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java +++ b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java @@ -76,7 +76,7 @@ public void open() { .getPath()); classes = new File(jar.getParentFile(), "classes").toString(); } catch (Exception e) { - LOGGER.error(e.getMessage()); + LOGGER.error("Failed to resolve Groovy classpath", e); } } LOGGER.info("groovy classes classpath: " + classes); From c2cde0f3debb0df3befcd64fcd4332c2d5857783 Mon Sep 17 00:00:00 2001 From: Lee SuJung <153787023+xhaktm00@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:17:42 +0900 Subject: [PATCH 128/179] [ZEPPELIN-6488] Refresh stale apache/zeppelin:0.10.0 Docker tags in the quickstart docs ### What is this PR for? The three `docker run` examples in the "Using the official docker image" section of `docs/quickstart/install.md` pin the image to `apache/zeppelin:0.10.0`, a release from several years ago. A first-time user following the Quickstart literally ends up running an image far behind the current docs. This PR: - updates the three examples to `apache/zeppelin:0.12.1`, the latest release tag currently available on Docker Hub - adds a one-line note next to the examples pointing to the [apache/zeppelin tags page](https://hub.docker.com/r/apache/zeppelin/tags) so readers can find the latest tag, preventing the docs from silently rotting at the next release Out of scope (open for discussion): the same stale tag also appears in `docs/interpreter/python.md`, `docs/interpreter/flink.md` (x2), `docs/interpreter/spark.md`, and `docs/interpreter/r.md`, and `docs/quickstart/docker.md` uses `FROM apache/zeppelin:0.8.0`. Would you prefer that I align those in this PR as well, or split them into a follow-up? I would be happy to do either. ### What type of PR is it? Documentation ### What is the Jira issue? * [ZEPPELIN-6488](https://issues.apache.org/jira/browse/ZEPPELIN-6488) ### How should this be tested? Documentation-only change, no unit tests required. * `grep -rn "apache/zeppelin:0.10.0" docs/quickstart/install.md` reports no occurrences * Verified the updated command works: `docker run -p 8080:8080 --rm --name zeppelin apache/zeppelin:0.12.1` pulls the image and Zeppelin responds on the mapped port (`/api/version` returns `0.12.1`) ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No (this is a documentation change) Closes #5366 from xhaktm00/ZEPPELIN-6488. Signed-off-by: Jongyoul Lee --- docs/quickstart/install.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/quickstart/install.md b/docs/quickstart/install.md index b252ec5265f..76a8fd973fd 100644 --- a/docs/quickstart/install.md +++ b/docs/quickstart/install.md @@ -88,16 +88,18 @@ Make sure that [docker](https://www.docker.com/community-edition) is installed i Use this command to launch Apache Zeppelin in a container. ```bash -docker run -p 8080:8080 --rm --name zeppelin apache/zeppelin:0.10.0 +docker run -p 8080:8080 --rm --name zeppelin apache/zeppelin:0.12.1 ``` +The examples below pin the image to `0.12.1`. You can find the latest available tag on the [apache/zeppelin tags page](https://hub.docker.com/r/apache/zeppelin/tags) on Docker Hub. + To persist `logs` and `notebook` directories, use the [volume](https://docs.docker.com/engine/reference/commandline/run/#mount-volume--v-read-only) option for docker container. ```bash docker run -u $(id -u) -p 8080:8080 --rm -v $PWD/logs:/logs -v $PWD/notebook:/notebook \ -e ZEPPELIN_LOG_DIR='/logs' -e ZEPPELIN_NOTEBOOK_DIR='/notebook' \ - --name zeppelin apache/zeppelin:0.10.0 + --name zeppelin apache/zeppelin:0.12.1 ``` `-u $(id -u)` is to make sure you have the permission to write logs and notebooks. @@ -108,7 +110,7 @@ and Flink interpreter requires Flink binary distribution. You can also mount the ```bash docker run -u $(id -u) -p 8080:8080 --rm -v /mnt/disk1/notebook:/notebook \ -v /usr/lib/spark-current:/opt/spark -v /mnt/disk1/flink-1.12.2:/opt/flink -e FLINK_HOME=/opt/flink \ --e SPARK_HOME=/opt/spark -e ZEPPELIN_NOTEBOOK_DIR='/notebook' --name zeppelin apache/zeppelin:0.10.0 +-e SPARK_HOME=/opt/spark -e ZEPPELIN_NOTEBOOK_DIR='/notebook' --name zeppelin apache/zeppelin:0.12.1 ``` If you have trouble accessing `localhost:8080` in the browser, Please clear browser cache. From a72b8f8fb5e8c2e3cd96b595518d56d0582f3d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=B1=ED=98=95=EC=A4=80?= <138356797+vividbaek@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:19:09 +0900 Subject: [PATCH 129/179] [ZEPPELIN-6480] Stop logging terminal dashboard HTML ### What is this PR for? Remove the INFO log that writes the full rendered terminal dashboard HTML. The dashboard HTML is already written to the paragraph output, so logging it duplicates the content, adds unnecessary log volume, and exposes terminal URL parameters in logs. The paragraph output rendering behavior remains unchanged. ### What type of PR is it? Improvement ### Todos * [x] Remove the full dashboard HTML log * [x] Preserve the paragraph output rendering * [x] Run the shell module build and tests ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6480 ### How should this be tested? ```bash ./mvnw test -pl shell The build completed successfully. ### Screenshots (if appropriate) Not applicable. ### Questions: - Does the license files need to update? No - Is there breaking changes for older versions? No - Does this needs documentation? No Closes #5365 from vividbaek/ZEPPELIN-6480-remove-terminal-dashboard-html-log. Signed-off-by: Jongyoul Lee --- .../main/java/org/apache/zeppelin/shell/TerminalInterpreter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/src/main/java/org/apache/zeppelin/shell/TerminalInterpreter.java b/shell/src/main/java/org/apache/zeppelin/shell/TerminalInterpreter.java index 5a4eb8bae71..173ccba2936 100644 --- a/shell/src/main/java/org/apache/zeppelin/shell/TerminalInterpreter.java +++ b/shell/src/main/java/org/apache/zeppelin/shell/TerminalInterpreter.java @@ -176,7 +176,6 @@ public void createTerminalDashboard(String noteId, String paragraphId, String ho jinjaParams.put("TERMINAL_SERVER_URL", terminalServerUrl); String terminalDashboardTemplate = jinjava.render(template, jinjaParams); - LOGGER.info(terminalDashboardTemplate); try { intpContext.out.setType(InterpreterResult.Type.ANGULAR); InterpreterResultMessageOutput outputUI = intpContext.out.getOutputAt(0); From 30bb6a8367c2b75c37225f3d44a9d23bf9e63b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=B1=ED=98=95=EC=A4=80?= <138356797+vividbaek@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:20:44 +0900 Subject: [PATCH 130/179] [ZEPPELIN-6477] Stop dumping stack trace on Groovy cancellation ### What is this PR for? Remove the `Thread.dumpStack()` call from Groovy paragraph cancellation because it writes an unnecessary stack trace directly to stderr. The existing `t.interrupt()` call is preserved, so the paragraph cancellation behavior remains unchanged. ### What type of PR is it? Improvement ### Todos * [x] Remove the unnecessary stack dump * [x] Preserve the thread interruption behavior * [x] Run the Groovy module build and tests ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6477 ### How should this be tested? ```bash ./mvnw test -pl groovy ``` The build completed successfully. ### Screenshots (if appropriate) Not applicable. ### Questions: - Does the license files need to update? No - Is there breaking changes for older versions? No - Does this needs documentation? No Closes #5364 from vividbaek/ZEPPELIN-6477-remove-groovy-cancel-stack-dump. Signed-off-by: Jongyoul Lee --- .../main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java index f2a88ccf39d..fd0a60cd803 100644 --- a/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java +++ b/groovy/src/main/java/org/apache/zeppelin/groovy/GroovyInterpreter.java @@ -196,7 +196,6 @@ public void cancel(InterpreterContext context) { if (object instanceof Thread) { try { Thread t = (Thread) object; - t.dumpStack(); t.interrupt(); //t.stop(); //TODO(dlukyanov): need some way to terminate maybe through GObject.. } catch (Throwable t) { From 0fbb61137ce43db7b4fd226585b624877eeebd8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=B1=ED=98=95=EC=A4=80?= <138356797+vividbaek@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:21:50 +0900 Subject: [PATCH 131/179] [ZEPPELIN-6466] Improve RepositorySystemFactory error reporting ### What is this PR for? Replace `printStackTrace()` in `RepositorySystemFactory` with SLF4J error logging so service creation failures are handled through the configured logging framework. Also add a meaningful message to the `RuntimeException` thrown when `locator.getService(RepositorySystem.class)` returns null. ### What type of PR is it? Improvement ### Todos * [x] Replace `printStackTrace()` with SLF4J logging * [x] Add a descriptive exception message * [x] Build the shaded interpreter JAR ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6466 ### How should this be tested? The following commands were run successfully: * `./mvnw test -pl zeppelin-interpreter --am` * 126 tests passed * `./mvnw clean package -pl zeppelin-interpreter,zeppelin-interpreter-shaded -DskipTests` * Build succeeded ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5362 from vividbaek/ZEPPELIN-6466-slf4j-repository-system-factory. Signed-off-by: Jongyoul Lee --- .../zeppelin/dep/RepositorySystemFactory.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/RepositorySystemFactory.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/RepositorySystemFactory.java index ae353f22e05..0c713cb96ef 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/RepositorySystemFactory.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/RepositorySystemFactory.java @@ -25,28 +25,30 @@ import org.eclipse.aether.spi.connector.transport.TransporterFactory; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.transport.http.HttpTransporterFactory; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Get maven repository instance. */ public class RepositorySystemFactory { + private static final Logger LOGGER = LoggerFactory.getLogger(RepositorySystemFactory.class); + public static RepositorySystem newRepositorySystem() { DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class ); locator.addService(TransporterFactory.class, FileTransporterFactory.class); locator.addService(TransporterFactory.class, HttpTransporterFactory.class); - locator.setErrorHandler( new DefaultServiceLocator.ErrorHandler() - { - @Override - public void serviceCreationFailed( Class type, Class impl, Throwable exception ) - { - exception.printStackTrace(); - } - } ); + locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() { + @Override + public void serviceCreationFailed(Class type, Class impl, Throwable exception) { + LOGGER.error("Service creation failed for type {} impl {}", type, impl, exception); + } + }); RepositorySystem system = locator.getService(RepositorySystem.class); if (system == null) { - throw new RuntimeException(); + throw new RuntimeException( + "Cannot create RepositorySystem (locator.getService returned null)"); } return system; } From 74fd060401a203888af1f0bc4769d95547f36de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:22:44 +0900 Subject: [PATCH 132/179] [ZEPPELIN-3225] Add missing @Override annotations in zeppelin-server ### What is this PR for? The original report is about missing Override annotations in ActiveDirectoryGroupRealm. Those were already added by ZEPPELIN-5130, so the class is clean on current master. To close out the issue with something useful, I scanned the whole zeppelin-server module for methods that implement or override a supertype method without the annotation, and found seven remaining cases: * five `toJson()` implementations of `JsonSerializable` (`HeliumConf`, `NpmPackage`, `WebpackResult`, `WatcherMessage`, `CredentialsInfoSaving`) * `shouldSkipClass` and `shouldSkipField` in `JsonExclusionStrategy`, which implement Gson's `ExclusionStrategy` ### What type of PR is it? Improvement ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-3225 ### How should this be tested? Annotation only change with no behaviour change, so the compiler is the check. `./mvnw compile -pl zeppelin-server` passes, RAT reports 0 unapproved licenses, and Checkstyle reports no new violations in the touched files. ### Questions: * Does the licenses files need update? No. * Is there breaking changes for older versions? No. * Does this needs documentation? No. Closes #5359 from kimyenac/ZEPPELIN-3225. Signed-off-by: Jongyoul Lee --- .../src/main/java/org/apache/zeppelin/helium/HeliumConf.java | 1 + .../src/main/java/org/apache/zeppelin/helium/NpmPackage.java | 1 + .../src/main/java/org/apache/zeppelin/helium/WebpackResult.java | 1 + .../org/apache/zeppelin/notebook/socket/WatcherMessage.java | 1 + .../java/org/apache/zeppelin/server/JsonExclusionStrategy.java | 2 ++ .../java/org/apache/zeppelin/user/CredentialsInfoSaving.java | 1 + 6 files changed, 7 insertions(+) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumConf.java b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumConf.java index c7fec86c7d0..a7f81677f8e 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumConf.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumConf.java @@ -96,6 +96,7 @@ public void setBundleDisplayOrder(List orderedPackageList) { bundleDisplayOrder = Collections.synchronizedList(orderedPackageList); } + @Override public String toJson() { return gson.toJson(this); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/NpmPackage.java b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/NpmPackage.java index c2234c67ef4..73fc788fbc7 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/NpmPackage.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/NpmPackage.java @@ -31,6 +31,7 @@ public class NpmPackage implements JsonSerializable { public String version; public Map dependencies; + @Override public String toJson() { return gson.toJson(this); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/WebpackResult.java b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/WebpackResult.java index 4175cadd002..3fa33a24ad8 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/WebpackResult.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/WebpackResult.java @@ -28,6 +28,7 @@ public class WebpackResult implements JsonSerializable { public final String [] errors = new String[0]; public final String [] warnings = new String[0]; + @Override public String toJson() { return gson.toJson(this); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/socket/WatcherMessage.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/socket/WatcherMessage.java index c982ca76a1e..3dd07354c9b 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/socket/WatcherMessage.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/socket/WatcherMessage.java @@ -40,6 +40,7 @@ private WatcherMessage(Builder builder) { this.subject = builder.subject; } + @Override public String toJson() { return gson.toJson(this); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/JsonExclusionStrategy.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/JsonExclusionStrategy.java index 3e7a6350fb6..675c4f5068d 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/JsonExclusionStrategy.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/JsonExclusionStrategy.java @@ -20,10 +20,12 @@ import com.google.gson.FieldAttributes; public class JsonExclusionStrategy implements ExclusionStrategy { + @Override public boolean shouldSkipClass(Class arg0) { return false; } + @Override public boolean shouldSkipField(FieldAttributes f) { return false; } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/user/CredentialsInfoSaving.java b/zeppelin-server/src/main/java/org/apache/zeppelin/user/CredentialsInfoSaving.java index e2af406c692..e24fb40b833 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/user/CredentialsInfoSaving.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/user/CredentialsInfoSaving.java @@ -30,6 +30,7 @@ public class CredentialsInfoSaving implements JsonSerializable { public Map credentialsMap; + @Override public String toJson() { return GSON.toJson(this); } From d3f9fa01ec453768307e2c971e5fdf1065d8e2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=ED=99=98?= <66408194+dev-donghwan@users.noreply.github.com> Date: Mon, 3 Aug 2026 23:28:11 +0900 Subject: [PATCH 133/179] [ZEPPELIN-6483][FOLLOWUP] Format HDFS modification time with Locale.ROOT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Follow-up to #5351, addressing the non-blocking nit from the [approving review](https://github.com/apache/zeppelin/pull/5351#pullrequestreview-4820385490): `new SimpleDateFormat(pattern)` still takes its calendar and digits from the JVM default *locale*, so the same class of environment dependence survives the GMT fix — e.g. under a `th-TH` default locale the Buddhist calendar renders 2015 as `2558-08-02 20:43GMT`. This change passes `Locale.ROOT` to the formatter in `listDate()` so the calendar and digits are stable regardless of the JVM default locale, exactly as suggested in the review. The new test mirrors the structure of `testListDateFormatsInGmtToMatchLabel` (save/restore of the global default in `finally`), switching the default locale to `th-TH` and asserting the listing still shows `2015-08-02 20:43GMT`. Reverting only the `listDate()` change makes it fail with the Buddhist-calendar output (`2558-08-02 20:43GMT`), so it pins the regression rather than asserting current behaviour. ### What type of PR is it? Improvement ### Todos * [x] - Pass `Locale.ROOT` to the `SimpleDateFormat` in `listDate()` * [x] - Add a regression test that fails without the fix ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6483 (resolved by #5351; this is the follow-up allowed in its review) ### How should this be tested? * `./mvnw test -pl file -Dtest=HDFSFileInterpreterTest` — 8 tests green (7 existing + 1 new) * Verified locally that reverting only the `listDate()` change makes `testListDateFormatsWithRootLocale` fail with `2558-08-02 20:43GMT` (Buddhist calendar year) in the listing ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5370 from dev-donghwan/ZEPPELIN-6483-followup. Signed-off-by: ChanHo Lee --- .../zeppelin/file/HDFSFileInterpreter.java | 5 ++++- .../file/HDFSFileInterpreterTest.java | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java b/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java index 662d02add81..43acdec7668 100644 --- a/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java +++ b/file/src/main/java/org/apache/zeppelin/file/HDFSFileInterpreter.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Locale; import java.util.Properties; import java.util.TimeZone; @@ -174,7 +175,9 @@ private String listPermission(OneFileStatus fs){ } private String listDate(OneFileStatus fs) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + // Locale.ROOT keeps the calendar and digits stable regardless of the JVM + // default locale (e.g. Buddhist calendar under th-TH). + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.ROOT); // Format in GMT so the value matches the "GMT" label appended in listOne(), // regardless of the JVM default time zone. sdf.setTimeZone(TimeZone.getTimeZone("GMT")); diff --git a/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java b/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java index dc4dcbe5cc8..81b5da80d28 100644 --- a/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java +++ b/file/src/test/java/org/apache/zeppelin/file/HDFSFileInterpreterTest.java @@ -30,6 +30,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Properties; import java.util.TimeZone; @@ -205,6 +206,27 @@ void testListDateFormatsInGmtToMatchLabel() { } } + @Test + void testListDateFormatsWithRootLocale() { + // ZEPPELIN-6483 follow-up: the timestamp must not depend on the JVM default + // locale either — under th-TH the CLDR default calendar is Buddhist, which + // would render 2015 as 2558 without Locale.ROOT in listDate(). + Locale original = Locale.getDefault(); + try { + Locale.setDefault(Locale.forLanguageTag("th-TH")); + HDFSFileInterpreter t = new MockHDFSFileInterpreter(new Properties()); + t.open(); + InterpreterResult result = t.interpret("ls -l /", null); + String out = result.message().get(0).getData(); + // modificationTime 1438548219672 == 2015-08-02 20:43 GMT + assertTrue(out.contains("2015-08-02 20:43GMT"), + "modification time should not depend on the default locale, but was:\n" + out); + t.close(); + } finally { + Locale.setDefault(original); + } + } + } /** From 404866f4171efa27abdf327a4f3d9ffaf3771909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=ED=99=98?= <66408194+dev-donghwan@users.noreply.github.com> Date: Tue, 4 Aug 2026 00:20:09 +0900 Subject: [PATCH 134/179] [ZEPPELIN-6590] Bump websocket-driver to 0.7.5 to address CVE-2026-54466 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The lockfiles of both web UIs (`zeppelin-web-angular` and `zeppelin-web`) resolve `websocket-driver` to 0.7.4, which is affected by [CVE-2026-54466 / GHSA-xv26-6w52-cph6](https://github.com/advisories/GHSA-xv26-6w52-cph6): the draft-75/76 frame parser accumulates the length header into an unbounded integer, so a client sending an indefinite sequence of continuation bytes (`0x80` or above) causes precision loss and mis-framing of subsequent payload data. The fix is in 0.7.5 (latest release), which closes the connection as soon as the accumulated length exceeds the configured max length. `websocket-driver` is a dev-only transitive dependency (`angular-devkit/build-angular` → `webpack-dev-server` → `sockjs` → `faye-websocket`), so shipped Zeppelin artifacts are not affected — but the vulnerable version keeps being flagged by dependency scanners. Since `faye-websocket`'s constraint is `>=0.5.1` and `sockjs`'s is `^0.7.4`, this is a lockfile-only bump: each `package-lock.json` changes only the resolved `websocket-driver` entry (version / resolved / integrity). 0.7.4 and 0.7.5 declare identical dependencies, so no other entry changes. Note: the dependabot security-update group PR #5354 covers `shell-quote` in the same directory but did not pick up `websocket-driver` (advisory published 2026-07-15, before that PR was created), presumably because it sits four levels deep in the dependency tree — hence this manual bump. The earlier bump attempt in #4798 (ZEPPELIN-6061, for a deprecation warning) was closed pending an Angular upgrade; master is on Angular 21 now, and this change does not touch `package.json` at all. ### What type of PR is it? Improvement ### Todos * [x] - Bump the `websocket-driver` lockfile entry to 0.7.5 in `zeppelin-web-angular/package-lock.json` and `zeppelin-web/package-lock.json` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6590 ### How should this be tested? * `cd zeppelin-web-angular && npm ci` — installs cleanly and resolves `websocket-driver0.7.5` (verified locally; `npm ls websocket-driver` shows a single 0.7.5 instance) * CI web build should pass unchanged — dev-server behavior is unaffected (0.7.5 only adds a max-length guard in frame parsing) ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5369 from dev-donghwan/ZEPPELIN-6590. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/package-lock.json | 6 +++--- zeppelin-web/package-lock.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index 544270d7377..6e5e275dbd2 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -21423,9 +21423,9 @@ } }, "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/zeppelin-web/package-lock.json b/zeppelin-web/package-lock.json index 19a8f4b58b6..78454256ea1 100644 --- a/zeppelin-web/package-lock.json +++ b/zeppelin-web/package-lock.json @@ -18638,9 +18638,9 @@ } }, "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", "dev": true, "dependencies": { "http-parser-js": ">=0.5.1", From e087aee5982462adbaa36c6a7c20e596b14a3b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Wed, 5 Aug 2026 23:35:34 +0900 Subject: [PATCH 135/179] [ZEPPELIN-3968] Fix wrong MySQL driver class in JDBC doc screenshot ### What is this PR for? The "Edit Properties" screenshot in the JDBC interpreter documentation shows `default.driver` as `org.mysql.jdbc.Driver`, which is not a real class. Following the docs as written gives a `ClassNotFoundException`. The correct value is `com.mysql.jdbc.Driver`, which is already what the property tables further down the same page use, so the screenshot was the only place left disagreeing with the rest of the doc. The screenshot is patched in place rather than recaptured. It dates from the 0.7 era, and a fresh capture would no longer match the surrounding images in the same walkthrough. To keep the font rendering identical, the `c`, `o` and `m` glyphs were taken from elsewhere in the same line of text (`jdbc`, `org`, `mysql`), and the remainder of the string was shifted right by the advance width difference between "org" (1445/1000 em) and "com" (1889/1000 em), about 11px at this scale. A pixel by pixel comparison against the original confirms only the `default.driver` value changed: 3,387 pixels inside x 936-1171, y 255-278. The surrounding table, the orange highlight box and the arrow annotation are untouched. ### What type of PR is it? Documentation ### Todos * [x] - Fix the driver class name in the screenshot ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-3968 ### How should this be tested? Open the "Files changed" tab and use the image diff on `docs/assets/themes/zeppelin/img/docs-img/edit_properties.png`. The `default.driver` row should read `com.mysql.jdbc.Driver`, everything else unchanged. The image is referenced from `docs/interpreter/jdbc.md`. ### Screenshots (if appropriate) Before: `default.driver` = `org.mysql.jdbc.Driver` After: `default.driver` = `com.mysql.jdbc.Driver` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5368 from kimyenac/ZEPPELIN-3968. Signed-off-by: ChanHo Lee --- .../zeppelin/img/docs-img/edit_properties.png | Bin 171574 -> 133309 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/assets/themes/zeppelin/img/docs-img/edit_properties.png b/docs/assets/themes/zeppelin/img/docs-img/edit_properties.png index e67d49bcff4a480ffd6739dc992fb49c060532e7..4ab3c96396ad23f76f5469f2a4a619cc049e31f0 100644 GIT binary patch literal 133309 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

    *W-1U=#^jTej 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 z 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�@sK!7;Kxf1u*f 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 Jo}5|0{{TKH0+0Xz literal 171574 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%0A?z*8yP6 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

    X%c#N^l$n)w$ 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 P{3u*gxtcFy^5FjfD&cB- From ada6cee24da67894789c7d6058af7859272283f0 Mon Sep 17 00:00:00 2001 From: HyeonUk Kang <43662405+hyunw9@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:00:54 +0900 Subject: [PATCH 136/179] [ZEPPELIN-6385] Refactor StringsCompleter to use method reference for Comparator ### What is this PR for? This PR refactors the anonymous Comparator implementation in StringsCompleter to use a method reference (`String::compareToIgnoreCase`). The change simplifies the code, improves readability, and aligns the class with modern Java best practices. ### What type of PR is it? Refactoring ### Todos * [x] - Replace anonymous Comparator class with method reference. ### What is the Jira issue? * [[ZEPPELIN-6385]](https://issues.apache.org/jira/browse/ZEPPELIN-6385) ### How should this be tested? Since the expected behavior remains unchanged, no additional tests are required. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? - No * Is there breaking changes for older versions? - No * Does this needs documentation? - No Closes #5126 from hyunw9/ZEPPELIN-6385. Signed-off-by: ChanHo Lee --- .../org/apache/zeppelin/completer/StringsCompleter.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/completer/StringsCompleter.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/completer/StringsCompleter.java index a4526622c59..1da78001507 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/completer/StringsCompleter.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/completer/StringsCompleter.java @@ -28,12 +28,7 @@ * Case-insensitive completer for a set of strings. */ public class StringsCompleter implements Completer { - private final SortedSet strings = new TreeSet<>(new Comparator() { - @Override - public int compare(String o1, String o2) { - return o1.compareToIgnoreCase(o2); - } - }); + private final SortedSet strings = new TreeSet<>(String::compareToIgnoreCase); public StringsCompleter() { } From 9b42f2654be2fea9fdddf310686270ebc005d4d6 Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:02:46 +0900 Subject: [PATCH 137/179] [ZEPPELIN-6462] Close interpreter-setting.json streams with try-with-resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `InterpreterSettingManager` discovers interpreters by reading each interpreter's `interpreter-setting.json`. Two helpers do this, and neither closes the stream it opens: ```java // registerInterpreterFromResource getInterpreterListFromJson(url.openStream()); // registerInterpreterFromPath getInterpreterListFromJson(new FileInputStream(interpreterJsonPath.toFile())); ``` The shared sink wraps the stream in an `InputStreamReader` and hands it to `gson.fromJson(...)`. Gson does not close a reader passed to it — the caller owns it — so the descriptor leaks on the normal path. There is no `finally` or try-with-resources either, so it also leaks when parsing throws, for example a `JsonSyntaxException` from a malformed setting file. This is not limited to startup. After installing an interpreter through `POST /api/interpreter/install`, `InterpreterService.downloadInterpreter()` calls `refreshInterpreterTemplates()`, which re-runs the whole directory scan. Every install therefore leaks one descriptor per interpreter directory, and the leaks accumulate on a long-running server. This PR wraps each stream in a try-with-resources at the call site that opens it. Parsing and registration behaviour is unchanged. No signatures or access modifiers change. ### What type of PR is it? Bug Fix ### Todos * [x] Close the stream opened in `registerInterpreterFromResource` * [x] Close the stream opened in `registerInterpreterFromPath` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6462 ### How should this be tested? ```bash ./mvnw package -pl zeppelin-server --am \ -Dtest='InterpreterSettingManagerTest,InterpreterFactoryTest,InterpreterSettingTest' \ -DfailIfNoTests=false ``` `Tests run: 26, Failures: 0, Errors: 0, Skipped: 0`, and `zeppelin-server` builds. No tests accompany this change. Asserting that a stream is closed requires a seam in production code to inject a tracked stream, and an earlier revision of this PR added one — that is not worth carrying for a two-line fix, so it has been removed along with the tests that used it. The remaining change is the try-with-resources itself. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5355 from big-cir/ZEPPELIN-6462. Signed-off-by: ChanHo Lee --- .../interpreter/InterpreterSettingManager.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java index e2959382206..f6086f4d06c 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java @@ -486,9 +486,10 @@ private boolean registerInterpreterFromResource(ClassLoader cl, String interpret } LOGGER.debug("Reading interpreter-setting.json from {} as Resource", url); - List registeredInterpreterList = - getInterpreterListFromJson(url.openStream()); - registerInterpreterSetting(registeredInterpreterList, interpreterDir, override); + try (InputStream stream = url.openStream()) { + List registeredInterpreterList = getInterpreterListFromJson(stream); + registerInterpreterSetting(registeredInterpreterList, interpreterDir, override); + } return true; } @@ -498,9 +499,10 @@ private boolean registerInterpreterFromPath(String interpreterDir, String interp Path interpreterJsonPath = Paths.get(interpreterDir, interpreterJson); if (Files.exists(interpreterJsonPath)) { LOGGER.debug("Reading interpreter-setting.json from file {}", interpreterJsonPath); - List registeredInterpreterList = - getInterpreterListFromJson(new FileInputStream(interpreterJsonPath.toFile())); - registerInterpreterSetting(registeredInterpreterList, interpreterDir, override); + try (InputStream stream = new FileInputStream(interpreterJsonPath.toFile())) { + List registeredInterpreterList = getInterpreterListFromJson(stream); + registerInterpreterSetting(registeredInterpreterList, interpreterDir, override); + } return true; } return false; From 904c0898a2d5e37e2a725b99e8ae2bec982ff509 Mon Sep 17 00:00:00 2001 From: Lee SuJung <153787023+xhaktm00@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:03:50 +0900 Subject: [PATCH 138/179] [ZEPPELIN-6489] Fix stale Shiro authentication documentation links MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The Shiro authentication docs URL referenced in `conf/shiro.ini.template` and in the Kerberos/Knox authentication filter error messages no longer resolves. The stale link has three defects: it uses `http://` instead of `https://` (template only), the path is missing the `setup/` segment, and the file name is missing an underscore (`shiroauthentication.html` → `shiro_authentication.html`). This PR updates all three pointers to the current docs address, which is published from `docs/setup/security/shiro_authentication.md`: https://zeppelin.apache.org/docs/latest/setup/security/shiro_authentication.html The surrounding comment/message text is unchanged. One line in `KnoxAuthenticationFilter` is re-wrapped to keep the longer URL within the 100-character checkstyle limit. ### What type of PR is it? Documentation ### Todos * [x] Update the stale URL in `conf/shiro.ini.template`, `KerberosAuthenticationFilter` and `KnoxAuthenticationFilter` ### What is the Jira issue? * [ZEPPELIN-6489](https://issues.apache.org/jira/browse/ZEPPELIN-6489) ### How should this be tested? No code behavior changes — the URLs appear only in a config template comment and log messages, so no unit tests are added. * Confirm the source page exists at `docs/setup/security/shiro_authentication.md` * Confirm no stale variants remain: ``` rg -n "shiroauthentication|docs/latest/security/shiro|http://zeppelin.apache.org/docs/latest/security" conf zeppelin-server ``` * Open https://zeppelin.apache.org/docs/latest/setup/security/shiro_authentication.html and confirm it loads (verified: HTTP 200) ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5361 from xhaktm00/ZEPPELIN-6489. Signed-off-by: ChanHo Lee --- conf/shiro.ini.template | 2 +- .../apache/zeppelin/realm/jwt/KnoxAuthenticationFilter.java | 4 ++-- .../zeppelin/realm/kerberos/KerberosAuthenticationFilter.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/shiro.ini.template b/conf/shiro.ini.template index 24b18e27109..c60f278d148 100644 --- a/conf/shiro.ini.template +++ b/conf/shiro.ini.template @@ -30,7 +30,7 @@ user3 = password4, role2 #activeDirectoryRealm = org.apache.zeppelin.realm.ActiveDirectoryGroupRealm #activeDirectoryRealm.systemUsername = userNameA -#use either systemPassword or hadoopSecurityCredentialPath, more details in http://zeppelin.apache.org/docs/latest/security/shiroauthentication.html +#use either systemPassword or hadoopSecurityCredentialPath, more details in https://zeppelin.apache.org/docs/latest/setup/security/shiro_authentication.html #activeDirectoryRealm.systemPassword = passwordA #activeDirectoryRealm.hadoopSecurityCredentialPath = jceks://file/user/zeppelin/zeppelin.jceks #activeDirectoryRealm.searchBase = CN=Users,DC=SOME_GROUP,DC=COMPANY,DC=COM diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/jwt/KnoxAuthenticationFilter.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/jwt/KnoxAuthenticationFilter.java index e2800908246..593cbbd050f 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/jwt/KnoxAuthenticationFilter.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/jwt/KnoxAuthenticationFilter.java @@ -68,8 +68,8 @@ protected boolean isAccessAllowed( } else { LOGGER.error( "Looks like this filter is enabled without enabling KnoxJwtRealm, please refer" - + " to https://zeppelin.apache.org/docs/latest/security/shiroauthentication.html" - + "#knox-sso"); + + " to https://zeppelin.apache.org/docs/latest/setup/security/" + + "shiro_authentication.html#knox-sso"); } } return accessAllowed; diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/kerberos/KerberosAuthenticationFilter.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/kerberos/KerberosAuthenticationFilter.java index 0f628356d11..4e96ab92bbd 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/kerberos/KerberosAuthenticationFilter.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/kerberos/KerberosAuthenticationFilter.java @@ -76,8 +76,8 @@ public void doFilterInternal(ServletRequest request, kerberosRealm.doKerberosAuth(request, response, filterChain); } else { LOGGER.error("Looks like this filter is enabled without enabling KerberosRealm, please refer" - + " to https://zeppelin.apache.org/docs/latest/security/shiroauthentication.html" - + "#kerberos-auth"); + + " to https://zeppelin.apache.org/docs/latest/setup/security/shiro_authentication.html" + + "#http-spnego-authentication"); } } } From ee44170d46b6f5841bdafb4f7163cd0eda482741 Mon Sep 17 00:00:00 2001 From: Stan <53285109+houhang1005@users.noreply.github.com> Date: Thu, 6 Aug 2026 10:04:40 +0800 Subject: [PATCH 139/179] [ZEPPELIN-6393] Fix GET job/{noteId} api, when target notebook id contains ERROR status paragraph ,it returns java.lang.NoClassDefFoundError: org/apache/commons/lang/StringUtils MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? use this api /api/notebook/job/{noteid} ,to get every paragraph status. when some status is ERROR, this api will always return: java.lang.NoClassDefFoundError: org/apache/commons/lang/StringUtils and this exception come from org.apache.zeppelin.rest.message.ParagraphJobStatus ### What type of PR is it? Bug Fix ### Todos ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6393 ### How should this be tested? * Strongly recommended: add automated unit tests for any new or changed behavior * Outline any manual steps to test the PR here. ### Screenshots (if appropriate) ### Questions: I found some history pr and they are the same situation with this. I guess ParagraphJobStatus.java also need change from org.apache.commons.lang.StringUtils to org.apache.commons.lang3.StringUtils to solve ERROR status of paragraph. Closes #5143 from houhang1005/master. Signed-off-by: ChanHo Lee --- .../org/apache/zeppelin/rest/message/ParagraphJobStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParagraphJobStatus.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParagraphJobStatus.java index 3d8d4472834..e43d996f4a5 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParagraphJobStatus.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParagraphJobStatus.java @@ -17,7 +17,7 @@ package org.apache.zeppelin.rest.message; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.zeppelin.notebook.Paragraph; import org.apache.zeppelin.scheduler.Job; From a15b82c711e730e2fac08cb73bf775cc604a786d Mon Sep 17 00:00:00 2001 From: namuuCY <156210154+namuuCY@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:07:33 +0900 Subject: [PATCH 140/179] [ZEPPELIN-5994] Fix cron tests for ZeppelinRestApiTest ### What is this PR for? This PR fixes and re-enables the cron REST API tests that were disabled in `ZeppelinRestApiTest`. Cron scheduling is disabled for security when Zeppelin runs in anonymous mode, even if the cron configuration is enabled. This PR separates the cron tests by authentication mode: - Verify that cron creation and deletion are forbidden in anonymous mode. - Add `AuthenticatedCronRestApiTest`, which starts Zeppelin with Shiro authentication enabled. - Verify the cron lifecycle for an authenticated administrator. - Verify cron folder restrictions and invalid cron expression handling. ### What type of PR is it? Bug Fix ### Todos - [x] Verify that cron operations are rejected in anonymous mode. - [x] Add authenticated cron REST API tests. - [x] Test cron folder restrictions. - [x] Test valid and invalid cron expressions. ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-5994 ### How should this be tested? Run the focused REST API tests: ```bash ./mvnw -pl zeppelin-server \ -Dtest=AuthenticatedCronRestApiTest \ test ./mvnw -pl zeppelin-server \ -Dtest='ZeppelinRestApiTest#testCronDisabledInAnonymousMode' \ test ``` ### Questions: - Does the license files need to update? No. - Is there breaking changes for older versions? No. - Does this needs documentation? No. This PR only updates test coverage. Closes #5367 from namuuCY/master. Signed-off-by: ChanHo Lee --- .../rest/AuthenticatedCronRestApiTest.java | 181 ++++++++++++++++++ .../zeppelin/rest/ZeppelinRestApiTest.java | 156 +++------------ 2 files changed, 210 insertions(+), 127 deletions(-) create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/rest/AuthenticatedCronRestApiTest.java diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AuthenticatedCronRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AuthenticatedCronRestApiTest.java new file mode 100644 index 00000000000..3aff15621fc --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AuthenticatedCronRestApiTest.java @@ -0,0 +1,181 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zeppelin.rest; + +import java.io.IOException; +import java.util.Map; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.zeppelin.MiniZeppelinServer; +import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; +import org.apache.zeppelin.notebook.Notebook; +import org.apache.zeppelin.notebook.Paragraph; +import org.apache.zeppelin.user.AuthenticationInfo; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AuthenticatedCronRestApiTest extends AbstractTestRestApi { + private static final String ADMIN_USER = "admin"; + private static final String ADMIN_PASSWORD = "password1"; + private static final String VALID_CRON_REQUEST = "{\"cron\":\"0 0 0 1 1 ? 2099\"}"; + + private static MiniZeppelinServer zepServer; + private Notebook notebook; + private AuthenticationInfo admin; + + @BeforeAll + static void init() throws Exception { + zepServer = new MiniZeppelinServer(AuthenticatedCronRestApiTest.class.getSimpleName()); + zepServer.addConfigFile("shiro.ini", ZEPPELIN_SHIRO); + zepServer.addInterpreter("md"); + zepServer.getZeppelinConfiguration().setProperty( + ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName(), "true"); + zepServer.getZeppelinConfiguration().setProperty( + ConfVars.ZEPPELIN_NOTEBOOK_CRON_FOLDERS.getVarName(), "/System"); + zepServer.start(); + } + + @AfterAll + static void destroy() throws Exception { + zepServer.destroy(); + } + + @BeforeEach + void setUp() { + zConf = zepServer.getZeppelinConfiguration(); + notebook = zepServer.getService(Notebook.class); + admin = new AuthenticationInfo(ADMIN_USER); + } + + @Test + void testCronForNonexistentNote() throws IOException { + try ( + CloseableHttpResponse response = + httpPost( + "/notebook/cron/notexistnote", + VALID_CRON_REQUEST, + ADMIN_USER, + ADMIN_PASSWORD)) { + assertThat("", response, isNotFound()); + } + } + + @Test + void testCronLifecycleInConfiguredFolder() throws Exception { + String noteId = null; + try { + assertTrue(zConf.isAuthenticationEnabled()); + assertTrue(zConf.isZeppelinNotebookCronEnable()); + noteId = notebook.createNote("/System/testCronLifecycleInConfiguredFolder", admin); + notebook.processNote(noteId, + note -> { + assertNotNull(note, "can't create new note"); + note.setName("testCronLifecycleInConfiguredFolder"); + Paragraph paragraph = note.addNewParagraph(admin); + Map config = paragraph.getConfig(); + config.put("enabled", true); + paragraph.setConfig(config); + paragraph.setText("%md This is test paragraph."); + notebook.saveNote(note, admin); + return null; + }); + + try ( + CloseableHttpResponse response = + httpPost( + "/notebook/cron/" + noteId, + VALID_CRON_REQUEST, + ADMIN_USER, + ADMIN_PASSWORD)) { + assertThat("", response, isAllowed()); + } + + try ( + CloseableHttpResponse response = + httpGet( + "/notebook/cron/" + noteId, + ADMIN_USER, + ADMIN_PASSWORD)) { + assertThat("", response, isAllowed()); + } + + String invalidCronRequest = "{\"cron\":\"a * * * * ?\"}"; + try ( + CloseableHttpResponse response = + httpPost( + "/notebook/cron/" + noteId, + invalidCronRequest, + ADMIN_USER, + ADMIN_PASSWORD)) { + assertThat("", response, isBadRequest()); + } + + try ( + CloseableHttpResponse response = + httpDelete( + "/notebook/cron/" + noteId, + ADMIN_USER, + ADMIN_PASSWORD)) { + assertThat("", response, isAllowed()); + } + } finally { + if (noteId != null) { + notebook.removeNote(noteId, admin); + } + } + } + + @Test + void testCronRejectedOutsideConfiguredFolder() throws Exception { + String noteId = null; + try { + noteId = notebook.createNote("/Other/testCronRejectedOutsideConfiguredFolder", admin); + notebook.processNote(noteId, + note -> { + assertNotNull(note, "can't create new note"); + note.setName("testCronRejectedOutsideConfiguredFolder"); + Paragraph paragraph = note.addNewParagraph(admin); + Map config = paragraph.getConfig(); + config.put("enabled", true); + paragraph.setConfig(config); + paragraph.setText("%md This is test paragraph."); + notebook.saveNote(note, admin); + return null; + }); + + try ( + CloseableHttpResponse response = + httpPost( + "/notebook/cron/" + noteId, + VALID_CRON_REQUEST, + ADMIN_USER, + ADMIN_PASSWORD)) { + assertThat("", response, isForbidden()); + } + } finally { + if (noteId != null) { + notebook.removeNote(noteId, admin); + } + } + } +} diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java index 5b3977c2ed4..385050ba77a 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java @@ -29,7 +29,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; @@ -54,6 +53,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -78,6 +78,8 @@ public static void init() throws Exception { zepServer.addInterpreter("sh"); zepServer.addInterpreter("spark"); zepServer.copyBinDir(); + zepServer.getZeppelinConfiguration().setProperty( + ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName(), "true"); zepServer.start(); TestHelper.configureSparkInterpreter(zepServer, sparkHome); } @@ -676,143 +678,43 @@ void testRunParagraphWithParams() throws Exception { } } - @Disabled // TODO(ZEPPELIN-5994): Fix and enable this test @Test - void testJobs() throws Exception { - // create a note and a paragraph + void testCronDisabledInAnonymousMode() throws Exception { String noteId = null; try { - System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName(), "true"); - noteId = notebook.createNote("note1_testJobs", anonymous); - // Use write lock, because name is overwritten + assertFalse(zConf.isAuthenticationEnabled()); + assertFalse(zConf.isZeppelinNotebookCronEnable()); + noteId = notebook.createNote("note1_testCronDisabledInAnonymousMode", anonymous); notebook.processNote(noteId, - note -> { - note.setName("note for run test"); - Paragraph paragraph = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); - paragraph.setText("%md This is test paragraph."); - - Map config = paragraph.getConfig(); - config.put("enabled", true); - paragraph.setConfig(config); - return null; - }); - - notebook.processNote(noteId, - note -> { - try { - note.runAll(AuthenticationInfo.ANONYMOUS, false, false, new HashMap<>()); - } catch (Exception e) { - fail(); - } - return null; - }); + note -> { + assertNotNull(note, "can't create new note"); + note.setName("note for anonymous cron test"); + Paragraph paragraph = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); + Map config = paragraph.getConfig(); + config.put("enabled", true); + paragraph.setConfig(config); + paragraph.setText("%md This is test paragraph."); + notebook.saveNote(note, anonymous); + return null; + }); String jsonRequest = "{\"cron\":\"* * * * * ?\" }"; - // right cron expression but not exist note. - CloseableHttpResponse postCron = httpPost("/notebook/cron/notexistnote", jsonRequest); - assertThat("", postCron, isNotFound()); - postCron.close(); - - // right cron expression. - postCron = httpPost("/notebook/cron/" + noteId, jsonRequest); - assertThat("", postCron, isAllowed()); - postCron.close(); - Thread.sleep(1000); - - // wrong cron expression. - jsonRequest = "{\"cron\":\"a * * * * ?\" }"; - postCron = httpPost("/notebook/cron/" + noteId, jsonRequest); - assertThat("", postCron, isBadRequest()); - postCron.close(); - Thread.sleep(1000); - - // remove cron job. - CloseableHttpResponse deleteCron = httpDelete("/notebook/cron/" + noteId); - assertThat("", deleteCron, isAllowed()); - deleteCron.close(); - } finally { - //cleanup - if (null != noteId) { - notebook.removeNote(noteId, anonymous); + try ( + CloseableHttpResponse postCron = + httpPost( + "/notebook/cron/" + noteId, + jsonRequest)) { + assertThat("", postCron, isForbidden()); + } + try ( + CloseableHttpResponse deleteCron = + httpDelete("/notebook/cron/" + noteId)) { + assertThat("", deleteCron, isForbidden()); } - System.clearProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName()); - } - } - - @Disabled // TODO(ZEPPELIN-5994): Fix and enable this test - @Test - void testCronDisable() throws Exception { - String noteId = null; - try { - // create a note and a paragraph - System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName(), "false"); - noteId = notebook.createNote("note1_testCronDisable", anonymous); - // use write lock because Name is overwritten - notebook.processNote(noteId, - note -> { - note.setName("note for run test"); - Paragraph paragraph = note.addNewParagraph(AuthenticationInfo.ANONYMOUS); - paragraph.setText("%md This is test paragraph."); - - Map config = paragraph.getConfig(); - config.put("enabled", true); - paragraph.setConfig(config); - return null; - }); - - notebook.processNote(noteId, - note -> { - try { - note.runAll(AuthenticationInfo.ANONYMOUS, true, true, new HashMap<>()); - } catch (Exception e) { - fail(); - } - return null; - }); - - - String jsonRequest = "{\"cron\":\"* * * * * ?\" }"; - // right cron expression. - CloseableHttpResponse postCron = httpPost("/notebook/cron/" + noteId, jsonRequest); - assertThat("", postCron, isForbidden()); - postCron.close(); - - System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName(), "true"); - System.setProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_FOLDERS.getVarName(), "/System"); - - // use write lock, because Name is overwritten - notebook.processNote(noteId, - note -> { - note.setName("System/test2"); - return null; - }); - notebook.processNote(noteId, - note -> { - try { - note.runAll(AuthenticationInfo.ANONYMOUS, true, true, new HashMap<>()); - } catch (Exception e) { - fail(); - } - return null; - }); - postCron = httpPost("/notebook/cron/" + noteId, jsonRequest); - assertThat("", postCron, isAllowed()); - postCron.close(); - Thread.sleep(1000); - - // remove cron job. - CloseableHttpResponse deleteCron = httpDelete("/notebook/cron/" + noteId); - assertThat("", deleteCron, isAllowed()); - deleteCron.close(); - Thread.sleep(1000); - - System.clearProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_FOLDERS.getVarName()); } finally { - //cleanup if (null != noteId) { notebook.removeNote(noteId, anonymous); } - System.clearProperty(ConfVars.ZEPPELIN_NOTEBOOK_CRON_ENABLE.getVarName()); } } From 2c448a3b2dd3868112235efafac58e7810a41ed0 Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:09:19 +0900 Subject: [PATCH 141/179] [ZEPPELIN-6484] Deduplicate IdHashes and add unit tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `IdHashes` existed twice with identical behaviour — `org.apache.zeppelin.util` in `zeppelin-interpreter` and `org.apache.zeppelin.notebook.utility` in `zeppelin-server` — and neither copy had any tests. The ticket left the scope open between "tests only" and "dedupe plus tests". This PR takes the dedupe path: `notebook.utility` held nothing but that one file, and `Note.java` was the only thing importing it, so removing it is a file deletion and an import switch. Splitting that into a second ticket would cost more than it saves. `org.apache.zeppelin.util.IdHashes` is kept as the canonical copy, matching the module dependency direction — `zeppelin-server` already depends on `zeppelin-interpreter`, not the other way round. The new `IdHashesTest` pins what `generateId()` guarantees: the character set (digits 1-9 and A-Z without I, L and O, left out so IDs stay unambiguous when read by a person), non-emptiness, and uniqueness. `encode()` is private, so all three go through `generateId()`. The expected character set is spelled out in the test rather than read back from `IdHashes`, so a change to the dictionary shows up as a failure instead of being silently followed. Note IDs are unaffected: `IdHashes` only mints IDs and never parses them, and the two copies produced identical output, so existing notes keep reading their stored IDs as before. ### What type of PR is it? Improvement ### Todos * [x] - Add `IdHashesTest` against the canonical `org.apache.zeppelin.util.IdHashes` * [x] - Remove the `zeppelin-server` `notebook.utility` copy and switch `Note.java` to the canonical import * [x] - Rebuild the shaded chain and confirm `zeppelin-server` still builds ### What is the Jira issue? * [ZEPPELIN-6484](https://issues.apache.org/jira/browse/ZEPPELIN-6484) ### How should this be tested? New tests: ``` ./mvnw package -pl zeppelin-interpreter --am -Dtest=IdHashesTest -DfailIfNoTests=false ``` `Tests run: 3, Failures: 0, Errors: 0, Skipped: 0` Dedupe, per the ticket's verification note — rebuild the shaded chain, then build `zeppelin-server`: ``` ./mvnw clean package -pl zeppelin-interpreter,zeppelin-interpreter-shaded --am -DskipTests ./mvnw package -pl zeppelin-server --am -Dtest='NoteTest,InterpreterSettingTest' -DfailIfNoTests=false ``` Both succeed. `NoteTest` (8 tests) covers the switched import directly, since the `Note` constructor is what calls `IdHashes.generateId()`; `InterpreterSettingTest` (12 tests) covers the canonical copy's other caller. `apache-rat` reports no unapproved licenses. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5379 from big-cir/ZEPPELIN-6484. Signed-off-by: ChanHo Lee --- .../apache/zeppelin/util/IdHashesTest.java | 74 ++++++++++++++++++ .../org/apache/zeppelin/notebook/Note.java | 2 +- .../zeppelin/notebook/utility/IdHashes.java | 76 ------------------- 3 files changed, 75 insertions(+), 77 deletions(-) create mode 100644 zeppelin-interpreter/src/test/java/org/apache/zeppelin/util/IdHashesTest.java delete mode 100644 zeppelin-server/src/main/java/org/apache/zeppelin/notebook/utility/IdHashes.java diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/util/IdHashesTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/util/IdHashesTest.java new file mode 100644 index 00000000000..5298126f766 --- /dev/null +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/util/IdHashesTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +class IdHashesTest { + + /** + * The characters generated IDs are expected to be built from: digits 1-9 and A-Z without + * I, L and O. Those three letters and the digit 0 are left out so that an ID stays + * unambiguous when a person reads it off a URL. + * + *

  • HTTP Security Headers
  • Notebook Storage
  • -
  • Git Storage
  • -
  • S3 Storage
  • -
  • Azure Storage
  • -
  • Google Cloud Storage
  • -
  • OSS Storage
  • -
  • MongoDB Storage
  • +
  • Git Storage
  • +
  • S3 Storage
  • +
  • Azure Storage
  • +
  • Google Cloud Storage
  • +
  • OSS Storage
  • +
  • MongoDB Storage
  • Operation
  • Configuration
  • diff --git a/docs/index.md b/docs/index.md index 0e471f4faf0..ffc9b1ecbb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -107,11 +107,11 @@ limitations under the License. * [Data Source Authorization](./setup/security/datasource_authorization.html) * [HTTP Security Headers](./setup/security/http_security_headers.html) * Notebook Storage: a guide about saving notebooks to external storage - * [Git Storage](./setup/storage/storage.html#notebook-storage-in-local-git-repository) - * [S3 Storage](./setup/storage/storage.html#notebook-storage-in-s3) - * [Azure Storage](./setup/storage/storage.html#notebook-storage-in-azure) - * [Google Cloud Storage](./setup/storage/storage.html#notebook-storage-in-gcs) - * [MongoDB Storage](./setup/storage/storage.html#notebook-storage-in-mongodb) + * [Git Storage](./setup/storage/notebook_storage.html#Git) + * [S3 Storage](./setup/storage/notebook_storage.html#S3) + * [Azure Storage](./setup/storage/notebook_storage.html#Azure) + * [Google Cloud Storage](./setup/storage/notebook_storage.html#GCS) + * [MongoDB Storage](./setup/storage/notebook_storage.html#MongoDB) * Operation * [Configuration](./setup/operation/configuration.html): lists for Apache Zeppelin * [Monitoring](./setup/operation/monitoring.html): monitoring instructions for Apache Zeppelin diff --git a/docs/pleasecontribute.md b/docs/pleasecontribute.md index 746b39dc87c..e21aaa9b50e 100644 --- a/docs/pleasecontribute.md +++ b/docs/pleasecontribute.md @@ -25,4 +25,4 @@ The content does not exist yet. We're always welcoming contribution. -If you're interested, please check [How to contribute (website)](./development/howtocontributewebsite.html). +If you're interested, please check [How to contribute (website)](./development/contribution/how_to_contribute_website.html). diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index fe5cf3bd0b9..c664d7ac246 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -89,7 +89,7 @@ If the context parameter is null, then it is replaced by an empty string. The fo Every interpreter belongs to an **Interpreter Group**. Interpreter Groups are units of interpreters that run in one single JVM process and can be started/stopped together. By default, every interpreter belongs to a separate group, but the group might contain more interpreters. For example, the Spark interpreter group includes Scala Spark, PySpark, IPySpark and Spark SQL. -Technically, Zeppelin interpreters from the same group run within the same JVM. For more information about this, please consult [the documentation on writing interpreters](../development/writing_zeppelin_interpreter.html). +Technically, Zeppelin interpreters from the same group run within the same JVM. For more information about this, please consult [the documentation on writing interpreters](../../development/writing_zeppelin_interpreter.html). Each interpreter belongs to a single group and is registered together. All relevant properties are listed in the interpreter setting as in the below example. diff --git a/docs/usage/other_features/zeppelin_context.md b/docs/usage/other_features/zeppelin_context.md index efb72b01abc..ad9f09c305f 100644 --- a/docs/usage/other_features/zeppelin_context.md +++ b/docs/usage/other_features/zeppelin_context.md @@ -195,7 +195,7 @@ Currently only [text](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ [options](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option), and [checkbox](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox) are supported. -Dynamic forms are described in detail here: [Dynamic Form](../usage/dynamic_form/intro.html). +Dynamic forms are described in detail here: [Dynamic Form](../dynamic_form/intro.html). In sql environment, you can create dynamic form in simple template. @@ -205,7 +205,7 @@ In sql environment, you can create dynamic form in simple template. select * from ${table=defaultTableName} where text like '%${search}%' ``` -To learn more about dynamic form, checkout [Dynamic Form](../usage/dynamic_form/intro.html). +To learn more about dynamic form, checkout [Dynamic Form](../dynamic_form/intro.html). ## Usage with Embedded Commands From f988eef9fe9a2853988193c7572c3b01d554441c Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:43:40 +0900 Subject: [PATCH 148/179] [ZEPPELIN-6521] Preserve withCredentials on HTTP requests in production builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? In production builds the interceptor re-clones from the original `httpRequest` when it adds `X-Requested-With`, discarding the `withCredentials: true` clone made one line earlier. `clone()` inherits from whatever it was cloned from (`update.withCredentials ?? this.withCredentials`), so the production request goes out with the default `false`. ```diff let httpRequestUpdated = httpRequest.clone({ withCredentials: true }); if (environment.production) { - httpRequestUpdated = httpRequest.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); + httpRequestUpdated = httpRequestUpdated.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); } ``` Two things the ticket does not cover. First, `BaseUrlService` builds the REST base from `location`, so every call to Zeppelin's own API is same-origin and the browser attaches cookies whether or not the flag is set; the flag has no reachable effect on those calls today. The classic UI's equivalent service remaps the port when the UI is served from the grunt dev server (`zeppelin-web/src/components/base-url/base-url.service.js:26-29`), which is what made `withCredentials` meaningful there, and the new UI has no such path. So this is a correctness fix — the interceptor now applies both of its settings consistently across builds, the way the classic UI does (`zeppelin-web/src/app/app.js:78` and `:161-163`) — rather than a behaviour fix for API traffic. The second is the subject of the next section. ### Scope and related issues **Third-party URL fetches go through this interceptor too, and this change narrows what they can reach.** `NoteImportComponent` passes a user-supplied URL straight to `HttpClient` (`note-import.component.ts:49`), so the "import note from URL" request carries the same `withCredentials` and `X-Requested-With` as a call to Zeppelin's own API. A browser rejects a credentialed cross-origin response whose `Access-Control-Allow-Origin` is `*`, and that wildcard is what public file hosts serve. Measured in Chromium against local servers reproducing each CORS configuration, with the `raw.githubusercontent.com` preflight response checked directly: | target host | dev build | production today | production after this PR | |---|---|---|---| | rejects `X-Requested-With` at preflight — `raw.githubusercontent.com` answers the preflight with 403 | blocked | blocked | blocked | | allows `X-Requested-With`, serves `Access-Control-Allow-Origin: *` | blocked | works | blocked | Only the second row changes, and it changes production to match what development already does, which is what this ticket asks for. The underlying problem is that the interceptor does not distinguish Zeppelin's own API from an arbitrary URL. The classic UI handles it by overriding `withCredentials: false` for exactly this request (`zeppelin-web/src/components/note-import/note-import.controller.js:95-97`); the new UI has no equivalent. That is a separate defect which predates this ticket and already breaks the feature in development builds today. Scoping the interceptor so that `withCredentials` and `X-Requested-With` are applied only to Zeppelin's own API would resolve it, and would not change anything this PR does for API calls. I have not filed a ticket for it yet — I would rather hear whether that scoping belongs in this PR or in a follow-up. ### What type of PR is it? Bug Fix ### Todos * [x] - Derive the production clone from the already-credentialed request * [x] - Confirm `X-Requested-With` is still added in production builds * [x] - Confirm development builds are unaffected ### What is the Jira issue? * [ZEPPELIN-6521](https://issues.apache.org/jira/browse/ZEPPELIN-6521) ### How should this be tested? There is no unit-test runner for this app to add a spec to: the `zeppelin` project in `angular.json` declares only `build`, `serve`, `extract-i18n` and `lint`, and `zeppelin-web-angular/src` contains no `.spec.ts`. A Playwright test is also a poor fit here, because the local suite runs against `ng serve` (`playwright.config.js:16`), where `environment.production` is `false` and the affected branch never executes — such a test would pass with or without this change unless run in CI mode. The change was verified three other ways instead. **1. Lint** ``` cd zeppelin-web-angular && npm run lint ``` Exit 0. 15 pre-existing `member-ordering` warnings in `projects/zeppelin-visualization`, none in the changed file; `lint:react` clean; `prettier --check` reports all files formatted. **2. `HttpRequest.clone()` inheritance, using the real class** Running both the old and the new form of the production branch through Angular's real `HttpRequest` class: ``` development branch withCredentials=true X-Requested-With=(none) production, before withCredentials=false X-Requested-With=XMLHttpRequest production, after withCredentials=true X-Requested-With=XMLHttpRequest ``` **3. Production bundle in a real browser** `ng build --configuration production` twice — once with this commit and once with it reverted, changing nothing else — serving `dist/zeppelin` statically and instrumenting the `XMLHttpRequest.prototype.withCredentials` setter. `BaseUrlService` derives the REST base from `location`, so the app issues its normal bootstrap calls against the static server; they 404, but Angular assigns `withCredentials` before `send()`, which is what is being observed. ``` API requests withCredentials assignments X-Requested-With before this commit 4 [] XMLHttpRequest after this commit 4 [true, true, true, true] XMLHttpRequest ``` `X-Requested-With` is present in both runs, which confirms the production branch really executed and that the change does not drop the header. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No — see "Scope and related issues" for the one behaviour that changes for third-party URL fetches * Does this needs documentation? No Closes #5377 from big-cir/ZEPPELIN-6521. Signed-off-by: Jongyoul Lee --- .../note-import/note-import-modal.spec.ts | 42 +++++++++++++++++++ .../src/app/app-http.interceptor.ts | 2 +- .../note-import/note-import.component.ts | 8 ++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts index 229967d719b..6361759afdd 100644 --- a/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts +++ b/zeppelin-web-angular/e2e/tests/share/note-import/note-import-modal.spec.ts @@ -10,6 +10,8 @@ * limitations under the License. */ +import { createServer } from 'node:http'; + import { test, expect } from '@playwright/test'; import { HomePage } from '../../../models/home-page'; import { NoteImportModal } from '../../../models/note-import-modal'; @@ -69,6 +71,46 @@ test.describe('Note Import Modal', () => { await expect(noteImportModal.importNoteButton).toBeEnabled(); }); + test('Given URL tab is selected, When importing from wildcard CORS origin, Then response should be readable', async () => { + const corsServer = createServer((request, response) => { + response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With'); + response.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); + response.setHeader('Access-Control-Allow-Origin', '*'); + response.setHeader('Connection', 'close'); + + if (request.method === 'OPTIONS') { + response.writeHead(204); + response.end(); + return; + } + + response.setHeader('Content-Type', 'application/json'); + response.end(JSON.stringify({ name: 'Missing paragraphs' })); + }); + + await new Promise((resolve, reject) => { + corsServer.once('error', reject); + corsServer.listen(0, '127.0.0.1', resolve); + }); + + try { + const address = corsServer.address(); + if (!address || typeof address === 'string') { + throw new Error('Failed to bind CORS test server'); + } + + await noteImportModal.switchToUrlTab(); + await noteImportModal.setImportUrl(`http://127.0.0.1:${address.port}/note.json`); + await noteImportModal.clickImportNote(); + + await expect(noteImportModal.errorAlert).toHaveText('Invalid JSON'); + } finally { + await new Promise((resolve, reject) => { + corsServer.close(error => (error ? reject(error) : resolve())); + }); + } + }); + test('Given Import Note modal is open, When entering import name, Then name should be set', async () => { const importName = `Imported Note ${Date.now()}`; await noteImportModal.setImportAsName(importName); diff --git a/zeppelin-web-angular/src/app/app-http.interceptor.ts b/zeppelin-web-angular/src/app/app-http.interceptor.ts index b1e287622ac..6a6a4a18533 100644 --- a/zeppelin-web-angular/src/app/app-http.interceptor.ts +++ b/zeppelin-web-angular/src/app/app-http.interceptor.ts @@ -28,7 +28,7 @@ export class AppHttpInterceptor implements HttpInterceptor { intercept(httpRequest: HttpRequest, next: HttpHandler): Observable> { let httpRequestUpdated = httpRequest.clone({ withCredentials: true }); if (environment.production) { - httpRequestUpdated = httpRequest.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); + httpRequestUpdated = httpRequestUpdated.clone({ setHeaders: { 'X-Requested-With': 'XMLHttpRequest' } }); } return next.handle(httpRequestUpdated).pipe( map(event => { diff --git a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts index a73627b9ba0..ef5fdb7f40e 100644 --- a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts +++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts @@ -10,7 +10,7 @@ * limitations under the License. */ -import { HttpClient } from '@angular/common/http'; +import { HttpBackend, HttpClient } from '@angular/common/http'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { ConfigurationService, MessageService, TicketService } from '@zeppelin/services'; @@ -37,6 +37,7 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn errorText?: string; importLoading = false; wsMaxLimit?: number; + private readonly externalHttpClient: HttpClient; @MessageListener(OP.IMPORT_NOTE) noteImported(_: MessageReceiveDataTypeMap[OP.IMPORT_NOTE]) { @@ -46,7 +47,7 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn importNote() { this.errorText = ''; this.importLoading = true; - this.httpClient.get(this.importUrl ?? '').subscribe( + this.externalHttpClient.get(this.importUrl ?? '').subscribe( data => { this.importLoading = false; this.processImportJson(data); @@ -106,9 +107,10 @@ export class NoteImportComponent extends MessageListenersManager implements OnIn private configurationService: ConfigurationService, private cdr: ChangeDetectorRef, private nzModalRef: NzModalRef, - private httpClient: HttpClient + httpBackend: HttpBackend ) { super(messageService); + this.externalHttpClient = new HttpClient(httpBackend); } async ngOnInit() { From ddb8bc6f35cdc6babd69150c447223a4068dd53a Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Sat, 8 Aug 2026 19:54:29 +0900 Subject: [PATCH 149/179] [MINOR] Prevent WebSocket tickets from being logged ### What is this PR for? This fixes CVE-2026-44614, where the WebSocket bearer ticket could be written to server or browser diagnostic logs in plaintext. The login and security ticket endpoints no longer log their complete ticket-bearing responses. Server-side WebSocket handling now logs only non-secret operation, principal, success, and error type metadata instead of the complete message, payload, or exception details. The active Angular SDK and classic UI likewise log only operation/principal metadata rather than complete WebSocket messages. Ticket response bodies, authentication behavior, and the WebSocket wire protocol remain unchanged. Both clients still attach the bearer ticket to outbound WebSocket frames, but no longer copy it or the complete payload to the browser console. ### What type of PR is it? Hot Fix ### Todos * [x] Remove ticket-bearing REST response logging * [x] Remove raw WebSocket message logging at DEBUG, TRACE, and ERROR * [x] Remove ticket-bearing WebSocket message logging from both browser clients * [x] Add regression coverage for login, `/api/security/ticket`, WebSocket failures, and classic-client console logging ### What is the Jira issue? Not applicable. This addresses [CVE-2026-44614](https://lists.apache.org/thread/zlphtbzb8p2sr604597kldpjhhqktsbz). ### How should this be tested? * `./mvnw -pl zeppelin-server --am -Dtest=SecurityRestApiTest,NotebookServerLoggingTest,NotebookServerTest -Dsurefire.failIfNoSpecifiedTests=false -Dmaven.gitcommitid.skip=true test` * 27 tests passed with no failures, errors, or skips. * `cd zeppelin-web && npm run karma-test` * 184 tests passed, including the two new WebSocket console regression tests. * `cd zeppelin-web-angular && npm run build-project:sdk` * SDK build passed. * Focused ESLint and Prettier checks passed for both changed clients. * A built-SDK sentinel smoke test confirmed that ticket and payload remain in the transmitted message but are absent from browser console arguments. * Apache RAT passed for `zeppelin-server`, `zeppelin-web-angular`, and `zeppelin-web` with no unapproved licenses. * `git diff --check apache/master...HEAD` The standalone `checkstyle:check` command reports the same existing baseline on clean `apache/master` and this branch: 1,795 repository-wide violations and 103 violations when restricted to the original server files. No violation is reported on a line added or modified by this PR. ### Screenshots (if appropriate) Not applicable. ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No. * Does this needs documentation? No. Closes #5388 from jongyoul/codex/cve-2026-44614-ticket-log-redaction. Signed-off-by: Jongyoul Lee --- .../apache/zeppelin/rest/LoginRestApi.java | 3 +- .../apache/zeppelin/rest/SecurityRestApi.java | 3 +- .../zeppelin/socket/NotebookServer.java | 22 +-- .../zeppelin/rest/SecurityRestApiTest.java | 123 ++++++++++++++++ .../socket/NotebookServerLoggingTest.java | 133 ++++++++++++++++++ .../projects/zeppelin-sdk/src/message.ts | 4 +- .../websocket/websocket-event.factory.js | 4 +- .../websocket/websocket-event.factory.test.js | 94 +++++++++++++ 8 files changed, 371 insertions(+), 15 deletions(-) create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerLoggingTest.java create mode 100644 zeppelin-web/src/components/websocket/websocket-event.factory.test.js diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java index d8b8c93b93e..b0e3f14c3e8 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/LoginRestApi.java @@ -242,7 +242,8 @@ public Response postLogin(@FormParam("userName") String userName, response = new JsonResponse<>(Response.Status.FORBIDDEN, "", null); } - LOGGER.info(response.toString()); + LOGGER.info("Login request completed: principal={}, success={}", + userName, response.getCode() == Response.Status.OK); return response.build(); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java index 5eec6e7713f..f145f8b1f6e 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java @@ -80,7 +80,8 @@ public Response ticket() { data.put("ticket", ticketEntry.getTicket()); JsonResponse> response = new JsonResponse<>(Response.Status.OK, "", data); - LOGGER.warn("{}", response); + LOGGER.info("WebSocket ticket request completed: principal={}, success=true", + ticketEntry.getPrincipal()); return response.build(); } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 090272ce5d9..2d78ae7fb57 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -274,17 +274,15 @@ public void onMessage(Session session, String msg) { } public void onMessage(NotebookSocket conn, String msg) { + Message receivedMessage = null; try { - Message receivedMessage = deserializeMessage(msg); + receivedMessage = deserializeMessage(msg); if (receivedMessage.op != OP.PING) { - LOGGER.debug("RECEIVE: " + receivedMessage.op + - ", RECEIVE PRINCIPAL: " + receivedMessage.principal + - ", RECEIVE ROLES: " + receivedMessage.roles + - ", RECEIVE DATA: " + receivedMessage.data); - } - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("RECEIVE MSG = " + receivedMessage); + LOGGER.debug("WebSocket message received: operation={}, principal={}", + receivedMessage.op, receivedMessage.principal); } + LOGGER.trace("WebSocket message processing started: operation={}, principal={}", + receivedMessage.op, receivedMessage.principal); TicketContainer.Entry ticketEntry = TicketContainer.instance.getTicketEntry(receivedMessage.principal); if (ticketEntry == null || StringUtils.isEmpty(ticketEntry.getTicket())) { @@ -485,7 +483,13 @@ public void onMessage(NotebookSocket conn, String msg) { break; } } catch (Exception e) { - LOGGER.error("Can't handle message: {}", msg, e); + String operation = receivedMessage == null || receivedMessage.op == null + ? "unknown" : receivedMessage.op.name(); + String principal = receivedMessage == null || StringUtils.isEmpty(receivedMessage.principal) + ? "unknown" : receivedMessage.principal; + LOGGER.error("WebSocket message handling completed: operation={}, principal={}, " + + "success=false, errorType={}", + operation, principal, e.getClass().getSimpleName()); try { conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info", e.getMessage()))); } catch (IOException iox) { diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java index 25912b063f3..960bc0cdbd6 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java @@ -19,9 +19,18 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; import org.apache.zeppelin.MiniZeppelinServer; +import org.apache.zeppelin.ticket.TicketContainer; import org.hamcrest.CoreMatchers; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -30,10 +39,14 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; class SecurityRestApiTest extends AbstractTestRestApi { Gson gson = new Gson(); @@ -69,6 +82,80 @@ void testTicket() throws IOException { get.close(); } + @Test + void testLoginTicketIsNotLogged() throws IOException { + String principal = "user1"; + TicketContainer.instance.removeTicket(principal); + TestAppender appender = new TestAppender(); + Logger logger = Logger.getLogger(LoginRestApi.class); + Level previousLevel = logger.getLevel(); + boolean previousAdditivity = logger.getAdditivity(); + logger.setLevel(Level.TRACE); + logger.setAdditivity(false); + logger.addAppender(appender); + + try { + HttpPost login = new HttpPost(getUrlToTest(zConf) + "/login"); + login.addHeader("Origin", getUrlToTest(zConf)); + List parameters = new ArrayList<>(); + parameters.add(new BasicNameValuePair("password", "password2")); + parameters.add(new BasicNameValuePair("userName", principal)); + login.setEntity(new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8)); + + try (CloseableHttpResponse post = getHttpClient().execute(login)) { + Map resp = gson.fromJson( + EntityUtils.toString(post.getEntity(), StandardCharsets.UTF_8), + new TypeToken>(){}.getType()); + Map body = (Map) resp.get("body"); + String ticket = body.get("ticket"); + assertThat("Login response ticket", ticket, CoreMatchers.notNullValue()); + assertThat("Login response ticket", ticket, CoreMatchers.not("anonymous")); + assertTrue(appender.contains("principal=" + principal)); + assertTrue(appender.contains("success=true")); + assertFalse(appender.contains(ticket), "Login logs must not contain the ticket"); + } + } finally { + logger.removeAppender(appender); + logger.setLevel(previousLevel); + logger.setAdditivity(previousAdditivity); + appender.close(); + TicketContainer.instance.removeTicket(principal); + } + } + + @Test + void testSecurityTicketIsNotLogged() throws IOException { + String principal = "user2"; + TicketContainer.instance.removeTicket(principal); + TestAppender appender = new TestAppender(); + Logger logger = Logger.getLogger(SecurityRestApi.class); + Level previousLevel = logger.getLevel(); + boolean previousAdditivity = logger.getAdditivity(); + logger.setLevel(Level.TRACE); + logger.setAdditivity(false); + logger.addAppender(appender); + + try (CloseableHttpResponse get = + httpGet("/security/ticket", principal, "password3")) { + Map resp = gson.fromJson( + EntityUtils.toString(get.getEntity(), StandardCharsets.UTF_8), + new TypeToken>(){}.getType()); + Map body = (Map) resp.get("body"); + String ticket = body.get("ticket"); + assertThat("Security response ticket", ticket, CoreMatchers.notNullValue()); + assertThat("Security response ticket", ticket, CoreMatchers.not("anonymous")); + assertTrue(appender.contains("principal=" + principal)); + assertTrue(appender.contains("success=true")); + assertFalse(appender.contains(ticket), "Security ticket logs must not contain the ticket"); + } finally { + logger.removeAppender(appender); + logger.setLevel(previousLevel); + logger.setAdditivity(previousAdditivity); + appender.close(); + TicketContainer.instance.removeTicket(principal); + } + } + @Test void testGetUserList() throws IOException { CloseableHttpResponse get = httpGet("/security/userlist/admi", "admin", "password1"); @@ -119,4 +206,40 @@ void testRolesEscaped() throws IOException { get.close(); } + private static class TestAppender extends AppenderSkeleton { + private final List events = new CopyOnWriteArrayList<>(); + + @Override + protected void append(LoggingEvent event) { + events.add(event); + } + + boolean contains(String value) { + for (LoggingEvent event : events) { + String message = event.getRenderedMessage(); + if (message != null && message.contains(value)) { + return true; + } + String[] throwable = event.getThrowableStrRep(); + if (throwable != null) { + for (String line : throwable) { + if (line.contains(value)) { + return true; + } + } + } + } + return false; + } + + @Override + public void close() { + } + + @Override + public boolean requiresLayout() { + return false; + } + } + } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerLoggingTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerLoggingTest.java new file mode 100644 index 00000000000..cd19dd8c6d3 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerLoggingTest.java @@ -0,0 +1,133 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zeppelin.socket; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.Level; +import org.apache.log4j.spi.LoggingEvent; +import org.apache.zeppelin.common.Message; +import org.apache.zeppelin.common.Message.OP; +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.ticket.TicketContainer; +import org.junit.jupiter.api.Test; + +class NotebookServerLoggingTest { + + @Test + void testWebSocketTicketIsNotLoggedOnMessageFailure() { + String principal = "ticket-log-test-" + UUID.randomUUID(); + TicketContainer.Entry ticketEntry = + TicketContainer.instance.getTicketEntry(principal, Collections.emptySet()); + String ticket = ticketEntry.getTicket(); + String sensitivePayload = "sensitive-payload-" + UUID.randomUUID(); + + ZeppelinConfiguration zConf = mock(ZeppelinConfiguration.class); + when(zConf.isAnonymousAllowed()).thenReturn(true); + NotebookServer notebookServer = new NotebookServer(); + notebookServer.setZeppelinConfiguration(zConf); + NotebookSocket conn = mock(NotebookSocket.class); + when(conn.getUser()).thenReturn(principal); + + Message message = new Message(OP.CONVERT_NOTE_NBFORMAT) + .put("ticketCopy", ticket) + .put("sensitivePayload", sensitivePayload); + message.principal = principal; + message.roles = "[]"; + message.ticket = ticket; + + TestAppender appender = new TestAppender(); + org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(NotebookServer.class); + Level previousLevel = logger.getLevel(); + boolean previousAdditivity = logger.getAdditivity(); + logger.setLevel(Level.TRACE); + logger.setAdditivity(false); + logger.addAppender(appender); + + try { + notebookServer.onMessage(conn, message.toJson()); + + assertTrue(appender.hasLevel(Level.ERROR), "The WebSocket error path must be exercised"); + assertTrue(appender.containsMessage("operation=" + OP.CONVERT_NOTE_NBFORMAT)); + assertTrue(appender.containsMessage("principal=" + principal)); + assertFalse(appender.contains(ticket), "WebSocket logs must not contain the ticket"); + assertFalse(appender.contains(sensitivePayload), + "WebSocket logs must not contain message payload data"); + } finally { + logger.removeAppender(appender); + logger.setLevel(previousLevel); + logger.setAdditivity(previousAdditivity); + appender.close(); + TicketContainer.instance.removeTicket(principal); + } + } + + private static class TestAppender extends AppenderSkeleton { + private final List events = new CopyOnWriteArrayList<>(); + + @Override + protected void append(LoggingEvent event) { + events.add(event); + } + + boolean hasLevel(Level level) { + return events.stream().anyMatch(event -> level.equals(event.getLevel())); + } + + boolean containsMessage(String value) { + return events.stream() + .map(LoggingEvent::getRenderedMessage) + .anyMatch(message -> message != null && message.contains(value)); + } + + boolean contains(String value) { + for (LoggingEvent event : events) { + String message = event.getRenderedMessage(); + if (message != null && message.contains(value)) { + return true; + } + String[] throwable = event.getThrowableStrRep(); + if (throwable != null) { + for (String line : throwable) { + if (line.contains(value)) { + return true; + } + } + } + } + return false; + } + + @Override + public void close() { + } + + @Override + public boolean requiresLayout() { + return false; + } + } +} diff --git a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts index 42821062eb3..6262bff26a4 100644 --- a/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts +++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/message.ts @@ -126,7 +126,7 @@ export class Message { retryWhen(errors => errors.pipe(mergeMap(() => this.close$.pipe(take(1), delay(4000))))) ) .subscribe(e => { - console.log('Receive:', e); + console.log('Receive:', e.op); this.received$.next(this.interceptReceived(e as WebSocketMessage)); }); } @@ -166,7 +166,7 @@ export class Message { data, ...this.ticket }; - console.log('Send:', message); + console.log('Send:', message.op, message.principal); this.ws.next(message); this.sent$.next(message); diff --git a/zeppelin-web/src/components/websocket/websocket-event.factory.js b/zeppelin-web/src/components/websocket/websocket-event.factory.js index 36e94231e52..18b2affb26c 100644 --- a/zeppelin-web/src/components/websocket/websocket-event.factory.js +++ b/zeppelin-web/src/components/websocket/websocket-event.factory.js @@ -45,7 +45,7 @@ function WebsocketEventFactory($rootScope, $websocket, $location, baseUrlSrv, sa } data.msgId = uniqueClientId + '-' + ++lastMsgIdSeqSent; - console.log('Send >> %o, %o, %o, %o, %o', data.op, data.principal, data.ticket, data.roles, data); + console.log('Send >> %o, %o', data.op, data.principal); return websocketCalls.ws.send(JSON.stringify(data)); }; @@ -59,7 +59,7 @@ function WebsocketEventFactory($rootScope, $websocket, $location, baseUrlSrv, sa payload = angular.fromJson(event.data); } - console.log('Receive << %o, %o', payload.op, payload); + console.log('Receive << %o', payload.op); let op = payload.op; let data = payload.data; diff --git a/zeppelin-web/src/components/websocket/websocket-event.factory.test.js b/zeppelin-web/src/components/websocket/websocket-event.factory.test.js new file mode 100644 index 00000000000..1d95f639802 --- /dev/null +++ b/zeppelin-web/src/components/websocket/websocket-event.factory.test.js @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('Factory: websocketEvents', function() { + let fakeWebsocket; + let messageCallback; + let ngToast; + let rootScope; + let websocketEvents; + + beforeEach(function() { + fakeWebsocket = { + onOpen: jasmine.createSpy('onOpen'), + onMessage: function(callback) { + messageCallback = callback; + }, + onError: jasmine.createSpy('onError'), + onClose: jasmine.createSpy('onClose'), + send: jasmine.createSpy('send'), + socket: {readyState: 1}, + }; + ngToast = {info: jasmine.createSpy('info')}; + + angular.mock.module('zeppelinWebApp', function($provide) { + $provide.value('$websocket', function() { + return fakeWebsocket; + }); + $provide.value('baseUrlSrv', {getWebsocketUrl: function() { + return 'ws://localhost/ws'; + }}); + $provide.value('saveAsService', {saveAs: angular.noop}); + $provide.value('ngToast', ngToast); + }); + }); + + beforeEach(inject(function($rootScope, _websocketEvents_) { + rootScope = $rootScope; + websocketEvents = _websocketEvents_; + })); + + it('does not log the ticket or payload when sending a message', function() { + const ticket = 'websocket-ticket-secret'; + const payloadSecret = 'paragraph-payload-secret'; + rootScope.ticket = { + principal: 'test-user', + ticket: ticket, + roles: '["users"]', + }; + spyOn(console, 'log'); + + websocketEvents.sendNewEvent({ + op: 'RUN_PARAGRAPH', + data: {paragraph: payloadSecret}, + }); + + const sentMessage = JSON.parse(fakeWebsocket.send.calls.mostRecent().args[0]); + expect(sentMessage.ticket).toBe(ticket); + expect(sentMessage.data.paragraph).toBe(payloadSecret); + expect(console.log).toHaveBeenCalledWith('Send >> %o, %o', 'RUN_PARAGRAPH', 'test-user'); + const consoleOutput = JSON.stringify(console.log.calls.allArgs()); + expect(consoleOutput).not.toContain(ticket); + expect(consoleOutput).not.toContain(payloadSecret); + }); + + it('does not log the payload when receiving a message', function() { + const payloadSecret = 'notice-payload-secret'; + spyOn(console, 'log'); + + messageCallback({ + data: JSON.stringify({ + op: 'NOTICE', + data: {notice: payloadSecret}, + }), + }); + + expect(ngToast.info).toHaveBeenCalledWith(payloadSecret); + expect(console.log).toHaveBeenCalledWith('Receive << %o', 'NOTICE'); + expect(JSON.stringify(console.log.calls.allArgs())).not.toContain(payloadSecret); + }); +}); From 03de344818b8153a8ab017da91475d53e91c5dbf Mon Sep 17 00:00:00 2001 From: minjcho <117441212+minjcho@users.noreply.github.com> Date: Sun, 9 Aug 2026 15:42:59 +0900 Subject: [PATCH 150/179] [ZEPPELIN-6153] Add display_name to the kernelspec when exporting to ipynb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Exporting a Zeppelin note to ipynb produces a `kernelspec` with only `language` and `name`: ```java JsonObject kernelspecJson = new JsonObject(); kernelspecJson.addProperty("language", "scala"); kernelspecJson.addProperty("name", "spark2-scala"); ``` The nbformat schema requires `kernelspec.display_name`, so renderers that validate the schema — GitHub in particular — refuse to display the exported notebook. The import side already models the field (`nbformat/Kernelspec.java` has `display_name`); only the export path in `JupyterUtil.getNbformat()` omits it. This PR writes `"display_name": "Zeppelin"` into the exported kernelspec, the default suggested in the JIRA issue. The value is kept as a constant (`JupyterUtil.KERNEL_DISPLAY_NAME`) and `Kernelspec` gains getters following the pattern of the sibling nbformat classes (`Metadata`, `Nbformat`), so the new round-trip test can assert on the deserialized object. The test exports `spark_example_notebook.zpln`, reads the result back, and checks the kernelspec carries both `name` and `display_name`. ### What type of PR is it? Bug Fix ### Todos * [x] Write `display_name` into the exported kernelspec * [x] Expose `Kernelspec` fields through getters * [x] Pin the behaviour with a round-trip test ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6153 ### How should this be tested? ```bash ./mvnw test -pl zeppelin-jupyter -Dtest=JupyterUtilTest -DfailIfNoTests=false ``` `Tests run: 5, Failures: 0, Errors: 0, Skipped: 0` To verify end-to-end: export any note to ipynb and push it to a GitHub repository — the notebook now renders instead of showing "Invalid Notebook". ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5397 from minjcho/ZEPPELIN-6153. Signed-off-by: ChanHo Lee --- .../apache/zeppelin/jupyter/JupyterUtil.java | 5 +++++ .../zeppelin/jupyter/nbformat/Kernelspec.java | 8 ++++++++ .../jupyter/nbformat/JupyterUtilTest.java | 17 +++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java index 81fda1a39dd..3135d572125 100644 --- a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java +++ b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/JupyterUtil.java @@ -64,6 +64,8 @@ public class JupyterUtil { private static final Gson PRETTY_GSON = new GsonBuilder().setPrettyPrinting().create(); + public static final String KERNEL_DISPLAY_NAME = "Zeppelin"; + private final RuntimeTypeAdapterFactory cellTypeFactory; private final RuntimeTypeAdapterFactory outputTypeFactory; @@ -239,6 +241,9 @@ public String getNbformat(String note) { JsonObject kernelspecJson = new JsonObject(); kernelspecJson.addProperty("language", "scala"); kernelspecJson.addProperty("name", "spark2-scala"); + // display_name is required by the nbformat schema. Renderers such as GitHub + // fail to display the notebook when it is missing. + kernelspecJson.addProperty("display_name", KERNEL_DISPLAY_NAME); JsonObject languageInfoJson = new JsonObject(); languageInfoJson.addProperty("codemirror_mode", "text/x-scala"); diff --git a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java index 62324168510..ddfd7e99af2 100644 --- a/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java +++ b/zeppelin-jupyter/src/main/java/org/apache/zeppelin/jupyter/nbformat/Kernelspec.java @@ -28,4 +28,12 @@ public class Kernelspec { @SerializedName("display_name") private String displayName; + + public String getName() { + return name; + } + + public String getDisplayName() { + return displayName; + } } diff --git a/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java b/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java index 7ae8e2449f2..ba30607f6e8 100644 --- a/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java +++ b/zeppelin-jupyter/src/test/java/org/apache/zeppelin/jupyter/nbformat/JupyterUtilTest.java @@ -114,4 +114,21 @@ void testgetNbformat() { assertEquals(3 , nbformat.getCells().stream().filter(c -> c instanceof MarkdownCell).count()); assertEquals(4 , nbformat.getCells().stream().filter(c -> c instanceof CodeCell).count()); } + + @Test + void testGetNbformatKernelspec() { + InputStream resource = getClass().getResourceAsStream("/spark_example_notebook.zpln"); + String text = new BufferedReader( + new InputStreamReader(resource, StandardCharsets.UTF_8)) + .lines() + .collect(Collectors.joining("\n")); + JupyterUtil util = new JupyterUtil(); + Nbformat nbformat = util.getNbformat(new StringReader(util.getNbformat(text))); + + Kernelspec kernelspec = nbformat.getMetadata().getKernelspec(); + assertNotNull(kernelspec); + assertEquals("spark2-scala", kernelspec.getName()); + // display_name is required by the nbformat schema, see ZEPPELIN-6153 + assertEquals(JupyterUtil.KERNEL_DISPLAY_NAME, kernelspec.getDisplayName()); + } } From 7d840af6d46869da1c3fefd819480e55c6bfe19d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=B1=ED=98=95=EC=A4=80?= <138356797+vividbaek@users.noreply.github.com> Date: Sun, 9 Aug 2026 15:49:28 +0900 Subject: [PATCH 151/179] [ZEPPELIN-6596] Improve editor fallback logging ## What is this PR for? Improve warning logs emitted when `InterpreterSettingManager#getEditorSetting` falls back to the default editor. The previous logs only recorded `e.getMessage()`, which could be null and did not preserve the stack trace. The updated logs include the relevant note, interpreter group, or interpreter name together with the throwable. The existing `DEFAULT_EDITOR` fallback behavior is unchanged. Paragraph text is not logged because it may contain notebook code or sensitive information. ## What type of PR is it? Bug Fix ## What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6596 ## How should this be tested? ```bash ./mvnw test -pl zeppelin-server \ -Dtest=InterpreterSettingManagerTest Result: Tests run: 12, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS Closes #5396 from vividbaek/ZEPPELIN-6596-editor-fallback-logging. Signed-off-by: ChanHo Lee --- .../InterpreterSettingManager.java | 14 +++-- .../InterpreterSettingManagerTest.java | 54 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java index f6086f4d06c..08d11629ba8 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java @@ -611,7 +611,10 @@ public Map getEditorSetting(String paragraphText, String noteId) try { return interpreterSetting.getDefaultInterpreterInfo().getEditor(); } catch (Exception e) { - LOGGER.warn(e.getMessage()); + LOGGER.warn( + "Failed to resolve editor setting for the default interpreter of note {}; " + + "using default editor", + noteId, e); return DEFAULT_EDITOR; } } else { @@ -648,7 +651,9 @@ public Map getEditorSetting(String paragraphText, String noteId) } return interpreterSetting.getDefaultInterpreterInfo().getEditor(); } catch (Exception e) { - LOGGER.warn(e.getMessage()); + LOGGER.warn( + "Failed to resolve editor setting for interpreter group {}; using default editor", + intpGroupName, e); return DEFAULT_EDITOR; } } @@ -660,7 +665,10 @@ public Map getEditorSetting(String paragraphText, String noteId) InterpreterSetting interpreterSetting = getInterpreterSettingByName(intpGroupName); return interpreterSetting.getInterpreterInfo(intpName).getEditor(); } catch (Exception e) { - LOGGER.warn(e.getMessage()); + LOGGER.warn( + "Failed to resolve editor setting for interpreter {} in group {}; " + + "using default editor", + intpName, intpGroupName, e); return DEFAULT_EDITOR; } } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java index 54d3ffaeb08..95e126fedff 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/InterpreterSettingManagerTest.java @@ -18,6 +18,10 @@ package org.apache.zeppelin.interpreter; +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.dep.Dependency; import org.apache.zeppelin.display.AngularObjectRegistryListener; @@ -219,6 +223,31 @@ void testGetEditor() { assertEquals("python", editor.get("language")); } + @Test + void testGetEditorFallbackLogging() { + Logger logger = Logger.getLogger(InterpreterSettingManager.class); + TestAppender appender = new TestAppender(); + logger.addAppender(appender); + + try { + Map editor = + interpreterSettingManager.getEditorSetting("%test.nonexistent", note1Id); + + assertEquals("text", editor.get("language")); + assertEquals(false, editor.get("editOnDblClick")); + + LoggingEvent warning = appender.getWarnEvent(); + assertNotNull(warning); + assertNotNull(warning.getRenderedMessage()); + assertTrue(warning.getRenderedMessage().contains("test")); + assertTrue(warning.getRenderedMessage().contains("nonexistent")); + assertNotNull(warning.getThrowableInformation()); + assertNotNull(warning.getThrowableInformation().getThrowable()); + } finally { + logger.removeAppender(appender); + } + } + @Test void testRestartShared() throws InterpreterException { InterpreterSetting interpreterSetting = interpreterSettingManager.getByName("test"); @@ -342,4 +371,29 @@ void testInterpreterIncludeExcludeTogether() throws Exception { System.clearProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_INTERPRETER_EXCLUDES.getVarName()); } } + + private static class TestAppender extends AppenderSkeleton { + private final List events = new ArrayList<>(); + + @Override + protected void append(LoggingEvent event) { + events.add(event); + } + + LoggingEvent getWarnEvent() { + return events.stream() + .filter(event -> Level.WARN.equals(event.getLevel())) + .findFirst() + .orElse(null); + } + + @Override + public void close() { + } + + @Override + public boolean requiresLayout() { + return false; + } + } } From 894186578ebdce07c7b1b48fe6c6b9a1ee7cc393 Mon Sep 17 00:00:00 2001 From: uommou <90598552+uommou@users.noreply.github.com> Date: Sun, 9 Aug 2026 17:02:13 +0900 Subject: [PATCH 152/179] [ZEPPELIN-6491] Remove Google Analytics from generated version docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? This PR removes Google Analytics from generated version documentation by disabling the analytics provider in the Jekyll configuration. Previously, running `bundle exec jekyll build --safe` generated HTML containing Google Analytics scripts because the `google_universal` analytics provider was enabled. This change disables the provider, removes the Zeppelin-specific Google Analytics tracking IDs, and adds a verification step to the documentation deployment process to help ensure future generated version documentation remains compliant with the ASF website privacy policy. ### What type of PR is it? Bug Fix ### Todos * [x] Disable the Google Analytics provider in `docs/_config.yml` * [x] Remove the Zeppelin-specific Google Analytics tracking IDs * [x] Add a verification step to `docs/README.md` * [x] Validate that generated HTML contains no Google Analytics references ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6491 ### How should this be tested? 1. Build the documentation. ```bash cd docs bundle exec jekyll build --safe ``` 2. Verify that no Google Analytics references exist in the generated HTML. ```bash ( grep -rnE --include='*.html' \ "google-analytics\.com|googletagmanager\.com|analytics\.js|ga\.js|UA-[0-9]" \ _site/ case $? in 0) echo "FAIL: analytics found"; exit 1 ;; 1) echo "PASS: no Google Analytics references found in generated HTML" ;; *) echo "ERROR: scan failed"; exit 2 ;; esac ) ``` **Validation results** * ✅ Documentation build completed successfully. ```text Configuration file: /Users/chaiwonhwang/Projects/zeppelin/docs/_config.yml Source: /Users/chaiwonhwang/Projects/zeppelin/docs Destination: /Users/chaiwonhwang/Projects/zeppelin/docs/_site Generating... done in 0.602 seconds. ``` * ✅ Generated HTML validation passed. ```text PASS: no Google Analytics references found in generated HTML ``` * ✅ Spot-checked the generated `index.html` and a nested documentation page. * ✅ Confirmed that the analytics include renders no Google Analytics script while normal local assets remain intact. ### Screenshots (if appropriate) N/A Validation results are included above. ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No. This change only affects future generated version documentation. Existing published documentation in ASF SVN is not modified by this PR. * Does this needs documentation? Yes. `docs/README.md` has been updated to document the verification step before deploying generated documentation. Closes #5398 from uommou/fix/ZEPPELIN-6491. Signed-off-by: YONGJAE LEE --- docs/README.md | 21 ++++++++++++++++++--- docs/_config.yml | 7 +------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index 1f67945f04d..736b58fa41c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -71,11 +71,26 @@ If you wish to help us and contribute to Zeppelin Documentation, please look at bundle exec jekyll build --safe ``` - 2. checkout ASF repo + 2. verify no analytics scripts in the generated output + + ``` + ( + grep -rnE --include='*.html' \ + "google-analytics\.com|googletagmanager\.com|analytics\.js|ga\.js|UA-[0-9]" \ + _site/ + case $? in + 0) echo "FAIL: analytics found"; exit 1 ;; + 1) ;; + *) echo "ERROR: scan failed"; exit 2 ;; + esac + ) + ``` + + 3. checkout ASF repo ``` svn co https://svn.apache.org/repos/asf/zeppelin asf-zeppelin ``` - 3. copy `zeppelin/docs/_site` to `asf-zeppelin/site/docs/[VERSION]` - 4. `svn commit` + 4. copy `zeppelin/docs/_site` to `asf-zeppelin/site/docs/[VERSION]` + 5. `svn commit` diff --git a/docs/_config.yml b/docs/_config.yml index 74b80adb9a3..cf009ae6ec8 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -103,12 +103,7 @@ JB : # Set 'provider' to false to turn analytics off globally. # analytics : - provider : google_universal - google_classic : - tracking_id : 'UA-45176241-2' - google_universal : - tracking_id : 'UA-45176241-5' - domain : 'zeppelin.apache.org' + provider : false getclicky : site_id : mixpanel : From 8595f2a148832862377b5638a7925e1850d38c2d Mon Sep 17 00:00:00 2001 From: Yerin Lee <91695537+yxinot@users.noreply.github.com> Date: Sun, 9 Aug 2026 17:04:18 +0900 Subject: [PATCH 153/179] [ZEPPELIN-6461] Fix InterruptedException handling in recoverRunningParagraphs ### What is this PR for? In `Notebook.recoverRunningParagraphs()`, the `InterruptedException` caught from `thread.join()` was handled with `e.printStackTrace()`, which bypasses the project's Log4j2 configuration. Additionally, the thread interrupt status was not restored, preventing callers from observing the interruption. This PR replaces `e.printStackTrace()` with SLF4J logging and adds `Thread.currentThread().interrupt()` to restore the interrupt status. ### What type of PR is it? Bug Fix ### Todos * [x] Replace `e.printStackTrace()` with `LOGGER.warn()` (SLF4J) * [x] Restore thread interrupt status with `Thread.currentThread().interrupt()` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6461 ### How should this be tested? ```bash ./mvnw test -pl zeppelin-server -Dtest=NotebookTest -DfailIfNoTests=false ``` ### Questions: - Does the license files need to update? No - Is there breaking changes for older versions? No - Does this needs documentation? No Closes #5393 from yxinot/ZEPPELIN-6461-fix-interrupted-exception-handling. Signed-off-by: YONGJAE LEE --- .../src/main/java/org/apache/zeppelin/notebook/Notebook.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java index 83f0032822f..10c2abca779 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Notebook.java @@ -207,7 +207,8 @@ private void recoverRunningParagraphs() { try { thread.join(); } catch (InterruptedException e) { - e.printStackTrace(); + LOGGER.warn("Paragraph recovery thread interrupted", e); + Thread.currentThread().interrupt(); } } From 6baf0f9ad1a9a464b6a15a6ca069572c02b5672f Mon Sep 17 00:00:00 2001 From: Gyeongtae Park Date: Sun, 9 Aug 2026 19:45:26 +0900 Subject: [PATCH 154/179] [ZEPPELIN-6528] Upgrade Apache Shiro from 1.13.0 to 2.0.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Upgrades Apache Shiro from 1.13.0 to 2.0.6, the current stable release line with active security patches. Shiro 2.x strengthens default password hashing (Argon2id instead of MD5) and provides Jakarta EE 10 support, which aligns with the jakarta.* namespace already in use by this project. This PR also resolves a transitive BouncyCastle version conflict introduced by shiro-crypto-hash:2.0.6 pulling in bcprov-jdk18on:1.82, and fixes the two compile-breaking API changes between Shiro 1.x and 2.x. ### What type of PR is it? Improvement ### Todos * [x] Bump shiro.version 1.13.0 → 2.0.6 in pom.xml * [x] Bump bouncycastle.version 1.80 → 1.82 to resolve DependencyConvergence conflict * [x] Replace removed DefaultLdapContextFactory with JndiLdapContextFactory in ActiveDirectoryGroupRealm * [x] Update StringUtils import to org.apache.shiro.lang.util in LdapRealm * [x] Update LifecycleUtils import to org.apache.shiro.lang.util in AbstractShiroTest and ShiroAuthenticationServiceTest ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6528 ### How should this be tested? 1. Build zeppelin-server module: ./mvnw compile -pl zeppelin-server -am -DskipTests 2. Run Shiro-related unit tests: ./mvnw test -pl zeppelin-server -Dtest="ShiroAuthenticationServiceTest,LdapRealmTest,LdapRealmDnInjectionTest,AnyOfRolesUserAuthorizationFilterTest" 3. Manually verify form login, LDAP authentication flows remain functional. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No — API-level changes are confined to internal realm and test infrastructure classes. * Does this needs documentation? No Closes #5293 from ParkGyeongTae/ZEPPELIN-6528. Signed-off-by: Jongyoul Lee --- pom.xml | 4 ++-- .../apache/zeppelin/realm/ActiveDirectoryGroupRealm.java | 6 ++---- .../src/main/java/org/apache/zeppelin/realm/LdapRealm.java | 4 ++-- .../zeppelin/service/ShiroAuthenticationServiceTest.java | 2 +- .../apache/zeppelin/service/shiro/AbstractShiroTest.java | 2 +- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 8ddaa73ec78..9e021cbfc6f 100644 --- a/pom.xml +++ b/pom.xml @@ -131,8 +131,8 @@ 2.15.1 3.2.2 1.4 - 1.13.0 - 1.80 + 2.0.6 + 1.82 3.6.3 4.2.29 1.14.2 diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java index 296b687797f..255bc8437f6 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/ActiveDirectoryGroupRealm.java @@ -27,7 +27,7 @@ import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.ldap.AbstractLdapRealm; -import org.apache.shiro.realm.ldap.DefaultLdapContextFactory; +import org.apache.shiro.realm.ldap.JndiLdapContextFactory; import org.apache.shiro.realm.ldap.LdapContextFactory; import org.apache.shiro.realm.ldap.LdapUtils; import org.apache.shiro.subject.PrincipalCollection; @@ -105,9 +105,7 @@ protected void onInit() { public LdapContextFactory getLdapContextFactory() { if (this.ldapContextFactory == null) { LOGGER.debug("No LdapContextFactory specified - creating a default instance."); - DefaultLdapContextFactory defaultFactory = new DefaultLdapContextFactory(); - defaultFactory.setPrincipalSuffix(this.principalSuffix); - defaultFactory.setSearchBase(this.searchBase); + JndiLdapContextFactory defaultFactory = new JndiLdapContextFactory(); defaultFactory.setUrl(this.url); defaultFactory.setSystemUsername(this.systemUsername); defaultFactory.setSystemPassword(getSystemPassword()); diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java index be8a0f0c68d..5c7ff9a1f36 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/realm/LdapRealm.java @@ -48,7 +48,7 @@ import org.apache.hadoop.security.alias.CredentialProvider; import org.apache.hadoop.security.alias.CredentialProviderFactory; import org.apache.shiro.SecurityUtils; -import org.apache.shiro.ShiroException; +import org.apache.shiro.lang.ShiroException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; @@ -66,7 +66,7 @@ import org.apache.shiro.session.Session; import org.apache.shiro.subject.MutablePrincipalCollection; import org.apache.shiro.subject.PrincipalCollection; -import org.apache.shiro.util.StringUtils; +import org.apache.shiro.lang.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceTest.java index f82539e715d..201a894fd3e 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceTest.java @@ -33,7 +33,7 @@ import org.apache.shiro.mgt.DefaultSecurityManager; import org.apache.shiro.realm.jdbc.JdbcRealm; import org.apache.shiro.subject.Subject; -import org.apache.shiro.util.LifecycleUtils; +import org.apache.shiro.lang.util.LifecycleUtils; import org.apache.shiro.util.ThreadContext; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.realm.jwt.KnoxJwtRealm; diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/service/shiro/AbstractShiroTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/service/shiro/AbstractShiroTest.java index e63d218ca2b..8ff7b274b09 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/service/shiro/AbstractShiroTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/service/shiro/AbstractShiroTest.java @@ -21,7 +21,7 @@ import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.support.SubjectThreadState; -import org.apache.shiro.util.LifecycleUtils; +import org.apache.shiro.lang.util.LifecycleUtils; import org.apache.shiro.util.ThreadState; import org.junit.jupiter.api.AfterAll; From e1d96d65d6c9314039a73d485d11e28d52f7b133 Mon Sep 17 00:00:00 2001 From: DONGHOON LEE <125895298+move-hoon@users.noreply.github.com> Date: Sun, 9 Aug 2026 21:05:19 +0900 Subject: [PATCH 155/179] [ZEPPELIN-6457] Extract shared Python ZeppelinContext helpers for PySpark and PyFlink ### What is this PR for? PySpark and PyFlink currently define their `ZeppelinContext` subclasses separately in the classic Python and IPython bootstrap resources, even though the implementations are effectively the same for each backend. This PR moves the PySpark and PyFlink implementations into the shared `zeppelin_context.py` resource and reuses them from both bootstrap paths. Backend-specific behavior remains unchanged: * PySpark handles Spark `DataFrame` objects through `_jdf`. * PyFlink handles Flink `Table` objects through `_j_table`. * PyFlink retains support for the `stream_type` argument. * Other object types fall back to `PyZeppelinContext.show()`. * `IPySparkZeppelinContext` and `IPyFlinkZeppelinContext` remain available as compatibility aliases. No new dependencies are introduced. ### What type of PR is it? Refactoring ### Todos * [x] Move the PySpark ZeppelinContext implementation to the shared resource * [x] Move the PyFlink ZeppelinContext implementation to the shared resource * [x] Reuse the shared implementations from Python and IPython bootstraps * [x] Keep the existing IPython class names as compatibility aliases * [x] Verify Spark and Flink interpreter packaging * [x] Verify PySpark `z.show(DataFrame)` behavior ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6457 ### How should this be tested? The following checks passed successfully: ```bash ./mvnw test \ -pl python \ -Dtest=PythonInterpreterTest#testBackendZeppelinContextsAvailable \ -DfailIfNoTests=false \ -Dmaven.gitcommitid.skip=true ``` Result: 1 test passed. ```bash PYSPARK_PYTHON="$(command -v python3.12)" \ PYSPARK_DRIVER_PYTHON="$(command -v python3.12)" \ ./mvnw test \ -pl spark/interpreter \ --am \ -Pspark-3.5 \ -Pspark-scala-2.12 \ -Dtest=PySparkInterpreterTest#testPySpark \ -Dsurefire.failIfNoSpecifiedTests=false \ -Dmaven.gitcommitid.skip=true ``` Results: * `PySparkInterpreterTest#testPySpark` passed. * Existing ScalaTest suite: 18 tests passed. * `z.show(DataFrame)` was exercised successfully. ```bash ./mvnw package \ -pl spark/interpreter \ --am \ -Pspark-3.5 \ -Pspark-scala-2.12 \ -DskipTests \ -Dmaven.gitcommitid.skip=true ``` Result: 12-module reactor build succeeded. ```bash ./mvnw package \ -pl flink/flink-scala-2.12 \ --am \ -Pflink-1.20 \ -DskipTests \ -Dmaven.gitcommitid.skip=true ``` Result: 13-module reactor build succeeded. The generated Spark and Flink interpreter JARs were also verified to contain the shared context resource and the corresponding classic and IPython bootstrap resources. `git diff --check` also passes. ### Screenshots (if appropriate) Not applicable. This PR does not change the user interface. ### Questions * Do the license files need to be updated? No. * Are there breaking changes for older versions? No. The existing IPython context names remain available as compatibility aliases. * Does this need documentation? No. There are no user-facing behavior or configuration changes. Closes #5405 from move-hoon/ZEPPELIN-6457-python-context. Signed-off-by: ParkGyeongTae --- .../resources/python/zeppelin_ipyflink.py | 17 +----------- .../main/resources/python/zeppelin_pyflink.py | 18 +------------ .../main/resources/python/zeppelin_context.py | 27 +++++++++++++++++++ .../python/PythonInterpreterTest.java | 15 +++++++++++ .../resources/python/zeppelin_ipyspark.py | 14 +--------- .../main/resources/python/zeppelin_pyspark.py | 15 +---------- 6 files changed, 46 insertions(+), 60 deletions(-) diff --git a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py index 18bab2111fa..6db99070778 100644 --- a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py +++ b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_ipyflink.py @@ -54,19 +54,4 @@ else: st_env = StreamTableEnvironment(intp.getJavaStreamTableEnvironment()) -class IPyFlinkZeppelinContext(PyZeppelinContext): - - def __init__(self, z, gateway): - super(IPyFlinkZeppelinContext, self).__init__(z, gateway) - - def show(self, obj, **kwargs): - from pyflink.table import Table - if isinstance(obj, Table): - if 'stream_type' in kwargs: - self.z.show(obj._j_table, kwargs['stream_type'], kwargs) - else: - print(self.z.showData(obj._j_table)) - else: - super(IPyFlinkZeppelinContext, self).show(obj, **kwargs) - -z = __zeppelin__ = IPyFlinkZeppelinContext(intp.getZeppelinContext(), gateway) +z = __zeppelin__ = PyFlinkZeppelinContext(intp.getZeppelinContext(), gateway) diff --git a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py index 88d1de6c59d..9d76c2633db 100644 --- a/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py +++ b/flink/flink-scala-2.12/src/main/resources/python/zeppelin_pyflink.py @@ -44,23 +44,7 @@ st_env = StreamTableEnvironment(intp.getJavaStreamTableEnvironment()) -from zeppelin_context import PyZeppelinContext - -#TODO(zjffdu) merge it with IPyFlinkZeppelinContext -class PyFlinkZeppelinContext(PyZeppelinContext): - - def __init__(self, z, gateway): - super(PyFlinkZeppelinContext, self).__init__(z, gateway) - - def show(self, obj, **kwargs): - from pyflink.table import Table - if isinstance(obj, Table): - if 'stream_type' in kwargs: - self.z.show(obj._j_table, kwargs['stream_type'], kwargs) - else: - print(self.z.showData(obj._j_table)) - else: - super(PyFlinkZeppelinContext, self).show(obj, **kwargs) +from zeppelin_context import PyFlinkZeppelinContext z = __zeppelin__ = PyFlinkZeppelinContext(intp.getZeppelinContext(), gateway) __zeppelin__._setup_matplotlib() diff --git a/python/src/main/resources/python/zeppelin_context.py b/python/src/main/resources/python/zeppelin_context.py index 8223966d40e..4325d9a4cc4 100644 --- a/python/src/main/resources/python/zeppelin_context.py +++ b/python/src/main/resources/python/zeppelin_context.py @@ -287,3 +287,30 @@ def _setup_matplotlib(self): matplotlib.use('Agg') warnings.warn("Unable to load inline matplotlib backend, " "falling back to Agg") + + +class PySparkZeppelinContext(PyZeppelinContext): + + def show(self, obj, **kwargs): + from pyspark.sql import DataFrame + if isinstance(obj, DataFrame): + print(self.z.showData(obj._jdf)) + else: + super(PySparkZeppelinContext, self).show(obj, **kwargs) + + +class PyFlinkZeppelinContext(PyZeppelinContext): + + def show(self, obj, **kwargs): + from pyflink.table import Table + if isinstance(obj, Table): + if 'stream_type' in kwargs: + self.z.show(obj._j_table, kwargs['stream_type'], kwargs) + else: + print(self.z.showData(obj._j_table)) + else: + super(PyFlinkZeppelinContext, self).show(obj, **kwargs) + + +IPySparkZeppelinContext = PySparkZeppelinContext +IPyFlinkZeppelinContext = PyFlinkZeppelinContext diff --git a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java index 7d0ad4f0e2a..839ab6aad32 100644 --- a/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java +++ b/python/src/test/java/org/apache/zeppelin/python/PythonInterpreterTest.java @@ -82,6 +82,21 @@ public void tearDown() throws InterpreterException { intpGroup.close(); } + @Test + void testBackendZeppelinContextsAvailable() throws InterpreterException, IOException { + InterpreterContext context = getInterpreterContext(); + InterpreterResult result = interpreter.interpret( + "from zeppelin_context import PySparkZeppelinContext, PyFlinkZeppelinContext, " + + "IPySparkZeppelinContext, IPyFlinkZeppelinContext\n" + + "print('%s %s' % (IPySparkZeppelinContext is PySparkZeppelinContext, " + + "IPyFlinkZeppelinContext is PyFlinkZeppelinContext))", + context); + + assertEquals(InterpreterResult.Code.SUCCESS, result.code()); + assertEquals("True True", + context.out.toInterpreterResultMessage().get(0).getData().trim()); + } + @Override public void testCodeCompletion() throws InterpreterException, IOException, InterruptedException { super.testCodeCompletion(); diff --git a/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py b/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py index 958802ccdbb..94da41b9d33 100644 --- a/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py +++ b/spark/interpreter/src/main/resources/python/zeppelin_ipyspark.py @@ -64,19 +64,7 @@ else: sqlContext = sqlc = __zSqlc__ = __zSpark__._wrapped -class IPySparkZeppelinContext(PyZeppelinContext): - - def __init__(self, z, gateway): - super(IPySparkZeppelinContext, self).__init__(z, gateway) - - def show(self, obj, **kwargs): - from pyspark.sql import DataFrame - if isinstance(obj, DataFrame): - print(self.z.showData(obj._jdf)) - else: - super(IPySparkZeppelinContext, self).show(obj, **kwargs) - -z = __zeppelin__ = IPySparkZeppelinContext(intp.getZeppelinContext(), gateway) +z = __zeppelin__ = PySparkZeppelinContext(intp.getZeppelinContext(), gateway) # add jars to path import sys diff --git a/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py b/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py index 52788ccdb32..fb3b6ee856c 100644 --- a/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py +++ b/spark/interpreter/src/main/resources/python/zeppelin_pyspark.py @@ -56,20 +56,7 @@ else: sqlContext = sqlc = __zSqlc__ = __zSpark__._wrapped -from zeppelin_context import PyZeppelinContext - -#TODO(zjffdu) merge it with IPySparkZeppelinContext -class PySparkZeppelinContext(PyZeppelinContext): - - def __init__(self, z, gateway): - super(PySparkZeppelinContext, self).__init__(z, gateway) - - def show(self, obj, **kwargs): - from pyspark.sql import DataFrame - if isinstance(obj, DataFrame): - print(self.z.showData(obj._jdf)) - else: - super(PySparkZeppelinContext, self).show(obj, **kwargs) +from zeppelin_context import PySparkZeppelinContext z = __zeppelin__ = PySparkZeppelinContext(intp.getZeppelinContext(), gateway) __zeppelin__._setup_matplotlib() From 560a808e3eab694654ab74c678ff1f1883c5c83c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8B=A4=EC=9D=80=20=28Daeun=20Kim=29?= <150661115+dani1552@users.noreply.github.com> Date: Sun, 9 Aug 2026 21:43:22 +0900 Subject: [PATCH 156/179] [ZEPPELIN-6507] Return empty list from FileInterpreter.completion() ### What is this PR for? `FileInterpreter.completion()` returns `null` rather than an empty list. Per *Effective Java* Item 54, methods that return a collection should never return `null`, since it forces every caller to add a special-case null check. In practice this base implementation is not reached today: the only concrete subclass, `HDFSFileInterpreter`, overrides `completion()` with a real implementation. However, if a future `FileInterpreter` subclass omits that override, the `null` would propagate through the completion call chain, which does not perform null checks. This PR changes the base implementation to return `Collections.emptyList()` and adds a unit test that pins the contract. ### What type of PR is it? Improvement ### Todos * [x] - Return `Collections.emptyList()` from `FileInterpreter.completion()` * [x] - Add `testCompletionReturnsEmptyListInsteadOfNull` to `FileInterpreterTest` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6507 ### How should this be tested? * `mvn test -pl file -Dtest=FileInterpreterTest` * `TestFileInterpreter`, the test double already present in `FileInterpreterTest`, does not override `completion()`, so the new test exercises the base implementation directly. * All 5 tests in `FileInterpreterTest` pass locally. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5394 from dani1552/ZEPPELIN-6507. Signed-off-by: ParkGyeongTae --- .../org/apache/zeppelin/file/FileInterpreter.java | 3 ++- .../apache/zeppelin/file/FileInterpreterTest.java | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/file/src/main/java/org/apache/zeppelin/file/FileInterpreter.java b/file/src/main/java/org/apache/zeppelin/file/FileInterpreter.java index 286d315ba83..50592cc5f35 100644 --- a/file/src/main/java/org/apache/zeppelin/file/FileInterpreter.java +++ b/file/src/main/java/org/apache/zeppelin/file/FileInterpreter.java @@ -24,6 +24,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -167,6 +168,6 @@ public Scheduler getScheduler() { @Override public List completion(String buf, int cursor, InterpreterContext interpreterContext) { - return null; + return Collections.emptyList(); } } diff --git a/file/src/test/java/org/apache/zeppelin/file/FileInterpreterTest.java b/file/src/test/java/org/apache/zeppelin/file/FileInterpreterTest.java index 6097d5fc59b..01066a1fed6 100644 --- a/file/src/test/java/org/apache/zeppelin/file/FileInterpreterTest.java +++ b/file/src/test/java/org/apache/zeppelin/file/FileInterpreterTest.java @@ -19,12 +19,15 @@ package org.apache.zeppelin.file; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertFalse; +import java.util.List; import java.util.Properties; import org.apache.zeppelin.interpreter.InterpreterException; +import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; import org.junit.jupiter.api.Test; /** @@ -178,4 +181,14 @@ void testComplexCommand() { assertTrue(args.flags.contains('h')); assertFalse(args.flags.contains('-')); } + + @Test + void testCompletionReturnsEmptyListInsteadOfNull() { + TestFileInterpreter interpreter = new TestFileInterpreter(new Properties()); + + List completions = interpreter.completion("ls", 2, null); + + assertNotNull(completions, "completion() should never return null"); + assertTrue(completions.isEmpty(), "Default completion() should return an empty list"); + } } From 9b8d82beb9eb884568fad896ee8f5b28a4c716f6 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Sun, 9 Aug 2026 22:36:06 +0900 Subject: [PATCH 157/179] [ZEPPELIN-6635] Remove unnecessary git add from lint-staged configuration ### What is this PR for? This PR removes unnecessary `git add` commands from the `lint-staged` configuration in `zeppelin-web-angular/package.json`. The project currently uses `lint-staged` v15, and lint-staged has automatically re-staged task modifications since v10. Keeping explicit `git add` entries is outdated and produce warnings, so this cleanup leaves the existing ESLint and Prettier tasks unchanged while relying on lint-staged's built-in staging behavior. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6635 ### How should this be tested? * Run the frontend pre-commit workflow with staged TypeScript/JavaScript/JSON/CSS/HTML changes and confirm `lint-staged` still runs ESLint/Prettier successfully. * Confirm no lint-staged warning is emitted for using `git add` in task configuration. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5402 from miinhho/remove-git-add-from-lint-staged. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 756dab31275..48421f7b218 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -118,12 +118,10 @@ "lint-staged": { "**/*.ts": [ "cross-env NODE_OPTIONS='--max-old-space-size=8192' eslint --fix", - "./node_modules/.bin/prettier --write", - "git add" + "./node_modules/.bin/prettier --write" ], "**/*.{js,json,css,html}": [ - "./node_modules/.bin/prettier --write", - "git add" + "./node_modules/.bin/prettier --write" ] } } From 206b6a319dd4e30bf8c5df7331847f440724fff0 Mon Sep 17 00:00:00 2001 From: HyeonUk Kang <43662405+hyunw9@users.noreply.github.com> Date: Sun, 9 Aug 2026 22:53:41 +0900 Subject: [PATCH 158/179] [ZEPPELIN-6208] Enable DuckDB support in JDBC Interpreter by excluding incompatible default properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What is this PR for? The JDBC interpreter forwards all of an interpreter's prefixed properties (default.*) straight to the JDBC driver when opening a connection. Many of these keys are consumed by Zeppelin itself or by the DBCP connection pool — e.g. driver, url, precode, statementPrecode, completer.ttlInSeconds, validationQuery, maxIdle — and are not valid JDBC connection properties. Lenient drivers (PostgreSQL, MySQL) silently ignore unknown properties, so this went unnoticed. But strict drivers reject the connection outright. For example, DuckDB fails with: SQLException: Invalid Input Error: The following options were not recognized: completer.ttlInSeconds, url, driver, maxIdle This currently makes it impossible to use DuckDB (and other strict drivers such as MS SQL Server) with the JDBC interpreter. Until now this was worked around with a driver-specific whitelist that only applied when the driver class was Presto/Trino (PRESTO_PROPERTIES). That approach is hard to maintain: every new strict driver needs its own if branch and allow-list, and it also strips any legitimate driver property the user added but that wasn't on the list. This PR replaces that with a generic, driver-agnostic deny-list: - Introduces NON_DRIVER_PROPERTIES, a single source of truth listing only Zeppelin-internal and DBCP pool keys (user/password are deliberately kept, since they are standard JDBC properties). - Adds toDriverProperties(), which returns a filtered copy of the properties handed to the driver, leaving the original untouched (the previous Presto code mutated the shared per-user Properties in place — a latent bug). - Removes the Presto/Trino special-case branch and the PRESTO_PROPERTIES whitelist; the generic filter subsumes it. - Adds an optional escape hatch, zeppelin.jdbc.driver.excludeProperties (comma-separated), so operators can exclude additional keys for future drivers without a code change. Result: DuckDB, MS SQL Server, Trino/Presto, and any future strict driver work through one consistent rule, while genuine driver properties (e.g. SSL, useSSL, sslmode) still pass through unchanged. What type of PR is it? Bug Fix Todos - [x] Replace Presto/Trino whitelist with a generic internal-property deny-list - [x] Keep user/password and arbitrary driver properties (e.g. SSL) flowing to the driver - [x] Add unit tests for the filtering logic - [x] Add end-to-end tests against real strict drivers (DuckDB embedded, Trino) | Property setting (1) | Property setting (2) | |:---:|:---:| | 스크린샷 2026-06-25 오후 9 20 23 | 스크린샷 2026-06-25 오후 9 20 29 | **2. Result — Before / After** | Before — DuckDB connection error | After — connected successfully | |:---:|:---:| | before-duckdb-error | after-success What is the Jira issue? - [ZEPPELIN-6208](https://issues.apache.org/jira/browse/ZEPPELIN-6208) How should this be tested? Automated tests added in JDBCInterpreterTest: - testToDriverProperties — internal/pool keys are removed; user, password, and arbitrary driver props (SSL) are kept; the original Properties is not mutated. - testToDriverPropertiesWithUserDefinedExcludes — zeppelin.jdbc.driver.excludeProperties strips additional user-specified keys. - testDuckDbConnectionWithInternalProperties — end-to-end: configures the interpreter with internal keys present and runs CREATE/INSERT/SELECT against an embedded DuckDB (no server needed). Fails on the old code, passes here. - testTrinoConnectionWithInternalProperties — end-to-end against a real Trino coordinator; auto-skipped via assumeTrue when none is reachable on localhost:8080. mvn -pl jdbc -am test -Dtest=JDBCInterpreterTest Manual: add a JDBC interpreter with default.driver=org.duckdb.DuckDBDriver, default.url=jdbc:duckdb:, add the org.duckdb:duckdb_jdbc dependency in the interpreter settings, leave an internal key such as default.completer.ttlInSeconds=120, and run a query — it now connects successfully. Questions: - Does the license files need to update? - X - Is there breaking changes for older versions? - X - Does this need documentation? - Optional Closes #5276 from hyunw9/ZEPPELIN-6208. Signed-off-by: Jongyoul Lee --- jdbc/pom.xml | 16 ++ .../apache/zeppelin/jdbc/JDBCInterpreter.java | 73 ++++++--- .../zeppelin/jdbc/JDBCInterpreterTest.java | 142 ++++++++++++++++++ 3 files changed, 209 insertions(+), 22 deletions(-) diff --git a/jdbc/pom.xml b/jdbc/pom.xml index 7225529055e..67cba4d95d9 100644 --- a/jdbc/pom.xml +++ b/jdbc/pom.xml @@ -43,6 +43,8 @@ 1.0.8 + 1.3.1.0 + 481 @@ -67,6 +69,20 @@ test + + org.duckdb + duckdb_jdbc + ${duckdb.jdbc.version} + test + + + + io.trino + trino-jdbc + ${trino.jdbc.version} + test + + org.apache.commons commons-lang3 diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java index 90c34614b5f..aa486fec43f 100644 --- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java +++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java @@ -147,14 +147,29 @@ public class JDBCInterpreter extends KerberosInterpreter { private static final String DBCP_STRING = "jdbc:apache:commons:dbcp:"; private static final String MAX_ROWS_KEY = "zeppelin.jdbc.maxRows"; - private static final Set PRESTO_PROPERTIES = new HashSet<>(Arrays.asList( - "user", "password", - "socksProxy", "httpProxy", "clientTags", "applicationNamePrefix", "accessToken", - "SSL", "SSLKeyStorePath", "SSLKeyStorePassword", "SSLTrustStorePath", - "SSLTrustStorePassword", "KerberosRemoteServiceName", "KerberosPrincipal", - "KerberosUseCanonicalHostname", "KerberosServicePrincipalPattern", - "KerberosConfigPath", "KerberosKeytabPath", "KerberosCredentialCachePath", - "extraCredentials", "roles", "sessionProperties")); + /** + * Properties that Zeppelin consumes internally (or hands to the DBCP connection + * pool) and therefore must NOT be forwarded to the JDBC driver as connection + * properties. + * + * Note: "user" and "password" are deliberately excluded from this set because + * they are standard JDBC connection properties and must reach the driver. + */ + private static final Set NON_DRIVER_PROPERTIES = new HashSet<>(Arrays.asList( + // connection metadata consumed by the interpreter itself + DRIVER_KEY, URL_KEY, + // SQL hooks executed by the interpreter, not the driver + PRECODE_KEY, STATEMENT_PRECODE_KEY, + // auto-completion settings + COMPLETER_TTL_KEY, COMPLETER_SCHEMA_FILTERS_KEY, + // proxy / credential settings handled by the interpreter + "proxy.user.property", JDBC_JCEKS_FILE, JDBC_JCEKS_CREDENTIAL_KEY, + // DBCP connection-pool settings applied in configConnectionPool() + "validationQuery", "testOnBorrow", "testOnCreate", "testOnReturn", + "testWhileIdle", "timeBetweenEvictionRunsMillis", "maxWaitMillis", + "maxIdle", "minIdle", "maxTotal")); + + static final String DRIVER_EXCLUDE_PROPERTIES_KEY = "zeppelin.jdbc.driver.excludeProperties"; private static final String ALLOW_LOAD_LOCAL = "allowLoadLocal"; @@ -486,28 +501,42 @@ private void configConnectionPool(GenericObjectPool connectionPool, Properties p connectionPool.setMaxWaitMillis(maxWaitMillis); } + /** + * Builds the property set handed to the JDBC driver: a copy of {@code properties} + * with all Zeppelin-internal and connection-pool keys ({@link #NON_DRIVER_PROPERTIES}) + * removed. The original is left untouched so it can still be used for pool + * configuration and lookups. Additional keys can be excluded via + * {@value #DRIVER_EXCLUDE_PROPERTIES_KEY} (comma-separated). + */ + // package private for testing purposes + Properties toDriverProperties(Properties properties) { + Set excludes = new HashSet<>(NON_DRIVER_PROPERTIES); + String userExcludes = getProperty(DRIVER_EXCLUDE_PROPERTIES_KEY); + if (StringUtils.isNotBlank(userExcludes)) { + for (String key : userExcludes.split(",")) { + excludes.add(key.trim()); + } + } + + Properties driverProperties = new Properties(); + for (String key : properties.stringPropertyNames()) { + if (!excludes.contains(key)) { + driverProperties.setProperty(key, properties.getProperty(key)); + } + } + return driverProperties; + } + private void createConnectionPool(String url, String user, Properties properties) throws SQLException, ClassNotFoundException { LOGGER.info("Creating connection pool for url: {}, user: {}", url, user); - /* Remove properties that is not valid properties for presto/trino by checking driver key. - * - Presto: com.facebook.presto.jdbc.PrestoDriver - * - Trino(ex. PrestoSQL): io.trino.jdbc.TrinoDriver / io.prestosql.jdbc.PrestoDriver - */ String driverClass = properties.getProperty(DRIVER_KEY); - if (driverClass != null && (driverClass.equals("com.facebook.presto.jdbc.PrestoDriver") - || driverClass.equals("io.prestosql.jdbc.PrestoDriver") - || driverClass.equals("io.trino.jdbc.TrinoDriver"))) { - for (String key : properties.stringPropertyNames()) { - if (!PRESTO_PROPERTIES.contains(key)) { - properties.remove(key); - } - } - } + Properties driverProperties = toDriverProperties(properties); ConnectionFactory connectionFactory = - new DriverManagerConnectionFactory(url, properties); + new DriverManagerConnectionFactory(url, driverProperties); PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory( connectionFactory, null); diff --git a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java index cc5002b22a8..f688e813104 100644 --- a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java +++ b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCInterpreterTest.java @@ -59,12 +59,14 @@ import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_STATEMENT_PRECODE; import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_URL; import static org.apache.zeppelin.jdbc.JDBCInterpreter.DEFAULT_USER; +import static org.apache.zeppelin.jdbc.JDBCInterpreter.DRIVER_EXCLUDE_PROPERTIES_KEY; import static org.apache.zeppelin.jdbc.JDBCInterpreter.PRECODE_KEY_TEMPLATE; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; /** @@ -189,6 +191,146 @@ void testDefaultProperties() { assertEquals("1000", jdbcInterpreter.getProperty(COMMON_MAX_LINE)); } + @Test + void testToDriverProperties() { + JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(new Properties()); + + Properties properties = new Properties(); + // genuine JDBC driver properties, must be kept + properties.setProperty("user", "trino_user"); + properties.setProperty("password", "secret"); + properties.setProperty("SSL", "true"); + // Zeppelin-internal / pool properties, must be removed (ZEPPELIN-6208) + properties.setProperty("driver", "io.trino.jdbc.TrinoDriver"); + properties.setProperty("url", "jdbc:trino://localhost:8080"); + properties.setProperty("precode", "set time zone 'UTC'"); + properties.setProperty("statementPrecode", "set time zone 'UTC'"); + properties.setProperty("completer.ttlInSeconds", "120"); + properties.setProperty("completer.schemaFilters", "public"); + properties.setProperty("validationQuery", "show databases"); + properties.setProperty("maxIdle", "8"); + + Properties driverProperties = jdbcInterpreter.toDriverProperties(properties); + + assertEquals(3, driverProperties.size()); + assertEquals("trino_user", driverProperties.getProperty("user")); + assertEquals("secret", driverProperties.getProperty("password")); + assertEquals("true", driverProperties.getProperty("SSL")); + assertFalse(driverProperties.containsKey("driver")); + assertFalse(driverProperties.containsKey("url")); + assertFalse(driverProperties.containsKey("precode")); + assertFalse(driverProperties.containsKey("statementPrecode")); + assertFalse(driverProperties.containsKey("completer.ttlInSeconds")); + assertFalse(driverProperties.containsKey("completer.schemaFilters")); + assertFalse(driverProperties.containsKey("validationQuery")); + assertFalse(driverProperties.containsKey("maxIdle")); + + // the original properties must not be mutated + assertTrue(properties.containsKey("driver")); + assertTrue(properties.containsKey("url")); + } + + @Test + void testToDriverPropertiesWithUserDefinedExcludes() { + Properties config = new Properties(); + config.setProperty(DRIVER_EXCLUDE_PROPERTIES_KEY, "SSL, customKey"); + JDBCInterpreter jdbcInterpreter = new JDBCInterpreter(config); + + Properties properties = new Properties(); + properties.setProperty("user", "trino_user"); + properties.setProperty("SSL", "true"); + properties.setProperty("customKey", "customValue"); + + Properties driverProperties = jdbcInterpreter.toDriverProperties(properties); + + assertEquals(1, driverProperties.size()); + assertEquals("trino_user", driverProperties.getProperty("user")); + assertFalse(driverProperties.containsKey("SSL")); + assertFalse(driverProperties.containsKey("customKey")); + } + + /** + * End-to-end check that a strict JDBC driver (DuckDB) can connect even though + * Zeppelin-internal properties are present in the interpreter configuration. + * Before ZEPPELIN-6208 those keys were forwarded to the driver and DuckDB + * rejected the connection. DuckDB runs in-process, so no external server is + * needed. + */ + @Test + void testDuckDbConnectionWithInternalProperties() + throws IOException, InterpreterException { + Properties properties = new Properties(); + properties.setProperty("default.driver", "org.duckdb.DuckDBDriver"); + properties.setProperty("default.url", "jdbc:duckdb:"); + properties.setProperty("default.user", ""); + properties.setProperty("default.password", ""); + // Internal keys that DuckDB's strict driver would reject if forwarded + properties.setProperty("default.completer.ttlInSeconds", "120"); + properties.setProperty("default.completer.schemaFilters", ""); + properties.setProperty("common.max_count", "1000"); + JDBCInterpreter t = new JDBCInterpreter(properties); + t.open(); + + String sqlQuery = "CREATE TABLE pokes (id INTEGER, name VARCHAR); " + + "INSERT INTO pokes VALUES (1, 'a'), (2, 'b'); " + + "SELECT * FROM pokes ORDER BY id;"; + InterpreterResult interpreterResult = t.interpret(sqlQuery, context); + + assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code()); + List resultMessages = context.out.toInterpreterResultMessage(); + InterpreterResultMessage tableMessage = resultMessages.stream() + .filter(m -> m.getType() == InterpreterResult.Type.TABLE) + .reduce((first, second) -> second) + .orElseThrow(() -> new AssertionError("No TABLE result produced")); + assertEquals("id\tname\n1\ta\n2\tb\n", tableMessage.getData()); + } + + private static boolean isTrinoAvailable(String host, int port) { + try (java.net.Socket socket = new java.net.Socket()) { + socket.connect(new java.net.InetSocketAddress(host, port), 1000); + return true; + } catch (IOException e) { + return false; + } + } + + /** + * End-to-end check against a real Trino coordinator. Like DuckDB, Trino has a + * strict driver that rejects unknown connection properties; before ZEPPELIN-6208 + * these were stripped by a driver-specific whitelist, now by the generic filter. + * Skipped automatically when no Trino server is reachable on localhost:8080. + */ + @Test + void testTrinoConnectionWithInternalProperties() + throws IOException, InterpreterException { + assumeTrue(isTrinoAvailable("localhost", 8080), + "Trino coordinator not reachable on localhost:8080, skipping"); + + Properties properties = new Properties(); + properties.setProperty("default.driver", "io.trino.jdbc.TrinoDriver"); + properties.setProperty("default.url", "jdbc:trino://localhost:8080"); + properties.setProperty("default.user", "test"); + properties.setProperty("default.password", ""); + // Internal keys that Trino's strict driver would reject if forwarded + properties.setProperty("default.completer.ttlInSeconds", "120"); + properties.setProperty("default.completer.schemaFilters", ""); + properties.setProperty("common.max_count", "1000"); + JDBCInterpreter t = new JDBCInterpreter(properties); + t.open(); + + String sqlQuery = + "SELECT nationkey AS id, name FROM tpch.tiny.nation ORDER BY nationkey LIMIT 2;"; + InterpreterResult interpreterResult = t.interpret(sqlQuery, context); + + assertEquals(InterpreterResult.Code.SUCCESS, interpreterResult.code()); + List resultMessages = context.out.toInterpreterResultMessage(); + InterpreterResultMessage tableMessage = resultMessages.stream() + .filter(m -> m.getType() == InterpreterResult.Type.TABLE) + .reduce((first, second) -> second) + .orElseThrow(() -> new AssertionError("No TABLE result produced")); + assertEquals("id\tname\n0\tALGERIA\n1\tARGENTINA\n", tableMessage.getData()); + } + @Test void testSelectQuery() throws IOException, InterpreterException { Properties properties = new Properties(); From 3d71dfef07cbef158e5544c46783cdec0cb32290 Mon Sep 17 00:00:00 2001 From: HyeonUk Kang <43662405+hyunw9@users.noreply.github.com> Date: Sun, 9 Aug 2026 22:58:29 +0900 Subject: [PATCH 159/179] [ZEPPELIN-6555] Avoid deadlock in ManagedInterpreterGroup.close() by not holding the group lock while closing session interpreters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `ManagedInterpreterGroup.close()` can deadlock with a concurrent `RemoteInterpreter.open()` because the two paths take the same two monitors in the opposite order. Two monitors are involved: the interpreter-group monitor and an individual interpreter's monitor. - `open()` takes the interpreter monitor first (`synchronized(this)`) and then the group monitor (via `getOrCreateSession()` and the angular-registry push). Order: interpreter → group. - `close(String)` is a `synchronized` method, so it holds the group monitor while it spawns the per-interpreter close threads and `join()`s them. Each close thread runs `interpreter.close()`, which takes the interpreter monitor. Order: group → interpreter. So when an interpreter is opened while its session is concurrently closed (for example, restarting or shutting down an interpreter while a paragraph on that session is still starting up), the two orders form a circular wait. ### What type of PR is it? Bug Fix ### Todos * [x] Stop holding the group monitor while closing session interpreters in `close(String)` * [x] Keep only the session-map removal and last-session teardown under the lock * [x] Add regression test `ManagedInterpreterGroupTest#close_doesNotDeadlockWithConcurrentOpen` ### What is the Jira issue? [[ZEPPELIN-6555]](https://issues.apache.org/jira/browse/ZEPPELIN-6555) ### How should this be tested? - Added a deterministic regression test,`ManagedInterpreterGroupTest#close_doesNotDeadlockWithConcurrentOpen`. ### Screenshots (if appropriate) ### Questions: * Does the license files need to update? - No * Is there breaking changes for older versions? - No * Does this needs documentation? - No Closes #5329 from hyunw9/ZEPPELIN-6555. Signed-off-by: Jongyoul Lee --- .../interpreter/ManagedInterpreterGroup.java | 35 +++--- .../ManagedInterpreterGroupTest.java | 109 ++++++++++++++++++ 2 files changed, 130 insertions(+), 14 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java index 8f2c16c0743..f3f5441319b 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java @@ -101,22 +101,29 @@ public void close() { * Close all interpreter instances in this session * @param sessionId */ - public synchronized void close(String sessionId) { - LOGGER.info("Close Session: {} for interpreter setting: {}", sessionId, interpreterSetting.getName()); - close(sessions.remove(sessionId)); + public void close(String sessionId) { + LOGGER.info("Close Session: {} for interpreter setting: {}", + sessionId, interpreterSetting.getName()); + + Collection interpreters = sessions.remove(sessionId); + close(interpreters); + //TODO(zjffdu) whether close InterpreterGroup if there's no session left in Zeppelin Server - if (sessions.isEmpty() && interpreterSetting != null) { - LOGGER.info("Remove this InterpreterGroup: {} as all the sessions are closed", id); - interpreterSetting.removeInterpreterGroup(id); - if (remoteInterpreterProcess != null) { - LOGGER.info("Kill RemoteInterpreterProcess"); - remoteInterpreterProcess.stop(); - try { - interpreterSetting.getRecoveryStorage().onInterpreterClientStop(remoteInterpreterProcess); - } catch (IOException e) { - LOGGER.error("Fail to store recovery data", e); + synchronized (this) { + if (sessions.isEmpty() && interpreterSetting != null) { + LOGGER.info("Remove this InterpreterGroup: {} as all the sessions are closed", id); + interpreterSetting.removeInterpreterGroup(id); + if (remoteInterpreterProcess != null) { + LOGGER.info("Kill RemoteInterpreterProcess"); + remoteInterpreterProcess.stop(); + try { + interpreterSetting.getRecoveryStorage() + .onInterpreterClientStop(remoteInterpreterProcess); + } catch (IOException e) { + LOGGER.error("Fail to store recovery data", e); + } + remoteInterpreterProcess = null; } - remoteInterpreterProcess = null; } } } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroupTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroupTest.java index 09a8974672c..c1bff6e264b 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroupTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroupTest.java @@ -21,13 +21,20 @@ import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.eclipse.aether.RepositoryException; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import java.io.IOException; +import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; class ManagedInterpreterGroupTest { @@ -89,4 +96,106 @@ void testInterpreterGroup() { interpreterGroup.close(); assertEquals(0, interpreterGroup.getSessionNum()); } + + @Test + @Timeout(30) + void close_doesNotDeadlockWithConcurrentOpen() throws Exception { + ManagedInterpreterGroup group = + new ManagedInterpreterGroup("g1", interpreterSetting, zConf); + + LockProbeInterpreter probe = new LockProbeInterpreter(new Properties()); + probe.setInterpreterGroup(group); + List s1 = new ArrayList<>(); + s1.add(probe); + group.sessions.put("s1", s1); + + CountDownLatch openerHasIntp = new CountDownLatch(1); + + // "opener": mirrors open() lock ordering (interpreter -> group). + Thread opener = new Thread(() -> { + synchronized (probe) { // interpreter monitor + openerHasIntp.countDown(); + try { + // wait until the close worker is blocked trying to take the interpreter monitor, which + // means the closer is holding the group monitor inside close(String). + probe.closeReached.await(); + Thread w; + while ((w = probe.worker) == null || w.getState() != Thread.State.BLOCKED) { + Thread.onSpinWait(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + group.getOrCreateSession("u", "s2"); // needs the group monitor + } + }, "deadlock-opener"); + opener.setDaemon(true); + + // "closer": the real method under test. + Thread closer = new Thread(() -> group.close("s1"), "deadlock-closer"); + closer.setDaemon(true); + + opener.start(); + assertTrue(openerHasIntp.await(5, TimeUnit.SECONDS), + "opener failed to acquire the interpreter monitor"); + closer.start(); + + opener.join(TimeUnit.SECONDS.toMillis(10)); + closer.join(TimeUnit.SECONDS.toMillis(10)); + + if (opener.isAlive() || closer.isAlive()) { + long[] deadlocked = ManagementFactory.getThreadMXBean().findDeadlockedThreads(); + fail("Deadlock: ManagedInterpreterGroup.close() holds the group monitor while joining the " + + "close-worker thread, which needs the interpreter monitor held by the concurrent " + + "open(). opener.alive=" + opener.isAlive() + ", closer.alive=" + closer.isAlive() + + ", jvmDetectedMonitorDeadlock=" + (deadlocked != null)); + } + } + + /** + * Minimal interpreter whose close() takes its own monitor, like RemoteInterpreter does via + * getOrCreateInterpreterProcess(). It signals when the close worker reaches the monitor so the + * test can force the interleaving deterministically. + */ + private static class LockProbeInterpreter extends Interpreter { + + final CountDownLatch closeReached = new CountDownLatch(1); + volatile Thread worker; + + LockProbeInterpreter(Properties properties) { + super(properties); + } + + @Override + public void close() { + worker = Thread.currentThread(); + closeReached.countDown(); + synchronized (this) { + } + } + + @Override + public void open() { + } + + @Override + public InterpreterResult interpret(String st, InterpreterContext context) { + return null; + } + + @Override + public void cancel(InterpreterContext context) { + } + + @Override + public FormType getFormType() { + return FormType.NATIVE; + } + + @Override + public int getProgress(InterpreterContext context) { + return 0; + } + } } From 149f51fed7d9d3fb4000cd08ade00b34ee09b42c Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Sun, 9 Aug 2026 23:09:50 +0900 Subject: [PATCH 160/179] [ZEPPELIN-6129] Restore parallel paragraph execution for concurrent interpreters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Paragraphs of the same interpreter cannot run in parallel, even when the interpreter is configured for concurrent execution (e.g. a presto JDBC interpreter with `zeppelin.jdbc.concurrent.use=true`). This is a regression from [ZEPPELIN-5900] (#4582). That PR switched `RemoteScheduler`'s executor to a per-scheduler `newSingleThreadExecutor` so that `RemoteSchedulerTest.testAbortOnPending` became deterministic. Before it, `RemoteScheduler` was constructed with the shared multi-threaded pool from `SchedulerFactory.getExecutor()`, and every interpreter could submit paragraphs to the remote side concurrently. Scheduling is two-tier: the server-side `RemoteScheduler` is a proxy, and each interpreter's remote-side `getScheduler()` (FIFO vs Parallel) decides the real concurrency. Once the server side became single-threaded, it gated every interpreter behind a single in-flight submission, so a remote `ParallelScheduler` never received a second job to run. The JDBC concurrency flag was read on the remote side but the server side never let a second paragraph through. The fix restores an interpreter-neutral pool on the server side and delegates parallelism back to the remote scheduler: - `RemoteScheduler`: paragraph mode now builds a bounded `newFixedThreadPool` sized from `zeppelin.interpreter.connection.poolsize` (default 100, matching the RPC connection pool). Note mode keeps `newSingleThreadExecutor` to preserve in-note paragraph ordering. The JDBC-specific `zeppelin.jdbc.concurrent.*` gate is removed — it only helped JDBC and left Shell / Markdown / MongoDB / Neo4j / Cassandra / Flink SQL and other always-parallel interpreters serialized on the server side. - The paragraph/note blocking-wait in `runJobInScheduler` is untouched. It is what keeps FIFO interpreters (Python, Spark, ...) serial and note mode ordered: a FIFO interpreter's second job never reaches RUNNING remotely, so the wait still serializes it. - Cancellation hardening for the now-multithreaded pool: `Job.aborted` is `volatile`, and `AbstractScheduler.runJob`'s abort gate runs under `synchronized(runningJob)`, so a cancel arriving right before run reliably skips execution instead of racing. - `JDBCUserConfigurations`: `paragraphIdStatementMap` is a `ConcurrentHashMap` and `cancelStatement` null-checks the statement, so a cancel arriving before the statement is registered is a no-op rather than an NPE. Net effect: interpreters whose remote `getScheduler()` returns a `ParallelScheduler` (Shell, Markdown, MongoDB, Neo4j, Cassandra, Flink SQL, JDBC with concurrency on, ...) regain parallel paragraph execution; FIFO interpreters and note mode stay serial. ### What type of PR is it? Bug Fix ### What is the Jira issue? [ZEPPELIN-6129](https://issues.apache.org/jira/browse/ZEPPELIN-6129) ### How should this be tested? Unit / integration: ``` ./mvnw test -pl zeppelin-interpreter,jdbc,zeppelin-server -am \ -Dtest=RemoteSchedulerTest,AbstractSchedulerAbortRaceTest,JobTest,JDBCUserConfigurationsTest,JDBCInterpreterTest ``` - `RemoteSchedulerTest#testParallelExecution_bothJobsRunConcurrently` — two jobs reach RUNNING simultaneously through `RemoteScheduler`; fails against the single-thread executor, passes with the neutral pool. - `RemoteSchedulerTest#testAbortOnPending_noteModeSerial` — note mode still serializes and aborts a queued job before it runs. - `AbstractSchedulerAbortRaceTest` — the abort gate and cancel share the job monitor (latch-driven, deterministic). - `JDBCUserConfigurationsTest` — cancel-before-register is a no-op, not an NPE. End-to-end (verified locally against a real server; the IT itself is kept out of this PR to keep CI light): two `%sh` paragraphs each running `sleep 5`, triggered via the async REST endpoint `POST /api/notebook/job/{noteId}/{paragraphId}`, with no concurrency property set (Shell is a `ParallelScheduler` by default). Status was polled and the two paragraphs were observed RUNNING at the same time: ``` both paragraphs observed RUNNING simultaneously at +3425ms total elapsed until both FINISHED: 8287ms ``` Serial execution would be ~10000ms (2 x sleep 5), and a single-thread pool can never reach simultaneous RUNNING because the second paragraph stays PENDING until the first finishes. The overlap at +3425ms and the ~8.3s wall-clock confirm the two paragraphs ran in parallel. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5332 from HwangRock/ZEPPELIN-6129. Signed-off-by: Jongyoul Lee --- .../zeppelin/jdbc/JDBCUserConfigurations.java | 18 +- .../jdbc/JDBCUserConfigurationsTest.java | 68 +++++++ .../zeppelin/scheduler/AbstractScheduler.java | 30 ++-- .../org/apache/zeppelin/scheduler/Job.java | 2 +- .../AbstractSchedulerAbortRaceTest.java | 168 ++++++++++++++++++ .../zeppelin/scheduler/RemoteScheduler.java | 46 ++++- .../scheduler/RemoteSchedulerTest.java | 139 ++++++++++++++- 7 files changed, 447 insertions(+), 24 deletions(-) create mode 100644 jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCUserConfigurationsTest.java create mode 100644 zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/AbstractSchedulerAbortRaceTest.java diff --git a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCUserConfigurations.java b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCUserConfigurations.java index 311fb0bad0c..bcaea51e0ca 100644 --- a/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCUserConfigurations.java +++ b/jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCUserConfigurations.java @@ -19,9 +19,9 @@ import java.sql.SQLException; import java.sql.Statement; -import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.concurrent.ConcurrentHashMap; /** * UserConfigurations for JDBC impersonation. @@ -33,7 +33,7 @@ public class JDBCUserConfigurations { private Boolean isSuccessful; public JDBCUserConfigurations() { - paragraphIdStatementMap = new HashMap<>(); + paragraphIdStatementMap = new ConcurrentHashMap<>(); } public void initStatementMap() throws SQLException { @@ -67,14 +67,26 @@ public void setUserProperty(UsernamePassword usernamePassword) { } public void saveStatement(String paragraphId, Statement statement) throws SQLException { + if (paragraphId == null) { + return; + } paragraphIdStatementMap.put(paragraphId, statement); } public void cancelStatement(String paragraphId) throws SQLException { - paragraphIdStatementMap.get(paragraphId).cancel(); + if (paragraphId == null) { + return; + } + Statement statement = paragraphIdStatementMap.get(paragraphId); + if (statement != null) { + statement.cancel(); + } } public void removeStatement(String paragraphId) { + if (paragraphId == null) { + return; + } paragraphIdStatementMap.remove(paragraphId); } diff --git a/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCUserConfigurationsTest.java b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCUserConfigurationsTest.java new file mode 100644 index 00000000000..40fa032a6e4 --- /dev/null +++ b/jdbc/src/test/java/org/apache/zeppelin/jdbc/JDBCUserConfigurationsTest.java @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.zeppelin.jdbc; + +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.sql.SQLException; +import java.sql.Statement; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +class JDBCUserConfigurationsTest { + + @Test + void cancelStatementBeforeSaveShouldNotThrowNPE() { + JDBCUserConfigurations jdbcUserConfigurations = new JDBCUserConfigurations(); + + assertDoesNotThrow(() -> jdbcUserConfigurations.cancelStatement("paragraph-not-registered")); + } + + @Test + void cancelStatementAfterSaveShouldCallCancelOnStatement() throws SQLException { + JDBCUserConfigurations jdbcUserConfigurations = new JDBCUserConfigurations(); + Statement statement = Mockito.mock(Statement.class); + jdbcUserConfigurations.saveStatement("paragraph-1", statement); + + jdbcUserConfigurations.cancelStatement("paragraph-1"); + + verify(statement).cancel(); + } + + @Test + void cancelStatementAfterRemoveShouldNotThrowNPE() throws SQLException { + JDBCUserConfigurations jdbcUserConfigurations = new JDBCUserConfigurations(); + Statement statement = Mockito.mock(Statement.class); + jdbcUserConfigurations.saveStatement("paragraph-1", statement); + jdbcUserConfigurations.removeStatement("paragraph-1"); + + assertDoesNotThrow(() -> jdbcUserConfigurations.cancelStatement("paragraph-1")); + verify(statement, never()).cancel(); + } + + @Test + void nullParagraphIdShouldBeNoOpAcrossAllMapOperations() throws SQLException { + JDBCUserConfigurations jdbcUserConfigurations = new JDBCUserConfigurations(); + Statement statement = Mockito.mock(Statement.class); + + assertDoesNotThrow(() -> jdbcUserConfigurations.saveStatement(null, statement)); + assertDoesNotThrow(() -> jdbcUserConfigurations.cancelStatement(null)); + assertDoesNotThrow(() -> jdbcUserConfigurations.removeStatement(null)); + verify(statement, never()).cancel(); + } +} diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/AbstractScheduler.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/AbstractScheduler.java index 7e99095b7ff..5bb3c82e020 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/AbstractScheduler.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/AbstractScheduler.java @@ -77,7 +77,11 @@ public void submit(Job job) { @Override public Job cancel(String jobId) { Job job = jobs.remove(jobId); - job.abort(); + // Synchronize on the same monitor as runJob()'s abort gate so that a cancellation + // happening right before the job is run is never missed (ZEPPELIN-6129). + synchronized (job) { + job.abort(); + } return job; } @@ -121,17 +125,21 @@ public void stop() { * @param runningJob */ protected void runJob(Job runningJob) { - if (runningJob.isAborted()) { - LOGGER.info("Job {} is aborted", runningJob.getId()); - runningJob.setStatus(Job.Status.ABORT); - runningJob.aborted = false; - return; - } + // Synchronize the abort gate on the same monitor cancel() uses, so a cancellation + // submitted right before the job runs is never missed (ZEPPELIN-6129). + synchronized (runningJob) { + if (runningJob.isAborted()) { + LOGGER.info("Job {} is aborted", runningJob.getId()); + runningJob.setStatus(Job.Status.ABORT); + runningJob.aborted = false; + return; + } - LOGGER.info("Job {} started by scheduler {}", runningJob.getId(), name); - // Don't set RUNNING status when it is RemoteScheduler, update it via JobStatusPoller - if (!getClass().getSimpleName().equals("RemoteScheduler")) { - runningJob.setStatus(Job.Status.RUNNING); + LOGGER.info("Job {} started by scheduler {}", runningJob.getId(), name); + // Don't set RUNNING status when it is RemoteScheduler, update it via JobStatusPoller + if (!getClass().getSimpleName().equals("RemoteScheduler")) { + runningJob.setStatus(Job.Status.RUNNING); + } } runningJob.run(); Object jobResult = runningJob.getReturn(); diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/Job.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/Job.java index b0ed600f45a..d8b4a739b87 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/Job.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/scheduler/Job.java @@ -89,7 +89,7 @@ public boolean isFailed() { private Date dateFinished; protected volatile Status status; - transient boolean aborted = false; + transient volatile boolean aborted = false; private volatile String errorMessage; private transient volatile Throwable exception; private transient JobListener listener; diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/AbstractSchedulerAbortRaceTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/AbstractSchedulerAbortRaceTest.java new file mode 100644 index 00000000000..e7f10d44514 --- /dev/null +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/scheduler/AbstractSchedulerAbortRaceTest.java @@ -0,0 +1,168 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.scheduler; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +/** + * Covers the "abort right before run" race between a cancelling thread + * ({@link AbstractScheduler#cancel(String)}) and the scheduler thread that is about to invoke + * {@link AbstractScheduler#runJob(Job)}. + * + *

    Honest limitation: a pure memory-visibility race on a non-volatile field cannot be + * reproduced deterministically without a specialized harness (e.g. jcstress) because it depends + * on JVM safepoints/JIT reordering. This class therefore verifies the observable behavior + * contract instead: (1) abort()/isAborted() agree, (2) a PENDING job aborted before runJob() is + * invoked never has its run() executed and ends in ABORT, and (3) cancel() and the runJob() gate + * are mutually exclusive on the same job monitor, which is a deterministic, latch-driven proof + * that the race window described in ZEPPELIN-6129 Task 2 is closed. + */ +class AbstractSchedulerAbortRaceTest { + + private FIFOScheduler scheduler; + + @AfterEach + void tearDown() { + if (scheduler != null) { + scheduler.stop(); + } + } + + @Test + void testAbortSetsIsAbortedTrue() { + SleepingJob job = new SleepingJob("abortJob", null, 5000); + + assertFalse(job.isAborted()); + job.abort(); + + assertTrue(job.isAborted()); + } + + @Test + void testCancelBeforeRunJobBlocksExecutionThroughSchedulerCancelPath() { + scheduler = new FIFOScheduler("cancel-gate-test"); + SleepingJob job = new SleepingJob("job1", null, 5000); + scheduler.submit(job); + + scheduler.cancel(job.getId()); + scheduler.runJob(job); + + assertEquals(Job.Status.ABORT, job.getStatus()); + assertNull(job.getReturn()); + } + + @Test + void testCancelAndRunJobGateAreMutuallyExclusiveOnJobMonitor() throws Exception { + scheduler = new FIFOScheduler("mutex-test"); + BlockingAbortJob job = new BlockingAbortJob("job1"); + scheduler.submit(job); + + Thread cancelThread = new Thread(() -> scheduler.cancel(job.getId()), "cancel-thread"); + cancelThread.start(); + + assertTrue(job.abortEntered.await(2, TimeUnit.SECONDS), + "cancel thread must reach jobAbort() and hold the job monitor"); + + Thread runJobThread = new Thread(() -> scheduler.runJob(job), "runjob-thread"); + runJobThread.start(); + + assertTrue(waitForState(runJobThread, Thread.State.BLOCKED, 2000), + "runJob() must block waiting for the same job monitor held by cancel()"); + assertFalse(job.runCalled, "job.run() must not start while cancel() still holds the monitor"); + + job.releaseAbort.countDown(); + cancelThread.join(2000); + runJobThread.join(2000); + + assertFalse(job.runCalled, "aborted job must never invoke run()"); + assertEquals(Job.Status.ABORT, job.getStatus()); + } + + private static boolean waitForState(Thread thread, Thread.State expected, long timeoutMs) + throws InterruptedException { + long deadline = System.currentTimeMillis() + timeoutMs; + while (System.currentTimeMillis() < deadline) { + if (thread.getState() == expected) { + return true; + } + Thread.sleep(10); + } + return thread.getState() == expected; + } + + /** + * Job whose {@code jobAbort()} blocks on a latch so the test can control exactly how long the + * cancelling thread holds the job monitor. + */ + private static class BlockingAbortJob extends Job { + + private final CountDownLatch abortEntered = new CountDownLatch(1); + private final CountDownLatch releaseAbort = new CountDownLatch(1); + private volatile boolean runCalled = false; + + BlockingAbortJob(String name) { + super(name, null); + } + + @Override + protected Object jobRun() { + runCalled = true; + return null; + } + + @Override + protected boolean jobAbort() { + abortEntered.countDown(); + try { + releaseAbort.await(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return true; + } + + @Override + public void setResult(Object result) { + } + + @Override + public Object getReturn() { + return null; + } + + @Override + public int progress() { + return 0; + } + + @Override + public Map info() { + return Collections.emptyMap(); + } + } +} diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/scheduler/RemoteScheduler.java b/zeppelin-server/src/main/java/org/apache/zeppelin/scheduler/RemoteScheduler.java index e5807877f92..c47afa8094b 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/scheduler/RemoteScheduler.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/scheduler/RemoteScheduler.java @@ -17,6 +17,8 @@ package org.apache.zeppelin.scheduler; +import org.apache.commons.lang3.StringUtils; +import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; import org.apache.zeppelin.interpreter.remote.RemoteInterpreter; import org.apache.zeppelin.scheduler.Job.Status; import org.apache.zeppelin.util.ExecutorUtil; @@ -36,17 +38,57 @@ public class RemoteScheduler extends AbstractScheduler { private static final Logger LOGGER = LoggerFactory.getLogger(RemoteScheduler.class); + private static final String PARAGRAPH_POOL_SIZE_KEY = + ConfVars.ZEPPELIN_INTERPRETER_CONNECTION_POOL_SIZE.getVarName(); + private static final int DEFAULT_PARAGRAPH_POOL_SIZE = + ConfVars.ZEPPELIN_INTERPRETER_CONNECTION_POOL_SIZE.getIntValue(); + private final RemoteInterpreter remoteInterpreter; private final ExecutorService executor; public RemoteScheduler(String name, RemoteInterpreter remoteInterpreter) { super(name); - this.executor = - Executors.newSingleThreadExecutor(new NamedThreadFactory("FIFO-" + name)); + this.executor = createExecutor(name, remoteInterpreter); this.remoteInterpreter = remoteInterpreter; } + /** + * Creates the server-side job submission pool. This pool only decides how many jobs can be + * submitted to the remote interpreter process concurrently; actual concurrency is still + * governed by the remote interpreter's own {@code Scheduler} (Parallel vs FIFO), so this pool + * must stay interpreter-neutral. + * + *

    "note" execution mode keeps a single-threaded pool because {@link #runJobInScheduler} + * blocks until each job fully finishes before submitting the next one, preserving in-note + * paragraph ordering. "paragraph" mode uses a bounded fixed pool sized from + * {@link ConfVars#ZEPPELIN_INTERPRETER_CONNECTION_POOL_SIZE} so any interpreter whose remote + * scheduler is a ParallelScheduler can actually run jobs concurrently. + */ + private static ExecutorService createExecutor(String name, RemoteInterpreter remoteInterpreter) { + String executionMode = remoteInterpreter.getProperty(".execution.mode", "paragraph"); + if (!"paragraph".equals(executionMode)) { + return Executors.newSingleThreadExecutor(new NamedThreadFactory("FIFO-" + name)); + } + int poolSize = resolveParagraphPoolSize(remoteInterpreter); + return Executors.newFixedThreadPool(poolSize, new NamedThreadFactory("FIFO-" + name)); + } + + private static int resolveParagraphPoolSize(RemoteInterpreter remoteInterpreter) { + String value = remoteInterpreter.getProperty(PARAGRAPH_POOL_SIZE_KEY); + if (StringUtils.isBlank(value)) { + return DEFAULT_PARAGRAPH_POOL_SIZE; + } + try { + int parsed = Integer.parseInt(value.trim()); + return parsed > 0 ? parsed : DEFAULT_PARAGRAPH_POOL_SIZE; + } catch (NumberFormatException e) { + LOGGER.warn("Invalid {} value: {}, falling back to default {}", + PARAGRAPH_POOL_SIZE_KEY, value, DEFAULT_PARAGRAPH_POOL_SIZE); + return DEFAULT_PARAGRAPH_POOL_SIZE; + } + } + @Override public void runJobInScheduler(Job job) { JobRunner jobRunner = new JobRunner(this, job); diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java index 2eb9afe9768..14fbdd09701 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/scheduler/RemoteSchedulerTest.java @@ -32,6 +32,8 @@ import org.slf4j.LoggerFactory; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -44,6 +46,8 @@ class RemoteSchedulerTest extends AbstractInterpreterTest { private SchedulerFactory schedulerSvc; private static final int TICK_WAIT = 100; private static final int MAX_WAIT_CYCLES = 100; + private static final int CONCURRENT_JOB_SLEEP_MS = 3000; + private static final int OVERLAP_WAIT_CYCLES = 30; private String note1Id; @Override @@ -132,8 +136,15 @@ public void setResult(Object results) { } @Test - void testAbortOnPending() throws Exception { + void testAbortOnPending_noteModeSerial() throws Exception { final RemoteInterpreter intpA = (RemoteInterpreter) interpreterSetting.getInterpreter("user1", note1Id, "mock"); + // Force "note" execution mode: RemoteScheduler keeps a single-threaded pool for it and its + // local dispatch gate (runJobInScheduler) blocks until job1 is fully executed - not just + // submitted - before even attempting job2. So job2 is deterministically still PENDING, and + // never dispatched, when it is aborted below, regardless of the paragraph-mode pool now + // being multi-threaded for every interpreter (ZEPPELIN-6129). + intpA.setProperty(".execution.mode", "note"); + intpA.setProperty(".noteId", note1Id); intpA.open(); Scheduler scheduler = intpA.getScheduler(); @@ -237,23 +248,48 @@ public void setResult(Object results) { scheduler.submit(job1); scheduler.submit(job2); + CountDownLatch job1Running = new CountDownLatch(1); + Thread runningWatcher = new Thread(() -> { + int cycles = 0; + while (job1Running.getCount() > 0 && cycles < MAX_WAIT_CYCLES) { + if (job1.isRunning()) { + job1Running.countDown(); + return; + } + try { + Thread.sleep(TICK_WAIT); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + cycles++; + } + }); + runningWatcher.start(); + + assertTrue(job1Running.await(MAX_WAIT_CYCLES * TICK_WAIT, TimeUnit.MILLISECONDS), + "job1 should reach RUNNING"); + runningWatcher.join(TICK_WAIT); - int cycles = 0; - while (!job1.isRunning() && cycles < MAX_WAIT_CYCLES) { - Thread.sleep(TICK_WAIT); - cycles++; - } assertTrue(job1.isRunning()); assertEquals(Status.PENDING, job2.getStatus()); job2.abort(); - cycles = 0; + int cycles = 0; while (!job1.isTerminated() && cycles < MAX_WAIT_CYCLES) { Thread.sleep(TICK_WAIT); cycles++; } + // job1 terminating only unblocks the scheduler thread to dequeue and abort job2; give it + // its own bounded wait instead of assuming it is already processed the instant job1 is done. + cycles = 0; + while (!job2.isTerminated() && cycles < MAX_WAIT_CYCLES) { + Thread.sleep(TICK_WAIT); + cycles++; + } + assertNotNull(job1.getDateFinished()); assertTrue(job1.isTerminated()); assertEquals("1000", job1.getReturn()); @@ -265,4 +301,93 @@ public void setResult(Object results) { schedulerSvc.removeScheduler("test"); } + @Test + void testParallelExecution_bothJobsRunConcurrently() throws Exception { + final RemoteInterpreter intpA = + (RemoteInterpreter) interpreterSetting.getInterpreter("user1", note1Id, "mock"); + // enable parallel execution on the remote interpreter side so that the two jobs + // are not serialized by the interpreter's own scheduler. RemoteScheduler itself must + // stay interpreter-neutral: no JDBC-specific property is needed to unlock concurrency. + intpA.setProperty("parallel", "true"); + intpA.open(); + + Scheduler scheduler = intpA.getScheduler(); + + Job job1 = createSleepingJob("jobId1", intpA, CONCURRENT_JOB_SLEEP_MS); + Job job2 = createSleepingJob("jobId2", intpA, CONCURRENT_JOB_SLEEP_MS); + + scheduler.submit(job1); + scheduler.submit(job2); + + CountDownLatch overlapDetected = new CountDownLatch(1); + Thread overlapWatcher = new Thread(() -> { + int cycles = 0; + while (overlapDetected.getCount() > 0 && cycles < OVERLAP_WAIT_CYCLES) { + if (job1.isRunning() && job2.isRunning()) { + overlapDetected.countDown(); + return; + } + try { + Thread.sleep(TICK_WAIT); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return; + } + cycles++; + } + }); + overlapWatcher.start(); + + boolean bothRanConcurrently = + overlapDetected.await(OVERLAP_WAIT_CYCLES * TICK_WAIT, TimeUnit.MILLISECONDS); + overlapWatcher.join(TICK_WAIT); + + assertTrue(bothRanConcurrently, "job1 and job2 should both be RUNNING at the same time"); + + intpA.close(); + schedulerSvc.removeScheduler("test"); + } + + private Job createSleepingJob(String jobId, RemoteInterpreter intpA, int sleepMillis) { + return new Job(jobId, jobId, null) { + Object results; + InterpreterContext context = InterpreterContext.builder() + .setNoteId("noteId") + .setParagraphId(jobId) + .setResourcePool(new LocalResourcePool("pool-" + jobId)) + .build(); + + @Override + public Object getReturn() { + return results; + } + + @Override + public int progress() { + return 0; + } + + @Override + public Map info() { + return null; + } + + @Override + protected Object jobRun() throws Throwable { + intpA.interpret(String.valueOf(sleepMillis), context); + return String.valueOf(sleepMillis); + } + + @Override + protected boolean jobAbort() { + return false; + } + + @Override + public void setResult(Object results) { + this.results = results; + } + }; + } + } From 2147d79acbca4d06d87e52b06e41228e17e04e8d Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Sun, 9 Aug 2026 23:15:46 +0900 Subject: [PATCH 161/179] [ZEPPELIN-6548] Use specific exceptions for Spark Scala fallback detection ### What is this PR for? This PR refines exception types in `SparkInterpreterLauncher` when the fallback Spark Scala version detection validates the `SPARK_HOME/jars` layout. Previously, `detectSparkScalaVersionByReplClass(...)` threw generic `Exception` for expected validation failures such as missing or duplicate `spark-repl` jars, or an unsupported `spark-repl` Scala suffix. This PR replaces those generic throw sites with more specific exception types while keeping the existing messages and caller behavior unchanged. Missing or duplicate `spark-repl` jars now throw `IOException`, and an unrecognized Scala suffix now throws `IllegalArgumentException`. This PR is a follow-up to [ZEPPELIN-6464](https://issues.apache.org/jira/browse/ZEPPELIN-6464) ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6548 ### How should this be tested? - Build and run the module tests: ``` ./mvnw test -pl zeppelin-server --am ``` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5340 from miinhho/refactor/specific-exception-in-spark-scala-fallback. Signed-off-by: Jongyoul Lee --- .../interpreter/launcher/SparkInterpreterLauncher.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java index 98e0e5e0b82..b2b01685eea 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/launcher/SparkInterpreterLauncher.java @@ -318,10 +318,10 @@ private String detectSparkScalaVersionByReplClass(String sparkHome) throws Excep } if (sparkReplJars.isEmpty()) { - throw new Exception("No spark-repl jar found in SPARK_HOME: " + sparkHome); + throw new IOException("No spark-repl jar found in SPARK_HOME: " + sparkHome); } if (sparkReplJars.size() > 1) { - throw new Exception("Multiple spark-repl jar found in SPARK_HOME: " + sparkHome); + throw new IOException("Multiple spark-repl jar found in SPARK_HOME: " + sparkHome); } String fileName = sparkReplJars.get(0).getFileName().toString(); @@ -330,7 +330,7 @@ private String detectSparkScalaVersionByReplClass(String sparkHome) throws Excep } else if (fileName.contains("spark-repl_2.13")) { return "2.13"; } else { - throw new Exception("Can not detect the scala version by spark-repl"); + throw new IllegalArgumentException("Can not detect the scala version by spark-repl"); } } From 427bf3aa5c8010cdbdb04b256c4e0bf0d78f054d Mon Sep 17 00:00:00 2001 From: gyowoo1113 <58352333+gyowoo1113@users.noreply.github.com> Date: Sun, 9 Aug 2026 23:20:18 +0900 Subject: [PATCH 162/179] [ZEPPELIN-6543] Handle invokeMethod serialization failure as InterpreterRPCException ### What is this PR for? This PR follows up on ZEPPELIN-6467 / PR #5312. Following PR #5312, `Resource.serializeObject()` propagates serialization failures as `IOException`. As a result, `RemoteInterpreterEventServer.invokeMethod()` can receive an exception while re-serializing a remote resource invocation result. The existing handler logged the exception and returned a null `ByteBuffer`, causing the generated Thrift client to report a missing result instead of preserving the original serialization failure. The Jira issue identified this behavior through code analysis, but the server-side deserialize-and-re-serialize failure path had not yet been reproduced. This PR adds a regression test using a serializable object that succeeds during the initial serialization and fails during the server-side second serialization. It then changes `invokeMethod()` to propagate the failure as `InterpreterRPCException`, allowing the original error message to reach the caller instead of being converted into an unrelated Thrift missing-result error. The behavior for successfully serialized results is unchanged. ### What type of PR is it? Bug Fix ### Todos * [x] Reproduce the server-side deserialize-and-re-serialize failure path with a regression test * [x] Propagate serialization failures as `InterpreterRPCException` * [x] Verify that the propagated exception contains the original failure message ### What is the Jira issue? [[ZEPPELIN-6543](https://issues.apache.org/jira/browse/ZEPPELIN-6543)] ### How should this be tested? `./mvnw test -pl zeppelin-server -Dtest=RemoteInterpreterEventServerTest` passes successfully. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No * Code inspection suggests that `Resource.serializeObject()` may return `null` when the result is not serializable, but this path is not covered by the regression test in this PR. Should this case also be handled in this PR, or should it be addressed separately? Closes #5349 from gyowoo1113/ZEPPELIN-6543-handle-invoke-method-serialization-failure. Signed-off-by: Jongyoul Lee --- .../RemoteInterpreterEventServer.java | 1 + .../RemoteInterpreterEventServerTest.java | 95 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServerTest.java diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java index bab3ee7b2ad..8cba498dac3 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServer.java @@ -441,6 +441,7 @@ public ByteBuffer invokeMethod(String intpGroupId, String invokeMethodJson) obj = Resource.serializeObject(ret); } catch (IOException e) { LOGGER.error("invokeMethod failed", e); + throw new InterpreterRPCException(e.toString()); } } return obj; diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServerTest.java new file mode 100644 index 00000000000..ad385c612e7 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/RemoteInterpreterEventServerTest.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zeppelin.interpreter; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.nio.ByteBuffer; + +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.interpreter.remote.InvokeResourceMethodEventMessage; +import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess; +import org.apache.zeppelin.interpreter.thrift.InterpreterRPCException; +import org.apache.zeppelin.resource.Resource; +import org.apache.zeppelin.resource.ResourceId; +import org.junit.jupiter.api.Test; + +public class RemoteInterpreterEventServerTest { + + @Test + void invokeMethodThrowsRpcExceptionWhenSerializationFails() throws Exception { + ZeppelinConfiguration zConf = mock(ZeppelinConfiguration.class); + InterpreterSettingManager manager = mock(InterpreterSettingManager.class); + RemoteInterpreterEventServer server = new RemoteInterpreterEventServer(zConf, manager); + + ManagedInterpreterGroup interpreterGroup = mock(ManagedInterpreterGroup.class); + RemoteInterpreterProcess remoteInterpreterProcess = mock(RemoteInterpreterProcess.class); + + when(manager.getInterpreterGroupById("pool-id")) + .thenReturn(interpreterGroup); + when(interpreterGroup.getRemoteInterpreterProcess()) + .thenReturn(remoteInterpreterProcess); + when(remoteInterpreterProcess.isRunning()) + .thenReturn(true); + + ByteBuffer remoteResult = Resource.serializeObject(new SerializableOnlyOnce()); + doReturn(remoteResult) + .when(remoteInterpreterProcess) + .callRemoteFunction(any()); + + ResourceId resourceId = ResourceId.fromJson( + "{\"resourcePoolId\":\"pool-id\",\"name\":\"resource-name\",\"noteId\":\"note-id\",\"paragraphId\":\"paragraph-id\"}" + ); + + InvokeResourceMethodEventMessage message = new InvokeResourceMethodEventMessage( + resourceId + , "someMethod" + , null + , null + , null); + + InterpreterRPCException exception = assertThrows( + InterpreterRPCException.class, + () -> server.invokeMethod("caller-group-id", message.toJson())); + + assertTrue(exception.toString().contains("failed on second serialization")); + } + private static class SerializableOnlyOnce implements Serializable { + private static final long serialVersionUID = 1L; + private static final int FAILURE_SERIALIZATION_COUNT = 2; + + private int serializationCount; + + private void writeObject(ObjectOutputStream outputStream) throws IOException { + serializationCount++; + + if (serializationCount == FAILURE_SERIALIZATION_COUNT) { + throw new IOException("failed on second serialization"); + } + + outputStream.defaultWriteObject(); + } + } +} From a7458a8a5ecb456e6e1cb8b5537775cc0695eed2 Mon Sep 17 00:00:00 2001 From: YeonKyung Ryu <80758099+celinayk@users.noreply.github.com> Date: Sun, 9 Aug 2026 23:55:30 +0900 Subject: [PATCH 163/179] [ZEPPELIN-6459] Align Docker image logging configuration and documentation with Log4j2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Docker-related scripts and docs still referenced Log4j 1.x style `log4j.properties` files, and the reporter suspected these were obsolete leftovers from a Log4j2 migration. Investigation showed the opposite: Zeppelin's default SLF4J binding is `slf4j-reload4j`, so `log4j.properties` is still the primary logging config, while `log4j2.properties` exists only for Flink's bundled real Log4j2 core — both are required, not obsolete. The real bug found: `DockerInterpreterProcess` (the `DockerInterpreterLauncher` feature) uploads `log4j.properties` and `log4j_yarn_cluster.properties` from the host to the interpreter container, but never `log4j2.properties`, even though `bin/common.sh` looks for it via `-Dlog4j.configurationFile` for every local interpreter process. This PR adds it to the transferred file list, aligns `docs/quickstart/docker.md`'s file list with the code, documents why `scripts/docker/zeppelin/bin/Dockerfile` needs all 4 log4j* files (so they aren't mistaken for duplicates again), and clarifies in `docs/setup/deployment/docker.md` that `ZEPPELIN_IN_DOCKER` applies to the all-in-one image, not the split `zeppelin-server`/`zeppelin-interpreter` images. ### What type of PR is it? Bug Fix ### Todos * [x] Add missing `log4j2.properties` to `DockerInterpreterProcess`'s container file transfer list * [x] Sync `docs/quickstart/docker.md`'s transferred-file list with the code * [x] Document why `scripts/docker/zeppelin/bin/Dockerfile` ships 4 log4j* files * [x] Clarify `ZEPPELIN_IN_DOCKER` scope in `docs/setup/deployment/docker.md` ### What is the Jira issue? [ZEPPELIN-6459](https://issues.apache.org/jira/browse/ZEPPELIN-6459) ### How should this be tested? * No existing unit test covers `DockerInterpreterProcess#copyRunFileToContainer` (it's private and untested), so no automated test was added for the transfer list itself; existing `DockerInterpreterProcessTest` (6 tests) still passes unchanged. * Manually verified: built the exact tar archive `DockerInterpreterProcess` produces using the same `TarUtils`/`TarFileEntry` production classes with the fixed `copyFiles` entries, injected it into a real Alpine container via the same upload-tar-then-extract mechanism `deployToContainer` uses, and confirmed `log4j.properties`, `log4j2.properties`, and `log4j_yarn_cluster.properties` all land at the expected `conf/` path inside the container with content identical (byte-for-byte `diff`) to the host source files. ### Screenshots (if appropriate) N/A (docs/config change, no UI impact) ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? Yes — `docs/quickstart/docker.md` and `docs/setup/deployment/docker.md` updated as part of this PR Closes #5371 from celinayk/ZEPPELIN-6459. Signed-off-by: ChanHo Lee --- docs/quickstart/docker.md | 3 ++- docs/setup/deployment/docker.md | 6 ++++++ scripts/docker/zeppelin/bin/Dockerfile | 5 +++++ .../interpreter/launcher/DockerInterpreterProcess.java | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/quickstart/docker.md b/docs/quickstart/docker.md index 17e6229d7bd..5ae3afcc3b5 100644 --- a/docs/quickstart/docker.md +++ b/docs/quickstart/docker.md @@ -142,7 +142,8 @@ Zeppelin service runs on local server, it auto configure itself to use `DockerIn - ${ZEPPELIN_HOME}/interpreter/${interpreterGroupName} - ${ZEPPELIN_HOME}/conf/zeppelin-site.xml - ${ZEPPELIN_HOME}/conf/log4j.properties - - ${ZEPPELIN\_HOME}/conf/log4j\_yarn_cluster.properties + - ${ZEPPELIN_HOME}/conf/log4j2.properties + - ${ZEPPELIN_HOME}/conf/log4j_yarn_cluster.properties - HADOOP\_CONF_DIR - SPARK\_CONF_DIR - /etc/krb5.conf diff --git a/docs/setup/deployment/docker.md b/docs/setup/deployment/docker.md index 9598dbf0d65..7e112db6c47 100644 --- a/docs/setup/deployment/docker.md +++ b/docs/setup/deployment/docker.md @@ -40,6 +40,12 @@ docker run -p 8080:8080 -e ZEPPELIN_IN_DOCKER=true --rm --name zeppelin apache/z Notice, please specify environment variable `ZEPPELIN_IN_DOCKER` when starting zeppelin in docker, otherwise you can not see the interpreter log. +Note: `ZEPPELIN_IN_DOCKER` applies to the all-in-one image built from +`scripts/docker/zeppelin/bin` (the `Dockerfile` referenced under "Building dockerfile +locally" below). The split `zeppelin-server`/`zeppelin-interpreter` images described in +"Build docker image for Zeppelin server & interpreters" already log to stdout by +default and don't need or support this flag. + * Zeppelin will run at `http://localhost:8080`. If you want to specify `logs` and `notebook` dir, diff --git a/scripts/docker/zeppelin/bin/Dockerfile b/scripts/docker/zeppelin/bin/Dockerfile index e4e91e30aa8..a7ffae2b94f 100644 --- a/scripts/docker/zeppelin/bin/Dockerfile +++ b/scripts/docker/zeppelin/bin/Dockerfile @@ -78,6 +78,11 @@ RUN echo "$LOG_TAG Download Zeppelin binary" && \ chmod 775 ${ZEPPELIN_HOME} && \ chmod -R 775 /opt/conda +# These 4 files are all required by bin/common.sh, not obsolete duplicates: +# log4j.properties / log4j_docker.properties configure reload4j, which backs the +# server and most interpreters; log4j2.properties / log4j2_docker.properties +# configure the real Log4j2 core that Flink bundles transitively. The "_docker" +# variants are only picked up when the ZEPPELIN_IN_DOCKER env var is set. COPY log4j.properties ${ZEPPELIN_HOME}/conf/ COPY log4j_docker.properties ${ZEPPELIN_HOME}/conf/ COPY log4j2.properties ${ZEPPELIN_HOME}/conf/ diff --git a/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java b/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java index 9c86a676083..b7ba89a4a5b 100644 --- a/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java +++ b/zeppelin-plugins/launcher/docker/src/main/java/org/apache/zeppelin/interpreter/launcher/DockerInterpreterProcess.java @@ -547,6 +547,8 @@ private void copyRunFileToContainer(String containerId) copyFiles.put( zeplConfPath + "/zeppelin-site.xml", containerZeplConfPath + "/zeppelin-site.xml"); copyFiles.put(zeplConfPath + "/log4j.properties", containerZeplConfPath + "/log4j.properties"); + copyFiles.put(zeplConfPath + "/log4j2.properties", + containerZeplConfPath + "/log4j2.properties"); copyFiles.put(zeplConfPath + "/log4j_yarn_cluster.properties", containerZeplConfPath + "/log4j_yarn_cluster.properties"); From a403bed905eca3653be08f051ae05021031aa203 Mon Sep 17 00:00:00 2001 From: YooJung Huh Date: Mon, 10 Aug 2026 02:20:38 +0900 Subject: [PATCH 164/179] [ZEPPELIN-6436] Fix stale module names and test commands in embedding search documentation ### What is this PR for? `docs/embedding-search.md` still referenced the `zeppelin-zengine` module, which was merged into `zeppelin-server` in ZEPPELIN-6355 before the embedding search feature was added in ZEPPELIN-6411. As a result, the implementation paths and the `mvn test -pl zeppelin-zengine` commands in the doc no longer match the current repository layout and the test commands fail as written. This PR updates the stale references so the documentation is accurate and the test commands actually run. ### What type of PR is it? Documentation ### Todos - [x] Replace `zeppelin-zengine` references with `zeppelin-server` in implementation paths - [x] Update `mvn test -pl` commands to target `zeppelin-server` - [x] Verify referenced source/test files exist at the corrected paths ### What is the Jira issue? [ZEPPELIN-6436](https://issues.apache.org/jira/browse/ZEPPELIN-6436) ### How should this be tested? Confirm no stale references remain: `rg -n "zeppelin-zengine" docs/embedding-search.md` image Optionally Confirm the corrected paths exist in the repo: `zeppelin-server/src/main/java/org/apache/zeppelin/search/EmbeddingSearch.java` `zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java` `zeppelin-server/src/test/java/org/apache/zeppelin/search/LuceneSearchTest.java` Run the corrected commands to confirm they work: `mvn test -pl zeppelin-server -Dtest=LuceneSearchTest` `ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-server -Dtest=EmbeddingSearchTest` ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? This PR is the documentation fix. Closes #5408 from gjenfwo/ZEPPELIN-6436-fix-embedding-search-docs. Signed-off-by: ChanHo Lee --- docs/embedding-search.md | 12 ++++++------ .../apache/zeppelin/search/EmbeddingSearchTest.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/embedding-search.md b/docs/embedding-search.md index 5dac212ed22..90fb266bb3e 100644 --- a/docs/embedding-search.md +++ b/docs/embedding-search.md @@ -126,13 +126,13 @@ Requires `zeppelin.search.enable = true` (already the default). ## Changes ### New files -- `zeppelin-zengine/.../search/EmbeddingSearch.java` — Core implementation (~700 lines) -- `zeppelin-zengine/.../search/EmbeddingSearchTest.java` — 11 tests including semantic validation +- `zeppelin-server/.../search/EmbeddingSearch.java` — Core implementation (~700 lines) +- `zeppelin-server/.../search/EmbeddingSearchTest.java` — 11 tests including semantic validation - `docs/embedding-search.md` — This document ### Modified files — Backend -- `zeppelin-zengine/pom.xml` — Add `onnxruntime` and `djl-tokenizers` dependencies -- `zeppelin-zengine/.../conf/ZeppelinConfiguration.java` — Add `ZEPPELIN_SEARCH_SEMANTIC_ENABLE` +- `zeppelin-server/pom.xml` — Add `onnxruntime` and `djl-tokenizers` dependencies +- `zeppelin-server/.../conf/ZeppelinConfiguration.java` — Add `ZEPPELIN_SEARCH_SEMANTIC_ENABLE` - `zeppelin-server/.../server/ZeppelinServer.java` — Wire `EmbeddingSearch` based on config - `NOTICE` — Attribution for ONNX Runtime and DJL @@ -201,11 +201,11 @@ Zeppelin uses Lucene 8.7.0. Upgrading to 9.x is a separate, larger effort. ```bash # Run embedding search tests (requires model download, ~86MB first time) -ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-zengine \ +ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-server \ -Dtest=EmbeddingSearchTest # Run existing Lucene tests (should still pass, no changes) -mvn test -pl zeppelin-zengine -Dtest=LuceneSearchTest +mvn test -pl zeppelin-server -Dtest=LuceneSearchTest ``` ### Key tests diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java index 2eb9d4be7b9..902925eb7c3 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/search/EmbeddingSearchTest.java @@ -54,7 +54,7 @@ *

    These tests require the ONNX model to be downloaded, so they are gated behind * the {@code ZEPPELIN_EMBEDDING_TEST} environment variable. To run: *

    - *   ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-zengine \
    + *   ZEPPELIN_EMBEDDING_TEST=true mvn test -pl zeppelin-server \
      *     -Dtest=EmbeddingSearchTest
      * 
    * From 4d02c15e510d8e9874f40284e0008994d56fede1 Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Mon, 10 Aug 2026 09:21:18 +0900 Subject: [PATCH 165/179] [ZEPPELIN-6575] Reclaim idle interpreters on the server with a per-setting timeout ### What is this PR for? An interpreter setting cannot have its own idle timeout today, and worse, trying to give it one fails silently. Idle reclaim is decided inside the interpreter process by `TimeoutLifecycleManager`, which reads its threshold from the configuration map the server pushes over Thrift when the process starts. That map is built by `ZeppelinConfiguration#getCompleteConfiguration()`: ```java for (ConfVars c : ConfVars.values()) { if (getString(c) != null) { completeConfiguration.put(c.getVarName(), getString(c)); } } ``` Its key set is closed over the `ConfVars` enum, so an interpreter setting property has no slot to travel in. An operator can put the threshold property on a single interpreter's settings, it is stored, it is shown again when the form is reopened - and the process still starts with the global value. No error, no warning. So the threshold is effectively all-or-nothing across every interpreter, which does not match how they differ in cost. A Spark interpreter holding tens of gigabytes of cluster memory is worth reclaiming aggressively; a JDBC interpreter that only keeps a few connections open is usually worth keeping. Today an operator who enables idle reclaim gets one number for both. This moves the decision to the server, which already knows the per-setting value: - `ManagedInterpreterGroup` records when the group was last used. The three hooks mirror the ones `RemoteInterpreterServer` already calls in-process (`interpret`, `getProgress`, `getStatus`), so no new notion of activity is introduced. `getStatus` matters most: `RemoteScheduler.JobStatusPoller` calls it while a paragraph runs, which is what keeps a long-running paragraph from having its interpreter pulled out from under it. - `IdleInterpreterReclaimer` walks `getAllInterpreterGroup()` on a timer, resolves the threshold from the owning interpreter setting (falling back to the global property), and closes the group by reusing `ManagedInterpreterGroup.close()`. It reads in-memory state only and never calls `isAlive()`/`isRunning()`, whose cost depends on the launcher - a socket connect with a 1s timeout for docker, an unbounded kube-apiserver round trip for k8s - and this runs over every group on a timer. - A group whose process is still launching is skipped. The handle field is assigned before `start()`, while the idle clock has been running since the group was created, so without this a launch slower than the threshold gets killed while coming up. Spark on YARN takes minutes to launch, so this is not hypothetical. **No new configuration property, and nothing changes unless asked for.** This follows the existing lifecycle manager class property, which already expresses whether idle reclaim is wanted at all. Its `NullLifecycleManager` default means an existing deployment sees no change whatsoever; `TimeoutLifecycleManager` now also enables server-driven reclaim. Any other implementation is left untouched. `ZeppelinConfiguration#getLifecycleManagerClass()` had no caller before this change. An interpreter setting overrides the threshold by carrying the same property name, where `0` or below means never reclaimed. This is opt-in per interpreter: a setting that carries nothing keeps following the global threshold exactly as before, so the JDBC interpreter above is still reclaimed on the global schedule until an operator marks it as exempt. What the change adds is the ability to say it at all. **`TimeoutLifecycleManager` is kept, not replaced.** It still runs in the interpreter process, because that is what shuts a process down if the Zeppelin server itself exits unexpectedly and can no longer reclaim anything. It is handed the same threshold resolved here rather than the global one, so the two sides agree instead of one of them shutting a process down on the wrong schedule. Closing a group twice cannot happen either: if the process shuts itself down it unregisters, which removes the group from `getAllInterpreterGroup()`; if the server closes the group first, the process and its scheduler are gone. That fallback is intentionally given up for one case only - a setting the operator marked as never reclaimed (`0`), whose process receives `Long.MAX_VALUE` and therefore will not self-terminate either. `TimeoutLifecycleManager` has no way to express "never" and would read a threshold of `0` as "shut down at the next check". ### What type of PR is it? Feature ### Todos * [x] - Track last-used time per interpreter group on the server * [x] - Close groups idle beyond the threshold, reusing `ManagedInterpreterGroup.close()` * [x] - Resolve the threshold per interpreter setting, falling back to the global property * [x] - Keep the in-process fallback consistent by pushing the resolved threshold to the process * [x] - Skip groups whose process is still launching * [x] - Unit tests, including guards against probing and against reclaiming a launching group * [x] - Document the per-interpreter threshold in `docs/usage/interpreter/overview.md` and `conf/zeppelin-site.xml.template` ### What is the Jira issue? * [ZEPPELIN-6575](https://issues.apache.org/jira/browse/ZEPPELIN-6575), a sub-task of [ZEPPELIN-6568](https://issues.apache.org/jira/browse/ZEPPELIN-6568) ### How should this be tested? `IdleInterpreterReclaimerTest` (9 tests) covers both directions of the override, the launching guard, the no-probe guard, threshold resolution, and that the default lifecycle manager changes nothing. ```bash export JAVA_HOME=$(/usr/libexec/java_home -v 11) ./mvnw package -pl zeppelin-server --am \ -Dtest=IdleInterpreterReclaimerTest,TimeoutLifecycleManagerTest -DfailIfNoTests=false ``` The two override tests fail before the change, because the per-setting value never reaches the process: ``` perSettingThresholdReclaimsEarlierThanTheGlobalOne the group should be reclaimed after the per setting threshold of 10s ==> expected: <0> but was: <1> perSettingThresholdCanOptOutOfAShortGlobalThreshold the setting opted out of reclaim, so the short global threshold must not apply ==> expected: <1> but was: <0> ``` `aGroupBeingLaunchedIsNotReclaimed` fails without the launching guard, and `scanNeverProbesTheInterpreterProcess` fails if the scan is written with `isAlive()`/`isRunning()`. Local runs, all passing: | Scope | Result | |---|---| | `org.apache.zeppelin.interpreter.**` (19 classes, includes recovery and launcher tests) | pass | | `notebook`, `rest`, `service`, `socket`, `server`, `notebook.repo` (39 classes, 318 tests) | pass | | `TimeoutLifecycleManagerTest` (existing idle reclaim behaviour) | pass, no regression | | `./mvnw clean org.apache.rat:apache-rat-plugin:check -Prat` | `Unapproved: 0` | Manual steps on a running server. This uses two of the lightweight built-in interpreters, `md` (markdown) and `sh` (shell), so that two interpreters run side by side under one server and one global threshold: 1. In `zeppelin-site.xml` set the lifecycle manager class to `TimeoutLifecycleManager`, the global threshold to `10s`, and the check interval to `5s`. 2. On the `md` interpreter setting only, add the threshold property with the value `0` to mark it as never reclaimed. Leave the `sh` setting untouched so that it follows the global 10s. 3. Run one `%md` paragraph and one `%sh` paragraph, then leave the note idle. Each interpreter setting gets its own process, and each process logs the threshold it was handed: ``` logs/zeppelin-interpreter-md-shared_process-*.log TimeoutLifecycleManager is started with checkInterval: 5000, timeoutThreshold: 9223372036854775807 logs/zeppelin-interpreter-sh-shared_process-*.log TimeoutLifecycleManager is started with checkInterval: 5000, timeoutThreshold: 10000 ``` Before this change both processes were handed the global `10000` and both were shut down after 10s of idle time; the `0` on the `md` setting had no effect at all. Now only `sh` is reclaimed, and the server log records why: ``` logs/zeppelin-*.log Reclaiming interpreter group sh-shared_process of interpreter setting sh: idle for 11603ms which exceeds its threshold of 10000ms ``` `ps` confirmed the `sh` process was gone about 15s after its last use, while the `md` process was still running after 33s of idle time. Both processes kept the lifecycle manager class the operator configured; only the threshold they received differed. Not verified locally, left to CI and to deployments that have the runtimes: the docker, k8s and yarn launchers. The reclaim path does not call into a launcher - it neither probes nor launches, only closes - so the exposure is limited to `close()`, which the existing restart endpoint already uses. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No. The two new files carry the ASF header and `apache-rat-plugin:check` reports no unapproved files. * Is there breaking changes for older versions? No. With the default `NullLifecycleManager` nothing is scheduled and no configuration is overridden for the interpreter process, so an untouched deployment behaves exactly as before. * Does this needs documentation? Yes, and it is included. `docs/usage/interpreter/overview.md` gains a "Per interpreter idle threshold" section, and the descriptions in `conf/zeppelin-site.xml.template` are extended. No values in the template were changed. Closes #5358 from big-cir/ZEPPELIN-6575. Signed-off-by: Jongyoul Lee --- conf/zeppelin-site.xml.template | 8 +- docs/usage/interpreter/overview.md | 23 ++ .../zeppelin/conf/ZeppelinConfiguration.java | 48 +++ .../InterpreterSettingManager.java | 11 + .../interpreter/ManagedInterpreterGroup.java | 56 ++- .../lifecycle/IdleInterpreterReclaimer.java | 204 +++++++++++ .../interpreter/remote/RemoteInterpreter.java | 16 + .../remote/RemoteInterpreterProcess.java | 17 +- .../IdleInterpreterReclaimerTest.java | 337 ++++++++++++++++++ 9 files changed, 708 insertions(+), 12 deletions(-) create mode 100644 zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimer.java create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimerTest.java diff --git a/conf/zeppelin-site.xml.template b/conf/zeppelin-site.xml.template index d5e54b91f16..d04aee833e6 100755 --- a/conf/zeppelin-site.xml.template +++ b/conf/zeppelin-site.xml.template @@ -576,7 +576,9 @@ zeppelin.interpreter.lifecyclemanager.class org.apache.zeppelin.interpreter.lifecycle.TimeoutLifecycleManager LifecycleManager class for managing the lifecycle of interpreters, by default interpreter will - be closed after timeout + be closed after timeout. With TimeoutLifecycleManager, Zeppelin server tracks the last use of each + interpreter group and closes the idle ones itself, so the threshold below can be overridden per + interpreter setting @@ -588,7 +590,9 @@ zeppelin.interpreter.lifecyclemanager.timeout.threshold 1h - Interpreter timeout threshold, by default it is 1 hour + Interpreter timeout threshold, by default it is 1 hour. Set the same property on an + individual interpreter setting to override it for that interpreter only, or set it to 0 there to + keep that interpreter from ever being reclaimed --> diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index c664d7ac246..862fb69074c 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -115,6 +115,29 @@ Before 0.8.0, Zeppelin doesn't have lifecycle management for interpreters. Users `NullLifecycleManager` will do nothing, i.e., the user needs to control the lifecycle of interpreter by themselves as before. `TimeoutLifecycleManager` will shut down interpreters after an interpreter remains idle for a while. By default, the idle threshold is 1 hour. Users can change this threshold via the `zeppelin.interpreter.lifecyclemanager.timeout.threshold` setting. `NullLifecycleManager` is the default lifecycle manager, and users can change it via `zeppelin.interpreter.lifecyclemanager.class`. +### Per interpreter idle threshold + +One global threshold is not always enough: a Spark interpreter holding tens of gigabytes of cluster +memory is worth reclaiming quickly, while a JDBC interpreter that only keeps a few connections open +is usually worth keeping. With `TimeoutLifecycleManager` configured, Zeppelin server keeps track of +when each interpreter group was last used and closes the idle ones itself, which lets an individual +interpreter setting override the global value. + +To do so, add `zeppelin.interpreter.lifecyclemanager.timeout.threshold` as a property of that +interpreter on the interpreter setting page, or in `interpreter.json`. The value accepts the same +formats as the global one, i.e. a plain number of milliseconds or a unit suffix such as `10m`: + +| Value on an interpreter setting | Effect on that interpreter | +|---|---| +| not set | the global `zeppelin.interpreter.lifecyclemanager.timeout.threshold` applies | +| `10m` | it is shut down after 10 minutes of idle time, whatever the global value is | +| `0` | it is never shut down for being idle | + +A paragraph that is still running keeps its interpreter alive regardless of the threshold. The check +runs every `zeppelin.interpreter.lifecyclemanager.timeout.checkinterval`, which is shared with the +global behaviour, so an interpreter can be shut down up to one interval after its threshold has +passed. + ## Inline Generic Configuration diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index 179dcce6e85..b2e15160b52 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -780,6 +780,38 @@ public String getLifecycleManagerClass() { return getString(ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_CLASS); } + /** + * Shared with {@code TimeoutLifecycleManager} so that both ways of reclaiming an idle + * interpreter check at the same cadence. + * + * @return interval in milliseconds between two idle checks + */ + public long getInterpreterIdleCheckInterval() { + return getTimeMillis(ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_CHECK_INTERVAL); + } + + /** + * Global idle threshold, which an interpreter setting can override with its own + * {@code zeppelin.interpreter.lifecyclemanager.timeout.threshold} property. + * + * @return threshold in milliseconds + */ + public long getInterpreterIdleTimeoutThreshold() { + return getTimeMillis(ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD); + } + + /** + * Reads a time valued property. {@link #getString(ConfVars)} returns null for a ConfVars + * declared with a numeric default, so the declared default is used when nothing is configured. + */ + private long getTimeMillis(ConfVars c) { + String value = getString(c); + if (StringUtils.isBlank(value)) { + return c.getLongValue(); + } + return parseTimeMillis(value); + } + public boolean getZeppelinImpersonateSparkProxyUser() { return getBoolean(ConfVars.ZEPPELIN_IMPERSONATE_SPARK_PROXY_USER); } @@ -1239,4 +1271,20 @@ public static long timeUnitToMill(String timeStrWithUnit) { return Duration.parse("PT" + timeStrWithUnit).toMillis(); } + /** + * Parses a time value that is either a plain millisecond number or carries a unit suffix, + * e.g. {@code 600000}, {@code 10m} or {@code 500ms}. + * + * @throws NumberFormatException if the value carries no unit and is not a number + * @throws java.time.format.DateTimeParseException if the unit suffix is not understood + */ + public static long parseTimeMillis(String timeStr) { + String trimmed = timeStr.trim(); + try { + return Long.parseLong(trimmed); + } catch (NumberFormatException e) { + return timeUnitToMill(trimmed); + } + } + } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java index 08d11629ba8..8b4c2fe55be 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java @@ -47,6 +47,7 @@ import org.apache.zeppelin.display.AngularObjectRegistryListener; import org.apache.zeppelin.helium.ApplicationEventListener; import org.apache.zeppelin.interpreter.Interpreter.RegisteredInterpreter; +import org.apache.zeppelin.interpreter.lifecycle.IdleInterpreterReclaimer; import org.apache.zeppelin.interpreter.recovery.RecoveryStorage; import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry; import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess; @@ -146,6 +147,7 @@ public class InterpreterSettingManager implements NoteEventListener { private Map jupyterKernelLanguageMap = new HashMap<>(); private List includesInterpreters; private List excludesInterpreters; + private final IdleInterpreterReclaimer idleInterpreterReclaimer; @Inject public InterpreterSettingManager(ZeppelinConfiguration zConf, @@ -206,6 +208,14 @@ public InterpreterSettingManager(ZeppelinConfiguration zConf, this.configStorage = configStorage; init(); + + this.idleInterpreterReclaimer = new IdleInterpreterReclaimer(zConf, this); + this.idleInterpreterReclaimer.start(); + } + + @VisibleForTesting + public IdleInterpreterReclaimer getIdleInterpreterReclaimer() { + return idleInterpreterReclaimer; } public RemoteInterpreterEventServer getInterpreterEventServer() { @@ -1121,6 +1131,7 @@ public void close(String settingId) { } public void close() { + idleInterpreterReclaimer.stop(); List closeThreads = interpreterSettings.values().stream() .map(intpSetting-> new Thread(intpSetting::close, intpSetting.getId() + "-close")) .peek(t -> t.setUncaughtExceptionHandler((th, e) -> diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java index f3f5441319b..3a2f78af895 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/ManagedInterpreterGroup.java @@ -19,6 +19,7 @@ package org.apache.zeppelin.interpreter; import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.interpreter.lifecycle.IdleInterpreterReclaimer; import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess; import org.apache.zeppelin.scheduler.Job; import org.apache.zeppelin.scheduler.Scheduler; @@ -43,6 +44,8 @@ public class ManagedInterpreterGroup extends InterpreterGroup { private RemoteInterpreterProcess remoteInterpreterProcess; // attached remote interpreter process private Object interpreterProcessCreationLock = new Object(); private final ZeppelinConfiguration zConf; + private volatile long lastUsedTimeInMillis = System.currentTimeMillis(); + private volatile boolean launchingInterpreterProcess; /** * Create InterpreterGroup with given id and interpreterSetting, used in ZeppelinServer @@ -64,19 +67,54 @@ public RemoteInterpreterProcess getOrCreateInterpreterProcess(String userName, Properties properties) throws IOException { synchronized (interpreterProcessCreationLock) { - if (remoteInterpreterProcess == null) { - LOGGER.info("Create InterpreterProcess for InterpreterGroup: {}", getId()); - remoteInterpreterProcess = interpreterSetting.createInterpreterProcess(id, userName, - properties); - remoteInterpreterProcess.start(userName); - remoteInterpreterProcess.init(zConf); - getInterpreterSetting().getRecoveryStorage() - .onInterpreterClientStart(remoteInterpreterProcess); + try { + if (remoteInterpreterProcess == null) { + LOGGER.info("Create InterpreterProcess for InterpreterGroup: {}", getId()); + launchingInterpreterProcess = true; + remoteInterpreterProcess = interpreterSetting.createInterpreterProcess(id, userName, + properties); + remoteInterpreterProcess.start(userName); + remoteInterpreterProcess.init(zConf, + IdleInterpreterReclaimer.processConfigurationOverrides(zConf, + interpreterSetting)); + getInterpreterSetting().getRecoveryStorage() + .onInterpreterClientStart(remoteInterpreterProcess); + } + return remoteInterpreterProcess; + } finally { + // Reset the idle clock before dropping the flag, so that this group is never momentarily + // visible as idle with a timestamp from before the launch. + onInterpreterUse(); + launchingInterpreterProcess = false; } - return remoteInterpreterProcess; } } + /** + * A launch takes a while - minutes for Spark on YARN - and counts as activity rather than as + * idle time. + * + * @return whether a process is currently being launched for this group + */ + public boolean isLaunchingInterpreterProcess() { + return launchingInterpreterProcess; + } + + /** + * Records that this group has just been used, so that server side idle reclaim does not consider + * it idle. A single volatile write on purpose: while a paragraph runs this is called on every + * status poll of that paragraph. + * + * @see org.apache.zeppelin.interpreter.lifecycle.IdleInterpreterReclaimer + */ + public void onInterpreterUse() { + lastUsedTimeInMillis = System.currentTimeMillis(); + } + + public long getLastUsedTimeInMillis() { + return lastUsedTimeInMillis; + } + public RemoteInterpreterProcess getInterpreterProcess() { return remoteInterpreterProcess; } diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimer.java new file mode 100644 index 00000000000..ccb48366b45 --- /dev/null +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimer.java @@ -0,0 +1,204 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.interpreter.lifecycle; + +import com.google.common.annotations.VisibleForTesting; + +import org.apache.commons.lang3.StringUtils; +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; +import org.apache.zeppelin.interpreter.InterpreterSetting; +import org.apache.zeppelin.interpreter.InterpreterSettingManager; +import org.apache.zeppelin.interpreter.ManagedInterpreterGroup; +import org.apache.zeppelin.scheduler.ExecutorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +/** + * Closes interpreter groups that have been idle for longer than a threshold, driven by Zeppelin + * server rather than by the interpreter process itself. + * + *

    {@link TimeoutLifecycleManager} does the same thing from inside the interpreter process, where + * the threshold can only arrive through the configuration map pushed over Thrift at startup. That + * map holds {@link ConfVars} entries only, so an interpreter setting property never reaches it and + * every process gets the same global threshold. Deciding here means the threshold of the owning + * interpreter setting can just be read. + * + *

    Follows {@code zeppelin.interpreter.lifecyclemanager.class}, which already says whether idle + * reclaim is wanted: its {@link NullLifecycleManager} default leaves a deployment untouched, and + * {@link TimeoutLifecycleManager} enables this. Any other implementation is left alone. The + * in-process manager stays as a fallback for a server that went away and is given the same resolved + * threshold by {@link #processConfigurationOverrides}. + */ +public class IdleInterpreterReclaimer { + + private static final Logger LOGGER = LoggerFactory.getLogger(IdleInterpreterReclaimer.class); + + private static final String SCHEDULER_NAME = "IdleInterpreterReclaimer"; + + /** + * Threshold property. On an interpreter setting, {@code 0} or below means never reclaimed. + */ + public static final String IDLE_TIMEOUT_THRESHOLD_PROPERTY = + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD.getVarName(); + + private final ZeppelinConfiguration zConf; + private final InterpreterSettingManager interpreterSettingManager; + + private ScheduledExecutorService checkScheduler; + + public IdleInterpreterReclaimer(ZeppelinConfiguration zConf, + InterpreterSettingManager interpreterSettingManager) { + this.zConf = zConf; + this.interpreterSettingManager = interpreterSettingManager; + } + + private static boolean isEnabled(ZeppelinConfiguration zConf) { + return TimeoutLifecycleManager.class.getName().equals(zConf.getLifecycleManagerClass()); + } + + public void start() { + if (!isEnabled(zConf)) { + LOGGER.debug("Server driven idle interpreter reclaim is off, {} is {}", + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_CLASS.getVarName(), + zConf.getLifecycleManagerClass()); + return; + } + long checkInterval = zConf.getInterpreterIdleCheckInterval(); + if (checkInterval <= 0) { + LOGGER.warn("Not starting idle interpreter reclaim: {} must be positive but is {}", + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_CHECK_INTERVAL.getVarName(), + checkInterval); + return; + } + checkScheduler = ExecutorFactory.singleton().createOrGetScheduled(SCHEDULER_NAME, 1); + // Fixed delay rather than fixed rate, so that a slow close does not queue up further checks. + checkScheduler.scheduleWithFixedDelay(this::reclaimIdleInterpreterGroups, + checkInterval, checkInterval, MILLISECONDS); + LOGGER.info("Server driven idle interpreter reclaim started with checkInterval: {}ms, " + + "default threshold: {}ms", checkInterval, zConf.getInterpreterIdleTimeoutThreshold()); + } + + public void stop() { + if (checkScheduler != null) { + ExecutorFactory.singleton().shutdown(SCHEDULER_NAME); + checkScheduler = null; + LOGGER.info("Server driven idle interpreter reclaim stopped"); + } + } + + /** + * Closes every interpreter group idle for longer than the threshold of its interpreter setting. + * Uses in-memory state only: {@code isAlive()} and {@code isRunning()} cost a socket connect for + * docker and a kube-apiserver round trip for k8s, and this walks every group on a timer. + */ + @VisibleForTesting + void reclaimIdleInterpreterGroups() { + long now = System.currentTimeMillis(); + for (ManagedInterpreterGroup interpreterGroup : + interpreterSettingManager.getAllInterpreterGroup()) { + try { + reclaimIfIdle(interpreterGroup, now); + } catch (Exception e) { + LOGGER.error("Fail to reclaim idle interpreter group: {}", interpreterGroup.getId(), e); + } + } + } + + private void reclaimIfIdle(ManagedInterpreterGroup interpreterGroup, long now) { + if (interpreterGroup.isLaunchingInterpreterProcess()) { + // The handle is published before the process is ready, and a launch can outlast the + // threshold, so this would close a process that is starting rather than an idle one. + return; + } + if (interpreterGroup.getInterpreterProcess() == null) { + // Like TimeoutLifecycleManager, only manage a group once its process has started. + return; + } + if (interpreterGroup.isEmpty()) { + // No session left: the group is already on its way out through close(). + return; + } + + InterpreterSetting interpreterSetting = interpreterGroup.getInterpreterSetting(); + long threshold = getIdleTimeoutThreshold(zConf, interpreterSetting); + if (threshold <= 0) { + LOGGER.debug("Interpreter group {} is never reclaimed, its threshold is {}ms", + interpreterGroup.getId(), threshold); + return; + } + + long idleTimeInMillis = now - interpreterGroup.getLastUsedTimeInMillis(); + if (idleTimeInMillis <= threshold) { + return; + } + + LOGGER.info("Reclaiming interpreter group {} of interpreter setting {}: idle for {}ms which " + + "exceeds its threshold of {}ms", interpreterGroup.getId(), + interpreterSetting == null ? "?" : interpreterSetting.getName(), + idleTimeInMillis, threshold); + interpreterGroup.close(); + } + + /** + * @return idle threshold in milliseconds for the given interpreter setting, taking its own + * {@link #IDLE_TIMEOUT_THRESHOLD_PROPERTY} property over the global configuration + */ + @VisibleForTesting + static long getIdleTimeoutThreshold(ZeppelinConfiguration zConf, + InterpreterSetting interpreterSetting) { + if (interpreterSetting != null) { + String override = + interpreterSetting.getJavaProperties().getProperty(IDLE_TIMEOUT_THRESHOLD_PROPERTY); + if (StringUtils.isNotBlank(override)) { + try { + return ZeppelinConfiguration.parseTimeMillis(override); + } catch (RuntimeException e) { + LOGGER.warn("Ignoring unparsable {} of interpreter setting {}: {}", + IDLE_TIMEOUT_THRESHOLD_PROPERTY, interpreterSetting.getName(), override, e); + } + } + } + return zConf.getInterpreterIdleTimeoutThreshold(); + } + + /** + * Gives the in-process {@link TimeoutLifecycleManager} fallback the threshold resolved here + * instead of the global one. A setting that opted out gets {@link Long#MAX_VALUE} rather than its + * own {@code 0}, which {@link TimeoutLifecycleManager} would read as "shut down at the next + * check" since it has no way to express "never". + * + * @return entries to put on top of {@link ZeppelinConfiguration#getCompleteConfiguration()}, + * empty when server driven reclaim is off + */ + public static Map processConfigurationOverrides( + ZeppelinConfiguration zConf, InterpreterSetting interpreterSetting) { + if (!isEnabled(zConf)) { + return Collections.emptyMap(); + } + long threshold = getIdleTimeoutThreshold(zConf, interpreterSetting); + return Collections.singletonMap(IDLE_TIMEOUT_THRESHOLD_PROPERTY, + String.valueOf(threshold <= 0 ? Long.MAX_VALUE : threshold)); + } +} diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java index 6bd2e202325..efa9ea99a02 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java @@ -111,6 +111,19 @@ public ManagedInterpreterGroup getInterpreterGroup() { return (ManagedInterpreterGroup) super.getInterpreterGroup(); } + /** + * Mirrors the {@code onInterpreterUse} hooks that {@code RemoteInterpreterServer} calls inside + * the interpreter process, so that server driven idle reclaim sees the same activity signal. + * Needed explicitly because {@link #getOrCreateInterpreterProcess()} returns the cached handle + * without going through the interpreter group once the process exists. + */ + private void markInterpreterGroupUsed() { + ManagedInterpreterGroup intpGroup = getInterpreterGroup(); + if (intpGroup != null) { + intpGroup.onInterpreterUse(); + } + } + @Override public void open() throws InterpreterException { synchronized (this) { @@ -194,6 +207,7 @@ public InterpreterResult interpret(final String st, final InterpreterContext con if (LOGGER.isDebugEnabled()) { LOGGER.debug("st:\n{}", st); } + markInterpreterGroupUsed(); final FormType form = getFormType(); RemoteInterpreterProcess interpreterProcess = null; @@ -292,6 +306,7 @@ public int getProgress(final InterpreterContext context) throws InterpreterExcep LOGGER.warn("getProgress is called when RemoterInterpreter is not opened for {}", className); return 0; } + markInterpreterGroupUsed(); RemoteInterpreterProcess interpreterProcess = null; try { interpreterProcess = getOrCreateInterpreterProcess(); @@ -325,6 +340,7 @@ public String getStatus(final String jobId) { LOGGER.warn("getStatus is called when RemoteInterpreter is not opened for {}", className); return Job.Status.UNKNOWN.name(); } + markInterpreterGroupUsed(); RemoteInterpreterProcess interpreterProcess = null; try { interpreterProcess = getOrCreateInterpreterProcess(); diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java index 95802a64fe7..e994439c890 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreterProcess.java @@ -29,7 +29,10 @@ import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.Map; /** * Abstract class for interpreter process @@ -101,8 +104,20 @@ public R callRemoteFunction(PooledRemoteClient.RemoteFunction fun } public void init(ZeppelinConfiguration zConf) { + init(zConf, Collections.emptyMap()); + } + + /** + * Pushes the server configuration into the interpreter process. + * + * @param overrides entries to put on top of the global configuration, for settings that are + * resolved per interpreter setting rather than globally + */ + public void init(ZeppelinConfiguration zConf, Map overrides) { + Map properties = new HashMap<>(zConf.getCompleteConfiguration()); + properties.putAll(overrides); callRemoteFunction(client -> { - client.init(zConf.getCompleteConfiguration()); + client.init(properties); return null; }); } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimerTest.java new file mode 100644 index 00000000000..877b834b04c --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/interpreter/lifecycle/IdleInterpreterReclaimerTest.java @@ -0,0 +1,337 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.interpreter.lifecycle; + +import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; +import org.apache.zeppelin.interpreter.AbstractInterpreterTest; +import org.apache.zeppelin.interpreter.ExecutionContext; +import org.apache.zeppelin.interpreter.InterpreterSetting; +import org.apache.zeppelin.interpreter.InterpreterSettingManager; +import org.apache.zeppelin.interpreter.ManagedInterpreterGroup; +import org.apache.zeppelin.interpreter.remote.RemoteInterpreter; +import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess; +import org.apache.zeppelin.scheduler.Job; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.Map; +import java.util.Properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Tests server driven idle reclaim, above all that an interpreter setting can override the global + * threshold in either direction. That override is what the interpreter process side + * {@link TimeoutLifecycleManager} cannot offer, because its threshold only reaches the process + * through the global configuration map. + */ +class IdleInterpreterReclaimerTest extends AbstractInterpreterTest { + + private static final String THRESHOLD_PROPERTY = + IdleInterpreterReclaimer.IDLE_TIMEOUT_THRESHOLD_PROPERTY; + + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + zConf.setProperty(ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_CLASS.getVarName(), + TimeoutLifecycleManager.class.getName()); + zConf.setProperty( + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_CHECK_INTERVAL.getVarName(), + "1000"); + // The reclaimer picks these up when it starts, and that already happened while + // super.setUp() built the InterpreterSettingManager, so restart it. + interpreterSettingManager.getIdleInterpreterReclaimer().stop(); + interpreterSettingManager.getIdleInterpreterReclaimer().start(); + } + + /** + * A setting may ask to be reclaimed sooner than the global threshold allows. The global + * threshold stays at its 1h default here, so only the per setting value of 10s can close it. + */ + @Test + void perSettingThresholdReclaimsEarlierThanTheGlobalOne() throws Exception { + InterpreterSetting interpreterSetting = + interpreterSettingManager.getInterpreterSettingByName("test"); + interpreterSetting.setProperty(THRESHOLD_PROPERTY, "10s"); + + startEchoInterpreter(); + assertEquals(1, interpreterSetting.getAllInterpreterGroups().size()); + + waitForInterpreterGroups(interpreterSetting, 0, 40); + assertEquals(0, interpreterSetting.getAllInterpreterGroups().size(), + "the group should be reclaimed after the per setting threshold of 10s"); + } + + /** + * The other direction: a non positive per setting threshold means keep it, whatever the short + * global threshold says. + */ + @Test + void perSettingThresholdCanOptOutOfAShortGlobalThreshold() throws Exception { + zConf.setProperty( + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD.getVarName(), "5s"); + + InterpreterSetting interpreterSetting = + interpreterSettingManager.getInterpreterSettingByName("test"); + interpreterSetting.setProperty(THRESHOLD_PROPERTY, "0"); + + startEchoInterpreter(); + assertEquals(1, interpreterSetting.getAllInterpreterGroups().size()); + + Thread.sleep(20 * 1000); + assertEquals(1, interpreterSetting.getAllInterpreterGroups().size(), + "the setting opted out of reclaim, so the short global threshold must not apply"); + } + + @Test + void globalThresholdAppliesWhenTheSettingDoesNotOverrideIt() throws Exception { + zConf.setProperty( + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD.getVarName(), "10s"); + + InterpreterSetting interpreterSetting = + interpreterSettingManager.getInterpreterSettingByName("test"); + + startEchoInterpreter(); + assertEquals(1, interpreterSetting.getAllInterpreterGroups().size()); + + waitForInterpreterGroups(interpreterSetting, 0, 40); + assertEquals(0, interpreterSetting.getAllInterpreterGroups().size()); + } + + /** + * A paragraph running for longer than the threshold must not have its interpreter pulled out + * from under it. While a job runs the server polls its status, which counts as use. + */ + @Test + void aRunningParagraphKeepsItsInterpreterAlive() throws Exception { + zConf.setProperty( + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD.getVarName(), "5s"); + + InterpreterSetting interpreterSetting = + interpreterSettingManager.getInterpreterSettingByName("test"); + final RemoteInterpreter sleepInterpreter = + (RemoteInterpreter) interpreterFactory.getInterpreter("test.sleep", + new ExecutionContext("user1", "note1", "test")); + + // Submit through the scheduler the way Zeppelin submits a paragraph, so that the job status + // poller runs. + sleepInterpreter.getScheduler().submit(new Job("test-job", null) { + @Override + public Object getReturn() { + return null; + } + + @Override + public int progress() { + return 0; + } + + @Override + public Map info() { + return null; + } + + @Override + protected Object jobRun() throws Throwable { + return sleepInterpreter.interpret("30000", createDummyInterpreterContext()); + } + + @Override + protected boolean jobAbort() { + return false; + } + + @Override + public void setResult(Object results) { + } + }); + + long deadline = System.currentTimeMillis() + 30 * 1000; + while (!sleepInterpreter.isOpened() && System.currentTimeMillis() < deadline) { + Thread.sleep(500); + } + assertTrue(sleepInterpreter.isOpened(), "interpreter did not start"); + assertEquals(1, interpreterSetting.getAllInterpreterGroups().size()); + + Thread.sleep(20 * 1000); + assertEquals(1, interpreterSetting.getAllInterpreterGroups().size(), + "a running paragraph must keep its interpreter group alive"); + } + + /** + * A probe is cheap for the local launcher but not for docker or k8s, and this scan walks every + * group on a timer. + */ + @Test + void scanNeverProbesTheInterpreterProcess() { + RemoteInterpreterProcess process = mock(RemoteInterpreterProcess.class); + + InterpreterSetting interpreterSetting = mock(InterpreterSetting.class); + when(interpreterSetting.getName()).thenReturn("probe-guard"); + when(interpreterSetting.getJavaProperties()).thenReturn(new Properties()); + + ManagedInterpreterGroup interpreterGroup = mock(ManagedInterpreterGroup.class); + when(interpreterGroup.getId()).thenReturn("probe-guard-shared_process"); + when(interpreterGroup.getInterpreterProcess()).thenReturn(process); + when(interpreterGroup.getInterpreterSetting()).thenReturn(interpreterSetting); + when(interpreterGroup.isEmpty()).thenReturn(false); + // Idle since the epoch, so it is well past any threshold and does get closed. + when(interpreterGroup.getLastUsedTimeInMillis()).thenReturn(0L); + + InterpreterSettingManager settingManager = mock(InterpreterSettingManager.class); + when(settingManager.getAllInterpreterGroup()) + .thenReturn(Collections.singletonList(interpreterGroup)); + + new IdleInterpreterReclaimer(zConf, settingManager).reclaimIdleInterpreterGroups(); + + verify(interpreterGroup).close(); + verify(process, never()).isAlive(); + verify(process, never()).isRunning(); + } + + /** + * The handle is published before the process is ready and the group has been idle since it was + * created, so without the launching check the scan closes a process that is starting up. + */ + @Test + void aGroupBeingLaunchedIsNotReclaimed() { + ManagedInterpreterGroup interpreterGroup = mock(ManagedInterpreterGroup.class); + when(interpreterGroup.getId()).thenReturn("launching-shared_process"); + when(interpreterGroup.isLaunchingInterpreterProcess()).thenReturn(true); + when(interpreterGroup.getInterpreterProcess()) + .thenReturn(mock(RemoteInterpreterProcess.class)); + when(interpreterGroup.isEmpty()).thenReturn(false); + when(interpreterGroup.getLastUsedTimeInMillis()).thenReturn(0L); + + InterpreterSettingManager settingManager = mock(InterpreterSettingManager.class); + when(settingManager.getAllInterpreterGroup()) + .thenReturn(Collections.singletonList(interpreterGroup)); + + new IdleInterpreterReclaimer(zConf, settingManager).reclaimIdleInterpreterGroups(); + + verify(interpreterGroup, never()).close(); + } + + @Test + void thresholdResolutionPrefersTheSettingAndFallsBackOnGarbage() { + zConf.setProperty( + ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_TIMEOUT_THRESHOLD.getVarName(), "1h"); + + assertEquals(3600000L, IdleInterpreterReclaimer.getIdleTimeoutThreshold(zConf, null), + "no setting at all means the global threshold"); + + InterpreterSetting interpreterSetting = mock(InterpreterSetting.class); + when(interpreterSetting.getName()).thenReturn("threshold-resolution"); + + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties(null)); + assertEquals(3600000L, + IdleInterpreterReclaimer.getIdleTimeoutThreshold(zConf, interpreterSetting), + "no override means the global threshold"); + + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("10s")); + assertEquals(10000L, + IdleInterpreterReclaimer.getIdleTimeoutThreshold(zConf, interpreterSetting)); + + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("600000")); + assertEquals(600000L, + IdleInterpreterReclaimer.getIdleTimeoutThreshold(zConf, interpreterSetting), + "a plain number is milliseconds"); + + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("0")); + assertEquals(0L, + IdleInterpreterReclaimer.getIdleTimeoutThreshold(zConf, interpreterSetting), + "zero opts the setting out of reclaim"); + + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("not-a-duration")); + assertEquals(3600000L, + IdleInterpreterReclaimer.getIdleTimeoutThreshold(zConf, interpreterSetting), + "an unparsable override must fall back to the global threshold"); + } + + /** + * A setting that opted out must not be shut down by the in-process fallback either. Its own + * {@code 0} would mean "shut down at the next check" there, so it never reaches the process. + */ + @Test + void optingOutDisablesTheInProcessFallbackToo() { + InterpreterSetting interpreterSetting = mock(InterpreterSetting.class); + when(interpreterSetting.getName()).thenReturn("opt-out"); + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("0")); + + Map overrides = + IdleInterpreterReclaimer.processConfigurationOverrides(zConf, interpreterSetting); + assertEquals(String.valueOf(Long.MAX_VALUE), overrides.get(THRESHOLD_PROPERTY)); + assertNull(overrides.get(ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_CLASS.getVarName()), + "the lifecycle manager the operator configured must be left alone"); + + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("10s")); + overrides = IdleInterpreterReclaimer.processConfigurationOverrides(zConf, interpreterSetting); + assertEquals("10000", overrides.get(THRESHOLD_PROPERTY), + "the process gets the resolved threshold, not the global one"); + } + + /** + * With the default lifecycle manager nothing is reclaimed and nothing is overridden, so an + * existing deployment is untouched. + */ + @Test + void defaultLifecycleManagerLeavesEverythingAlone() { + zConf.setProperty(ConfVars.ZEPPELIN_INTERPRETER_LIFECYCLE_MANAGER_CLASS.getVarName(), + NullLifecycleManager.class.getName()); + + InterpreterSetting interpreterSetting = mock(InterpreterSetting.class); + when(interpreterSetting.getJavaProperties()).thenReturn(thresholdProperties("10s")); + + assertTrue(IdleInterpreterReclaimer.processConfigurationOverrides(zConf, interpreterSetting) + .isEmpty()); + } + + private Properties thresholdProperties(String threshold) { + Properties properties = new Properties(); + if (threshold != null) { + properties.setProperty(THRESHOLD_PROPERTY, threshold); + } + return properties; + } + + private void startEchoInterpreter() throws Exception { + RemoteInterpreter echoInterpreter = + (RemoteInterpreter) interpreterFactory.getInterpreter("test.echo", + new ExecutionContext("user1", "note1", "test")); + echoInterpreter.interpret("hello", createDummyInterpreterContext()); + assertTrue(echoInterpreter.isOpened()); + } + + private void waitForInterpreterGroups(InterpreterSetting interpreterSetting, + int expectedSize, + int maxSeconds) throws Exception { + long deadline = System.currentTimeMillis() + maxSeconds * 1000L; + while (interpreterSetting.getAllInterpreterGroups().size() != expectedSize + && System.currentTimeMillis() < deadline) { + Thread.sleep(1000); + } + } +} From 2892d46258c58cafc22767d0e27dfd30da8fd9e5 Mon Sep 17 00:00:00 2001 From: chaeyoung kim <152389483+chelsseeey@users.noreply.github.com> Date: Mon, 10 Aug 2026 10:26:38 +0900 Subject: [PATCH 166/179] [ZEPPELIN-6628] Add an internal-link check to the docs build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? Adds a CI job that builds the Jekyll site under `docs/` and validates its internal links with html-proofer, and fixes the broken links that turning the check on exposes. The docs link to each other with relative paths, and nothing validates them today. No workflow builds the site at all, so a wrong path passes `quick`, `core` and `frontend` alike and only surfaces once the site is published. Three such links exist on master. `JB.BASE_PATH` has to be accounted for. Template links are rendered with that prefix (`/docs/0.13.0-SNAPSHOT/...`), which exists only on the published site, so an unadjusted run reports every templated link as broken — 322 internal links, all of them failing. The job reads `BASE_PATH` out of `_config.yml` and strips it with `--swap-urls`, so links resolve against the built tree and a version bump does not silently break the job. Scope is deliberately narrow: `--disable-external` skips external URLs and `--no-check-internal-hash` skips anchor fragments, both of which fail for reasons outside this repository and would make the job flaky. `--allow-missing-href` keeps the `` anchors the docs use as link targets from being reported as errors. The job is report-only for now (`continue-on-error: true`), as the issue asks. Broken links show up in the log without blocking a merge; the comment in the workflow says when to drop that. The change has two parts. **Fix the broken internal links** - `docs/setup/operation/configuration.md` — raw HTML link, one `../` short. From `/setup/operation/` it resolved to `/setup/usage/other_features/customizing_homepage.html`; the page is at `/usage/...`. - `docs/setup/deployment/yarn_install.md` — `install.html` resolved to `/setup/deployment/install.html`; the install guide is at `/quickstart/install.html`. Matches how `upgrading.md` and `flink_and_spark_cluster.md` already link it. - `docs/development/helium/writing_spell.md` — the URL is wrapped in literal quotes inside the markdown link, so it renders as `href="%22https://www.npmjs.com/%22"`. Not mentioned on the Jira issue, but master does not pass the check without it. **Add the check** New `.github/workflows/docs.yml`, triggered only on changes under `docs/**` and on the workflow itself. ### What type of PR is it? Improvement ### Todos None. Dropping `continue-on-error` is deliberately left for a follow-up, as the issue asks; the workflow carries a comment saying so. ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6628 ### How should this be tested? The new job runs on this PR, since it touches `docs/**`. Locally, using the container from `docs/README.md`: ```bash docker run --rm -v "$PWD/docs:/docs" -w /docs ruby:3.3.5 bash -c ' bundle install && bundle exec jekyll build --safe -d _site && gem install html-proofer -v 5.2.2 --no-document && BASE_PATH=$(ruby -ryaml -e '"'"'puts(YAML.load_file("_config.yml")["JB"]["BASE_PATH"] || "")'"'"') && htmlproofer _site --root-dir _site --checks Links --disable-external \ --no-enforce-https --no-check-internal-hash --allow-missing-href \ --swap-urls "^${BASE_PATH}:"' ``` On master, this reports the three failures above. With this PR applied it reports none: ``` Checking 321 internal links Ran on 94 files! HTML-Proofer finished successfully. ``` Reverting any one of the three link fixes brings back that failure, and only that one, which confirms the check detects each of them. ### Screenshots (if appropriate) No ### Questions: * Does the license files need to update? No. No new dependency ships with the site — html-proofer is installed in the CI job only, and `docs/Gemfile` is untouched. The one new file lives under `.github/`, which the rat profile excludes; `./mvnw apache-rat:check -Prat` passes. * Is there breaking changes for older versions? No. Documentation and CI only. * Does this needs documentation? No. Closes #5395 from chelsseeey/ZEPPELIN-6628-docs-internal-link-check. Signed-off-by: Jongyoul Lee --- .github/workflows/docs.yml | 62 ++++++++++++++++++++++++ docs/development/helium/writing_spell.md | 2 +- docs/setup/deployment/yarn_install.md | 2 +- docs/setup/operation/configuration.md | 2 +- 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000000..f9d77459a74 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,62 @@ +name: docs + +on: + push: + branches-ignore: + - 'dependabot/**' + paths: + - 'docs/**' + - '.github/workflows/docs.yml' + pull_request: + branches: + - master + - 'branch-*' + paths: + - 'docs/**' + - '.github/workflows/docs.yml' + +permissions: + contents: read + +jobs: + internal-link-check: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v5 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3' + bundler-cache: true + working-directory: docs + - name: Build the Jekyll site + working-directory: docs + run: bundle exec jekyll build --safe -d _site + - name: Check internal links + working-directory: docs + # Report-only: broken links are printed in the log but do not fail the + # build yet. Remove this once the job has been green for a while, so + # that broken links start blocking merges (ZEPPELIN-6628). + continue-on-error: true + run: | + gem install html-proofer -v 5.2.2 --no-document + # Template links are prefixed with JB.BASE_PATH (e.g. + # /docs/0.13.0-SNAPSHOT), a prefix that only exists once the site is + # published. Strip it so links resolve against the built tree. Read it + # from _config.yml so a version bump does not break this job. + BASE_PATH=$(ruby -ryaml -e 'puts(YAML.load_file("_config.yml")["JB"]["BASE_PATH"] || "")') + echo "Stripping BASE_PATH prefix: ${BASE_PATH}" + # Only internal links are in scope. External URLs are skipped because + # they break for reasons outside this repository and would make the + # job flaky; anchor fragments are skipped for the same reason. The + # --allow-missing-href flag keeps `` anchors, which the + # docs use as link targets, from being reported as errors. + htmlproofer _site \ + --root-dir _site \ + --checks Links \ + --disable-external \ + --no-enforce-https \ + --no-check-internal-hash \ + --allow-missing-href \ + --swap-urls "^${BASE_PATH}:" diff --git a/docs/development/helium/writing_spell.md b/docs/development/helium/writing_spell.md index e781a98243c..b2988a90ae4 100644 --- a/docs/development/helium/writing_spell.md +++ b/docs/development/helium/writing_spell.md @@ -63,7 +63,7 @@ Making a new spell is similar to [Helium Visualization#write-new-visualization]( - Add framework dependency called zeppelin-spell into `package.json` - Write code using framework -- Publish your spell to [npm]("https://www.npmjs.com/") +- Publish your spell to [npm](https://www.npmjs.com/) ### 1. Create a npm package diff --git a/docs/setup/deployment/yarn_install.md b/docs/setup/deployment/yarn_install.md index 994180126e3..4c7e87bf599 100644 --- a/docs/setup/deployment/yarn_install.md +++ b/docs/setup/deployment/yarn_install.md @@ -76,7 +76,7 @@ This document assumes Spark 1.6.0 is installed at /usr/lib/spark. #### Zeppelin Checkout source code from [git://git.apache.org/zeppelin.git](https://github.com/apache/zeppelin.git) or download binary package from [Download page](https://zeppelin.apache.org/download.html). -You can refer [Install](install.html) page for the details. +You can refer [Install](../../quickstart/install.html) page for the details. This document assumes that Zeppelin is located under `/home/zeppelin/zeppelin`. ## Zeppelin Configuration diff --git a/docs/setup/operation/configuration.md b/docs/setup/operation/configuration.md index 9588cd25a5b..0a53f5179ee 100644 --- a/docs/setup/operation/configuration.md +++ b/docs/setup/operation/configuration.md @@ -236,7 +236,7 @@ Sources descending by priority:
    ZEPPELIN_NOTEBOOK_HOMESCREEN_HIDE
    zeppelin.notebook.homescreen.hide
    false - Hide the note ID set by ZEPPELIN_NOTEBOOK_HOMESCREEN on the Apache Zeppelin homescreen.
    For the further information, please read
    Customize your Zeppelin homepage. + Hide the note ID set by ZEPPELIN_NOTEBOOK_HOMESCREEN on the Apache Zeppelin homescreen.
    For the further information, please read Customize your Zeppelin homepage.
    ZEPPELIN_WAR_TEMPDIR
    From 0e72120aaecaa13993b862fbd8b714cc6e5e2b54 Mon Sep 17 00:00:00 2001 From: HwangRock <157935545+HwangRock@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:55:20 +0900 Subject: [PATCH 167/179] [ZEPPELIN-5858] Fix moveNote/saveNote race that duplicates notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `moveNote` mutates the folder tree, the `notesInfo` mapping and the notebook repo without holding any lock, while `saveNote` derives its target file name from the path carried by the `Note` object at save time. A save racing with a move therefore writes the note back to its pre-move path, and the same noteId ends up on disk twice. ZEPPELIN-5858 describes exactly this and ships a reproduction; this PR ports that reproduction onto the current API and fixes the race. Reproduced on current master with the ported test (`VFSNotebookRepoWithDelay` extends `VFSNotebookRepo` and injects repo latency, e.g. remote storage): ``` Saving note 2MXKZT37A to folder_1/note_2MXKZT37A.zpln Move note 2MXKZT37A to /folder_2/note Move note 2MXKZT37A from /folder_1/note to /folder_2/note Saving note 2MXKZT37A to folder_1/note_2MXKZT37A.zpln <- stale path, resurrects the old file Expected exactly one .zpln file, but found: [folder_2/note_2MXKZT37A.zpln, folder_1/note_2MXKZT37A.zpln] ``` The fix serializes NoteManager's persistent mutations: `moveNote`, `removeNote` and `moveFolder` now run their tree, mapping and repo mutations inside the monitor `saveNote` already synchronizes on. Save callers and `moveNote` share the cached `Note` instance, so a save that loses the monitor to a concurrent move derives its file name from the already-updated path once it enters — no note is written to its pre-move location. `saveNote`'s existing contract (the `Note` object's path is authoritative; `addOrUpdateNoteNode` syncs the mapping to it) is deliberately left untouched, since rename-by-save flows like `Notebook.updateNote` and note import depend on it. Two deliberate details: - The fixed lock order in this code base is note `readLock` -> NoteManager monitor, because every save caller runs inside `processNote` holding the note's readLock. `moveNote` therefore updates the cached note path directly via the note cache instead of calling `processNote` while holding the monitor, and the rename-triggered resave stays outside the monitor and reuses `saveNote`. This keeps the lock order consistent on every path. - The rename-triggered resave realigns the reloaded note with the move target before saving: a note evicted from the cache is reloaded from disk at that point, and the on-disk JSON still carries the pre-move name. Verified the causality both ways: the reproduction test fails with two `.zpln` files for the same noteId on master, passes with this change, and fails again if only the `NoteManager` change is reverted. ### What type of PR is it? Bug Fix ### Todos * [x] Port the reproduction attached to ZEPPELIN-5858 onto the current NotebookRepo API * [x] Serialize NoteManager mutations ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-5858 ### How should this be tested? `mvn test -pl zeppelin-server -Dtest=NotebookServiceRaceConditionTest` — the test runs `renameNote` and `insertParagraph` concurrently against a delay-injecting `VFSNotebookRepo` subclass, then walks the notebook directory and asserts exactly one `.zpln` file remains. Without the `NoteManager` change it finds the same noteId at both the old and the new path. Regression: `NoteManagerTest`, `NotebookServiceTest`, `NotebookTest`, `LuceneSearchTest`, `ZeppelinRestApiTest` (86 tests) all pass. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5325 from HwangRock/ZEPPELIN-5858. Signed-off-by: ChanHo Lee --- .../apache/zeppelin/notebook/NoteManager.java | 119 ++++++----- .../NoteManagerMoveResaveRaceTest.java | 196 ++++++++++++++++++ .../repo/VFSNotebookRepoWithDelay.java | 82 ++++++++ .../repo/VFSNotebookRepoWithGetGate.java | 86 ++++++++ .../NotebookServiceRaceConditionTest.java | 164 +++++++++++++++ 5 files changed, 596 insertions(+), 51 deletions(-) create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerMoveResaveRaceTest.java create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithDelay.java create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithGetGate.java create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceRaceConditionTest.java diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java index 0635fde994c..c31cad72b8c 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/NoteManager.java @@ -187,11 +187,9 @@ public void saveNote(Note note, AuthenticationInfo subject) throws IOException { if (note.isRemoved()) { LOGGER.warn("Try to save note: {} when it is removed", note.getId()); } else { - addOrUpdateNoteNode(this.noteTree, new NoteInfo(note), false); - noteCache.putNote(note); - // Make sure to execute `notebookRepo.save()` successfully in concurrent context - // Otherwise, the NullPointerException will be thrown when invoking notebookRepo.get() in the following operations. synchronized (this) { + addOrUpdateNoteNode(this.noteTree, new NoteInfo(note), false); + noteCache.putNote(note); this.notebookRepo.save(note, subject); } } @@ -220,12 +218,14 @@ public void saveNote(Note note) throws IOException { * @throws IOException */ public void removeNote(String noteId, AuthenticationInfo subject) throws IOException { - NoteTree tree = this.noteTree; - String notePath = tree.notesInfo.remove(noteId); - Folder folder = getOrCreateFolder(tree, getFolderName(notePath)); - folder.removeNote(getNoteName(notePath)); - noteCache.removeNote(noteId); - this.notebookRepo.remove(noteId, notePath, subject); + synchronized (this) { + NoteTree tree = this.noteTree; + String notePath = tree.notesInfo.remove(noteId); + Folder folder = getOrCreateFolder(tree, getFolderName(notePath)); + folder.removeNote(getNoteName(notePath)); + noteCache.removeNote(noteId); + this.notebookRepo.remove(noteId, notePath, subject); + } } public void moveNote(String noteId, @@ -235,33 +235,37 @@ public void moveNote(String noteId, throw new IOException("No metadata found for this note: " + noteId); } - NoteTree tree = this.noteTree; - if (!isNotePathAvailable(tree, newNotePath)) { - throw new NotePathAlreadyExistsException("Note '" + newNotePath + "' existed"); - } - - // move the old NoteNode from notePath to newNotePath - String notePath = tree.notesInfo.get(noteId); - NoteNode noteNode = getNoteNode(tree, notePath); - noteNode.getParent().removeNote(getNoteName(notePath)); - noteNode.setNotePath(newNotePath); - String newParent = getFolderName(newNotePath); - Folder newFolder = getOrCreateFolder(tree, newParent); - newFolder.addNoteNode(noteNode); - - // update noteInfo mapping - tree.notesInfo.put(noteId, newNotePath); - - // update notebookrepo - this.notebookRepo.move(noteId, notePath, newNotePath, subject); + String notePath; + synchronized (this) { + NoteTree tree = this.noteTree; + if (!isNotePathAvailable(tree, newNotePath)) { + throw new NotePathAlreadyExistsException("Note '" + newNotePath + "' existed"); + } - // Update path of the note - if (!StringUtils.equals(notePath, newNotePath)) { - processNote(noteId, - note -> { - note.setPath(newNotePath); - return null; - }); + // move the old NoteNode from notePath to newNotePath + notePath = tree.notesInfo.get(noteId); + NoteNode noteNode = getNoteNode(tree, notePath); + noteNode.getParent().removeNote(getNoteName(notePath)); + noteNode.setNotePath(newNotePath); + String newParent = getFolderName(newNotePath); + Folder newFolder = getOrCreateFolder(tree, newParent); + newFolder.addNoteNode(noteNode); + + // update noteInfo mapping + tree.notesInfo.put(noteId, newNotePath); + + // update notebookrepo + this.notebookRepo.move(noteId, notePath, newNotePath, subject); + + // Update path of the note. Access the cache directly to avoid the readLock and the + // disk load that processNote would add while we hold this monitor. The reverse edge + // via noteCache.putNote() -> LRU eviction is safe: NoteCache only ever tryLock()s. + if (!StringUtils.equals(notePath, newNotePath)) { + Note cachedNote = noteCache.getNote(noteId); + if (cachedNote != null) { + cachedNote.setPath(newNotePath); + } + } } // save note if note name is changed, because we need to update the note field in note json. @@ -270,7 +274,19 @@ public void moveNote(String noteId, if (!StringUtils.equals(oldNoteName, newNoteName)) { processNote(noteId, note -> { - this.notebookRepo.save(note, subject); + // null when the noteId already left the mapping, e.g. a concurrent remove. + if (note == null) { + return null; + } + // newNotePath was fixed at method entry, so re-read the current path and save + // it under the same monitor to keep a concurrent move out of the gap. + synchronized (this) { + String currentPath = this.noteTree.notesInfo.get(noteId); + if (currentPath != null) { + note.setPath(currentPath); + saveNote(note, subject); + } + } return null; }); } @@ -279,20 +295,21 @@ public void moveNote(String noteId, public void moveFolder(String folderPath, String newFolderPath, AuthenticationInfo subject) throws IOException { - - // update notebookrepo - this.notebookRepo.move(folderPath, newFolderPath, subject); - - // update filesystem tree - NoteTree tree = this.noteTree; - Folder folder = getFolder(tree, folderPath); - folder.getParent().removeFolder(folder.getName(), subject); - Folder newFolder = getOrCreateFolder(tree, newFolderPath); - newFolder.getParent().addFolder(newFolder.getName(), folder); - - // update notesInfo - for (NoteInfo noteInfo : folder.getNoteInfoRecursively()) { - tree.notesInfo.put(noteInfo.getId(), noteInfo.getPath()); + synchronized (this) { + // update notebookrepo + this.notebookRepo.move(folderPath, newFolderPath, subject); + + // update filesystem tree + NoteTree tree = this.noteTree; + Folder folder = getFolder(tree, folderPath); + folder.getParent().removeFolder(folder.getName(), subject); + Folder newFolder = getOrCreateFolder(tree, newFolderPath); + newFolder.getParent().addFolder(newFolder.getName(), folder); + + // update notesInfo + for (NoteInfo noteInfo : folder.getNoteInfoRecursively()) { + tree.notesInfo.put(noteInfo.getId(), noteInfo.getPath()); + } } } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerMoveResaveRaceTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerMoveResaveRaceTest.java new file mode 100644 index 00000000000..36e05fac336 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/NoteManagerMoveResaveRaceTest.java @@ -0,0 +1,196 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.notebook; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; +import org.apache.zeppelin.interpreter.InterpreterFactory; +import org.apache.zeppelin.interpreter.InterpreterSettingManager; +import org.apache.zeppelin.notebook.repo.NotebookRepo; +import org.apache.zeppelin.notebook.repo.VFSNotebookRepoWithGetGate; +import org.apache.zeppelin.storage.ConfigStorage; +import org.apache.zeppelin.user.AuthenticationInfo; +import org.apache.zeppelin.user.Credentials; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Reproduction test for ZEPPELIN-5858. {@link NoteManager#moveNote} only re-saves a note (to + * refresh the {@code path} field baked into its JSON) when the move changes the note's leaf + * name, and it re-saves using the destination path that was passed into that specific + * {@code moveNote} call, captured before the (possibly slow) reload from {@link NotebookRepo}. + * If a second {@code moveNote} call for the same note (with the same leaf name, so it takes no + * re-save path of its own) completes while the first call is still reloading the note, the + * first call resumes and saves the note back at its own, now-stale destination path -- leaving + * behind two {@code .zpln} files for the same noteId. + * + *

    The scenario is pinned deterministically with {@link VFSNotebookRepoWithGetGate}, which + * parks the reloading {@code get()} call after it has read the note from disk, and with the + * note cache threshold lowered to 1 (evicting the target note via a filler note) so the reload + * actually happens. + */ +class NoteManagerMoveResaveRaceTest { + + private static final String DEFAULT_INTERPRETER_GROUP = "test"; + private static final long JOIN_TIMEOUT_MILLIS = 30_000L; + private static final long GATE_ARRIVAL_TIMEOUT_SECONDS = 30L; + + private File notebookDir; + private Notebook notebook; + private NoteManager noteManager; + private VFSNotebookRepoWithGetGate notebookRepo; + + @BeforeEach + void setUp() throws Exception { + notebookDir = Files.createTempDirectory("notebookDir").toAbsolutePath().toFile(); + ZeppelinConfiguration zConf = ZeppelinConfiguration.load(); + zConf.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_NOTEBOOK_DIR.getVarName(), + notebookDir.getAbsolutePath()); + // Must be set before NoteManager is constructed, since NoteCache reads the threshold once + // at construction time. + zConf.setProperty(ConfVars.ZEPPELIN_NOTE_CACHE_THRESHOLD.getVarName(), "1"); + + NoteParser noteParser = new GsonNoteParser(zConf); + ConfigStorage storage = ConfigStorage.createConfigStorage(zConf); + notebookRepo = new VFSNotebookRepoWithGetGate(); + notebookRepo.init(zConf, noteParser); + + InterpreterSettingManager mockInterpreterSettingManager = mock(InterpreterSettingManager.class); + InterpreterFactory mockInterpreterFactory = mock(InterpreterFactory.class); + Credentials credentials = new Credentials(); + noteManager = new NoteManager(notebookRepo, zConf); + AuthorizationService authorizationService = + new AuthorizationService(noteManager, zConf, storage); + notebook = + new Notebook( + zConf, + authorizationService, + notebookRepo, + noteManager, + mockInterpreterFactory, + mockInterpreterSettingManager, + credentials, + null); + notebook.initNotebook(); + notebook.waitForFinishInit(1, TimeUnit.MINUTES); + } + + @AfterEach + void tearDown() { + notebookDir.delete(); + } + + /** + * Given a note evicted from the (threshold=1) note cache, when a second, unrelated-looking + * {@code moveNote} call (same leaf name, so no re-save of its own) runs to completion while + * the first {@code moveNote} call's re-save is still reloading the note from the repo, then + * the first call must not resurrect a {@code .zpln} file at its own, now-stale destination. + */ + @Test + void testConcurrentMoveNoteResaveRace() throws Exception { + String noteId = notebook.createNote( + "/folder_0/note", DEFAULT_INTERPRETER_GROUP, AuthenticationInfo.ANONYMOUS, true); + + // A filler note pushes the target note out of the (threshold=1) cache, forcing the re-save + // path in moveNote to reload it from the repo. + notebook.createNote( + "/filler", DEFAULT_INTERPRETER_GROUP, AuthenticationInfo.ANONYMOUS, true); + assertEquals(1, noteManager.getCacheSize(), + "creating the filler note should have evicted the target note from the cache; " + + "the race scenario depends on a cache miss during moveNote's re-save"); + + notebookRepo.armGate(); + + List thread1Errors = Collections.synchronizedList(new ArrayList<>()); + List thread2Errors = Collections.synchronizedList(new ArrayList<>()); + + // Thread 1: rename note -> renamed. Leaf name changes, so moveNote reloads (cache miss) + // and parks inside the gated get() call, having already read the (still current) note + // path from disk. + Thread thread1 = new Thread(() -> { + try { + notebook.moveNote(noteId, "/folder_1/renamed", AuthenticationInfo.ANONYMOUS); + } catch (Throwable t) { + thread1Errors.add(t); + } + }, "move-note-race-thread-1"); + thread1.start(); + + assertTrue( + notebookRepo.awaitArrival(GATE_ARRIVAL_TIMEOUT_SECONDS, TimeUnit.SECONDS), + "Thread 1's gated get() call never arrived. The scenario did not pin as expected: " + + "either the target note was not evicted from the cache, or moveNote's re-save " + + "path was not entered."); + + // Thread 2: rename renamed -> renamed (different folder, same leaf name), while thread 1 + // is parked. Leaf name is unchanged, so this move takes no re-save path of its own and + // runs to completion using only the (fast) synchronized block in moveNote. + Thread thread2 = new Thread(() -> { + try { + notebook.moveNote(noteId, "/folder_2/renamed", AuthenticationInfo.ANONYMOUS); + } catch (Throwable t) { + thread2Errors.add(t); + } + }, "move-note-race-thread-2"); + thread2.start(); + thread2.join(JOIN_TIMEOUT_MILLIS); + assertFalse(thread2.isAlive(), "Thread 2's moveNote did not finish within the timeout"); + + // Only now let thread 1 resume: it will save the reloaded note back at its own, stale + // destination path ("/folder_1/renamed"), even though thread 2 already moved the note to + // "/folder_2/renamed". + notebookRepo.release(); + thread1.join(JOIN_TIMEOUT_MILLIS); + assertFalse(thread1.isAlive(), "Thread 1's moveNote did not finish within the timeout"); + + assertTrue(thread1Errors.isEmpty(), () -> "Thread 1 threw: " + thread1Errors); + assertTrue(thread2Errors.isEmpty(), () -> "Thread 2 threw: " + thread2Errors); + + List zplnFilesForNote = findZplnFilesForNote(noteId); + assertEquals(1, zplnFilesForNote.size(), + () -> "Expected exactly one .zpln file for note " + noteId + ", but found: " + + zplnFilesForNote); + } + + private List findZplnFilesForNote(String noteId) throws IOException { + Path notebookPath = notebookDir.toPath(); + try (Stream paths = Files.walk(notebookPath)) { + return paths + .filter(p -> p.toString().endsWith("_" + noteId + ".zpln")) + .map(p -> notebookPath.relativize(p).toString()) + .collect(Collectors.toList()); + } + } +} diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithDelay.java b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithDelay.java new file mode 100644 index 00000000000..14fa241e363 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithDelay.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.notebook.repo; + +import java.io.IOException; +import java.io.OutputStream; +import org.apache.commons.io.IOUtils; +import org.apache.commons.vfs2.FileObject; +import org.apache.commons.vfs2.NameScope; +import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars; +import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.user.AuthenticationInfo; + +/** + * Test-only subclass of {@link VFSNotebookRepo} that injects an artificial delay after the + * destination file name has been resolved in {@code save()} and after {@code move()} starts. + * This reproduces the ZEPPELIN-5858 moveNote/saveNote race condition: a concurrent move + * (rename) and save on the same note can both write a {@code {oldPath}_{noteId}.zpln} and a + * {@code {newPath}_{noteId}.zpln} file, leaving a duplicated noteId in the repo. + */ +public class VFSNotebookRepoWithDelay extends VFSNotebookRepo { + + private final long delayInMillis; + + public VFSNotebookRepoWithDelay(long delayInMillis) { + this.delayInMillis = delayInMillis; + } + + @Override + public synchronized void save(Note note, AuthenticationInfo subject) throws IOException { + // write to tmp file first, then rename it to the {note_name}_{note_id}.zpln + FileObject noteJson = rootNotebookFileObject.resolveFile( + buildNoteTempFileName(note), NameScope.DESCENDENT); + OutputStream out = null; + try { + out = noteJson.getContent().getOutputStream(false); + IOUtils.write(note.toJson().getBytes(zConf.getString(ConfVars.ZEPPELIN_ENCODING)), out); + } finally { + if (out != null) { + out.close(); + } + } + // Destination file name is captured before the delay, simulating a network round trip + // that happens after the note path has already been read. This ordering is the essence + // of the race: capturing after the delay would not reproduce it. + String noteFileName = buildNoteFileName(note); + delay(); + noteJson.moveTo(rootNotebookFileObject.resolveFile(noteFileName, NameScope.DESCENDENT)); + } + + @Override + public void move(String noteId, String notePath, String newNotePath, + AuthenticationInfo subject) throws IOException { + // Delay at the start simulates a slow remote repo, widening the window for a concurrent + // save to race with this move. + delay(); + super.move(noteId, notePath, newNotePath, subject); + } + + private void delay() { + try { + Thread.sleep(delayInMillis); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithGetGate.java b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithGetGate.java new file mode 100644 index 00000000000..66524847ea3 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/notebook/repo/VFSNotebookRepoWithGetGate.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.notebook.repo; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.zeppelin.notebook.Note; +import org.apache.zeppelin.user.AuthenticationInfo; + +/** + * Test-only subclass of {@link VFSNotebookRepo} that parks the first {@code get()} call after + * arming, once the note has already been read from disk. This reproduces the reload path taken + * by {@code NoteManager#moveNote} when the re-save block (leaf name changed) misses the note + * cache: {@code loadAndProcessNote} calls {@code NotebookRepo#get()} to reload the note before + * re-saving it at the (possibly stale) target path passed into the outer {@code moveNote} call. + * Parking here, after the disk read, lets a second, concurrent {@code moveNote} call for the + * same note run to completion (including its own re-save skip, when the leaf name did not + * change) before the parked call resumes and saves using its now-stale destination path. + */ +public class VFSNotebookRepoWithGetGate extends VFSNotebookRepo { + + private static final long GATE_SELF_TIMEOUT_SECONDS = 30; + + private final AtomicBoolean armed = new AtomicBoolean(false); + private volatile CountDownLatch arrivedLatch; + private volatile CountDownLatch releaseLatch; + + /** + * Arm the gate. Only the next {@code get()} call parks; every call afterwards passes + * through untouched, so filler note loads and repeated reads do not get caught by mistake. + */ + public void armGate() { + arrivedLatch = new CountDownLatch(1); + releaseLatch = new CountDownLatch(1); + armed.set(true); + } + + /** + * Wait for the gated {@code get()} call to arrive and park. Returns false, instead of + * blocking forever, if it never arrives within the timeout so the caller can fail the test + * with a clear message rather than hang. + */ + public boolean awaitArrival(long timeout, TimeUnit unit) throws InterruptedException { + return arrivedLatch.await(timeout, unit); + } + + /** + * Let the parked {@code get()} call resume and return to its caller. + */ + public void release() { + releaseLatch.countDown(); + } + + @Override + public Note get(String noteId, String notePath, AuthenticationInfo subject) throws IOException { + Note note = super.get(noteId, notePath, subject); + if (armed.compareAndSet(true, false)) { + arrivedLatch.countDown(); + try { + // Self-timeout so a test bug (forgetting to call release()) fails fast instead of + // hanging the build forever. + releaseLatch.await(GATE_SELF_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + return note; + } +} diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceRaceConditionTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceRaceConditionTest.java new file mode 100644 index 00000000000..2affa776906 --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceRaceConditionTest.java @@ -0,0 +1,164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.zeppelin.conf.ZeppelinConfiguration; +import org.apache.zeppelin.interpreter.InterpreterFactory; +import org.apache.zeppelin.interpreter.InterpreterSettingManager; +import org.apache.zeppelin.notebook.AuthorizationService; +import org.apache.zeppelin.notebook.GsonNoteParser; +import org.apache.zeppelin.notebook.NoteManager; +import org.apache.zeppelin.notebook.NoteParser; +import org.apache.zeppelin.notebook.Notebook; +import org.apache.zeppelin.notebook.repo.NotebookRepo; +import org.apache.zeppelin.notebook.repo.VFSNotebookRepoWithDelay; +import org.apache.zeppelin.notebook.scheduler.NoSchedulerService; +import org.apache.zeppelin.storage.ConfigStorage; +import org.apache.zeppelin.user.AuthenticationInfo; +import org.apache.zeppelin.user.Credentials; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Reproduction test for ZEPPELIN-5858: a concurrent 'move' (rename) and 'save' (insert + * paragraph) on the same note can race in the notebook repo, leaving two {@code .zpln} files + * for the same noteId (old path + new path) behind. {@link VFSNotebookRepoWithDelay} injects + * an artificial delay to widen the race window. + */ +class NotebookServiceRaceConditionTest { + + private static NotebookService notebookService; + + private File notebookDir; + private Notebook notebook; + private NotebookRepo notebookRepo; + private ServiceContext context = + new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<>()); + + private ServiceCallback callback = mock(ServiceCallback.class); + + @BeforeEach + void setUp() throws Exception { + notebookDir = Files.createTempDirectory("notebookDir").toAbsolutePath().toFile(); + ZeppelinConfiguration zConf = ZeppelinConfiguration.load(); + zConf.setProperty(ZeppelinConfiguration.ConfVars.ZEPPELIN_NOTEBOOK_DIR.getVarName(), + notebookDir.getAbsolutePath()); + NoteParser noteParser = new GsonNoteParser(zConf); + ConfigStorage storage = ConfigStorage.createConfigStorage(zConf); + notebookRepo = new VFSNotebookRepoWithDelay(5000L); + notebookRepo.init(zConf, noteParser); + + InterpreterSettingManager mockInterpreterSettingManager = mock(InterpreterSettingManager.class); + InterpreterFactory mockInterpreterFactory = mock(InterpreterFactory.class); + Credentials credentials = new Credentials(); + NoteManager noteManager = new NoteManager(notebookRepo, zConf); + AuthorizationService authorizationService = + new AuthorizationService(noteManager, zConf, storage); + notebook = + new Notebook( + zConf, + authorizationService, + notebookRepo, + noteManager, + mockInterpreterFactory, + mockInterpreterSettingManager, + credentials, + null); + notebook.initNotebook(); + notebook.waitForFinishInit(1, TimeUnit.MINUTES); + notebookService = + new NotebookService( + notebook, authorizationService, zConf, new NoSchedulerService()); + } + + @AfterEach + void tearDown() { + notebookDir.delete(); + } + + /** + * Concurrent 'insertParagraph' (save) and 'renameNote' (move) on the same note. The delayed + * repo widens the window between reading a note's path and writing to it, so both operations + * can write a {@code .zpln} file for the same noteId: one at the old path, one at the new + * path. Thread 2 starts the move first (delay simulates a slow remote write); thread 1 saves + * shortly after, while the move is still in flight. + */ + @Test + void testConcurrentMoveAndSave() throws IOException, InterruptedException { + // given a note + String noteId = notebookService.createNote("/folder_1/note", "test", true, context, callback); + + // when executing 'move' (renameNote) and 'save' (insertParagraph) concurrently + CountDownLatch latch = new CountDownLatch(2); + ExecutorService threadPool = Executors.newFixedThreadPool(2); + threadPool.execute(() -> { + try { + // ensure we 'save' after 'move' has started processing, but before 'move' has finished + Thread.sleep(1000L); + notebookService.insertParagraph(noteId, 1, Collections.emptyMap(), context, callback); + latch.countDown(); + } catch (IOException | InterruptedException ex) { + // ignore + } + }); + threadPool.execute(() -> { + try { + notebookService.renameNote(noteId, "/folder_2/note", false, context, callback); + latch.countDown(); + } catch (IOException ex) { + // ignore + } + }); + assertTrue(latch.await(100, TimeUnit.SECONDS)); + threadPool.shutdown(); + + // then only a single .zpln file exists for this note under notebookDir + List zplnFiles = findZplnFiles(); + assertEquals(1, zplnFiles.size(), + () -> "Expected exactly one .zpln file, but found: " + zplnFiles); + } + + private List findZplnFiles() throws IOException { + Path notebookPath = notebookDir.toPath(); + try (Stream paths = Files.walk(notebookPath)) { + return paths + .filter(p -> p.toString().endsWith(".zpln")) + .map(p -> notebookPath.relativize(p).toString()) + .collect(Collectors.toList()); + } + } +} From 1f80e7a7678cb3d580a49c0637ade7ecc04c9d3c Mon Sep 17 00:00:00 2001 From: Lee SuJung <153787023+xhaktm00@users.noreply.github.com> Date: Mon, 10 Aug 2026 23:58:56 +0900 Subject: [PATCH 168/179] [ZEPPELIN-6556] Personalized mode leaks a non-owner's paragraph edits into the shared master paragraph MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? A note can be switched to personalized mode so that each user gets their own copy of a paragraph and one user's form values and results do not affect another's. However, `NotebookService.runParagraph` writes the caller's `params`, `text`, `title` and `config` into the shared master paragraph *before* it checks whether the note is personalized: ```java p.setText(text); p.setTitle(title); p.setAuthenticationInfo(context.getAutheInfo()); if (params != null && !params.isEmpty()) { p.settings.setParams(params); // master paragraph } if (config != null && !config.isEmpty()) { p.mergeConfig(config); // master paragraph } if (note.isPersonalizedMode()) { p = p.getUserParagraph(context.getAutheInfo().getUser()); ... // the user copy gets the same values } ``` `notebook.saveNote(...)` then persists the polluted master. The same ordering exists in `updateParagraph`, and `setParagraphUsingMessage` is worse: its personalized branch re-fetches the master via `note.getParagraph(paragraphId)` instead of resolving the user copy, so it writes the same values into the master twice and never touches the user copy at all. So in personalized mode, a non-owner who edits a dynamic form and runs the paragraph silently overwrites the shared original. Because `Paragraph.userParagraphMap` is transient, the per-user copies do not survive a restart. The corruption stays invisible while the copies exist and surfaces later: - after a server restart the user copies are gone and every user sees whatever the last runner wrote - turning personalized mode off (`Note.clearUserParagraphs`) exposes the polluted master - a user opening the note for the first time clones the polluted master **The fix**: resolve the target paragraph *first* — when the note is personalized, switch to `getUserParagraph(user)` before any write — so the master paragraph is never mutated by another user's run or update. Applied to `runParagraph`, `updateParagraph` and `setParagraphUsingMessage`. Since the two branches wrote identical values, this also removes the duplicated write blocks. The only caller of `setParagraphUsingMessage` is `spell()`, which now records the spell result on the user copy in personalized mode — the intended behavior — instead of on the shared master. Note: `PersonalizeActionsIT.testDynamicFormAction` asserts the correct behavior (a non-owner's edit must not leak) but was passing against the old server behavior only because a late WebSocket broadcast reverted the typed form value before the run. ### What type of PR is it? Bug Fix ### Todos * [x] Resolve the user paragraph before writing params/text/title/config in `runParagraph`, `updateParagraph` and `setParagraphUsingMessage` * [x] Fix `setParagraphUsingMessage` re-fetching the master in its personalized branch * [x] Add a unit test that asserts master paragraph integrity in personalized mode ### What is the Jira issue? * [ZEPPELIN-6556](https://issues.apache.org/jira/browse/ZEPPELIN-6556) ### How should this be tested? New test `NotebookServiceTest#testRunParagraphInPersonalizedModeDoesNotPolluteMasterParagraph`: on a personalized note, it runs and then updates a paragraph as `user1` with new params/title, and asserts that the master paragraph's params and title are unchanged while `getUserParagraph("user1")` picks up the new values. ``` ./mvnw -pl zeppelin-server test -Dtest=NotebookServiceTest -DfailIfNoTests=false ``` Result with the fix: `Tests run: 6, Failures: 0, Errors: 0`. Manual verification: create a note with `%md echo "hello, ${name=original}"`, run it, enable personalized mode, log in as a second user, change the form value and run. Then turn personalized mode off (or restart the server): the paragraph must still show `original`. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5360 from xhaktm00/ZEPPELIN-6556. Signed-off-by: ChanHo Lee --- .../zeppelin/service/NotebookService.java | 52 +++++++---- .../zeppelin/service/NotebookServiceTest.java | 87 ++++++++++++++++++- 2 files changed, 119 insertions(+), 20 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java b/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java index 554b85f4de2..38ce280ad6e 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/service/NotebookService.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -452,14 +453,19 @@ public boolean runParagraph(Note note, callback.onFailure(new IOException("paragraph is disabled."), context); return false; } - p.setText(text); - p.setTitle(title); - p.setAuthenticationInfo(context.getAutheInfo()); - if (params != null && !params.isEmpty()) { - p.settings.setParams(params); - } - if (config != null && !config.isEmpty()) { - p.mergeConfig(config); + // In personalized mode only the note owner may update the master paragraph, so that + // new users inherit the owner's changes while a non-owner's changes stay in their copy. + if (!note.isPersonalizedMode() + || authorizationService.isOwner(note.getId(), context.getUserAndRoles())) { + p.setText(text); + p.setTitle(title); + p.setAuthenticationInfo(context.getAutheInfo()); + if (params != null && !params.isEmpty()) { + p.settings.setParams(params); + } + if (config != null && !config.isEmpty()) { + p.mergeConfig(config); + } } if (note.isPersonalizedMode()) { @@ -761,10 +767,15 @@ public void updateParagraph(String noteId, callback.onFailure(new ParagraphNotFoundException(paragraphId), context); return null; } - p.settings.setParams(params); - p.mergeConfig(config); - p.setTitle(title); - p.setText(text); + // In personalized mode only the note owner may update the master paragraph, so that + // new users inherit the owner's changes while a non-owner's changes stay in their copy. + if (!note.isPersonalizedMode() + || authorizationService.isOwner(noteId, context.getUserAndRoles())) { + p.settings.setParams(params); + p.mergeConfig(config); + p.setTitle(title); + p.setText(text); + } if (note.isPersonalizedMode()) { p = p.getUserParagraph(context.getAutheInfo().getUser()); p.settings.setParams(params); @@ -1393,16 +1404,21 @@ private Paragraph setParagraphUsingMessage(Note note, Message fromMessage, Strin String text, String title, Map params, Map config) { Paragraph p = note.getParagraph(paragraphId); - p.setText(text); - p.setTitle(title); AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal, fromMessage.roles, fromMessage.ticket); - p.setAuthenticationInfo(subject); - p.settings.setParams(params); - p.setConfig(config); + // In personalized mode only the note owner may update the master paragraph, so that + // new users inherit the owner's changes while a non-owner's changes stay in their copy. + if (!note.isPersonalizedMode() + || authorizationService.isOwner(note.getId(), new HashSet<>(subject.getUsersAndRoles()))) { + p.setText(text); + p.setTitle(title); + p.setAuthenticationInfo(subject); + p.settings.setParams(params); + p.setConfig(config); + } if (note.isPersonalizedMode()) { - p = note.getParagraph(paragraphId); + p = p.getUserParagraph(subject.getUser()); p.setText(text); p.setTitle(title); p.setAuthenticationInfo(subject); diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java index 0a176ac8b40..2d53f34dec8 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/service/NotebookServiceTest.java @@ -36,6 +36,7 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -88,6 +89,7 @@ class NotebookServiceTest { private File confDir; private SearchService searchService; private Notebook notebook; + private AuthorizationService authorizationService; private ServiceContext context = new ServiceContext(AuthenticationInfo.ANONYMOUS, new HashSet<>()); @@ -136,8 +138,7 @@ void setUp(TestInfo testInfo) throws Exception { when(mockInterpreterSetting.getStatus()).thenReturn(InterpreterSetting.Status.READY); Credentials credentials = new Credentials(); NoteManager noteManager = new NoteManager(notebookRepo, zConf); - AuthorizationService authorizationService = - new AuthorizationService(noteManager, zConf, storage); + authorizationService = new AuthorizationService(noteManager, zConf, storage); notebook = new Notebook( zConf, @@ -588,6 +589,88 @@ void testParagraphOperations() throws IOException { verify(callback).onSuccess(p, context); } + @Test + void testRunParagraphInPersonalizedModeDoesNotPolluteMasterParagraph() throws IOException { + String note1Id = notebookService.createNote("/note_personalized", "test", true, context, callback); + // make "admin" the note owner so that "user1" below is a non-owner + authorizationService.setOwners(note1Id, Collections.singleton("admin")); + Map masterParams = new HashMap<>(); + masterParams.put("name", "master"); + String paragraphId = notebook.processNote(note1Id, + note1 -> { + note1.setPersonalizedMode(true); + Paragraph p = note1.getParagraph(0); + p.setText("1+1"); + p.settings.setParams(masterParams); + return p.getId(); + }); + + ServiceContext user1Context = new ServiceContext(new AuthenticationInfo("user1"), + new HashSet<>(Collections.singleton("user1"))); + Map user1Params = new HashMap<>(); + user1Params.put("name", "user1"); + + reset(callback); + boolean runStatus = notebook.processNote(note1Id, + note1 -> { + return notebookService.runParagraph(note1, paragraphId, "user1_title", "1+1", + user1Params, new HashMap<>(), null, false, true, user1Context, callback); + }); + assertTrue(runStatus); + + notebook.processNote(note1Id, + note1 -> { + Paragraph master = note1.getParagraph(paragraphId); + assertEquals(masterParams, master.settings.getParams()); + assertNull(master.getTitle()); + Paragraph user1Paragraph = master.getUserParagraph("user1"); + assertEquals(user1Params, user1Paragraph.settings.getParams()); + assertEquals("user1_title", user1Paragraph.getTitle()); + return null; + }); + + // updateParagraph must not pollute the master paragraph either + reset(callback); + Map user1UpdatedParams = new HashMap<>(); + user1UpdatedParams.put("name", "user1_updated"); + notebookService.updateParagraph(note1Id, paragraphId, "user1_updated_title", "1+1", + user1UpdatedParams, new HashMap<>(), user1Context, callback); + + notebook.processNote(note1Id, + note1 -> { + Paragraph master = note1.getParagraph(paragraphId); + assertEquals(masterParams, master.settings.getParams()); + assertNull(master.getTitle()); + Paragraph user1Paragraph = master.getUserParagraph("user1"); + assertEquals(user1UpdatedParams, user1Paragraph.settings.getParams()); + assertEquals("user1_updated_title", user1Paragraph.getTitle()); + return null; + }); + + // the note owner's changes must reach the master paragraph so new users inherit them + reset(callback); + ServiceContext adminContext = new ServiceContext(new AuthenticationInfo("admin"), + new HashSet<>(Collections.singleton("admin"))); + Map adminParams = new HashMap<>(); + adminParams.put("name", "admin"); + notebookService.updateParagraph(note1Id, paragraphId, "admin_title", "1+1", + adminParams, new HashMap<>(), adminContext, callback); + + notebook.processNote(note1Id, + note1 -> { + Paragraph master = note1.getParagraph(paragraphId); + assertEquals(adminParams, master.settings.getParams()); + assertEquals("admin_title", master.getTitle()); + Paragraph adminParagraph = master.getUserParagraph("admin"); + assertEquals(adminParams, adminParagraph.settings.getParams()); + assertEquals("admin_title", adminParagraph.getTitle()); + // the non-owner's personal copy must keep their own values + Paragraph user1Paragraph = master.getUserParagraph("user1"); + assertEquals(user1UpdatedParams, user1Paragraph.settings.getParams()); + return null; + }); + } + @Test void testNormalizeNotePath() throws IOException { assertEquals("/Untitled Note", notebookService.normalizeNotePath(" ")); From 2029a3496ecde03a38bb446aa503c10c2bf8a6d5 Mon Sep 17 00:00:00 2001 From: Chaiwon Hwang <90598552+uommou@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:23:07 +0900 Subject: [PATCH 169/179] [ZEPPELIN-6503] Update README.md Core features section to reflect current capabilities ### What is this PR for? Update the `Core features` section in `README.md` to better reflect Apache Zeppelin's current capabilities. The previous section only mentioned the web-based notebook editor and built-in Apache Spark support. This update highlights multi-language interpreter support, process isolation, visualization, dynamic forms, notebook scheduling, and flexible deployment options. ### What type of PR is it? Documentation ### What is the Jira issue? [ZEPPELIN-6503](https://issues.apache.org/jira/browse/ZEPPELIN-6503) ### How should this be tested? Documentation-only change. - Reviewed the rendered Markdown content - Verified the diff with `git diff --check` ### Screenshots (if appropriate) Not applicable. ### Questions - Does the license file need to be updated? No - Is there breaking API change? No - Does this need documentation? No additional documentation is required Closes #5410 from uommou/fix/ZEPPELIN-6503. Signed-off-by: Jongyoul Lee --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 13a01d35294..7cb0bbc22fc 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,12 @@ **Zeppelin**, a web-based notebook that enables interactive data analytics. You can make beautiful data-driven, interactive and collaborative documents with SQL, Scala and more. Core features: - * Web based notebook style editor. - * Built-in Apache Spark support + * Web-based notebook style editor with real-time collaboration + * Multi-language support: Spark, Flink, Python, SQL, Shell, and 20+ interpreters + * Pluggable interpreter architecture with process isolation + * Built-in visualization and dynamic forms + * Notebook scheduling (cron) + * Flexible deployment: local, Docker, Kubernetes, YARN To know more about Zeppelin, visit our web site [https://zeppelin.apache.org](https://zeppelin.apache.org) From 4728b91e2700dbf2ad014ad2e797e1cfef3342b5 Mon Sep 17 00:00:00 2001 From: Cheng Pan Date: Wed, 12 Aug 2026 14:47:03 +0800 Subject: [PATCH 170/179] [ZEPPELIN-6639] Migrate Cassandra interpreter tests to Testcontainers with Cassandra 4.x ## What is this PR for? The Cassandra interpreter tests use `cassandra-unit` which embeds Cassandra 3.11.5 in-process. Cassandra 3.x is EOL (unmaintained, archived) and crashes on JDK 17 because `Unsafe.objectFieldOffset()` on hidden classes (lambdas) throws `UnsupportedOperationException` during `PREPARE` statement storage -- a hard JVM restriction no flag can override. This PR migrates the tests to Testcontainers with Cassandra 4.1.3 (the latest maintained 4.1.x), which handles JDK 17 correctly. This is a prerequisite for JDK 17 support. ## What type of PR is it? Improvement ## What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6639 ## How should this be tested? - `cassandra` module: 39 tests pass on JDK 11 and JDK 17 with Docker - `./mvnw test -pl cassandra` ## Questions - Does the licenses file need update? No - Is there breaking changes for older versions? No - Does this needs documentation? No ## Details - Replace `cassandra-unit` dependency with `org.testcontainers:cassandra` (`cassandra:4.1.3` image) - Add `org.testcontainers:cassandra` to root `pom.xml` dependencyManagement - Rewrite `CassandraInterpreterTest` to use `CassandraContainer` instead of `EmbeddedCassandraServerHelper` - Load CQL test data via `CqlSession` instead of `CQLDataLoader` - Update test expectation HTML files to match Cassandra 4.x table option output: - `additional_write_policy = '99p'` (new in 4.x) - `read_repair = 'BLOCKING'` (replaces `dclocal_read_repair_chance` + `read_repair_chance`) - `speculative_retry = '99p'` (replaces `'99PERCENTILE'`) - `compression chunk_length_in_kb = 16` (was 64) - `NoResultWithExecutionInfo.html`: replace hardcoded `localhost:9142` with `TRIED_HOSTS`/`QUERIED_HOSTS` placeholders - Normalize `localhost/<unresolved>:port` in test assertions (JDK 17+ `InetSocketAddress.toString()` renders unresolved addresses differently) Assisted-by: GLM 5.2 Closes #5412 from pan3793/ZEPPELIN-6639. Signed-off-by: Jongyoul Lee --- cassandra/pom.xml | 21 ++----- .../cassandra/CassandraInterpreterTest.java | 58 ++++++++++++------- .../scalate/DescribeKeyspace_live_data.html | 2 +- ...DescribeTable_live_data_complex_table.html | 2 +- .../scalate/NoResultWithExecutionInfo.html | 2 +- pom.xml | 7 +++ 6 files changed, 53 insertions(+), 39 deletions(-) diff --git a/cassandra/pom.xml b/cassandra/pom.xml index 91ba86bbc0e..e4e53309ebf 100644 --- a/cassandra/pom.xml +++ b/cassandra/pom.xml @@ -37,8 +37,6 @@ 1.9.8 - 5.12.1 - 4.3.1.0 ${scala.2.12.version} 2.12 @@ -137,26 +135,17 @@ - net.java.dev.jna - jna - ${jna.version} + org.testcontainers + cassandra test - org.cassandraunit - cassandra-unit - ${cassandra.unit.version} - test - - - com.datastax.oss - java-driver-core - - + org.testcontainers + junit-jupiter + test - org.mockito mockito-core diff --git a/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java b/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java index 8a6cce4ee9e..4426d47d00e 100644 --- a/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java +++ b/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java @@ -27,13 +27,13 @@ import org.apache.zeppelin.interpreter.InterpreterContext; import org.apache.zeppelin.interpreter.InterpreterResult; import org.apache.zeppelin.interpreter.InterpreterResult.Code; -import org.cassandraunit.CQLDataLoader; -import org.cassandraunit.dataset.cql.ClassPathCQLDataSet; -import org.cassandraunit.utils.EmbeddedCassandraServerHelper; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.testcontainers.containers.CassandraContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -65,28 +65,40 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; -public class CassandraInterpreterTest { // extends AbstractCassandraUnit4CQLTestCase { +@Testcontainers +public class CassandraInterpreterTest { private static final String ARTISTS_TABLE = "zeppelin.artists"; private static volatile CassandraInterpreter interpreter; + private static CqlSession session; + private final InterpreterContext intrContext = InterpreterContext.builder() .setParagraphTitle("Paragraph1") .build(); + @Container + public static CassandraContainer cassandra = + new CassandraContainer<>("cassandra:4.1.3"); + @BeforeAll - public static synchronized void setUp() throws IOException, InterruptedException { - System.setProperty("cassandra.skip_wait_for_gossip_to_settle", "0"); - System.setProperty("cassandra.load_ring_state", "false"); - System.setProperty("cassandra.initial_token", "0"); - System.setProperty("cassandra.num_tokens", "nil"); - System.setProperty("cassandra.allocate_tokens_for_local_replication_factor", "nil"); - EmbeddedCassandraServerHelper.startEmbeddedCassandra(); - CqlSession session = EmbeddedCassandraServerHelper.getSession(); - new CQLDataLoader(session).load(new ClassPathCQLDataSet("prepare_all.cql", "zeppelin")); + public static synchronized void setUp() throws IOException { + session = CqlSession.builder() + .addContactPoint(java.net.InetSocketAddress.createUnresolved( + cassandra.getHost(), cassandra.getMappedPort(9042))) + .withLocalDatacenter("datacenter1") + .build(); + + String cql = IOUtils.resourceToString("/prepare_all.cql", StandardCharsets.UTF_8); + for (String stmt : cql.split(";")) { + String trimmed = stmt.trim(); + if (!trimmed.isEmpty()) { + session.execute(trimmed); + } + } Properties properties = new Properties(); - properties.setProperty(CASSANDRA_CLUSTER_NAME, EmbeddedCassandraServerHelper.getClusterName()); + properties.setProperty(CASSANDRA_CLUSTER_NAME, "Test Cluster"); properties.setProperty(CASSANDRA_COMPRESSION_PROTOCOL, "NONE"); properties.setProperty(CASSANDRA_CREDENTIALS_USERNAME, "none"); properties.setProperty(CASSANDRA_CREDENTIALS_PASSWORD, "none"); @@ -111,9 +123,9 @@ public static synchronized void setUp() throws IOException, InterruptedException properties.setProperty(CASSANDRA_SOCKET_READ_TIMEOUT_MILLIS, "12000"); properties.setProperty(CASSANDRA_SOCKET_TCP_NO_DELAY, "true"); - properties.setProperty(CASSANDRA_HOSTS, EmbeddedCassandraServerHelper.getHost()); + properties.setProperty(CASSANDRA_HOSTS, cassandra.getHost()); properties.setProperty(CASSANDRA_PORT, - Integer.toString(EmbeddedCassandraServerHelper.getNativeTransportPort())); + Integer.toString(cassandra.getMappedPort(9042))); properties.setProperty("datastax-java-driver.advanced.connection.pool.local.size", "1"); interpreter = new CassandraInterpreter(properties); interpreter.open(); @@ -122,6 +134,9 @@ public static synchronized void setUp() throws IOException, InterruptedException @AfterAll public static void tearDown() { interpreter.close(); + if (session != null) { + session.close(); + } } @Test @@ -333,7 +348,7 @@ void should_execute_statement_with_timestamp_option() throws Exception { String statement2 = "@timestamp=15\n" + "INSERT INTO zeppelin.ts(key,val) VALUES('k','v2');"; - CqlSession session = EmbeddedCassandraServerHelper.getSession(); + CqlSession session = CassandraInterpreterTest.session; // Insert v1 with current timestamp interpreter.interpret(statement1, intrContext); System.out.println("going to read data from zeppelin.ts;"); @@ -562,14 +577,17 @@ void should_display_statistics_for_non_select_statement() { // When final InterpreterResult actual = interpreter.interpret(query, intrContext); - final int port = EmbeddedCassandraServerHelper.getNativeTransportPort(); - final String address = EmbeddedCassandraServerHelper.getHost(); + final int port = cassandra.getMappedPort(9042); + final String address = cassandra.getHost(); // Then final String expected = rawResult.replaceAll("TRIED_HOSTS", address + ":" + port) .replaceAll("QUERIED_HOSTS", address + ":" + port); assertEquals(Code.SUCCESS, actual.code()); - assertEquals(expected, reformatHtml(actual.message().get(0).getData())); + // JDK 17+ renders unresolved InetSocketAddress as "host/:port" + String actualHtml = reformatHtml(actual.message().get(0).getData()) + .replaceAll(address + "/<unresolved>:", address + ":"); + assertEquals(expected, actualHtml); } @Test diff --git a/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html b/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html index 8d721ef2338..ed67b250cd3 100644 --- a/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html +++ b/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html @@ -1 +1 @@ -


      live_data

    ReplicationDurable Writes
    {'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor' : '1'}false

    Tables
    Column TypeColumn NameData Type
    pk1uuid
    pk2int
    my_static1text
    my_static2text
     clustering1timestamp
     clustering2int
     clustering3text
    entries_indexed_mapmap<int, text>
    indexed1text
    indexed2int
    key_indexed_mapmap<int, text>
    my_listlist<text>
    my_mapmap<int, text>
    my_udtfrozen<live_data.address>
    my_udt_listfrozen<list<frozen<live_data.address>>>
    simpledouble

     complex_table's indices

    NameTarget
    clustering2idxclustering2
    idx1indexed1
    idx2indexed2
    keys_map_idxkeys(key_indexed_map)
    pk2idxpk2
    Column TypeColumn NameData Type
    sensor_iduuid
    monthint
    characteristicsmap<text, text>
    model_numbertext
    providertext
     datetimestamp
    valuedouble
    Column TypeColumn NameData Type
    station_iduuid
    sensorsfrozen<map<uuid, frozen<live_data.geolocation>>>

    User Defined Types
    Column NameData Type
    numberint
    streettext
    zipint
    citytext
    countrytext
    Column NameData Type
    latitudedouble
    longitudedouble
    \ No newline at end of file +


      live_data

    ReplicationDurable Writes
    {'class' : 'org.apache.cassandra.locator.SimpleStrategy', 'replication_factor' : '1'}false

    Tables
    Column TypeColumn NameData Type
    pk1uuid
    pk2int
    my_static1text
    my_static2text
     clustering1timestamp
     clustering2int
     clustering3text
    entries_indexed_mapmap<int, text>
    indexed1text
    indexed2int
    key_indexed_mapmap<int, text>
    my_listlist<text>
    my_mapmap<int, text>
    my_udtfrozen<live_data.address>
    my_udt_listfrozen<list<frozen<live_data.address>>>
    simpledouble

     complex_table's indices

    NameTarget
    clustering2idxclustering2
    idx1indexed1
    idx2indexed2
    keys_map_idxkeys(key_indexed_map)
    pk2idxpk2
    Column TypeColumn NameData Type
    sensor_iduuid
    monthint
    characteristicsmap<text, text>
    model_numbertext
    providertext
     datetimestamp
    valuedouble
    Column TypeColumn NameData Type
    station_iduuid
    sensorsfrozen<map<uuid, frozen<live_data.geolocation>>>

    User Defined Types
    Column NameData Type
    numberint
    streettext
    zipint
    citytext
    countrytext
    Column NameData Type
    latitudedouble
    longitudedouble
    \ No newline at end of file diff --git a/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html b/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html index b31dc11ee55..09cb963f474 100644 --- a/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html +++ b/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html @@ -1 +1 @@ -


     complex_table

    Column TypeColumn NameData Type
    pk1uuid
    pk2int
    my_static1text
    my_static2text
     clustering1timestamp
     clustering2int
     clustering3text
    entries_indexed_mapmap<int, text>
    indexed1text
    indexed2int
    key_indexed_mapmap<int, text>
    my_listlist<text>
    my_mapmap<int, text>
    my_udtfrozen<live_data.address>
    my_udt_listfrozen<list<frozen<live_data.address>>>
    simpledouble

     complex_table's indices

    NameTarget
    clustering2idxclustering2
    idx1indexed1
    idx2indexed2
    keys_map_idxkeys(key_indexed_map)
    pk2idxpk2
    \ No newline at end of file +


     complex_table

    Column TypeColumn NameData Type
    pk1uuid
    pk2int
    my_static1text
    my_static2text
     clustering1timestamp
     clustering2int
     clustering3text
    entries_indexed_mapmap<int, text>
    indexed1text
    indexed2int
    key_indexed_mapmap<int, text>
    my_listlist<text>
    my_mapmap<int, text>
    my_udtfrozen<live_data.address>
    my_udt_listfrozen<list<frozen<live_data.address>>>
    simpledouble

     complex_table's indices

    NameTarget
    clustering2idxclustering2
    idx1indexed1
    idx2indexed2
    keys_map_idxkeys(key_indexed_map)
    pk2idxpk2
    \ No newline at end of file diff --git a/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html b/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html index bd713adad2e..f15b05dcaee 100644 --- a/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html +++ b/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html @@ -1 +1 @@ -
    No Result      
    InformationValue
    StatementCREATE TABLE IF NOT EXISTS no_select(id int PRIMARY KEY);
    Tried Hostslocalhost:9142
    Queried Hostslocalhost:9142
    Schema in Agreementtrue
    \ No newline at end of file +
    No Result      
    InformationValue
    StatementCREATE TABLE IF NOT EXISTS no_select(id int PRIMARY KEY);
    Tried HostsTRIED_HOSTS
    Queried HostsQUERIED_HOSTS
    Schema in Agreementtrue
    \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9e021cbfc6f..a8e8a7f8f88 100644 --- a/pom.xml +++ b/pom.xml @@ -450,6 +450,13 @@ test + + org.testcontainers + cassandra + ${testcontainers.version} + test + + org.apache.hadoop hadoop-client-api From e887d7c41403d4dcd16114aa361f2097058e7bcf Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Wed, 12 Aug 2026 16:10:01 +0900 Subject: [PATCH 171/179] [ZEPPELIN-6528] Handle forbidden interpreter responses in classic UI ### What is this PR for? Apache Shiro 2.0.6 returns HTTP 403 for an authenticated user who lacks a required role. Shiro 1.13.0 returned HTTP 401 for the same authorization denial. The classic interpreter page only handled HTTP 401, so a 403 response did not show the permission error toast or redirect the user. This also caused `AuthenticationIT.testAnyOfRolesUser` to fail with `Expected ngToast not found`. This PR handles both 401 and 403 responses and adds controller tests covering both statuses. ### What type of PR is it? Bug Fix ### Todos * [x] Handle HTTP 403 authorization denials in the classic interpreter page * [x] Preserve the existing HTTP 401 behavior * [x] Add regression tests for both response statuses ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6528 ### How should this be tested? ```bash cd zeppelin-web npm run karma-test -- --single-run ``` Local validation: * ESLint passed for the changed controller and test. * `git diff --check` passed. * Karma compiled the application and test bundle successfully, but the browser run could not start locally because Firefox is not installed in the worktree environment. ### Screenshots N/A ### Questions * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this need documentation? No Closes #5416 from jongyoul/codex/ZEPPELIN-6528-handle-shiro-403. Signed-off-by: Cheng Pan --- .../app/interpreter/interpreter.controller.js | 2 +- .../interpreter.controller.test.js | 68 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 zeppelin-web/src/app/interpreter/interpreter.controller.test.js diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js b/zeppelin-web/src/app/interpreter/interpreter.controller.js index dddae0022cf..63db4d15250 100644 --- a/zeppelin-web/src/app/interpreter/interpreter.controller.js +++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js @@ -114,7 +114,7 @@ function InterpreterCtrl($rootScope, $scope, $http, baseUrlSrv, ngToast, $timeou $scope.interpreterSettings = res.data.body; checkDownloadingDependencies(); }).catch(function(res) { - if (res.status === 401) { + if (res.status === 401 || res.status === 403) { ngToast.danger({ content: 'You don\'t have permission on this page', verticalPosition: 'bottom', diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.test.js b/zeppelin-web/src/app/interpreter/interpreter.controller.test.js new file mode 100644 index 00000000000..0ceb6afda3f --- /dev/null +++ b/zeppelin-web/src/app/interpreter/interpreter.controller.test.js @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('Controller: Interpreter', function() { + beforeEach(angular.mock.module('zeppelinWebApp')); + + const baseUrlSrvMock = { + getBase: () => '/', + getRestApiBase: () => '', + }; + + let $controller; + let $httpBackend; + let $rootScope; + let ngToast; + + beforeEach(inject((_$controller_, _$httpBackend_, _$rootScope_, _ngToast_) => { + $controller = _$controller_; + $httpBackend = _$httpBackend_; + $rootScope = _$rootScope_; + ngToast = _ngToast_; + })); + + afterEach(function() { + $httpBackend.verifyNoOutstandingExpectation(); + $httpBackend.verifyNoOutstandingRequest(); + }); + + [401, 403].forEach((status) => { + it(`should display an authorization error for HTTP ${status}`, function() { + spyOn(ngToast, 'danger'); + spyOn(window, 'setTimeout'); + + $httpBackend.expectGET('/interpreter/property/types').respond(200, {body: []}); + $httpBackend.expectGET('/interpreter/setting').respond(status, {}); + $httpBackend.expectGET('/interpreter').respond(200, {body: []}); + $httpBackend.expectGET('/interpreter/repository').respond(200, {body: []}); + + $controller('InterpreterCtrl', { + $scope: $rootScope.$new(), + baseUrlSrv: baseUrlSrvMock, + $route: {current: {$$route: {originalPath: '/interpreter'}}}, + }); + $httpBackend.flush(); + + expect(ngToast.danger).toHaveBeenCalledWith({ + content: 'You don\'t have permission on this page', + verticalPosition: 'bottom', + timeout: '3000', + }); + expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 3000); + }); + }); +}); From 856cf2ad8ec066262b5c0af64db6ec31b2bf64a4 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Wed, 12 Aug 2026 23:24:45 +0900 Subject: [PATCH 172/179] [ZEPPELIN-6567] Give the Angular shell a self-contained unit test setup ### What is this PR for? This PR gives zeppelin-web-angular a self-contained unit test setup for Angular shell code. Previously, the shell unit test path depended on `projects/zeppelin-react` for `Vitest`/`jsdom`. That meant the shell test command crossed a package boundary, the Vitest config could not normally import `vitest/config`, and the spec tsconfig was not usable for real type checking. This PR adds `Vitest`/`jsdom` to the Angular package itself, adds a shell-only Vitest config and spec tsconfig, and wires `test:shell` into the existing npm run lint path so it runs through the Maven/GitHub test phase. It also keeps the Vitest setup file outside `src`, so it is not pulled into production Angular compilation. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6567 ### How should this be tested? Run from zeppelin-web-angular: ```sh npm run test:shell ``` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5401 from miinhho/self-contained-angular-shell-test-setup. Signed-off-by: ChanHo Lee --- zeppelin-web-angular/README.md | 4 +- zeppelin-web-angular/eslint.config.js | 20 +- zeppelin-web-angular/package-lock.json | 1816 +++++++++++++++-- zeppelin-web-angular/package.json | 13 +- zeppelin-web-angular/pom.xml | 11 + .../react-mount/react-mount.directive.spec.ts | 65 + zeppelin-web-angular/src/tsconfig.spec.json | 9 + zeppelin-web-angular/test/test-setup.ts | 13 + zeppelin-web-angular/vitest.shell.config.mts | 21 + 9 files changed, 1847 insertions(+), 125 deletions(-) create mode 100644 zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts create mode 100644 zeppelin-web-angular/src/tsconfig.spec.json create mode 100644 zeppelin-web-angular/test/test-setup.ts create mode 100644 zeppelin-web-angular/vitest.shell.config.mts diff --git a/zeppelin-web-angular/README.md b/zeppelin-web-angular/README.md index 9084494005d..f90c26f32b7 100644 --- a/zeppelin-web-angular/README.md +++ b/zeppelin-web-angular/README.md @@ -53,7 +53,7 @@ Run `npm run build` to build the project. The build artifacts will be stored in ### Running Unit Tests -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +Run `npm run test:shell` to execute the Angular shell unit tests via [Vitest](https://vitest.dev). ## Implementation Progress @@ -273,4 +273,4 @@ import * from '*' // Other third party modules import * from '@zeppelin/*' // This project modules // BLANK LINE import * from './*' // Same level modules -``` \ No newline at end of file +``` diff --git a/zeppelin-web-angular/eslint.config.js b/zeppelin-web-angular/eslint.config.js index b6bb00f695f..aa5cbc21ae7 100644 --- a/zeppelin-web-angular/eslint.config.js +++ b/zeppelin-web-angular/eslint.config.js @@ -38,7 +38,7 @@ module.exports = tseslint.config( linterOptions: { reportUnusedDisableDirectives: 'error' } }, { - files: ['**/*.ts'], + files: ['**/*.{ts,mts}'], // == legacy `plugin:@angular-eslint/recommended` (sets the TS parser and // the @angular-eslint plugin). The @typescript-eslint plugin is registered // separately below because tsRecommended does not bring it in. @@ -157,6 +157,24 @@ module.exports = tseslint.config( '@angular-eslint/directive-selector': ['error', { type: 'attribute', prefix: 'lib', style: 'camelCase' }] } }, + { + // Shell unit specs live outside the Angular build tsconfig, which excludes + // *.spec.ts. Point type-aware linting at the spec program explicitly. + files: ['src/**/*.spec.ts', 'test/test-setup.ts', 'vitest.shell.config.mts'], + languageOptions: { + parserOptions: { + project: ['./src/tsconfig.spec.json'], + tsconfigRootDir: __dirname + } + } + }, + { + // The shell test setup intentionally loads Zone.js for its side effects. + files: ['test/test-setup.ts'], + rules: { + 'import/no-unassigned-import': 'off' + } + }, { // ZEPPELIN-6325 / ZEPPELIN-6372: keep public-api.ts barrels alphabetically // ordered by module specifier. Delegated to eslint-plugin-perfectionist diff --git a/zeppelin-web-angular/package-lock.json b/zeppelin-web-angular/package-lock.json index 6e5e275dbd2..661678df451 100644 --- a/zeppelin-web-angular/package-lock.json +++ b/zeppelin-web-angular/package-lock.json @@ -58,7 +58,7 @@ "@types/jquery": "3.5.16", "@types/lodash": "4.14.144", "@types/mathjax": "^0.0.35", - "@types/node": "~12.19.16", + "@types/node": "22.12.0", "@types/parse5": "^5.0.2", "@types/webpack-env": "^1.18.8", "angular-eslint": "21.4.0", @@ -74,6 +74,7 @@ "eslint-plugin-prefer-arrow": "^1.2.3", "https-proxy-agent": "^2.2.1", "husky": "9.1.7", + "jsdom": "29.1.1", "lint-staged": "^15.5.2", "monaco-editor-webpack-plugin": "7.0.1", "ng-packagr": "^21.2.3", @@ -83,7 +84,8 @@ "style-loader": "^4.0.0", "ts-node": "~7.0.0", "typescript": "~5.9.3", - "typescript-eslint": "^8.33.1" + "typescript-eslint": "^8.33.1", + "vitest": "4.1.8" }, "engines": { "node": ">=22.12.0" @@ -611,18 +613,6 @@ } } }, - "node_modules/@angular-builders/custom-webpack/node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, "node_modules/@angular-builders/custom-webpack/node_modules/@vitejs/plugin-basic-ssl": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", @@ -1216,18 +1206,6 @@ } } }, - "node_modules/@angular-devkit/build-angular/node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -1642,23 +1620,6 @@ "typescript": "*" } }, - "node_modules/@angular/animations": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.15.tgz", - "integrity": "sha512-Z8AsLTwc++Fcu0fJnclAF9zMfumAd5KXrwtSdyECqLpqd+lEmmsOpeOl6P7loqdDz99KYh/8UF4eJxdMvnsaKw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@angular/core": "21.2.15" - } - }, "node_modules/@angular/cdk": { "version": "21.2.13", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.13.tgz", @@ -2081,18 +2042,6 @@ "listr2": "9.0.5" } }, - "node_modules/@angular/cli/node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" - } - }, "node_modules/@angular/cli/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2526,6 +2475,57 @@ "@antv/gl-matrix": "^2.7.1" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -4268,6 +4268,19 @@ "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -4292,6 +4305,146 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", + "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.3.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", + "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@ctrl/tinycolor": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", @@ -7421,6 +7574,40 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.3.tgz", + "integrity": "sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.3.tgz", + "integrity": "sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/binding-linux-x64-gnu": { "version": "1.0.0-rc.4", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", @@ -8438,6 +8625,17 @@ "@types/node": "*" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", @@ -8459,6 +8657,13 @@ "@types/node": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/diff-match-patch": { "version": "1.0.36", "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz", @@ -8598,11 +8803,14 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "12.19.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.16.tgz", - "integrity": "sha512-7xHmXm/QJ7cbK2laF+YYD7gb5MggHIIQwqyjin3bpEGiSuvScMQ5JZZXPvRipi1MwckTQbJZROMns/JxdnIL1Q==", + "version": "22.12.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.12.0.tgz", + "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } }, "node_modules/@types/parse5": { "version": "5.0.3", @@ -8950,42 +9158,172 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "node_modules/@vitest/expect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", "dev": true, "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "node_modules/@vitest/mocker": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "node_modules/@vitest/pretty-format": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.8", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, "license": "MIT", "dependencies": { @@ -9710,6 +10048,16 @@ "node": ">=12.0.0" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -9901,6 +10249,16 @@ "node": ">=18.0.0" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -10250,6 +10608,16 @@ "node": ">=0.8" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -11021,6 +11389,20 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", @@ -11264,6 +11646,20 @@ "node": ">= 12" } }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -11352,6 +11748,13 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-equal": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", @@ -11508,7 +11911,6 @@ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "dev": true, "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -12910,6 +13312,16 @@ "node": ">=0.10.0" } }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", @@ -14030,6 +14442,52 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/html-encoding-sniffer/node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/html-encoding-sniffer/node_modules/@noble/hashes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz", + "integrity": "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/htmlparser2": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", @@ -14808,6 +15266,13 @@ "node": ">=0.10.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -15153,6 +15618,126 @@ "node": ">=12.0.0" } }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/@noble/hashes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz", + "integrity": "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/jsdom/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jsdom/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -15406,25 +15991,286 @@ } } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, "engines": { - "node": ">=14" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" }, "node_modules/lint-staged": { "version": "15.5.2", @@ -15896,6 +16742,13 @@ "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==", "license": "Apache-2.0" }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -16413,9 +17266,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -17110,6 +17963,20 @@ "dev": true, "license": "MIT" }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -17615,6 +18482,13 @@ "url": "https://opencollective.com/express" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -18852,6 +19726,19 @@ "node": ">=11.0.0" } }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scandirectory": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/scandirectory/-/scandirectory-8.1.1.tgz", @@ -19299,6 +20186,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -19600,6 +20494,13 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -19610,6 +20511,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, "node_modules/stdin-discarder": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", @@ -19826,6 +20734,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/systemjs": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/systemjs/-/systemjs-5.0.0.tgz", @@ -20088,6 +21003,23 @@ "dev": true, "license": "MIT" }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -20105,14 +21037,44 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", "dev": true, "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz", + "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.10" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", + "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" }, "engines": { "node": ">=8.0" @@ -20148,6 +21110,32 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/tree-dump": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.1.0.tgz", @@ -20520,13 +21508,11 @@ } }, "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, - "license": "MIT", - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", @@ -20714,6 +21700,500 @@ "url": "https://bevry.me/fund" } }, + "node_modules/vite": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", + "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.25", + "rolldown": "~1.2.1", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.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 + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@oxc-project/types": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.143.0.tgz", + "integrity": "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.3.tgz", + "integrity": "sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.3.tgz", + "integrity": "sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.3.tgz", + "integrity": "sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.3.tgz", + "integrity": "sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.3.tgz", + "integrity": "sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.3.tgz", + "integrity": "sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.3.tgz", + "integrity": "sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.3.tgz", + "integrity": "sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.3.tgz", + "integrity": "sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.3.tgz", + "integrity": "sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/vite/node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/vite/node_modules/rolldown": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.3.tgz", + "integrity": "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.143.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.3", + "@rolldown/binding-darwin-arm64": "1.2.3", + "@rolldown/binding-darwin-x64": "1.2.3", + "@rolldown/binding-freebsd-x64": "1.2.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", + "@rolldown/binding-linux-arm64-gnu": "1.2.3", + "@rolldown/binding-linux-arm64-musl": "1.2.3", + "@rolldown/binding-linux-ppc64-gnu": "1.2.3", + "@rolldown/binding-linux-s390x-gnu": "1.2.3", + "@rolldown/binding-linux-x64-gnu": "1.2.3", + "@rolldown/binding-linux-x64-musl": "1.2.3", + "@rolldown/binding-openharmony-arm64": "1.2.3", + "@rolldown/binding-win32-arm64-msvc": "1.2.3", + "@rolldown/binding-win32-x64-msvc": "1.2.3" + } + }, + "node_modules/vite/node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vitest": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/watchpack": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", @@ -20756,6 +22236,16 @@ "node": ">= 8" } }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, "node_modules/webpack": { "version": "5.107.2", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.2.tgz", @@ -21447,6 +22937,64 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/whatwg-url/node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/whatwg-url/node_modules/@noble/hashes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz", + "integrity": "sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -21554,6 +23102,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -21722,6 +23287,23 @@ "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", "license": "MIT" }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/zeppelin-web-angular/package.json b/zeppelin-web-angular/package.json index 48421f7b218..5a724f9a9c4 100644 --- a/zeppelin-web-angular/package.json +++ b/zeppelin-web-angular/package.json @@ -14,10 +14,11 @@ "build:projects": "npm run build-project:sdk && npm run build-project:vis", "build-project:sdk": "ng build --project zeppelin-sdk", "build-project:vis": "ng build --project zeppelin-visualization", - "lint": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint && npm run lint:react && prettier --check \"**/*.{ts,tsx,js,json,css,html}\"", - "lint:fix": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint --fix && npm run lint:fix:react && prettier --write \"**/*.{ts,tsx,js,json,css,html}\"", + "lint": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint && npm run lint:react && prettier --check \"**/*.{ts,tsx,mts,js,json,css,html}\"", + "lint:fix": "cross-env NODE_OPTIONS='--max-old-space-size=8192' ng lint --fix && npm run lint:fix:react && prettier --write \"**/*.{ts,tsx,mts,js,json,css,html}\"", "lint:react": "cd projects/zeppelin-react && npm run lint", "lint:fix:react": "cd projects/zeppelin-react && npm run lint:fix", + "test:shell": "vitest run --config vitest.shell.config.mts", "test:eslint-rules": "node --test eslint-rules/", "e2e": "playwright test", "e2e:fast": "playwright test --project=chromium", @@ -85,7 +86,7 @@ "@types/jquery": "3.5.16", "@types/lodash": "4.14.144", "@types/mathjax": "^0.0.35", - "@types/node": "~12.19.16", + "@types/node": "22.12.0", "@types/parse5": "^5.0.2", "@types/webpack-env": "^1.18.8", "angular-eslint": "21.4.0", @@ -101,6 +102,7 @@ "eslint-plugin-prefer-arrow": "^1.2.3", "https-proxy-agent": "^2.2.1", "husky": "9.1.7", + "jsdom": "29.1.1", "lint-staged": "^15.5.2", "monaco-editor-webpack-plugin": "7.0.1", "ng-packagr": "^21.2.3", @@ -110,13 +112,14 @@ "style-loader": "^4.0.0", "ts-node": "~7.0.0", "typescript": "~5.9.3", - "typescript-eslint": "^8.33.1" + "typescript-eslint": "^8.33.1", + "vitest": "4.1.8" }, "overrides": { "@babel/runtime": "^7.27.0" }, "lint-staged": { - "**/*.ts": [ + "**/*.{ts,mts}": [ "cross-env NODE_OPTIONS='--max-old-space-size=8192' eslint --fix", "./node_modules/.bin/prettier --write" ], diff --git a/zeppelin-web-angular/pom.xml b/zeppelin-web-angular/pom.xml index 6c9a164688e..3f2fee17ff1 100644 --- a/zeppelin-web-angular/pom.xml +++ b/zeppelin-web-angular/pom.xml @@ -118,6 +118,17 @@ + + npm test shell + + npm + + test + + run test:shell + + + npm e2e diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts new file mode 100644 index 00000000000..7a9862707f2 --- /dev/null +++ b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts @@ -0,0 +1,65 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ElementRef, NgZone, SimpleChange } from '@angular/core'; +import { describe, expect, it, vi } from 'vitest'; + +import { ReactRemoteLoaderService } from './react-remote-loader.service'; +import { ReactExposedModule, ReactMountHandle, ReactProps } from './react-mount-handle'; +import { ReactMountDirective } from './react-mount.directive'; + +describe('ReactMountDirective', () => { + it('mounts React remotes outside the Angular zone without TestBed', async () => { + const host = new ElementRef(document.createElement('div')); + const ngZone = new NgZone({}); + const mountedOutsideZone: boolean[] = []; + let insideRunOutsideAngular = false; + const unmount = vi.fn(); + const mountHandle: ReactMountHandle = { + update: vi.fn(), + unmount + }; + const remote: ReactExposedModule = { + mount: (_element: HTMLElement, _props: ReactProps) => { + mountedOutsideZone.push(insideRunOutsideAngular); + return mountHandle; + } + }; + const loadModule = vi.fn(async (): Promise => remote as T); + const loader = { loadModule } as Pick; + // zone.js cannot patch the native async/await vitest emits. + // isInAngularZone() is therefore always false past the await. + const runOutsideAngular = ngZone.runOutsideAngular.bind(ngZone); + vi.spyOn(ngZone, 'runOutsideAngular').mockImplementation((fn: () => unknown) => { + insideRunOutsideAngular = true; + try { + return runOutsideAngular(fn); + } finally { + insideRunOutsideAngular = false; + } + }); + const directive = new ReactMountDirective(host, ngZone, loader as ReactRemoteLoaderService); + + directive.module = 'paragraph-footer'; + directive.ngOnChanges({ + module: new SimpleChange(undefined, directive.module, true) + }); + await vi.waitFor(() => expect(mountedOutsideZone).toHaveLength(1)); + + expect(loadModule).toHaveBeenCalledWith('paragraph-footer'); + expect(mountedOutsideZone).toEqual([true]); + + directive.ngOnDestroy(); + + expect(unmount).toHaveBeenCalledOnce(); + }); +}); diff --git a/zeppelin-web-angular/src/tsconfig.spec.json b/zeppelin-web-angular/src/tsconfig.spec.json new file mode 100644 index 00000000000..ba47facd5a4 --- /dev/null +++ b/zeppelin-web-angular/src/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": ["mathjax", "node"] + }, + "include": ["**/*.spec.ts", "../test/test-setup.ts", "../vitest.shell.config.mts"], + "exclude": [] +} diff --git a/zeppelin-web-angular/test/test-setup.ts b/zeppelin-web-angular/test/test-setup.ts new file mode 100644 index 00000000000..7d0997c797d --- /dev/null +++ b/zeppelin-web-angular/test/test-setup.ts @@ -0,0 +1,13 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import 'zone.js'; diff --git a/zeppelin-web-angular/vitest.shell.config.mts b/zeppelin-web-angular/vitest.shell.config.mts new file mode 100644 index 00000000000..4799e537f6e --- /dev/null +++ b/zeppelin-web-angular/vitest.shell.config.mts @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + include: ['src/**/*.spec.ts'], + setupFiles: ['./test/test-setup.ts'] + } +}); From c199b4074278316c99e5cc53304aeca3992b5f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Thu, 13 Aug 2026 01:05:56 +0900 Subject: [PATCH 173/179] [ZEPPELIN-6638] Time out the React remote entry load ### What is this PR for? `ReactRemoteLoaderService` settles `loadContainer()` only from the script tag's `onload` and `onerror`. Neither fires while a request is merely pending, and there is no timer. A `remoteEntry.js` request that the server accepts and never answers therefore leaves the promise pending for as long as the browser keeps the connection open, which is minutes. `onError` is never called, so the hosts that depend on it never fall back. The paragraph footer keeps an empty mount div instead of restoring `zeppelin-notebook-paragraph-footer`, and the published paragraph renders nothing. Both look like a slow page rather than a failed load. This bounds the script load with `environment.reactRemoteLoadTimeoutMs` (10 s, or 0 to disable) and reuses the existing `fail()` path on expiry, which removes the tag and leaves the caches drained so a later mount can retry. The chunks that `container.get()` pulls are left alone. They are fetched by the remote's own webpack runtime, which already bounds them with `output.chunkLoadTimeout` (120 s by default). A second, shorter timer over that path would cut off a multi-megabyte chunk on a slow connection, which is a worse failure than the one being fixed. ### What type of PR is it? Bug Fix ### Todos None ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6638 ### How should this be tested? * Two new Playwright cases in `e2e/tests/notebook/paragraph/react-footer.spec.ts`: one holds `remoteEntry.js` open without ever answering and asserts the Angular footer comes back, one answers after a delay well inside the budget and asserts the React footer still renders. The first fails on master and passes here; verified by setting the budget to 0, which reproduces the current behaviour and makes it fail. * The existing abort and delay cases in the same suite, and `e2e/tests/notebook/published/published-paragraph.spec.ts`, for regressions. Chromium, all green. * A production build (`npm run build`). * A unit spec for the service would be the better home for the timer, but the Angular shell has no test harness on master yet (ZEPPELIN-6566, ZEPPELIN-6567, ZEPPELIN-6637) and this file carries an `Injectable` decorator, which the current setup cannot compile. Left to a follow-up once that lands. ### Screenshots (if appropriate) No ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? Yes, the loader section of `projects/zeppelin-react/README.md` is updated in this PR Closes #5409 from kimyenac/ZEPPELIN-6638. Signed-off-by: YONGJAE LEE --- .../notebook/paragraph/react-footer.spec.ts | 42 +++++++++++++++++++ .../projects/zeppelin-react/README.md | 4 +- .../react-remote-loader.service.ts | 20 ++++++++- .../src/environments/environment.prod.ts | 3 +- .../src/environments/environment.ts | 5 ++- 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts index fd102b36d4d..b82065f9bc9 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/paragraph/react-footer.spec.ts @@ -83,6 +83,48 @@ test.describe('React Paragraph Footer', () => { await expect(page.locator('[data-testid="react-paragraph-footer"]')).toHaveCount(0); }); + test('when the remote never answers, paragraphs fall back to the Angular footer', async ({ page }) => { + const { noteId } = testNotebook; + + await test.step('Given a remote that accepts the request and never answers', async () => { + // The handler settles nothing on purpose: the request is left open. + await page.route('**/remoteEntry.js', () => {}); + }); + + await test.step('When the notebook opens with the React footer enabled', async () => { + await page.goto(`/#/notebook/${noteId}?reactFooter=true`); + await waitForZeppelinReady(page); + }); + + await test.step('Then the Angular footer takes over once the load budget expires', async () => { + await expect(page.locator('[data-testid="angular-paragraph-footer"]').first()).toBeAttached({ timeout: 30000 }); + await expect(page.locator('[data-testid="react-paragraph-footer"]')).toHaveCount(0); + }); + }); + + test('a remote that answers within the budget still renders the React footer', async ({ page }) => { + const { noteId } = testNotebook; + + await test.step('Given a remote that answers slowly but well inside the budget', async () => { + await page.route('**/remoteEntry.js', async route => { + await new Promise(r => setTimeout(r, 2000)); + await route.continue(); + }); + }); + + await test.step('When the notebook opens with the React footer enabled', async () => { + await page.goto(`/#/notebook/${noteId}?reactFooter=true`); + await waitForZeppelinReady(page); + }); + + await test.step('Then the React footer renders and no fallback happens', async () => { + await expect(page.locator('[data-testid="react-paragraph-footer-content"]').first()).toBeAttached({ + timeout: 20000 + }); + await expect(page.locator('[data-testid="angular-paragraph-footer"]')).toHaveCount(0); + }); + }); + test('navigating away during remoteEntry load does not throw', async ({ page }) => { const { noteId } = testNotebook; diff --git a/zeppelin-web-angular/projects/zeppelin-react/README.md b/zeppelin-web-angular/projects/zeppelin-react/README.md index f452ee1455a..a32e90643f3 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/README.md +++ b/zeppelin-web-angular/projects/zeppelin-react/README.md @@ -21,7 +21,9 @@ React micro-frontend that runs alongside the Angular host via [Webpack Module Fe The Angular host's `src/app/share/react-mount/` exports two pieces: - `ReactRemoteLoaderService` — loads `remoteEntry.js` once per page, - caches per-module promises, evicts on error. + caches per-module promises, evicts on error. The load is bounded by + `environment.reactRemoteLoadTimeoutMs`, so a remote that stalls instead + of failing still reaches the host's `onError` and its fallback. - `ReactMountDirective` — owns the host element, mounts outside the Angular zone, forwards `[reactProps]` changes through `handle.update(...)`, and unmounts on destroy. Re-checks `destroyed` diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts b/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts index c3f45911ea5..2c903f529af 100644 --- a/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts +++ b/zeppelin-web-angular/src/app/share/react-mount/react-remote-loader.service.ts @@ -45,14 +45,20 @@ export class ReactRemoteLoaderService { script.src = environment.reactRemoteEntryUrl; script.async = true; - // Remove the tag on *any* failure (network error or loaded-but-unregistered): - // containerPromise resets on rejection, so each retry would otherwise leak a tag. + const timeoutMs = environment.reactRemoteLoadTimeoutMs; + let timer: ReturnType | undefined; + + // Remove the tag on *any* failure (network error, timeout, or + // loaded-but-unregistered): containerPromise resets on rejection, so each + // retry would otherwise leak a tag. const fail = (message: string) => { + clearTimeout(timer); script.remove(); reject(new Error(message)); }; script.onload = () => { + clearTimeout(timer); if (!window.reactApp) { fail('window.reactApp not registered after script load'); return; @@ -60,6 +66,16 @@ export class ReactRemoteLoaderService { resolve(window.reactApp); }; script.onerror = () => fail(`Failed to load React remote at ${script.src}`); + + // A request the server accepts but never answers fires neither onload nor + // onerror, so without this the promise stays pending for minutes. + if (timeoutMs > 0) { + timer = setTimeout( + () => fail(`Timed out after ${timeoutMs} ms loading the React remote at ${script.src}`), + timeoutMs + ); + } + document.head.appendChild(script); }); diff --git a/zeppelin-web-angular/src/environments/environment.prod.ts b/zeppelin-web-angular/src/environments/environment.prod.ts index 8613a332bc6..606214bc641 100644 --- a/zeppelin-web-angular/src/environments/environment.prod.ts +++ b/zeppelin-web-angular/src/environments/environment.prod.ts @@ -12,5 +12,6 @@ export const environment = { production: true, - reactRemoteEntryUrl: '/assets/react/remoteEntry.js' + reactRemoteEntryUrl: '/assets/react/remoteEntry.js', + reactRemoteLoadTimeoutMs: 10000 }; diff --git a/zeppelin-web-angular/src/environments/environment.ts b/zeppelin-web-angular/src/environments/environment.ts index c20bf371d28..aab3beca1be 100644 --- a/zeppelin-web-angular/src/environments/environment.ts +++ b/zeppelin-web-angular/src/environments/environment.ts @@ -16,7 +16,10 @@ export const environment = { production: false, - reactRemoteEntryUrl: 'http://localhost:3001/remoteEntry.js' + reactRemoteEntryUrl: 'http://localhost:3001/remoteEntry.js', + // Budget for fetching remoteEntry.js, after which the host falls back. + // Set to 0 to disable the timer. + reactRemoteLoadTimeoutMs: 10000 }; /* From 0f4991d6681d8b9c407e97f355cbf41d290df6d3 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Thu, 13 Aug 2026 09:11:06 +0900 Subject: [PATCH 174/179] [ZEPPELIN-6432] Modernize the Jekyll documentation build ### What is this PR for? Modernize the versioned documentation build and keep its publication output compatible with `zeppelin-site`. - Replace `github-pages` / Jekyll 3.9.5 / Redcarpet with Jekyll 4.4.1 and Kramdown GFM. - Make Docker the documented environment for dependency updates, preview, and production builds. - Exclude build-only files from `_site` and document the Zeppelin-to-`zeppelin-site` publication boundary. - Remove obsolete third-party analytics, comment, sharing, and feed integrations. - Replace two externally hosted graph diagrams with original Apache-licensed SVG diagrams. - Preserve Apache Zeppelin's approved ASF Matomo site ID 69 only in `--safe` production builds. - Add a generated-site check for non-ASF embedded resources and unapproved trackers. This also prevents the build manifests covered by ZEPPELIN-6431 from being copied into future versioned documentation snapshots. Cleaning historical snapshots remains work in `apache/zeppelin-site`. ### What type of PR is it? Improvement ### Todos * [x] Upgrade the Jekyll and Ruby toolchain. * [x] Document and verify the Docker-only build. * [x] Remove legacy integrations and empty Atom/RSS feeds. * [x] Replace external documentation images with original local SVG diagrams. * [x] Preserve approved ASF Matomo tracking for production docs. * [x] Verify generated output and external-resource policy. ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6432 * Related: https://issues.apache.org/jira/browse/ZEPPELIN-6431 ### How should this be tested? From `docs/`: ```bash docker run --rm \ --user "$(id -u):$(id -g)" \ -e HOME=/usr/local/bundle \ -e BUNDLE_FROZEN=true \ -v "$PWD:/docs" \ -w /docs \ ruby:4.0.6 \ bash -lc "bundle install && bundle exec jekyll build --safe" ``` Then: ```bash docker run --rm \ -v "$PWD:/docs:ro" \ -w /docs \ ruby:4.0.6 \ ruby check_external_resources.rb _site ``` The final verification generated 94 HTML files with Jekyll 4.4.1, emitted no build warnings, retained ASF Matomo site ID 69 only in the safe build, and produced no Atom/RSS or build-manifest output. It also verified that both original SVG diagrams are present in the generated site without the previous GitHub/S3 resource URLs. The full Apache RAT check passed for all 56 reactor modules. ### Screenshots (if appropriate) The replacement diagrams are committed as SVG files and rendered directly by the documentation page; this PR does not change the documentation CSS or page layout. ### Questions: * Does the license files need to update? No. * Is there breaking changes for older versions? No runtime behavior changes; this affects the documentation build and generated output. * Does this needs documentation? `docs/README.md` and `docs/AGENTS.md` are updated. Closes #5372 from jongyoul/codex/docs-agents-guide. Signed-off-by: Jongyoul Lee --- docs/AGENTS.md | 198 ++++++++++++ docs/Gemfile | 4 +- docs/Gemfile.lock | 288 ++++-------------- docs/README.md | 110 +++---- docs/_config.yml | 54 +--- docs/_includes/JB/analytics | 18 -- .../JB/analytics-providers/getclicky | 12 - .../JB/analytics-providers/google-classic | 11 - .../JB/analytics-providers/google-universal | 11 - .../_includes/JB/analytics-providers/mixpanel | 11 - docs/_includes/JB/analytics-providers/piwik | 10 - docs/_includes/JB/comments | 16 - docs/_includes/JB/comments-providers/disqus | 14 - docs/_includes/JB/comments-providers/facebook | 9 - .../JB/comments-providers/intensedebate | 6 - docs/_includes/JB/comments-providers/livefyre | 6 - docs/_includes/JB/matomo | 33 ++ docs/_includes/JB/sharing | 8 - docs/_includes/themes/zeppelin/default.html | 12 +- docs/_includes/themes/zeppelin/post.html | 2 - .../docs-img/labeled-property-graph-model.svg | 86 ++++++ .../img/docs-img/property-graph-example.svg | 87 ++++++ docs/atom.xml | 28 -- docs/check_external_resources.rb | 90 ++++++ .../contribution/how_to_contribute_code.md | 2 +- .../contribution/how_to_contribute_website.md | 2 +- .../writing_visualization_transformation.md | 3 +- .../writing_zeppelin_interpreter.md | 2 +- docs/index.md | 5 +- docs/interpreter/bigquery.md | 2 +- docs/interpreter/cassandra.md | 174 +++++------ docs/interpreter/elasticsearch.md | 8 +- docs/interpreter/flink.md | 36 +-- docs/interpreter/hdfs.md | 5 +- docs/interpreter/livy.md | 4 +- docs/interpreter/mahout.md | 20 +- docs/interpreter/markdown.md | 2 +- docs/interpreter/mongodb.md | 2 +- docs/interpreter/neo4j.md | 2 +- docs/interpreter/python.md | 2 +- docs/interpreter/shell.md | 6 +- docs/interpreter/spark.md | 19 +- docs/quickstart/docker.md | 4 +- docs/rss.xml | 28 -- .../deployment/flink_and_spark_cluster.md | 4 +- docs/setup/deployment/yarn_install.md | 4 +- docs/setup/operation/configuration.md | 8 +- docs/setup/operation/upgrading.md | 2 +- docs/setup/security/http_security_headers.md | 2 +- docs/setup/security/shiro_authentication.md | 2 +- docs/setup/storage/notebook_storage.md | 20 +- docs/usage/display_system/angular_frontend.md | 8 +- docs/usage/display_system/basic.md | 4 +- docs/usage/dynamic_form/intro.md | 10 +- docs/usage/interpreter/dynamic_loading.md | 4 +- docs/usage/interpreter/overview.md | 2 +- docs/usage/other_features/zeppelin_context.md | 8 +- docs/usage/rest_api/configuration.md | 12 +- docs/usage/rest_api/credential.md | 26 +- docs/usage/rest_api/helium.md | 80 ++--- docs/usage/rest_api/interpreter.md | 72 ++--- docs/usage/rest_api/notebook.md | 231 +++++++------- docs/usage/rest_api/notebook_repository.md | 20 +- docs/usage/rest_api/zeppelin_server.md | 14 +- 64 files changed, 1014 insertions(+), 971 deletions(-) create mode 100644 docs/AGENTS.md delete mode 100644 docs/_includes/JB/analytics delete mode 100644 docs/_includes/JB/analytics-providers/getclicky delete mode 100644 docs/_includes/JB/analytics-providers/google-classic delete mode 100644 docs/_includes/JB/analytics-providers/google-universal delete mode 100644 docs/_includes/JB/analytics-providers/mixpanel delete mode 100755 docs/_includes/JB/analytics-providers/piwik delete mode 100644 docs/_includes/JB/comments delete mode 100644 docs/_includes/JB/comments-providers/disqus delete mode 100644 docs/_includes/JB/comments-providers/facebook delete mode 100644 docs/_includes/JB/comments-providers/intensedebate delete mode 100644 docs/_includes/JB/comments-providers/livefyre create mode 100644 docs/_includes/JB/matomo delete mode 100644 docs/_includes/JB/sharing create mode 100644 docs/assets/themes/zeppelin/img/docs-img/labeled-property-graph-model.svg create mode 100644 docs/assets/themes/zeppelin/img/docs-img/property-graph-example.svg delete mode 100644 docs/atom.xml create mode 100644 docs/check_external_resources.rb delete mode 100644 docs/rss.xml diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 00000000000..7f2b05cef5e --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,198 @@ + + +# AGENTS.md + +> Scoped guidance for work under `docs/`. This file complements the +> repository-root `AGENTS.md`. + +## Scope And Ownership + +- `docs/` is the source for Apache Zeppelin's versioned product documentation. +- The main `zeppelin.apache.org` website is maintained in + `apache/zeppelin-site`; its homepage does not need to use the same generator + as these versioned docs. +- Markdown, layouts, includes, and assets in this directory are built here. + The generated site is written to `docs/_site/`. +- `docs/_site/` is generated and gitignored. Never edit or commit it. + +## Build Model + +The current build is: + +```text +docs sources + docs/_config.yml + -> Jekyll from docs/Gemfile.lock + -> docs/_site/ + -> zeppelin-site/docs// during a separate publication step +``` + +- `Gemfile` declares Jekyll and its documentation build dependencies. +- `Gemfile.lock` pins the actual Ruby dependency versions. The Docker commands + use `bundle exec` so the pinned Jekyll version is used. +- `_config.yml` supplies `ZEPPELIN_VERSION` and `JB.BASE_PATH`. +- `_includes/JB/setup` applies `JB.BASE_PATH` only for a safe build. Therefore + a publication build must include `--safe`. +- `Rakefile` contains legacy Jekyll-Bootstrap helpers. It is not the primary + build entry point; use the Docker commands below. +- The Maven build does not generate this site. +- Docker is the supported build environment. Do not install or run Ruby, + Bundler, or Jekyll directly on the host. + +## Preview And Build + +Preview with Docker: + +```bash +cd docs +docker run --rm -it \ + --user "$(id -u):$(id -g)" \ + -e HOME=/usr/local/bundle \ + -e BUNDLE_FROZEN=true \ + -v "$PWD:/docs" \ + -w /docs \ + -p '4000:4000' \ + ruby:4.0.6 \ + bash -lc "bundle install && bundle exec jekyll serve --watch --host 0.0.0.0" +``` + +Open `http://localhost:4000`. The preview intentionally runs without +`--safe`, so links are rooted at `/` instead of the production version path. +The container uses the current user's UID and GID so generated files remain +owned by that user on the host. The Ruby image's writable gem directory is +also used as the container home for that user. + +Build the publication artifact with Docker: + +```bash +cd docs +docker run --rm \ + --user "$(id -u):$(id -g)" \ + -e HOME=/usr/local/bundle \ + -e BUNDLE_FROZEN=true \ + -v "$PWD:/docs" \ + -w /docs \ + ruby:4.0.6 \ + bash -lc "bundle install && bundle exec jekyll build --safe" +``` + +The output must be under `_site/`, and generated links and assets must use the +`JB.BASE_PATH` configured in `_config.yml`. + +When `Gemfile` changes, update `Gemfile.lock` inside Docker: + +```bash +cd docs +docker run --rm \ + --user "$(id -u):$(id -g)" \ + -e HOME=/usr/local/bundle \ + -v "$PWD:/docs" \ + -w /docs \ + ruby:4.0.6 \ + bundle lock --update +``` + +Run the publication build after updating the lockfile. + +## Authoring Conventions + +- Preserve the ASF license header in every new source file. +- Follow the front matter used by nearby pages: + + ```yaml + --- + layout: page + title: "Page title" + description: "Short description" + group: section/subsection + --- + ``` + +- Include `{% include JB/setup %}` before page content when following the + existing page layout. +- Prefix internal site links and assets with `{{BASE_PATH}}` when an absolute + site path is needed. Production docs are hosted below `/docs//`, + not at the domain root. +- Update `_includes/themes/zeppelin/_navigation.html` when a page must appear + in the global documentation navigation. +- Keep filenames, headings, and link targets stable unless the task explicitly + includes redirects or link migration. +- Check the corresponding source code or configuration template when + documenting runtime behavior. Do not infer current behavior from an older + documentation page. + +## Version Handling + +- `ZEPPELIN_VERSION` and `JB.BASE_PATH` in `_config.yml` must identify the same + version. +- `dev/change_zeppelin_version.sh` updates both values as part of a repository + version change. Do not change them for an ordinary documentation edit. +- Before producing release docs, verify that `JB.BASE_PATH` is exactly + `/docs/`. + +## Publication Boundary + +- Building this directory does not publish the website. +- The generated `_site/` tree is copied into + `apache/zeppelin-site/docs//` by separate release/site work. +- The `zeppelin-site` repository owns the homepage, ASF staging/publishing, + and the mapping or redirect for `/docs/latest/`. +- Do not modify `zeppelin-site`, historical documentation snapshots, or + publication branches unless the user explicitly includes that work. + +## ASF Website Policy + +- Follow the ASF project website policy at + `https://privacy.apache.org/policies/website-policy.html` and the Infra CSP + guidance at `https://infra.apache.org/csp.html`. +- Do not add Google Analytics or any other third-party analytics, tracker, + tracking pixel, advertising tag, or external monitoring script. +- Do not load JavaScript, CSS, fonts, images, or other assets from non-ASF + domains. Host an asset in this repository when its license permits, or use a + normal external link instead of embedding it. +- Third-party embeds require the consent and DPA handling described by the ASF + policy. Prefer a direct link unless the task explicitly includes an approved + consent flow. +- The production layout uses the ASF-hosted Matomo instance provisioned for + Apache Zeppelin as site ID `69`. Do not replace it with another analytics + service or change its endpoint without Privacy team approval. + +## Verification + +For every documentation change: + +1. Run the Docker publication build above from `docs/`. +2. Confirm `_site/index.html` and the generated file for each changed page + exist. +3. Check generated navigation, links, images, and code blocks for the affected + pages. +4. Confirm generated URLs use the configured `/docs//` prefix. +5. Check the generated site for external trackers and embedded resources: + + ```bash + docker run --rm \ + -v "$PWD:/docs:ro" \ + -w /docs \ + ruby:4.0.6 \ + ruby check_external_resources.rb _site + ``` + +6. Run `git status --short` and keep `_site/` and incidental dependency changes + out of the commit. + +For navigation, layout, CSS, or JavaScript changes, also run the preview server +and inspect the affected pages at desktop and narrow viewport widths. diff --git a/docs/Gemfile b/docs/Gemfile index 9cc8cfef180..160ec9c8fef 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -14,9 +14,7 @@ # limitations under the License. # source 'https://rubygems.org' -gem 'github-pages' -gem 'redcarpet' -gem 'jekyll-twitter-plugin' +gem 'jekyll', '4.4.1' gem 'nokogiri', '1.19.3' gem 'mini_portile2', '2.8.4' diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index e27c883f6f5..7ac28335bcb 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,237 +1,69 @@ GEM remote: https://rubygems.org/ specs: - activesupport (7.2.3.1) - base64 - benchmark (>= 0.3) - bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - logger (>= 1.4.2) - minitest (>= 5.1, < 6) - securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) base64 (0.3.0) - benchmark (0.5.0) bigdecimal (4.1.2) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) colorator (1.1.0) - commonmarker (0.23.10) - concurrent-ruby (1.3.6) - connection_pool (3.0.2) - dnsruby (1.72.2) - simpleidn (~> 0.2.1) - drb (2.2.3) + concurrent-ruby (1.3.8) + csv (3.3.5) em-websocket (0.5.3) eventmachine (>= 0.12.9) http_parser.rb (~> 0) - ethon (0.16.0) - ffi (>= 1.15.0) eventmachine (1.2.7) - execjs (2.9.1) - faraday (2.14.1) - faraday-net_http (>= 2.0, < 3.5) - json - logger - faraday-net_http (3.4.2) - net-http (~> 0.5) - ffi (1.17.0) - ffi (1.17.0-arm64-darwin) - ffi (1.17.0-x86_64-linux-gnu) + ffi (1.17.4) + ffi (1.17.4-arm64-darwin) + ffi (1.17.4-x86_64-linux-gnu) forwardable-extended (2.6.0) - gemoji (4.1.0) - github-pages (231) - github-pages-health-check (= 1.18.2) - jekyll (= 3.9.5) - jekyll-avatar (= 0.8.0) - jekyll-coffeescript (= 1.2.2) - jekyll-commonmark-ghpages (= 0.4.0) - jekyll-default-layout (= 0.1.5) - jekyll-feed (= 0.17.0) - jekyll-gist (= 1.5.0) - jekyll-github-metadata (= 2.16.1) - jekyll-include-cache (= 0.2.1) - jekyll-mentions (= 1.6.0) - jekyll-optional-front-matter (= 0.3.2) - jekyll-paginate (= 1.1.0) - jekyll-readme-index (= 0.3.0) - jekyll-redirect-from (= 0.16.0) - jekyll-relative-links (= 0.6.1) - jekyll-remote-theme (= 0.4.3) - jekyll-sass-converter (= 1.5.2) - jekyll-seo-tag (= 2.8.0) - jekyll-sitemap (= 1.4.0) - jekyll-swiss (= 1.0.0) - jekyll-theme-architect (= 0.2.0) - jekyll-theme-cayman (= 0.2.0) - jekyll-theme-dinky (= 0.2.0) - jekyll-theme-hacker (= 0.2.0) - jekyll-theme-leap-day (= 0.2.0) - jekyll-theme-merlot (= 0.2.0) - jekyll-theme-midnight (= 0.2.0) - jekyll-theme-minimal (= 0.2.0) - jekyll-theme-modernist (= 0.2.0) - jekyll-theme-primer (= 0.6.0) - jekyll-theme-slate (= 0.2.0) - jekyll-theme-tactile (= 0.2.0) - jekyll-theme-time-machine (= 0.2.0) - jekyll-titles-from-headings (= 0.5.3) - jemoji (= 0.13.0) - kramdown (= 2.4.0) - kramdown-parser-gfm (= 1.1.0) - liquid (= 4.0.4) - mercenary (~> 0.3) - minima (= 2.5.1) - nokogiri (>= 1.13.6, < 2.0) - rouge (= 3.30.0) - terminal-table (~> 1.4) - github-pages-health-check (1.18.2) - addressable (~> 2.3) - dnsruby (~> 1.60) - octokit (>= 4, < 8) - public_suffix (>= 3.0, < 6.0) - typhoeus (~> 1.3) - html-pipeline (2.14.3) - activesupport (>= 2) - nokogiri (>= 1.4) - http_parser.rb (0.8.0) - i18n (1.14.8) + google-protobuf (4.35.1) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-arm64-darwin) + bigdecimal + rake (~> 13.3) + google-protobuf (4.35.1-x86_64-linux-gnu) + bigdecimal + rake (~> 13.3) + http_parser.rb (0.8.1) + i18n (1.15.2) concurrent-ruby (~> 1.0) - jekyll (3.9.5) + jekyll (4.4.1) addressable (~> 2.4) + base64 (~> 0.2) colorator (~> 1.0) + csv (~> 3.0) em-websocket (~> 0.5) - i18n (>= 0.7, < 2) - jekyll-sass-converter (~> 1.0) + i18n (~> 1.0) + jekyll-sass-converter (>= 2.0, < 4.0) jekyll-watch (~> 2.0) - kramdown (>= 1.17, < 3) + json (~> 2.6) + kramdown (~> 2.3, >= 2.3.1) + kramdown-parser-gfm (~> 1.0) liquid (~> 4.0) - mercenary (~> 0.3.3) + mercenary (~> 0.3, >= 0.3.6) pathutil (~> 0.9) - rouge (>= 1.7, < 4) + rouge (>= 3.0, < 5.0) safe_yaml (~> 1.0) - jekyll-avatar (0.8.0) - jekyll (>= 3.0, < 5.0) - jekyll-coffeescript (1.2.2) - coffee-script (~> 2.2) - coffee-script-source (~> 1.12) - jekyll-commonmark (1.4.0) - commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.4.0) - commonmarker (~> 0.23.7) - jekyll (~> 3.9.0) - jekyll-commonmark (~> 1.4.0) - rouge (>= 2.0, < 5.0) - jekyll-default-layout (0.1.5) - jekyll (>= 3.0, < 5.0) - jekyll-feed (0.17.0) - jekyll (>= 3.7, < 5.0) - jekyll-gist (1.5.0) - octokit (~> 4.2) - jekyll-github-metadata (2.16.1) - jekyll (>= 3.4, < 5.0) - octokit (>= 4, < 7, != 4.4.0) - jekyll-include-cache (0.2.1) - jekyll (>= 3.7, < 5.0) - jekyll-mentions (1.6.0) - html-pipeline (~> 2.3) - jekyll (>= 3.7, < 5.0) - jekyll-optional-front-matter (0.3.2) - jekyll (>= 3.0, < 5.0) - jekyll-paginate (1.1.0) - jekyll-readme-index (0.3.0) - jekyll (>= 3.0, < 5.0) - jekyll-redirect-from (0.16.0) - jekyll (>= 3.3, < 5.0) - jekyll-relative-links (0.6.1) - jekyll (>= 3.3, < 5.0) - jekyll-remote-theme (0.4.3) - addressable (~> 2.0) - jekyll (>= 3.5, < 5.0) - jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) - rubyzip (>= 1.3.0, < 3.0) - jekyll-sass-converter (1.5.2) - sass (~> 3.4) - jekyll-seo-tag (2.8.0) - jekyll (>= 3.8, < 5.0) - jekyll-sitemap (1.4.0) - jekyll (>= 3.7, < 5.0) - jekyll-swiss (1.0.0) - jekyll-theme-architect (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-cayman (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-dinky (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-hacker (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-leap-day (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-merlot (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-midnight (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-minimal (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-modernist (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-primer (0.6.0) - jekyll (> 3.5, < 5.0) - jekyll-github-metadata (~> 2.9) - jekyll-seo-tag (~> 2.0) - jekyll-theme-slate (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-tactile (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-theme-time-machine (0.2.0) - jekyll (> 3.5, < 5.0) - jekyll-seo-tag (~> 2.0) - jekyll-titles-from-headings (0.5.3) - jekyll (>= 3.3, < 5.0) - jekyll-twitter-plugin (2.1.0) + terminal-table (>= 1.8, < 4.0) + webrick (~> 1.7) + jekyll-sass-converter (3.1.0) + sass-embedded (~> 1.75) jekyll-watch (2.2.1) listen (~> 3.0) - jemoji (0.13.0) - gemoji (>= 3, < 5) - html-pipeline (~> 2.2) - jekyll (>= 3.0, < 5.0) - json (2.19.5) - kramdown (2.4.0) - rexml + json (2.21.1) + kramdown (2.5.2) + rexml (>= 3.4.4) kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) liquid (4.0.4) - listen (3.9.0) + listen (3.10.0) + logger rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) logger (1.7.0) - mercenary (0.3.6) + mercenary (0.4.0) mini_portile2 (2.8.4) - minima (2.5.1) - jekyll (>= 3.5, < 5.0) - jekyll-feed (~> 0.9) - jekyll-seo-tag (~> 2.1) - minitest (5.27.0) - net-http (0.9.1) - uri (>= 0.11.1) nokogiri (1.19.3) mini_portile2 (~> 2.8.2) racc (~> 1.4) @@ -239,40 +71,28 @@ GEM racc (~> 1.4) nokogiri (1.19.3-x86_64-linux-gnu) racc (~> 1.4) - octokit (4.25.1) - faraday (>= 1, < 3) - sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (5.1.1) + public_suffix (7.0.5) racc (1.8.1) + rake (13.4.2) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - redcarpet (3.6.0) - rexml (3.4.2) - rouge (3.30.0) - rubyzip (2.3.2) + rexml (3.4.4) + rouge (4.7.0) safe_yaml (1.0.5) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sawyer (0.9.2) - addressable (>= 2.3.5) - faraday (>= 0.17.3, < 3) - securerandom (0.4.1) - simpleidn (0.2.3) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.1) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - unicode-display_width (1.8.0) - uri (1.1.1) - webrick (1.8.2) + sass-embedded (1.102.0) + google-protobuf (~> 4.31) + rake (>= 13) + sass-embedded (1.102.0-arm64-darwin) + google-protobuf (~> 4.31) + sass-embedded (1.102.0-x86_64-linux-gnu) + google-protobuf (~> 4.31) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + unicode-display_width (2.6.0) + webrick (1.9.2) PLATFORMS arm64-darwin @@ -280,12 +100,10 @@ PLATFORMS x86_64-linux DEPENDENCIES - github-pages - jekyll-twitter-plugin + jekyll (= 4.4.1) mini_portile2 (= 2.8.4) nokogiri (= 1.19.3) - redcarpet webrick (~> 1.8) BUNDLED WITH - 2.5.16 + 4.0.16 diff --git a/docs/README.md b/docs/README.md index 736b58fa41c..a14a176e442 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,94 +3,68 @@ This README will walk you through building the documentation of Apache Zeppelin. The documentation is included here with Apache Zeppelin source code. The online documentation at [https://zeppelin.apache.org/docs/](https://zeppelin.apache.org/docs/latest/) is also generated from the files found in here. ## Build documentation -Zeppelin is using [Jekyll](https://jekyllrb.com/) which is a static site generator and [Github Pages](https://pages.github.com/) as a site publisher. For the more details, see [help.github.com/articles/about-github-pages-and-jekyll/](https://help.github.com/articles/about-github-pages-and-jekyll/). +Zeppelin uses [Jekyll](https://jekyllrb.com/) to generate the static versioned documentation published on the Apache Zeppelin website. **Requirements** -``` -# ruby --version >= 2.0.0 -# Install Bundler using gem -gem install bundler - -cd $ZEPPELIN_HOME/docs -# Install all dependencies declared in the Gemfile -bundle install -``` - -For the further information about requirements, please see [here](https://help.github.com/articles/setting-up-your-github-pages-site-locally-with-jekyll/#requirements). - -On OS X 10.9, you may need to do +- [Docker](https://docs.docker.com/get-docker/) -``` -xcode-select --install -``` - -**Docker** +Ruby, Bundler, and Jekyll run only inside the Docker container. No host Ruby +installation is required. -Local docker environments are also supported and have been tested using: -* [Docker version 20.10.2](https://docs.docker.com/get-docker/) +## Preview documentation -## Run website locally -If you don't want to encounter ugly rendered pages, run the documentation site in your local environment first. +From `$ZEPPELIN_HOME/docs`, run: -In `$ZEPPELIN_HOME/docs`, run one of the desired commands: - -**Run locally** -``` -bundle exec jekyll serve --watch -``` - -**Run locally using docker** -``` +```bash docker run --rm -it \ - -v $PWD:/docs \ - -w /docs \ - -p '4000:4000' \ - ruby:3.3.5 \ - bash -c "bundle install && bundle exec jekyll serve --watch --host 0.0.0.0" + --user "$(id -u):$(id -g)" \ + -e HOME=/usr/local/bundle \ + -e BUNDLE_FROZEN=true \ + -v "$PWD:/docs" \ + -w /docs \ + -p '4000:4000' \ + ruby:4.0.6 \ + bash -lc "bundle install && bundle exec jekyll serve --watch --host 0.0.0.0" ``` -Using the above command, Jekyll will start a web server at `http://localhost:4000` and watch the `/docs` directory for updates. - - +Jekyll starts at `http://localhost:4000` and watches the `docs/` sources for +updates. The container runs with the current user's UID and GID so generated +files are not owned by `root` on the host. ## Contribute to Zeppelin documentation If you wish to help us and contribute to Zeppelin Documentation, please look at [Zeppelin Documentation's contribution guideline](https://zeppelin.apache.org/contribution/contributions.html). - ## For committers only ### Bumping up version in a new release - * `ZEPPELIN_VERSION` and `BASE_PATH` property in _config.yml - -### Deploy to ASF svnpubsub infra - 1. generate static website in `./_site` +- Update `ZEPPELIN_VERSION` and `JB.BASE_PATH` in `_config.yml`. - ``` - # go to /docs under Zeppelin source - bundle exec jekyll build --safe - ``` +### Build versioned documentation - 2. verify no analytics scripts in the generated output +From `$ZEPPELIN_HOME/docs`, run: - ``` - ( - grep -rnE --include='*.html' \ - "google-analytics\.com|googletagmanager\.com|analytics\.js|ga\.js|UA-[0-9]" \ - _site/ - case $? in - 0) echo "FAIL: analytics found"; exit 1 ;; - 1) ;; - *) echo "ERROR: scan failed"; exit 2 ;; - esac - ) - ``` +```bash +docker run --rm \ + --user "$(id -u):$(id -g)" \ + -e HOME=/usr/local/bundle \ + -e BUNDLE_FROZEN=true \ + -v "$PWD:/docs" \ + -w /docs \ + ruby:4.0.6 \ + bash -lc "bundle install && bundle exec jekyll build --safe" +``` - 3. checkout ASF repo +Check the generated site for external resources and trackers: - ``` - svn co https://svn.apache.org/repos/asf/zeppelin asf-zeppelin - ``` +```bash +docker run --rm \ + -v "$PWD:/docs:ro" \ + -w /docs \ + ruby:4.0.6 \ + ruby check_external_resources.rb _site +``` - 4. copy `zeppelin/docs/_site` to `asf-zeppelin/site/docs/[VERSION]` - 5. `svn commit` +The generated site is written to `_site/`. Copy it to +`zeppelin-site/docs//` as part of the separate website publication +workflow. diff --git a/docs/_config.yml b/docs/_config.yml index cf009ae6ec8..eb2b9317025 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,11 +2,12 @@ # For more see: http://jekyllrb.com/docs/permalinks/ permalink: /:categories/:year/:month/:day/:title -exclude: [".rvmrc", ".rbenv-version", "README.md", "Rakefile", "changelog.md", "vendor", "node_modules", "scss"] +exclude: [".rvmrc", ".rbenv-version", "AGENTS.md", "Gemfile", "Gemfile.lock", "README.md", "Rakefile", "changelog.md", "check_external_resources.rb", "vendor", "node_modules", "scss"] highlighter: rouge -markdown: redcarpet -redcarpet: - extensions: ["tables"] +markdown: kramdown +kramdown: + input: GFM + show_warnings: true encoding: utf-8 # Themes are encouraged to use these universal variables @@ -18,8 +19,6 @@ author : name : The Apache Software Foundation email : dev@zeppelin.apache.org github : apache - twitter : ASF - feedburner : feedname ZEPPELIN_VERSION : 0.13.0-SNAPSHOT @@ -36,6 +35,7 @@ production_url : http://zeppelin.apache.org # JB : version : 0.3.0 + matomo_site_id : 69 # All links will be namespaced by BASE_PATH if defined. # Links in your website should always be prefixed with {{BASE_PATH}} @@ -77,48 +77,6 @@ JB : archive_path: /archive.html categories_path : /categories.html tags_path : /tags.html - atom_path : /atom.xml - rss_path : /rss.xml - - # Settings for comments helper - # Set 'provider' to the comment provider you want to use. - # Set 'provider' to false to turn commenting off globally. - # - comments : - provider : disqus - disqus : - short_name : jekyllbootstrap - livefyre : - site_id : 123 - intensedebate : - account : 123abc - facebook : - appid : 123 - num_posts: 5 - width: 580 - colorscheme: light - - # Settings for analytics helper - # Set 'provider' to the analytics provider you want to use. - # Set 'provider' to false to turn analytics off globally. - # - analytics : - provider : false - getclicky : - site_id : - mixpanel : - token : '_MIXPANEL_TOKEN_' - piwik : - baseURL : 'myserver.tld/piwik' # Piwik installation address (without protocol) - idsite : '1' # the id of the site on Piwik - - # Settings for sharing helper. - # Sharing is for things like tweet, plusone, like, reddit buttons etc. - # Set 'provider' to the sharing provider you want to use. - # Set 'provider' to false to turn sharing off globally. - # - sharing : - provider : false # Settings for all other include helpers can be defined by creating # a hash with key named for the given helper. ex: diff --git a/docs/_includes/JB/analytics b/docs/_includes/JB/analytics deleted file mode 100644 index 48d87c25fa0..00000000000 --- a/docs/_includes/JB/analytics +++ /dev/null @@ -1,18 +0,0 @@ -{% if site.safe and site.JB.analytics.provider and page.JB.analytics != false %} - -{% case site.JB.analytics.provider %} -{% when "google_classic" %} - {% include JB/analytics-providers/google-classic %} -{% when "google_universal" %} - {% include JB/analytics-providers/google-universal %} -{% when "getclicky" %} - {% include JB/analytics-providers/getclicky %} -{% when "mixpanel" %} - {% include JB/analytics-providers/mixpanel %} -{% when "piwik" %} - {% include JB/analytics-providers/piwik %} -{% when "custom" %} - {% include custom/analytics %} -{% endcase %} - -{% endif %} \ No newline at end of file diff --git a/docs/_includes/JB/analytics-providers/getclicky b/docs/_includes/JB/analytics-providers/getclicky deleted file mode 100644 index e9462f4f67f..00000000000 --- a/docs/_includes/JB/analytics-providers/getclicky +++ /dev/null @@ -1,12 +0,0 @@ - - diff --git a/docs/_includes/JB/analytics-providers/google-classic b/docs/_includes/JB/analytics-providers/google-classic deleted file mode 100644 index af099078a58..00000000000 --- a/docs/_includes/JB/analytics-providers/google-classic +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/docs/_includes/JB/analytics-providers/google-universal b/docs/_includes/JB/analytics-providers/google-universal deleted file mode 100644 index dae744b994a..00000000000 --- a/docs/_includes/JB/analytics-providers/google-universal +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/docs/_includes/JB/analytics-providers/mixpanel b/docs/_includes/JB/analytics-providers/mixpanel deleted file mode 100644 index 4406eb048d2..00000000000 --- a/docs/_includes/JB/analytics-providers/mixpanel +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/docs/_includes/JB/analytics-providers/piwik b/docs/_includes/JB/analytics-providers/piwik deleted file mode 100755 index f016ed7ca4f..00000000000 --- a/docs/_includes/JB/analytics-providers/piwik +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/docs/_includes/JB/comments b/docs/_includes/JB/comments deleted file mode 100644 index 4e9e600f6c0..00000000000 --- a/docs/_includes/JB/comments +++ /dev/null @@ -1,16 +0,0 @@ -{% if site.JB.comments.provider and page.comments != false %} - -{% case site.JB.comments.provider %} -{% when "disqus" %} - {% include JB/comments-providers/disqus %} -{% when "livefyre" %} - {% include JB/comments-providers/livefyre %} -{% when "intensedebate" %} - {% include JB/comments-providers/intensedebate %} -{% when "facebook" %} - {% include JB/comments-providers/facebook %} -{% when "custom" %} - {% include custom/comments %} -{% endcase %} - -{% endif %} \ No newline at end of file diff --git a/docs/_includes/JB/comments-providers/disqus b/docs/_includes/JB/comments-providers/disqus deleted file mode 100644 index 618a7b737bd..00000000000 --- a/docs/_includes/JB/comments-providers/disqus +++ /dev/null @@ -1,14 +0,0 @@ -
    - - -blog comments powered by Disqus diff --git a/docs/_includes/JB/comments-providers/facebook b/docs/_includes/JB/comments-providers/facebook deleted file mode 100644 index 6b3e5e06921..00000000000 --- a/docs/_includes/JB/comments-providers/facebook +++ /dev/null @@ -1,9 +0,0 @@ -
    - -
    \ No newline at end of file diff --git a/docs/_includes/JB/comments-providers/intensedebate b/docs/_includes/JB/comments-providers/intensedebate deleted file mode 100644 index ab0c3c9769c..00000000000 --- a/docs/_includes/JB/comments-providers/intensedebate +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/docs/_includes/JB/comments-providers/livefyre b/docs/_includes/JB/comments-providers/livefyre deleted file mode 100644 index 704b80392b1..00000000000 --- a/docs/_includes/JB/comments-providers/livefyre +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/docs/_includes/JB/matomo b/docs/_includes/JB/matomo new file mode 100644 index 00000000000..136bbb1b773 --- /dev/null +++ b/docs/_includes/JB/matomo @@ -0,0 +1,33 @@ + + + + + diff --git a/docs/_includes/JB/sharing b/docs/_includes/JB/sharing deleted file mode 100644 index f5b11518bd2..00000000000 --- a/docs/_includes/JB/sharing +++ /dev/null @@ -1,8 +0,0 @@ -{% if site.safe and site.JB.sharing.provider and page.JB.sharing != false %} - -{% case site.JB.sharing.provider %} -{% when "custom" %} - {% include custom/sharing %} -{% endcase %} - -{% endif %} \ No newline at end of file diff --git a/docs/_includes/themes/zeppelin/default.html b/docs/_includes/themes/zeppelin/default.html index d2cd0719da3..36d88a36031 100644 --- a/docs/_includes/themes/zeppelin/default.html +++ b/docs/_includes/themes/zeppelin/default.html @@ -9,11 +9,6 @@ - - - @@ -37,9 +32,9 @@ - - - + {% if site.safe %} + {% include JB/matomo %} + {% endif %} @@ -54,6 +49,5 @@
    - {% include JB/analytics %} diff --git a/docs/_includes/themes/zeppelin/post.html b/docs/_includes/themes/zeppelin/post.html index 2774711aecb..14934d35b5b 100644 --- a/docs/_includes/themes/zeppelin/post.html +++ b/docs/_includes/themes/zeppelin/post.html @@ -43,7 +43,5 @@

    {{ page.title }} {% if page.tagline %}{{page.tagline}}{% endi {% endif %}

    -
    - {% include JB/comments %} diff --git a/docs/assets/themes/zeppelin/img/docs-img/labeled-property-graph-model.svg b/docs/assets/themes/zeppelin/img/docs-img/labeled-property-graph-model.svg new file mode 100644 index 00000000000..0d2a53fa7f0 --- /dev/null +++ b/docs/assets/themes/zeppelin/img/docs-img/labeled-property-graph-model.svg @@ -0,0 +1,86 @@ + + + + Labeled property graph data model + People, notebooks, and a dataset represented as labeled nodes connected by typed relationships with properties. + + + + + + + + + + + + AUTHORED + since: 2024 + + + + VIEWED + date: Jul 18 + + + + READS + format: parquet + + + + READS + format: csv + + + + :Person:Author + name: Mina + team: Analytics + + + + :Person + name: Yun + team: Operations + + + + :Notebook + title: Flight Analysis + version: 3 + + + + :Notebook + title: Revenue Forecast + version: 7 + + + + :Dataset + name: Flight Records + owner: Data Platform + diff --git a/docs/assets/themes/zeppelin/img/docs-img/property-graph-example.svg b/docs/assets/themes/zeppelin/img/docs-img/property-graph-example.svg new file mode 100644 index 00000000000..7ae1a683dca --- /dev/null +++ b/docs/assets/themes/zeppelin/img/docs-img/property-graph-example.svg @@ -0,0 +1,87 @@ + + + + Property graph example + Four nodes connected by labeled, directed edges, with properties attached to both nodes and edges. + + + + + + + + + + + + KNOWS + + since: 2022 + + + + CREATED + + role: owner + + + + CONTRIBUTED + + commits: 18 + + + + READS + + format: parquet + + + name: Mina + age: 34 + + 1 + person + + + 2 + person + + name: Yun + + + title: Flight Analysis + language: Python + + 3 + notebook + + + 4 + dataset + + name: Flight Records + rows: 2.1M + diff --git a/docs/atom.xml b/docs/atom.xml deleted file mode 100644 index 7ec29339dd6..00000000000 --- a/docs/atom.xml +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: nil -title : ---- - - - - {{ site.title }} - - - {{ site.time | date_to_xmlschema }} - {{ site.production_url }} - - {{ site.author.name }} - {{ site.author.email }} - - - {% for post in site.posts %} - - {{ post.title }} - - {{ post.date | date_to_xmlschema }} - {{ site.production_url }}{{ post.id }} - {{ post.content | xml_escape }} - - {% endfor %} - - diff --git a/docs/check_external_resources.rb b/docs/check_external_resources.rb new file mode 100644 index 00000000000..563754687db --- /dev/null +++ b/docs/check_external_resources.rb @@ -0,0 +1,90 @@ +#!/usr/bin/env ruby +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require "uri" + +SITE_DIR = ARGV.fetch(0, "_site") +RESOURCE_TAGS = %w[script img iframe link source video audio embed object].freeze +RESOURCE_PATTERN = + /<(#{RESOURCE_TAGS.join("|")})\b[^>]*\b(?:src|href|data)\s*=\s*["']([^"']+)["']/i +CSS_URL_PATTERN = /url\(\s*["']?([^"')]+)["']?\s*\)/i +TRACKER_PATTERN = + /google-analytics|googletag|gtag\s*\(|mixpanel|getclicky|piwik|disqus|connect\.facebook|(?:platform\.)?twitter\.com\/widgets/i +MATOMO_CODE_PATTERN = /matomo\.(?:js|php)|setTrackerUrl|\b_paq\b/i +ASF_MATOMO_URL = "https://analytics.apache.org/" + +def remote_host(value) + return nil unless value.match?(%r{\A(?:https?:)?//}i) + + normalized = value.start_with?("//") ? "https:#{value}" : value + URI.parse(normalized).host || :invalid +rescue URI::InvalidURIError + :invalid +end + +def asf_host?(host) + host != :invalid && (host == "apache.org" || host.end_with?(".apache.org")) +end + +violations = [] + +unless Dir.exist?(SITE_DIR) + warn "Site directory not found: #{SITE_DIR}" + exit 1 +end + +html_files = Dir.glob(File.join(SITE_DIR, "**", "*.html")).sort +if html_files.empty? + warn "No HTML files found in #{SITE_DIR}" + exit 1 +end + +html_files.each do |file| + File.read(file).scan(RESOURCE_PATTERN) do |tag, value| + host = remote_host(value) + next if host.nil? || asf_host?(host) + + violations << "#{file}: external #{tag} resource #{value}" + end +end + +Dir.glob(File.join(SITE_DIR, "**", "*.css")).sort.each do |file| + File.read(file).scan(CSS_URL_PATTERN) do |match| + value = match.first + host = remote_host(value) + next if host.nil? || asf_host?(host) + + violations << "#{file}: external CSS resource #{value}" + end +end + +Dir.glob(File.join(SITE_DIR, "**", "*.{html,js,css}")).sort.each do |file| + content = File.read(file) + violations << "#{file}: tracker or external embed code" if content.match?(TRACKER_PATTERN) + if content.match?(MATOMO_CODE_PATTERN) && !content.include?(ASF_MATOMO_URL) + violations << "#{file}: Matomo must use #{ASF_MATOMO_URL}" + end +end + +if violations.empty? + puts "No disallowed external resources or trackers found in #{SITE_DIR}" + exit 0 +end + +warn violations.join("\n") +exit 1 diff --git a/docs/development/contribution/how_to_contribute_code.md b/docs/development/contribution/how_to_contribute_code.md index 645371be2ae..1464c339b35 100644 --- a/docs/development/contribution/how_to_contribute_code.md +++ b/docs/development/contribution/how_to_contribute_code.md @@ -159,6 +159,6 @@ You can find issues for

    What is Apache Zeppelin?

    -

    +

    Multi-purpose notebook which supports

    -

    +

    20+ language backends

      @@ -161,4 +161,3 @@ limitations under the License. * [Mailing List](https://zeppelin.apache.org/community.html) * [Apache Zeppelin Wiki](https://cwiki.apache.org/confluence/display/ZEPPELIN/Zeppelin+Home) * [Stackoverflow Questions about Zeppelin (tag: `apache-zeppelin`)](http://stackoverflow.com/questions/tagged/apache-zeppelin) - diff --git a/docs/interpreter/bigquery.md b/docs/interpreter/bigquery.md index da696a74f2e..4f067a279d4 100644 --- a/docs/interpreter/bigquery.md +++ b/docs/interpreter/bigquery.md @@ -51,7 +51,7 @@ limitations under the License. zeppelin.bigquery.sql_dialect - BigQuery SQL dialect (standardSQL or legacySQL). If empty, [query prefix](https://cloud.google.com/bigquery/docs/reference/standard-sql/enabling-standard-sql#sql-prefix) like '#standardSQL' can be used. + BigQuery SQL dialect (standardSQL or legacySQL). If empty, [query prefix](https://cloud.google.com/bigquery/docs/reference/standard-sql/enabling-standard-sql#sql-prefix) like '#standardSQL' can be used. zeppelin.bigquery.region diff --git a/docs/interpreter/cassandra.md b/docs/interpreter/cassandra.md index a49ae7e2421..d2aa4124ee2 100644 --- a/docs/interpreter/cassandra.md +++ b/docs/interpreter/cassandra.md @@ -40,7 +40,7 @@ limitations under the License. In a notebook, to enable the **Cassandra** interpreter, click on the **Gear** icon and select **Cassandra** -
      +
      ![Interpreter Binding]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/cassandra-InterpreterBinding.png) ![Interpreter Selection]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/cassandra-InterpreterSelection.png) @@ -52,7 +52,7 @@ In a paragraph, use **_%cassandra_** to select the **Cassandra** interpreter and To access the interactive help, type **HELP;** -
      +
      ![Interactive Help]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/cassandra-InteractiveHelp.png)
      @@ -69,27 +69,27 @@ The **Cassandra** interpreter accepts the following commands Help command - `HELP` + `HELP` Display the interactive help menu Schema commands - `DESCRIBE KEYSPACE`, `DESCRIBE CLUSTER`, `DESCRIBE TABLES` ... + `DESCRIBE KEYSPACE`, `DESCRIBE CLUSTER`, `DESCRIBE TABLES` ... Custom commands to describe the Cassandra schema Option commands - `@consistency`, `@fetchSize` ... + `@consistency`, `@fetchSize` ... Inject runtime options to all statements in the paragraph Prepared statement commands - `@prepare`, `@bind`, `@remove_prepared` + `@prepare`, `@bind`, `@remove_prepared` Let you register a prepared command and re-use it later by injecting bound values Native CQL statements - All CQL-compatible statements (`SELECT`, `INSERT`, `CREATE`, ...) + All CQL-compatible statements (`SELECT`, `INSERT`, `CREATE`, ...) All CQL statements are executed directly against the Cassandra server @@ -242,7 +242,7 @@ To make schema discovery easier and more interactive, the following commands are DESCRIBE TYPES; - List all existing keyspaces in the cluster and for each, all the user-defined types name + List all existing keyspaces in the cluster and for each, all the user-defined types name DESCRIBE FUNCTIONS; @@ -303,7 +303,7 @@ To make schema discovery easier and more interactive, the following commands are The schema objects (cluster, keyspace, table, type, function and aggregate) are displayed in a tabular format. There is a drop-down menu on the top left corner to expand objects details. On the top right menu is shown the Icon legend. -
      +
      ![Describe Schema]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/cassandra-DescribeSchema.png)
      @@ -444,17 +444,17 @@ Sometimes you want to be able to format output of your statement. Cassandra inte Float precision floatPrecision=value - Precision when formatting float values. Any positive integer value, or `-1` to show everything + Precision when formatting float values. Any positive integer value, or `-1` to show everything Double precision doublePrecision=value - Precision when formatting double values. Any positive integer value, or `-1` to show everything + Precision when formatting double values. Any positive integer value, or `-1` to show everything Decimal precision decimalPrecision=value - Precision when formatting decimal values. Any positive integer value, or `-1` to show everything + Precision when formatting decimal values. Any positive integer value, or `-1` to show everything Timestamp Format @@ -537,7 +537,7 @@ Example: #### @prepare -You can use the syntax _"@prepare[statement-name]=SELECT..."_ to create a prepared statement. +You can use the syntax `@prepare[statement-name]=SELECT...` to create a prepared statement. The _statement-name_ is **mandatory** because the interpreter prepares the given statement with the Java driver and saves the generated prepared statement in an **internal hash map**, using the provided _statement-name_ as search key. @@ -577,9 +577,9 @@ Bound values are not mandatory for the **@bind** statement. However if you provi * **null** is parsed as-is * **boolean** (`true`|`false`) are parsed as-is * collection values must follow the **[standard CQL syntax]**: - * list: ['list_item1', 'list_item2', ...] - * set: {'set_item1', 'set_item2', …} - * map: {'key1': 'val1', 'key2': 'val2', …} + * list: `['list_item1', 'list_item2', ...]` + * set: `{'set_item1', 'set_item2', …}` + * map: `{'key1': 'val1', 'key2': 'val2', …}` * **tuple** values should be enclosed between parenthesis (see **[Tuple CQL syntax]**): ('text', 123, true) * **udt** values should be enclosed between brackets (see **[UDT CQL syntax]**): {stree_name: 'Beverly Hills', number: 104, zip_code: 90020, state: 'California', …} @@ -595,7 +595,7 @@ Bound values are not mandatory for the **@bind** statement. However if you provi #### @remove_prepare To avoid for a prepared statement to stay forever in the prepared statement map, you can use the -**@remove_prepare[statement-name]** syntax to remove it. +`@remove_prepare[statement-name]` syntax to remove it. Removing a non-existing prepared statement yields no error. ## Using Dynamic Forms @@ -675,41 +675,41 @@ Below are the configuration parameters supported by interpreter and their defaul Default Value - `cassandra.cluster` + `cassandra.cluster` Name of the Cassandra cluster to connect to Test Cluster - `cassandra.compression.protocol` - On wire compression. Possible values are: `NONE`, `SNAPPY`, `LZ4` - `NONE` + `cassandra.compression.protocol` + On wire compression. Possible values are: `NONE`, `SNAPPY`, `LZ4` + `NONE` - `cassandra.credentials.username` + `cassandra.credentials.username` If security is enable, provide the login none - `cassandra.credentials.password` + `cassandra.credentials.password` If security is enable, provide the password none - `cassandra.hosts` - + `cassandra.hosts` + Comma separated Cassandra hosts (DNS name or IP address).
      Ex: `192.168.0.12,node2,node3` - `localhost` + `localhost` - `cassandra.interpreter.parallelism` + `cassandra.interpreter.parallelism` Number of concurrent paragraphs(queries block) that can be executed 10 - `cassandra.keyspace` + `cassandra.keyspace` Default keyspace to connect to. @@ -718,11 +718,11 @@ Below are the configuration parameters supported by interpreter and their defaul in all of your queries - `system` + `system` - `cassandra.load.balancing.policy` - + `cassandra.load.balancing.policy` + Load balancing policy. Default = `DefaultLoadBalancingPolicy` To Specify your own policy, provide the fully qualify class name (FQCN) of your policy. At runtime the driver will instantiate the policy using class name. @@ -730,66 +730,66 @@ Below are the configuration parameters supported by interpreter and their defaul DEFAULT - `cassandra.max.schema.agreement.wait.second` + `cassandra.max.schema.agreement.wait.second` Cassandra max schema agreement wait in second 10 - `cassandra.pooling.connection.per.host.local` + `cassandra.pooling.connection.per.host.local` Protocol V3 and above default = 1 1 - `cassandra.pooling.connection.per.host.remote` + `cassandra.pooling.connection.per.host.remote` Protocol V3 and above default = 1 1 - `cassandra.pooling.heartbeat.interval.seconds` + `cassandra.pooling.heartbeat.interval.seconds` Cassandra pool heartbeat interval in secs 30 - `cassandra.pooling.max.request.per.connection` + `cassandra.pooling.max.request.per.connection` Protocol V3 and above default = 1024 1024 - `cassandra.pooling.pool.timeout.millisecs` + `cassandra.pooling.pool.timeout.millisecs` Cassandra pool time out in millisecs 5000 - `cassandra.protocol.version` - Cassandra binary protocol version (`V3`, `V4`, ...) - `DEFAULT` (detected automatically) + `cassandra.protocol.version` + Cassandra binary protocol version (`V3`, `V4`, ...) + `DEFAULT` (detected automatically) cassandra.query.default.consistency - + Cassandra query default consistency level
      Available values: `ONE`, `TWO`, `THREE`, `QUORUM`, `LOCAL_ONE`, `LOCAL_QUORUM`, `EACH_QUORUM`, `ALL` - `ONE` + `ONE` - `cassandra.query.default.fetchSize` + `cassandra.query.default.fetchSize` Cassandra query default fetch size 5000 - `cassandra.query.default.serial.consistency` - + `cassandra.query.default.serial.consistency` + Cassandra query default serial consistency level
      Available values: `SERIAL`, `LOCAL_SERIAL` - `SERIAL` + `SERIAL` - `cassandra.reconnection.policy` - + `cassandra.reconnection.policy` + Cassandra Reconnection Policy. Default = `ExponentialReconnectionPolicy` To Specify your own policy, provide the fully qualify class name (FQCN) of your policy. @@ -798,8 +798,8 @@ Below are the configuration parameters supported by interpreter and their defaul DEFAULT - `cassandra.retry.policy` - + `cassandra.retry.policy` + Cassandra Retry Policy. Default = `DefaultRetryPolicy` To Specify your own policy, provide the fully qualify class name (FQCN) of your policy. @@ -808,23 +808,23 @@ Below are the configuration parameters supported by interpreter and their defaul DEFAULT - `cassandra.socket.connection.timeout.millisecs` + `cassandra.socket.connection.timeout.millisecs` Cassandra socket default connection timeout in millisecs 500 - `cassandra.socket.read.timeout.millisecs` + `cassandra.socket.read.timeout.millisecs` Cassandra socket read timeout in millisecs 12000 - `cassandra.socket.tcp.no_delay` + `cassandra.socket.tcp.no_delay` Cassandra socket TCP no delay true - `cassandra.speculative.execution.policy` - + `cassandra.speculative.execution.policy` + Cassandra Speculative Execution Policy. Default = `NoSpeculativeExecutionPolicy` To Specify your own policy, provide the fully qualify class name (FQCN) of your policy. @@ -833,7 +833,7 @@ Below are the configuration parameters supported by interpreter and their defaul DEFAULT - `cassandra.ssl.enabled` + `cassandra.ssl.enabled` Enable support for connecting to the Cassandra configured with SSL. To connect to Cassandra configured with SSL use true @@ -842,63 +842,63 @@ Below are the configuration parameters supported by interpreter and their defaul false - `cassandra.ssl.truststore.path` + `cassandra.ssl.truststore.path` Filepath for the truststore file to use for connection to Cassandra with SSL. - `cassandra.ssl.truststore.password` + `cassandra.ssl.truststore.password` Password for the truststore file to use for connection to Cassandra with SSL. - `cassandra.format.output` - Output format for data - strict CQL (`cql`), or human-readable (`human`) - `human` + `cassandra.format.output` + Output format for data - strict CQL (`cql`), or human-readable (`human`) + `human` - `cassandra.format.locale` + `cassandra.format.locale` Which locale to use for output (any locale supported by JVM could be specified) - `en_US` + `en_US` - `cassandra.format.timezone` + `cassandra.format.timezone` For which timezone format time/date-related types (any timezone supported by JVM could be specified) - `UTC` + `UTC` - `cassandra.format.timestamp` - Format string for `timestamp` columns (any valid
      DateTimeFormatter pattern could be used) - `yyyy-MM-dd'T'HH:mm:ss.SSSXXX` + `cassandra.format.timestamp` + Format string for `timestamp` columns (any valid DateTimeFormatter pattern could be used) + `yyyy-MM-dd'T'HH:mm:ss.SSSXXX` - `cassandra.format.time` - Format string for `time` columns (any valid DateTimeFormatter pattern could be used) - `HH:mm:ss.SSS` + `cassandra.format.time` + Format string for `time` columns (any valid DateTimeFormatter pattern could be used) + `HH:mm:ss.SSS` - `cassandra.format.date` - Format string for `date` columns (any valid DateTimeFormatter pattern could be used) - `yyyy-MM-dd` + `cassandra.format.date` + Format string for `date` columns (any valid DateTimeFormatter pattern could be used) + `yyyy-MM-dd` - `cassandra.format.float_precision` - Precision when formatting values of `float` type - `5` + `cassandra.format.float_precision` + Precision when formatting values of `float` type + `5` - `cassandra.format.double_precision` - Precision when formatting values of `double` type - `12` + `cassandra.format.double_precision` + Precision when formatting values of `double` type + `12` - `cassandra.format.decimal_precision` - Precision when formatting values of `decimal` type - `-1` (show everything) + `cassandra.format.decimal_precision` + Precision when formatting values of `decimal` type + `-1` (show everything) @@ -908,7 +908,7 @@ Besides these parameters, it's also possible to set other driver parameters by a **4.0** _(Zeppelin {{ site.ZEPPELIN_VERSION }})_ : -* Refactor to use unified Java driver 4.7 ([ZEPPELIN-4378](https://issues.apache.org/jira/browse/ZEPPELIN-4378): +* Refactor to use unified Java driver 4.7 ([ZEPPELIN-4378](https://issues.apache.org/jira/browse/ZEPPELIN-4378)): * changes in configuration were necessary, as new driver has different architecture, and configuration options * interpreter got support for DSE-specific data types, and other extensions * support for `@retryPolicy` is removed, as only single retry policy is shipped with driver @@ -918,7 +918,7 @@ Besides these parameters, it's also possible to set other driver parameters by a **3.1** _(Zeppelin {{ site.ZEPPELIN_VERSION }})_ : -* Upgrade Java driver to 3.7.2 ([ZEPPELIN-4331](https://issues.apache.org/jira/browse/ZEPPELIN-4331); +* Upgrade Java driver to 3.7.2 ([ZEPPELIN-4331](https://issues.apache.org/jira/browse/ZEPPELIN-4331)); **3.0** _(Zeppelin {{ site.ZEPPELIN_VERSION }})_ : @@ -952,6 +952,6 @@ Besides these parameters, it's also possible to set other driver parameters by a [standard CQL syntax]: http://docs.datastax.com/en/cql/3.1/cql/cql_using/use_collections_c.html [Tuple CQL syntax]: http://docs.datastax.com/en/cql/3.1/cql/cql_reference/tupleType.html [UDT CQL syntax]: http://docs.datastax.com/en/cql/3.1/cql/cql_using/cqlUseUDT.html -[Zeppelin Dynamic Form](../usage/dynamic_form/intro.html) -[Interpreter Binding Mode](../usage/interpreter/interpreter_binding_mode.html) +[Zeppelin Dynamic Form]: ../usage/dynamic_form/intro.html +[Interpreter Binding Mode]: ../usage/interpreter/interpreter_binding_mode.html [JIRA]: https://issues.apache.org/jira/browse/ZEPPELIN diff --git a/docs/interpreter/elasticsearch.md b/docs/interpreter/elasticsearch.md index 6e0530a0e58..9ae3113f680 100644 --- a/docs/interpreter/elasticsearch.md +++ b/docs/interpreter/elasticsearch.md @@ -58,12 +58,12 @@ It is generally used as the underlying engine/technology that powers application elasticsearch.basicauth.username - Username for a basic authentication (http) + Username for a basic authentication (http) elasticsearch.basicauth.password - Password for a basic authentication (http) + Password for a basic authentication (http) elasticsearch.result.size @@ -72,7 +72,7 @@ It is generally used as the underlying engine/technology that powers application -
      +
      ![Interpreter configuration]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/elasticsearch-config.png)
      @@ -199,7 +199,7 @@ Suppose we have a JSON document: The data will be flattened like this: -content_length | date | request.headers[0] | request.headers[1] | request.method | request.url | status +content_length | date | `request.headers[0]` | `request.headers[1]` | request.method | request.url | status ---------------|------|--------------------|--------------------|----------------|-------------|------- 1234 | 2015-12-08T21:03:13.588Z | Accept: \*.\* | Host: apache.org | GET | /zeppelin/4cd001cd-c517-4fa9-b8e5-a06b8f4056c4 | 403 diff --git a/docs/interpreter/flink.md b/docs/interpreter/flink.md index 309a2c98205..e97b575cc85 100644 --- a/docs/interpreter/flink.md +++ b/docs/interpreter/flink.md @@ -98,11 +98,12 @@ Apache Flink is supported in Zeppelin with the Flink interpreter group which con * Support multiple insert statements + Multi-tenancy Multiple user can work in one Zeppelin instance without affecting each other. - + Rest API Support You can not only submit Flink job via Zeppelin notebook UI, but also can do that via its rest api (You can use Zeppelin as Flink job server). @@ -176,17 +177,17 @@ You can also add and set other Flink properties which are not listed in the tabl Description - `FLINK_HOME` + `FLINK_HOME` Location of Flink installation. It is must be specified, otherwise you can not use Flink in Zeppelin - `HADOOP_CONF_DIR` + `HADOOP_CONF_DIR` Location of hadoop conf, this is must be set if running in yarn mode - `HIVE_CONF_DIR` + `HIVE_CONF_DIR` Location of hive conf, this is must be set if you want to connect to hive metastore @@ -208,12 +209,12 @@ You can also add and set other Flink properties which are not listed in the tabl jobmanager.memory.process.size 1024m - Total memory size of JobManager, e.g. 1024m. It is official [Flink property](https://ci.apache.org/projects/flink/flink-docs-release-1.13/docs/deployment/config/) + Total memory size of JobManager, e.g. 1024m. It is official [Flink property](https://ci.apache.org/projects/flink/flink-docs-release-1.13/docs/deployment/config/) taskmanager.memory.process.size 1024m - Total memory size of TaskManager, e.g. 1024m. It is official [Flink property](https://ci.apache.org/projects/flink/flink-docs-release-1.13/docs/deployment/config/) + Total memory size of TaskManager, e.g. 1024m. It is official [Flink property](https://ci.apache.org/projects/flink/flink-docs-release-1.13/docs/deployment/config/) taskmanager.numberOfTaskSlots @@ -253,27 +254,27 @@ You can also add and set other Flink properties which are not listed in the tabl flink.udf.jars.packages - Packages (comma separated) that would be searched for the udf defined in `flink.udf.jars`. Specifying this can reduce the number of classes to scan, otherwise all the classes in udf jar will be scanned. + Packages (comma separated) that would be searched for the udf defined in `flink.udf.jars`. Specifying this can reduce the number of classes to scan, otherwise all the classes in udf jar will be scanned. flink.execution.jars - Additional user jars (comma separated), these jars could be either local files or hdfs files if you have hadoop installed. It can be used to specify Flink connector jars or udf jars (no udf class auto-registration like `flink.udf.jars`) + Additional user jars (comma separated), these jars could be either local files or hdfs files if you have hadoop installed. It can be used to specify Flink connector jars or udf jars (no udf class auto-registration like `flink.udf.jars`) flink.execution.packages - Additional user packages (comma separated), e.g. `org.apache.flink:flink-json:1.10.0` + Additional user packages (comma separated), e.g. `org.apache.flink:flink-json:1.10.0` zeppelin.flink.concurrentBatchSql.max 10 - Max concurrent sql of Batch Sql (`%flink.bsql`) + Max concurrent sql of Batch Sql (`%flink.bsql`) zeppelin.flink.concurrentStreamSql.max 10 - Max concurrent sql of Stream Sql (`%flink.ssql`) + Max concurrent sql of Stream Sql (`%flink.ssql`) zeppelin.pyflink.python @@ -316,17 +317,17 @@ You can also add and set other Flink properties which are not listed in the tabl max number of row returned by sql interpreter - `zeppelin.flink.job.check_interval` + `zeppelin.flink.job.check_interval` 1000 Check interval (in milliseconds) to check Flink job progress - `flink.interpreter.close.shutdown_cluster` + `flink.interpreter.close.shutdown_cluster` true Whether shutdown Flink cluster when closing interpreter - `zeppelin.interpreter.close.cancel_job` + `zeppelin.interpreter.close.cancel_job` true Whether cancel Flink job when closing interpreter @@ -745,12 +746,12 @@ In this section, we will list and explain all the supported local properties in refreshInterval 3000 - Used in `%flink.ssql` to specify frontend refresh interval for streaming data visualization. + Used in `%flink.ssql` to specify frontend refresh interval for streaming data visualization. template {0} - Used in `%flink.ssql` to specify html template for `single` type of streaming data visualization, And you can use `{i}` as placeholder for the {i}th column of the result. + Used in `%flink.ssql` to specify html template for `single` type of streaming data visualization, And you can use `{i}` as placeholder for the {i}th column of the result. parallelism @@ -760,7 +761,7 @@ In this section, we will list and explain all the supported local properties in maxParallelism - Used in %flink.ssql & %flink.bsql to specify the flink sql job max parallelism in case you want to change parallelism later. For more details, refer this [link](https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/parallel.html#setting-the-maximum-parallelism) + Used in %flink.ssql & %flink.bsql to specify the flink sql job max parallelism in case you want to change parallelism later. For more details, refer this [link](https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/parallel.html#setting-the-maximum-parallelism) savepointDir @@ -797,4 +798,3 @@ Zeppelin is shipped with several Flink tutorial notes which may be helpful for y [Join our community](http://zeppelin.apache.org/community.html) to discuss with others. - diff --git a/docs/interpreter/hdfs.md b/docs/interpreter/hdfs.md index bec3785aad5..37fca3af67b 100644 --- a/docs/interpreter/hdfs.md +++ b/docs/interpreter/hdfs.md @@ -54,8 +54,8 @@ limitations under the License. This interpreter connects to HDFS using the HTTP WebHDFS interface. It supports the basic shell file commands applied to HDFS, it currently only supports browsing. -* You can use ls [PATH] and ls -l [PATH] to list a directory. If the path is missing, then the current directory is listed. ls supports a -h flag for human readable file sizes. -* You can use cd [PATH] to change your current directory by giving a relative or an absolute path. +* You can use `ls [PATH]` and `ls -l [PATH]` to list a directory. If the path is missing, then the current directory is listed. `ls` supports a `-h` flag for human readable file sizes. +* You can use `cd [PATH]` to change your current directory by giving a relative or an absolute path. * You can invoke pwd to see your current directory. > **Tip :** Use ( Ctrl + . ) for autocompletion. @@ -73,4 +73,3 @@ Here is an example: ```bash $> curl "http://localhost:50070/webhdfs/v1/?op=LISTSTATUS" ``` - diff --git a/docs/interpreter/livy.md b/docs/interpreter/livy.md index b48ad0472ba..1db8a86eed1 100644 --- a/docs/interpreter/livy.md +++ b/docs/interpreter/livy.md @@ -173,7 +173,7 @@ Example: `spark.driver.memory` to `livy.spark.driver.memory` zeppelin.livy.http.headers key_1: value_1; key_2: value_2 - custom http headers when calling livy rest api. Each http header is separated by `;`, and each header is one key value pair where key value is separated by `:` + custom http headers when calling livy rest api. Each http header is separated by `;`, and each header is one key value pair where key value is separated by `:` zeppelin.livy.tableWithUTFCharacters @@ -244,7 +244,7 @@ That means you can query the table via `%livy.sql` when this table is registered Livy debugging: If you see any of these in error console -> Connect to livyhost:8998 [livyhost/127.0.0.1, livyhost/0:0:0:0:0:0:0:1] failed: Connection refused +> Connect to livyhost:8998 `[livyhost/127.0.0.1, livyhost/0:0:0:0:0:0:0:1]` failed: Connection refused Looks like the livy server is not up yet or the config is wrong diff --git a/docs/interpreter/mahout.md b/docs/interpreter/mahout.md index ecab15668c6..0baa8987eae 100644 --- a/docs/interpreter/mahout.md +++ b/docs/interpreter/mahout.md @@ -47,28 +47,28 @@ The `add_mahout.py` script contains several command line arguments for advanced Example - `--zeppelin_home` - This is the path to the Zeppelin installation. This flag is not needed if the script is run from the top-level installation directory or from the `zeppelin/scripts/mahout` directory. - `/path/to/zeppelin` + `--zeppelin_home` + This is the path to the Zeppelin installation. This flag is not needed if the script is run from the top-level installation directory or from the `zeppelin/scripts/mahout` directory. + `/path/to/zeppelin` - `--mahout_home` - If the user has already installed Mahout, this flag can set the path to `MAHOUT_HOME`. If this is set, downloading Mahout will be skipped. - `/path/to/mahout_home` + `--mahout_home` + If the user has already installed Mahout, this flag can set the path to `MAHOUT_HOME`. If this is set, downloading Mahout will be skipped. + `/path/to/mahout_home` - `--restart_later` + `--restart_later` Restarting is necessary for updates to take effect. By default the script will restart Zeppelin for you. Restart will be skipped if this flag is set. NA - `--force_download` + `--force_download` This flag will force the script to re-download the binary even if it already exists. This is useful for previously failed downloads. NA - `--overwrite_existing` - This flag will force the script to overwrite existing `%sparkMahout` and `%flinkMahout` interpreters. Useful when you want to just start over. + `--overwrite_existing` + This flag will force the script to overwrite existing `%sparkMahout` and `%flinkMahout` interpreters. Useful when you want to just start over. NA diff --git a/docs/interpreter/markdown.md b/docs/interpreter/markdown.md index a9c830652db..907925e664c 100644 --- a/docs/interpreter/markdown.md +++ b/docs/interpreter/markdown.md @@ -27,7 +27,7 @@ limitations under the License. [Markdown](http://daringfireball.net/projects/markdown/) is a plain text formatting syntax designed so that it can be converted to HTML. Apache Zeppelin uses [flexmark](https://github.com/vsch/flexmark-java) and [markdown4j](https://github.com/jdcasey/markdown4j) as markdown parsers. -In Zeppelin notebook, you can use ` %md ` in the beginning of a paragraph to invoke the Markdown interpreter and generate static html from Markdown plain text. +In Zeppelin notebook, you can use `%md` in the beginning of a paragraph to invoke the Markdown interpreter and generate static html from Markdown plain text. In Zeppelin, Markdown interpreter is enabled by default and uses the [flexmark](https://github.com/vsch/flexmark-java) parser. diff --git a/docs/interpreter/mongodb.md b/docs/interpreter/mongodb.md index 84c813fc69e..6dc51f52391 100644 --- a/docs/interpreter/mongodb.md +++ b/docs/interpreter/mongodb.md @@ -46,7 +46,7 @@ Second, create mongodb interpreter in Zeppelin. mongo.shell.path mongosh - MongoDB shell local path.
      Use `which mongosh` to get local path in linux or mac.
      (For below [version 5.0](https://www.mongodb.com/docs/manual/release-notes/5.0/#shell-changes), check `mongo`) + MongoDB shell local path.
      Use `which mongosh` to get local path in linux or mac.
      (For below [version 5.0](https://www.mongodb.com/docs/manual/release-notes/5.0/#shell-changes), check `mongo`) mongo.shell.command.table.limit diff --git a/docs/interpreter/neo4j.md b/docs/interpreter/neo4j.md index 436532ff56a..50476e213d1 100644 --- a/docs/interpreter/neo4j.md +++ b/docs/interpreter/neo4j.md @@ -76,7 +76,7 @@ The Neo4j Interpreter supports all Neo4j versions since v3 via the official [Neo -
      +
      ![Interpreter configuration]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/neo4j-config.png)
      diff --git a/docs/interpreter/python.md b/docs/interpreter/python.md index 8600975c1d2..661fb500b40 100644 --- a/docs/interpreter/python.md +++ b/docs/interpreter/python.md @@ -382,7 +382,7 @@ Python interpreter create a variable `z` which represent `ZeppelinContext` for y z.checkbox(name, options, defaultChecked=[]) - Create dynamic form Checkbox `name` with options and defaultChecked. options should be a list of Tuple(first element is key, + Create dynamic form Checkbox `name` with options and defaultChecked. options should be a list of Tuple(first element is key, the second element is the displayed value) e.g. z.checkbox("f3", [("o1","1"), ("o2","2")],["o1"]) diff --git a/docs/interpreter/shell.md b/docs/interpreter/shell.md index 865b9150fb4..70c7a971a97 100644 --- a/docs/interpreter/shell.md +++ b/docs/interpreter/shell.md @@ -28,7 +28,7 @@ Zeppelin Shell has two interpreters the default is the %sh interpreter. ### Shell interpreter Shell interpreter uses [Apache Commons Exec](https://commons.apache.org/proper/commons-exec) to execute external processes. -In Zeppelin notebook, you can use ` %sh ` in the beginning of a paragraph to invoke system shell and run commands. +In Zeppelin notebook, you can use `%sh` in the beginning of a paragraph to invoke system shell and run commands. ### Terminal interpreter Terminal interpreter uses [hterm](https://chromium.googlesource.com/apps/libapps/+/HEAD/hterm), [Pty4J](https://github.com/JetBrains/pty4j) analog terminal operation. @@ -110,7 +110,7 @@ export KINIT_FAIL_THRESHOLD=10 The shell interpreter also supports interpolation of `ZeppelinContext` objects into the paragraph text. The following example shows one use of this facility: -####In Scala cell: +#### In Scala cell: ```scala z.put("dataFileName", "members-list-003.parquet") @@ -119,7 +119,7 @@ val members = spark.read.parquet(z.get("dataFileName")) // ... ``` -####In later Shell cell: +#### In later Shell cell: ```bash %sh diff --git a/docs/interpreter/spark.md b/docs/interpreter/spark.md index f7311a2133e..fa533e27547 100644 --- a/docs/interpreter/spark.md +++ b/docs/interpreter/spark.md @@ -89,12 +89,12 @@ Apache Spark is supported in Zeppelin with Spark interpreter group which consist You can visualize Spark Dataset/DataFrame vis Python's plotting libraries. - + Multi-tenancy Multiple user can work in one Zeppelin instance without affecting each other. - + Rest API Support You can not only submit Spark job via Zeppelin notebook UI, but also can do that via its rest api (You can use Zeppelin as Spark job server). @@ -129,19 +129,20 @@ You can also set other Spark properties which are not listed in the table. For a Description - `SPARK_HOME` + `SPARK_HOME` Location of spark distribution - + spark.master local[*] Spark master uri.
      e.g. spark://master_host:7077 - + spark.submit.deployMode The deploy mode of Spark driver program, either "client" or "cluster", Which means to launch driver program locally ("client") or remotely ("cluster") on one of the nodes inside the cluster. + spark.app.name Zeppelin @@ -188,21 +189,21 @@ You can also set other Spark properties which are not listed in the table. For a Comma-separated list of Maven coordinates of jars to include on the driver and executor classpaths. The coordinates should be groupId:artifactId:version. If spark.jars.ivySettings is given artifacts will be resolved according to the configuration in the file, otherwise artifacts will be searched for in the local maven repo, then maven central and finally any additional remote repositories given by the command-line option --repositories. - `PYSPARK_PYTHON` + `PYSPARK_PYTHON` python Python binary executable to use for PySpark in both driver and executors (default is python). Property spark.pyspark.python take precedence if it is set - `PYSPARK_DRIVER_PYTHON` + `PYSPARK_DRIVER_PYTHON` python - Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). + Python binary executable to use for PySpark in driver only (default is `PYSPARK_PYTHON`). Property spark.pyspark.driver.python take precedence if it is set zeppelin.pyspark.useIPython false - Whether use IPython when the ipython prerequisites are met in `%spark.pyspark` + Whether use IPython when the ipython prerequisites are met in `%spark.pyspark` zeppelin.spark.concurrentSQL diff --git a/docs/quickstart/docker.md b/docs/quickstart/docker.md index 5ae3afcc3b5..99767a95445 100644 --- a/docs/quickstart/docker.md +++ b/docs/quickstart/docker.md @@ -174,7 +174,7 @@ Supports all running modes of `local[*]`, `yarn-client`, and `yarn-cluster` of z | properties name | Value | Description | | ----- | ----- | ----- | - | SPARK\_CONF_DIR | /spark--path.../conf/ | Spark--path/conf/ path local on the zeppelin service | + | SPARK\_CONF_DIR | `/spark--path.../conf/` | `Spark--path/conf/` path local on the zeppelin service | #### HADOOP\_CONF_DIR @@ -191,7 +191,7 @@ Supports all running modes of `local[*]`, `yarn-client`, and `yarn-cluster` of z | properties name | Value | Description | | ----- | ----- | ----- | - | HADOOP\_CONF_DIR | hadoop--path/etc/hadoop | hadoop--path/etc/hadoop path local on the zeppelin service | + | HADOOP\_CONF_DIR | `hadoop--path/etc/hadoop` | `hadoop--path/etc/hadoop` path local on the zeppelin service | #### Accessing Spark UI (or Service running in interpreter container) diff --git a/docs/rss.xml b/docs/rss.xml deleted file mode 100644 index 8c2a9dd9a8c..00000000000 --- a/docs/rss.xml +++ /dev/null @@ -1,28 +0,0 @@ ---- -layout: nil -title : ---- - - - - - {{ site.title }} - {{ site.title }} - {{ site.author.name }} - {{ site.production_url }}{{ site.rss_path }} - {{ site.production_url }} - {{ site.time | date_to_xmlschema }} - {{ site.time | date_to_xmlschema }} - 1800 - -{% for post in site.posts %} - - {{ post.title }} - {{ post.content | xml_escape }} - {{ site.production_url }}{{ post.url }} - {{ site.production_url }}{{ post.id }} - {{ post.date | date_to_xmlschema }} - -{% endfor %} - - - diff --git a/docs/setup/deployment/flink_and_spark_cluster.md b/docs/setup/deployment/flink_and_spark_cluster.md index de87ec7eb7c..ab1f20d21e8 100644 --- a/docs/setup/deployment/flink_and_spark_cluster.md +++ b/docs/setup/deployment/flink_and_spark_cluster.md @@ -253,7 +253,7 @@ build-target/bin/start-cluster.sh In a browser, navigate to http://`yourip`:8082 to see the Flink Web-UI. Click on 'Task Managers' in the left navigation bar. Ensure there is at least one Task Manager present. -
      ![alt text]({{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/flink-webui.png "The Flink Web-UI")
      +
      ![alt text]({{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/flink-webui.png "The Flink Web-UI")
      If no task managers are present, restart the Flink cluster with the following commands: @@ -330,7 +330,7 @@ spark/sbin/start-master.sh --webui-port 8082 Open a browser and navigate to http://`yourip`:8082 to ensure the Spark master is running. -
      ![alt text]({{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/spark-master-webui1.png "It should look like this...")
      +
      ![alt text]({{BASE_PATH}}/assets/themes/zeppelin/img/screenshots/spark-master-webui1.png "It should look like this...")
      Toward the top of the page there will be a *URL*: spark://`yourhost`:7077. Note this URL, the Spark Master URI, it will be needed in subsequent steps. diff --git a/docs/setup/deployment/yarn_install.md b/docs/setup/deployment/yarn_install.md index 4c7e87bf599..58cf90d6ccf 100644 --- a/docs/setup/deployment/yarn_install.md +++ b/docs/setup/deployment/yarn_install.md @@ -109,7 +109,7 @@ hdp-select status hadoop-client | sed 's/hadoop-client - \(.*\)/\1/' cd /home/zeppelin/zeppelin bin/zeppelin-daemon.sh start ``` -After successful start, visit http://[zeppelin-server-host-name]:8080 with your web browser. +After successful start, visit `http://[zeppelin-server-host-name]:8080` with your web browser. ### Stop Zeppelin @@ -123,7 +123,7 @@ Zeppelin provides various distributed processing frameworks to process data that ### Hive Zeppelin supports Hive through JDBC interpreter. You might need the information to use Hive and can find in your hive-site.xml -Once Zeppelin server has started successfully, visit http://[zeppelin-server-host-name]:8080 with your web browser. Click on Interpreter tab next to Notebook dropdown. Look for Hive configurations and set them appropriately. Set them as per Hive installation on YARN cluster. +Once Zeppelin server has started successfully, visit `http://[zeppelin-server-host-name]:8080` with your web browser. Click on Interpreter tab next to Notebook dropdown. Look for Hive configurations and set them appropriately. Set them as per Hive installation on YARN cluster. Click on Save button. Once these configurations are updated, Zeppelin will prompt you to restart the interpreter. Accept the prompt and the interpreter will reload the configurations. ### Spark diff --git a/docs/setup/operation/configuration.md b/docs/setup/operation/configuration.md index 0a53f5179ee..1e994e0263e 100644 --- a/docs/setup/operation/configuration.md +++ b/docs/setup/operation/configuration.md @@ -51,7 +51,7 @@ Sources descending by priority:
      ZEPPELIN_PORT
      zeppelin.server.port
      8080 - Zeppelin server port
      + Zeppelin server port
      Note: Please make sure you're not using the same port with Zeppelin web application development port (default: 9000). @@ -302,7 +302,7 @@ Sources descending by priority:
      ZEPPELIN_NOTEBOOK_S3_CANNED_ACL
      zeppelin.notebook.s3.cannedAcl
      - Save notebooks to S3 with the given [Canned ACL](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/CannedAccessControlList.html) which determines the S3 permissions. + Save notebooks to S3 with the given [Canned ACL](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/CannedAccessControlList.html) which determines the S3 permissions.
      ZEPPELIN_NOTEBOOK_S3_PATH_STYLE_ACCESS
      @@ -422,7 +422,7 @@ Sources descending by priority:
      ZEPPELIN_NOTEBOOK_GIT_REMOTE_USERNAME
      zeppelin.notebook.git.remote.username
      token - GitHub username. By default it is `token` to use GitHub's API + GitHub username. By default it is `token` to use GitHub's API
      ZEPPELIN_NOTEBOOK_GIT_REMOTE_ACCESS_TOKEN
      @@ -434,7 +434,7 @@ Sources descending by priority:
      ZEPPELIN_NOTEBOOK_GIT_REMOTE_ORIGIN
      zeppelin.notebook.git.remote.origin
      token - GitHub remote name. Default is `origin` + GitHub remote name. Default is `origin`
      ZEPPELIN_RUN_MODE
      diff --git a/docs/setup/operation/upgrading.md b/docs/setup/operation/upgrading.md index 673fcac59c7..b34521ad122 100644 --- a/docs/setup/operation/upgrading.md +++ b/docs/setup/operation/upgrading.md @@ -58,7 +58,7 @@ So, copying `notebook` and `conf` directory should be enough. ### Upgrading from Zeppelin 0.6 to 0.7 - From 0.7, we don't use `ZEPPELIN_JAVA_OPTS` as default value of `ZEPPELIN_INTP_JAVA_OPTS` and also the same for `ZEPPELIN_MEM`/`ZEPPELIN_INTP_MEM`. If user want to configure the jvm opts of interpreter process, please set `ZEPPELIN_INTP_JAVA_OPTS` and `ZEPPELIN_INTP_MEM` explicitly. If you don't set `ZEPPELIN_INTP_MEM`, Zeppelin will set it to `-Xms1024m -Xmx1024m -XX:MaxMetaspaceSize=512m` by default. - - Mapping from `%jdbc(prefix)` to `%prefix` is no longer available. Instead, you can use %[interpreter alias] with multiple interpreter setttings on GUI. + - Mapping from `%jdbc(prefix)` to `%prefix` is no longer available. Instead, you can use `%[interpreter alias]` with multiple interpreter setttings on GUI. - Usage of `ZEPPELIN_PORT` is not supported in ssl mode. Instead use `ZEPPELIN_SSL_PORT` to configure the ssl port. Value from `ZEPPELIN_PORT` is used only when `ZEPPELIN_SSL` is set to `false`. - The support on Spark 1.1.x to 1.3.x is deprecated. - From 0.7, we uses `pegdown` as the `markdown.parser.type` option for the `%md` interpreter. Rendered markdown might be different from what you expected diff --git a/docs/setup/security/http_security_headers.md b/docs/setup/security/http_security_headers.md index 95dcd2d0d44..4d7566dd25f 100644 --- a/docs/setup/security/http_security_headers.md +++ b/docs/setup/security/http_security_headers.md @@ -27,7 +27,7 @@ Apache Zeppelin can be configured to include HTTP Headers which aids in preventi ## Setting up HTTP Strict Transport Security (HSTS) Response Header -Enabling HSTS Response Header prevents Man-in-the-middle attacks by automatically redirecting HTTP requests to HTTPS when Zeppelin Server is running on SSL. Read on how to configure SSL for Zeppelin [here] (../operation/configuration.html). Even if web page contains any resource which gets served over HTTP or any HTTP links, it will automatically be redirected to HTTPS for the target domain. +Enabling HSTS Response Header prevents Man-in-the-middle attacks by automatically redirecting HTTP requests to HTTPS when Zeppelin Server is running on SSL. Read on how to configure SSL for Zeppelin [here](../operation/configuration.html). Even if web page contains any resource which gets served over HTTP or any HTTP links, it will automatically be redirected to HTTPS for the target domain. It also prevents MITM attack by not allowing User to override the invalid certificate message, when Attacker presents invalid SSL certificate to the User. The following property needs to be updated in the zeppelin-site.xml in order to enable HSTS. You can choose appropriate value for "max-age". diff --git a/docs/setup/security/shiro_authentication.md b/docs/setup/security/shiro_authentication.md index 98cebc937ae..d5ded4e1711 100644 --- a/docs/setup/security/shiro_authentication.md +++ b/docs/setup/security/shiro_authentication.md @@ -322,7 +322,7 @@ Since Shiro provides **url-based security**, you can hide the information by com ``` In this case, only who have `admin` role can see **Interpreter Setting**, **Credential** and **Configuration** information. -If you want to grant this permission to other users, you can change **roles[ ]** as you defined at `[users]` section. +If you want to grant this permission to other users, you can change **`roles[ ]`** as you defined at `[users]` section. ### Apply multiple roles in Shiro configuration By default, Shiro will allow access to a URL if only user is part of "**all the roles**" defined like this: diff --git a/docs/setup/storage/notebook_storage.md b/docs/setup/storage/notebook_storage.md index e7a5b26ccc0..4d7e3cadc20 100644 --- a/docs/setup/storage/notebook_storage.md +++ b/docs/setup/storage/notebook_storage.md @@ -41,7 +41,7 @@ There are few notebook storage systems available for a use out of the box: Multiple storage systems can be used at the same time by providing a comma-separated list of the class-names in the configuration. By default, only first two of them will be automatically kept in sync by Zeppelin. -
      +
      ## Notebook Storage in local Git repository @@ -55,7 +55,7 @@ To enable versioning for all your local notebooks though a standard Git reposito ``` -
      +
      ## Notebook Storage in hadoop compatible file system repository @@ -71,7 +71,7 @@ If your hadoop cluster is kerberized, then you need to specify `zeppelin.server. ``` -
      +
      ## Notebook Storage in S3 @@ -83,7 +83,7 @@ Notebooks may be stored in S3, and optionally encrypted. The [``DefaultAWSCrede - Credential profiles file at the default location (````~/.aws/credentials````) used by the AWS CLI - Instance profile credentials delivered through the Amazon EC2 metadata service -
      +
      The following folder structure will be created in S3: ``` @@ -205,7 +205,7 @@ Or using the following setting in **zeppelin-site.xml**: ``` -
      +
      ### S3 Object Permissions @@ -226,7 +226,7 @@ Or using the following setting in **zeppelin-site.xml**: ``` -
      +
      #### S3 Enable Path Style Access @@ -246,7 +246,7 @@ Or using the following setting in **zeppelin-site.xml**: ``` -
      +
      ## Notebook Storage in Azure @@ -308,7 +308,7 @@ Optionally, you can specify Azure folder structure name in the file **zeppelin-s ``` -
      +
      ## Notebook Storage in Google Cloud Storage @@ -414,13 +414,13 @@ file for authentication with GCS, update the following property : ``` -
      +
      ## Notebook Storage in OSS Notebooks may be stored in Aliyun OSS. -
      +
      The following folder structure will be created in OSS: ``` diff --git a/docs/usage/display_system/angular_frontend.md b/docs/usage/display_system/angular_frontend.md index affdc282869..6a2cbd0a0ec 100644 --- a/docs/usage/display_system/angular_frontend.md +++ b/docs/usage/display_system/angular_frontend.md @@ -24,8 +24,8 @@ limitations under the License.
      ## Basic Usage -In addition to the [backend Angular API](./angular_backend.html) to handle Angular objects binding, Apache Zeppelin also exposes a simple AngularJS **z** object on the front-end side to expose the same capabilities. -This **z** object is accessible in the Angular isolated scope for each paragraph. +In addition to the [backend Angular API](./angular_backend.html) to handle Angular objects binding, Apache Zeppelin also exposes a simple AngularJS **`z`** object on the front-end side to expose the same capabilities. +This **`z`** object is accessible in the Angular isolated scope for each paragraph. ### Bind / Unbind Variables @@ -126,6 +126,7 @@ How does the front-end AngularJS API compares to the [backend Angular API](./ang Back-end API + Initiate binding z.angularbind(var, initialValue, paragraphId) @@ -161,8 +162,7 @@ How does the front-end AngularJS API compares to the [backend Angular API](./ang z.runNote(noteId) - - + Both APIs are pretty similar, except for value watching where it is done naturally by AngularJS internals on the front-end and by user custom watcher functions in the back-end. diff --git a/docs/usage/display_system/basic.md b/docs/usage/display_system/basic.md index 01d46297fcf..0f0faebeb8c 100644 --- a/docs/usage/display_system/basic.md +++ b/docs/usage/display_system/basic.md @@ -86,11 +86,11 @@ A [Property Graph](https://github.com/tinkerpop/gremlin/wiki/Defining-a-Property * each edge has a label that denotes the type of relationship between its two vertices. * each edge has a collection of properties defined by a map from key to value. - +![Property graph example]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/property-graph-example.svg) A [Labelled Property Graph](https://neo4j.com/developer/graph-database/#property-graph) is a Property Graph where the nodes can be tagged with **labels** representing their different roles in the graph model - +![Labeled property graph data model]({{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/labeled-property-graph-model.svg) ### What are the APIs? diff --git a/docs/usage/dynamic_form/intro.md b/docs/usage/dynamic_form/intro.md index 8328bd00878..8c6c67f4494 100644 --- a/docs/usage/dynamic_form/intro.md +++ b/docs/usage/dynamic_form/intro.md @@ -102,7 +102,7 @@ Some language backends can programmatically create forms. For example [ZeppelinC Here are some examples: ### Text input form -
      +
      {% highlight scala %} @@ -125,7 +125,7 @@ print("Hello "+z.textbox("name")) Use `z.input()` instead in version 0.7.3 or prior. `z.input()` is deprecated in 0.8.0. ### Text input form with default value -
      +
      {% highlight scala %} @@ -148,7 +148,7 @@ print("Hello "+z.textbox("name", "sun")) Use `z.input()` instead in version 0.7.3 or prior. `z.input()` is deprecated in 0.8.0. ### Password form -
      +
      {% highlight scala %} @@ -169,7 +169,7 @@ print("Password is "+ z.password("my_password")) ### Select form -
      +
      {% highlight scala %} @@ -202,7 +202,7 @@ print("Hello "+z.select("day", [("1","mon"), #### Checkbox form -
      +
      {% highlight scala %} diff --git a/docs/usage/interpreter/dynamic_loading.md b/docs/usage/interpreter/dynamic_loading.md index 404421bfa68..107d85b2734 100644 --- a/docs/usage/interpreter/dynamic_loading.md +++ b/docs/usage/interpreter/dynamic_loading.md @@ -40,7 +40,7 @@ You can **load** interpreters located in Maven repository using REST API, like t ``` http://[zeppelin-server]:[zeppelin-port]/api/interpreter/load/[interpreter_group_name]/[interpreter_name] ``` -The Restful method will be **POST**. And the parameters you need are: +The Restful method will be **`POST`**. And the parameters you need are: 1. **Artifact:** Maven artifact ( groupId:artifactId:version ) @@ -89,7 +89,7 @@ If you want to **unload** the interpreters using REST API, ``` http://[zeppelin-server]:[zeppelin-port]/api/interpreter/unload/[interpreter_group_name]/[interpreter_name] ``` -In this case, the Restful method will be **DELETE**. +In this case, the Restful method will be **`DELETE`**.
      ## What is the next step after Loading ? diff --git a/docs/usage/interpreter/overview.md b/docs/usage/interpreter/overview.md index 862fb69074c..6833cf09aa3 100644 --- a/docs/usage/interpreter/overview.md +++ b/docs/usage/interpreter/overview.md @@ -51,7 +51,7 @@ The interpreter settings are the configuration of a given interpreter on the Zep -Properties are exported as environment variables on the system if the property name consists of upper-case characters, numbers or underscores ([A-Z_0-9]). Otherwise, the property is set as a common interpreter property. +Properties are exported as environment variables on the system if the property name consists of upper-case characters, numbers or underscores (`[A-Z_0-9]`). Otherwise, the property is set as a common interpreter property. e.g. You can define `SPARK_HOME` and `HADOOP_CONF_DIR` in spark's interpreter setting, they are be passed to Spark interpreter process as environment variable which is used by Spark. You may use parameters from the context of the interpreter by adding #{contextParameterName} in the interpreter property value. The parameter can be of the following types: string, number, boolean. diff --git a/docs/usage/other_features/zeppelin_context.md b/docs/usage/other_features/zeppelin_context.md index ad9f09c305f..a4a87474d53 100644 --- a/docs/usage/other_features/zeppelin_context.md +++ b/docs/usage/other_features/zeppelin_context.md @@ -56,7 +56,7 @@ other interpreters that can access the `z` object (Flink already support to show `ZeppelinContext` extends map and it's shared between the Apache Spark and Python environments. So you can put some objects using Scala (in an Apache Spark cell) and read it from Python, and vice versa. -
      +
      {% highlight scala %} @@ -143,7 +143,7 @@ bank = z.getAsDataFrame('bank') `ZeppelinContext` provides functions for creating forms. In Scala and Python environments, you can create forms programmatically. -
      +
      {% highlight scala %} @@ -229,7 +229,7 @@ Some interpreters can interpolate object values from `z` into the paragraph text interpolated into a paragraph text by using such a pattern containing the object's name. The following example shows one use of this facility: -####In Scala cell: +#### In Scala cell: ```scala %spark @@ -237,7 +237,7 @@ The following example shows one use of this facility: z.put("minAge", 35) ``` -####In later SQL cell: +#### In later SQL cell: ```sql %spark.sql diff --git a/docs/usage/rest_api/configuration.md b/docs/usage/rest_api/configuration.md index 249e1ad1077..3e9e4072849 100644 --- a/docs/usage/rest_api/configuration.md +++ b/docs/usage/rest_api/configuration.md @@ -38,12 +38,12 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method return all key/value pair of configurations on the server.
      + This ```GET``` method return all key/value pair of configurations on the server.
      Note: For security reason, some pairs would not be shown. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/configurations/all``` + ```http://[zeppelin-server]:[zeppelin-port]/api/configurations/all``` Success code @@ -56,7 +56,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple sample JSON response - + ```json { @@ -98,12 +98,12 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method return all prefix matched key/value pair of configurations on the server.
      + This ```GET``` method return all prefix matched key/value pair of configurations on the server.
      Note: For security reason, some pairs would not be shown. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/configurations/prefix/[prefix]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/configurations/prefix/[prefix]``` Success code @@ -116,7 +116,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple sample JSON response - + ```json { diff --git a/docs/usage/rest_api/credential.md b/docs/usage/rest_api/credential.md index c66d0986f69..28fbb313a9c 100644 --- a/docs/usage/rest_api/credential.md +++ b/docs/usage/rest_api/credential.md @@ -38,11 +38,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns all key/value pairs of the credential information on the server. + This ```GET``` method returns all key/value pairs of the credential information on the server. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/credential``` + ```http://[zeppelin-server]:[zeppelin-port]/api/credential``` Success code @@ -55,7 +55,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple sample JSON response - + ```json { @@ -85,11 +85,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```PUT``` method creates the credential information with new properties. + This ```PUT``` method creates the credential information with new properties. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/credential/``` + ```http://[zeppelin-server]:[zeppelin-port]/api/credential/``` Success code @@ -101,7 +101,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON input - + ```json { @@ -114,7 +114,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -133,11 +133,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```DELETE``` method deletes the credential information. + This ```DELETE``` method deletes the credential information. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/credential``` + ```http://[zeppelin-server]:[zeppelin-port]/api/credential``` Success code @@ -149,7 +149,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json {"status":"OK"} @@ -166,11 +166,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```DELETE``` method deletes a given credential entity. + This ```DELETE``` method deletes a given credential entity. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/credential/[entity]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/credential/[entity]``` Success code @@ -182,7 +182,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json {"status":"OK"} diff --git a/docs/usage/rest_api/helium.md b/docs/usage/rest_api/helium.md index 35db5858e7d..21d5d48262a 100644 --- a/docs/usage/rest_api/helium.md +++ b/docs/usage/rest_api/helium.md @@ -38,11 +38,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns all the available helium packages in configured registries. + This ```GET``` method returns all the available helium packages in configured registries. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/package``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/package``` Success code @@ -54,7 +54,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -95,11 +95,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns all enabled helium packages in configured registries. + This ```GET``` method returns all enabled helium packages in configured registries. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/enabledPackage``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/enabledPackage``` Success code @@ -111,7 +111,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -152,11 +152,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns specified helium package information + This ```GET``` method returns specified helium package information URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/package/[Package Name]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/package/[Package Name]``` Success code @@ -168,7 +168,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -209,11 +209,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns suggested helium package for the paragraph. + This ```GET``` method returns suggested helium package for the paragraph. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/suggest/[Note ID]/[Paragraph ID]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/suggest/[Note ID]/[Paragraph ID]``` Success code @@ -228,7 +228,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -269,11 +269,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```POST``` method loads helium package to target paragraph. + This ```POST``` method loads helium package to target paragraph. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/load/[Note ID]/[Paragraph ID]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/load/[Note ID]/[Paragraph ID]``` Success code @@ -288,7 +288,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -308,11 +308,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns bundled helium visualization javascript. When refresh=true (optional) is provided, Zeppelin rebuilds bundle. Otherwise, it's provided from cache + This ```GET``` method returns bundled helium visualization javascript. When refresh=true (optional) is provided, Zeppelin rebuilds bundle. Otherwise, it's provided from cache URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/bundle/load/[Package Name][?refresh=true]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/bundle/load/[Package Name][?refresh=true]``` Success code @@ -332,11 +332,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```POST``` method enables a helium package. Needs artifact name in input payload + This ```POST``` method enables a helium package. Needs artifact name in input payload URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/enable/[Package Name]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/enable/[Package Name]``` Success code @@ -356,7 +356,7 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Sample JSON response - + ```json {"status":"OK"} @@ -372,11 +372,11 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Description - This ```POST``` method disables a helium package. + This ```POST``` method disables a helium package. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/disable/[Package Name]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/disable/[Package Name]``` Success code @@ -388,7 +388,7 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Sample JSON response - + ```json {"status":"OK"} @@ -404,11 +404,11 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Description - This ```GET``` method returns display order of enabled visualization packages. + This ```GET``` method returns display order of enabled visualization packages. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/order/visualization``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/order/visualization``` Success code @@ -420,7 +420,7 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Sample JSON response - + ```json {"status":"OK","body":["zeppelin_horizontalbar","zeppelin-bubblechart"]} @@ -436,11 +436,11 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Description - This ```POST``` method sets visualization packages display order. + This ```POST``` method sets visualization packages display order. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/order/visualization``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/order/visualization``` Success code @@ -452,7 +452,7 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Sample JSON input - + ```json ["zeppelin-bubblechart", "zeppelin_horizontalbar"] @@ -461,7 +461,7 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Sample JSON response - + ```json {"status":"OK"} @@ -477,11 +477,11 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA Description - This ```GET``` method returns configuration for all Helium packages + This ```GET``` method returns configuration for all Helium packages URL - ```http://[zeppelin-server]:[zeppelin-port]/api/helium/config``` + ```http://[zeppelin-server]:[zeppelin-port]/api/helium/config``` Success code @@ -494,17 +494,17 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA
      - ### Get configuration for specific package +### Get configuration for specific package - + - + @@ -523,11 +523,11 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA - + - + @@ -540,17 +540,17 @@ zeppelin-examples/zeppelin-example-clock/target/zeppelin-example-clock-0.7.0-SNA
      DescriptionThis ```GET``` method returns configuration for the specified package name and artifactThis ```GET``` method returns configuration for the specified package name and artifact
      URL```http://[zeppelin-server]:[zeppelin-port]/api/helium/config/[Package Name]/[Artifact]``````http://[zeppelin-server]:[zeppelin-port]/api/helium/config/[Package Name]/[Artifact]```
      Success code
      DescriptionThis ```POST``` method updates configuration for specified package name and artifactThis ```POST``` method updates configuration for specified package name and artifact
      URL```http://[zeppelin-server]:[zeppelin-port]/api/helium/config/[Package Name]/[Artifact]``````http://[zeppelin-server]:[zeppelin-port]/api/helium/config/[Package Name]/[Artifact]```
      Success code

      - ### Get Spell configuration for single package +### Get Spell configuration for single package - + - + diff --git a/docs/usage/rest_api/interpreter.md b/docs/usage/rest_api/interpreter.md index 9d81dd60e06..8e22f3e8ed3 100644 --- a/docs/usage/rest_api/interpreter.md +++ b/docs/usage/rest_api/interpreter.md @@ -40,11 +40,11 @@ The role of registered interpreters, settings and interpreters group are describ - + - + @@ -56,7 +56,7 @@ The role of registered interpreters, settings and interpreters group are describ - - + - + @@ -133,7 +133,7 @@ The role of registered interpreters, settings and interpreters group are describ - - + - + @@ -220,7 +220,7 @@ The role of registered interpreters, settings and interpreters group are describ - - + - + @@ -284,7 +284,7 @@ The role of registered interpreters, settings and interpreters group are describ - - - + - + @@ -375,7 +375,7 @@ The role of registered interpreters, settings and interpreters group are describ - - - + - + @@ -467,7 +467,7 @@ The role of registered interpreters, settings and interpreters group are describ - - + - + @@ -500,7 +500,7 @@ The role of registered interpreters, settings and interpreters group are describ - - - + - + @@ -543,7 +543,7 @@ The role of registered interpreters, settings and interpreters group are describ - - - + - + @@ -594,11 +594,11 @@ The role of registered interpreters, settings and interpreters group are describ - + - + @@ -610,7 +610,7 @@ The role of registered interpreters, settings and interpreters group are describ - - +
      DescriptionThis ```GET``` method returns specified package Spell configurationThis ```GET``` method returns specified package Spell configuration
      URL```http://[zeppelin-server]:[zeppelin-port]/api/helium/spell/config/[Package Name]``````http://[zeppelin-server]:[zeppelin-port]/api/helium/spell/config/[Package Name]```
      Success code
      DescriptionThis ```GET``` method returns all the registered interpreters available on the server.This ```GET``` method returns all the registered interpreters available on the server.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter```
      Success code
      Sample JSON response + ```json { @@ -117,11 +117,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```GET``` method returns all the interpreters settings registered on the server.This ```GET``` method returns all the interpreters settings registered on the server.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting```
      Success code
      Sample JSON response + ```json { @@ -201,11 +201,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```GET``` method returns a registered interpreter setting on the server.This ```GET``` method returns a registered interpreter setting on the server.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/[setting ID]``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/[setting ID]```
      Success code
      Sample JSON response + ```json { @@ -265,11 +265,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```POST``` method adds a new interpreter setting using a registered interpreter to the server.This ```POST``` method adds a new interpreter setting using a registered interpreter to the server.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting```
      Success code
      Sample JSON input + ```json { @@ -316,7 +316,7 @@ The role of registered interpreters, settings and interpreters group are describ
      Sample JSON response + ```json { @@ -359,11 +359,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```PUT``` method updates an interpreter setting with new properties.This ```PUT``` method updates an interpreter setting with new properties.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/[interpreter ID]``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/[interpreter ID]```
      Success code
      Sample JSON input + ```json { @@ -407,7 +407,7 @@ The role of registered interpreters, settings and interpreters group are describ
      Sample JSON response + ```json { @@ -451,11 +451,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```DELETE``` method deletes an given interpreter setting.This ```DELETE``` method deletes an given interpreter setting.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/[interpreter ID]``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/[interpreter ID]```
      Success code
      Sample JSON response + ```json {"status":"OK"} @@ -484,11 +484,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```PUT``` method restarts the given interpreter id.This ```PUT``` method restarts the given interpreter id.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/restart/[interpreter ID]``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/setting/restart/[interpreter ID]```
      Success code
      Sample JSON input (Optional) + ```json { @@ -511,7 +511,7 @@ The role of registered interpreters, settings and interpreters group are describ
      Sample JSON response + ```json {"status":"OK"} @@ -527,11 +527,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```POST``` method adds new repository.This ```POST``` method adds new repository.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/repository``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/repository```
      Success code
      Sample JSON input + ```json { @@ -556,7 +556,7 @@ The role of registered interpreters, settings and interpreters group are describ
      Sample JSON response + ```json {"status":"OK"} @@ -572,11 +572,11 @@ The role of registered interpreters, settings and interpreters group are describ
      DescriptionThis ```DELETE``` method delete repository with given id.This ```DELETE``` method delete repository with given id.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/repository/[repository ID]``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/repository/[repository ID]```
      Success code
      DescriptionThis ```GET``` method returns available types for interpreter property.This ```GET``` method returns available types for interpreter property.
      URL```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/property/types``````http://[zeppelin-server]:[zeppelin-port]/api/interpreter/property/types```
      Success code
      Sample JSON response + ```json { @@ -620,7 +620,7 @@ The role of registered interpreters, settings and interpreters group are describ } ```

      @@ -630,11 +630,11 @@ The role of registered interpreters, settings and interpreters group are describ Description - This ```GET``` method returns interpreter settings metadata info. + This ```GET``` method returns interpreter settings metadata info. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/metadata/[setting ID]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/interpreter/metadata/[setting ID]``` Success code diff --git a/docs/usage/rest_api/notebook.md b/docs/usage/rest_api/notebook.md index 0f858024f83..76a17c15755 100644 --- a/docs/usage/rest_api/notebook.md +++ b/docs/usage/rest_api/notebook.md @@ -37,13 +37,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method lists the available notes on your server. + This ```GET``` method lists the available notes on your server. Notebook JSON contains the ```name``` and ```id``` of all notes. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook``` Success code @@ -55,7 +55,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -83,13 +83,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method creates a new note using the given name or default name if none given. + This ```POST``` method creates a new note using the given name or default name if none given. The body field of the returned JSON contains the new note id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook``` Success code @@ -101,7 +101,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (without paragraphs) - + ```json {"name": "name of new note"} @@ -110,7 +110,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (with initial paragraphs) - + ```json { @@ -143,7 +143,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -162,13 +162,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method gets the status of all paragraphs by the given note id. + This ```GET``` method gets the status of all paragraphs by the given note id. The body field of the returned JSON contains of the array that compose of the paragraph id, paragraph status, paragraph finish date, paragraph started date. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]``` Success code @@ -180,7 +180,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -212,13 +212,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method retrieves an existing note's information using the given id. + This ```GET``` method retrieves an existing note's information using the given id. The body field of the returned JSON contain information about paragraphs in the note. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]``` Success code @@ -230,7 +230,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -319,12 +319,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```DELETE``` method deletes a note by the given note id. + This ```DELETE``` method deletes a note by the given note id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]``` Success code @@ -336,7 +336,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK","message": ""} @@ -351,7 +351,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method clones a note by the given id and create a new note using the given name + This ```POST``` method clones a note by the given id and create a new note using the given name or default name if none given. If what you want to copy is a certain version of note, you need to specify the revisionId. The body field of the returned JSON contains the new note id. @@ -359,7 +359,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]``` Success code @@ -371,7 +371,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json { @@ -383,7 +383,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -402,12 +402,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```PUT``` method renames a note by the given id using the given name. + This ```PUT``` method renames a note by the given id using the given name. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/rename``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/rename``` Success code @@ -423,7 +423,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json {"name": "new name of a note"} @@ -432,7 +432,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status":"OK"} @@ -448,12 +448,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method exports a note by the given id and generates a JSON + This ```GET``` method exports a note by the given id and generates a JSON URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/export/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/export/[noteId]``` Success code @@ -463,8 +463,9 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Fail code 500 - sample JSON response - + + sample JSON response + ```json { @@ -503,12 +504,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method imports a note from the note JSON input + This ```POST``` method imports a note from the note JSON input URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/import``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/import``` Success code @@ -520,7 +521,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json @@ -554,7 +555,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -572,7 +573,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - + This ```POST``` method runs all paragraphs in the given note id.
      If you can not find Note id 404 returns. If there is a problem with the interpreter returns a 412 error. @@ -580,7 +581,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]``` Success code @@ -592,7 +593,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} @@ -601,7 +602,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON error response - + ```json { @@ -628,12 +629,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```DELETE``` method stops all paragraphs in the given note id. + This ```DELETE``` method stops all paragraphs in the given note id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]``` Success code @@ -645,7 +646,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status":"OK"} @@ -660,12 +661,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```PUT``` method clear all paragraph results from note of given id. + This ```PUT``` method clear all paragraph results from note of given id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/clear``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/clear``` Success code @@ -685,14 +686,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} ``` - @@ -703,13 +703,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method create a new paragraph using JSON payload. + This ```POST``` method create a new paragraph using JSON payload. The body field of the returned JSON contain the new paragraph id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph``` Success code @@ -721,7 +721,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (add to the last) - + ```json { @@ -733,7 +733,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (add to specific index) - + ```json { @@ -746,7 +746,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (providing paragraph config) - + ```json { @@ -770,7 +770,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -789,13 +789,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method retrieves an existing paragraph's information using the given id. + This ```GET``` method retrieves an existing paragraph's information using the given id. The body field of the returned JSON contain information about paragraph. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]``` Success code @@ -807,7 +807,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -865,13 +865,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method gets the status of a single paragraph by the given note and paragraph id. + This ```GET``` method gets the status of a single paragraph by the given note and paragraph id. The body field of the returned JSON contains of the array that compose of the paragraph id, paragraph status, paragraph finish date, paragraph started date. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]/[paragraphId]``` Success code @@ -883,7 +883,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -907,12 +907,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```PUT``` method update paragraph contents using given id, e.g. {"text": "hello"} + This ```PUT``` method update paragraph contents using given id, e.g. {"text": "hello"} URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]``` Success code @@ -936,7 +936,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json { @@ -948,7 +948,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -966,12 +966,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```PUT``` method update paragraph configuration using given id so that user can change paragraph setting such as graph type, show or hide editor/result and paragraph size, etc. You can update certain fields you want, for example you can update colWidth field only by sending request with payload {"colWidth": 12.0}. + This ```PUT``` method update paragraph configuration using given id so that user can change paragraph setting such as graph type, show or hide editor/result and paragraph size, etc. You can update certain fields you want, for example you can update colWidth field only by sending request with payload {"colWidth": 12.0}. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]/config``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]/config``` Success code @@ -995,7 +995,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json { @@ -1030,7 +1030,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1101,12 +1101,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```DELETE``` method deletes a paragraph by the given note and paragraph id. + This ```DELETE``` method deletes a paragraph by the given note and paragraph id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]``` Success code @@ -1118,7 +1118,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK","message": ""} @@ -1133,12 +1133,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method runs the paragraph asynchronously by given note and paragraph id. This API always return SUCCESS even if the execution of the paragraph fails later because the API is asynchronous + This ```POST``` method runs the paragraph asynchronously by given note and paragraph id. This API always return SUCCESS even if the execution of the paragraph fails later because the API is asynchronous URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]/[paragraphId]``` Success code @@ -1150,7 +1150,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (optional, only needed when if you want to update dynamic form's value) - + ```json { @@ -1165,7 +1165,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} @@ -1180,12 +1180,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method runs the paragraph synchronously by given note and paragraph id. This API can return SUCCESS or ERROR depending on the outcome of the paragraph execution + This ```POST``` method runs the paragraph synchronously by given note and paragraph id. This API can return SUCCESS or ERROR depending on the outcome of the paragraph execution URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/run/[noteId]/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/run/[noteId]/[paragraphId]``` Success code @@ -1197,7 +1197,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input (optional, only needed when if you want to update dynamic form's value) - + ```json { @@ -1212,7 +1212,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} @@ -1221,7 +1221,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON error - + ```json { @@ -1244,12 +1244,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```DELETE``` method stops the paragraph by given note and paragraph id. + This ```DELETE``` method stops the paragraph by given note and paragraph id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]/[paragraphId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[noteId]/[paragraphId]``` Success code @@ -1261,7 +1261,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} @@ -1276,12 +1276,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method moves a paragraph to the specific index (order) from the note. + This ```POST``` method moves a paragraph to the specific index (order) from the note. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]/move/[newIndex]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/paragraph/[paragraphId]/move/[newIndex]``` Success code @@ -1293,7 +1293,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK","message": ""} @@ -1308,12 +1308,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - ```GET``` request will return list of matching paragraphs + ```GET``` request will return list of matching paragraphs URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/search?q=[query]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/search?q=[query]``` Success code @@ -1325,7 +1325,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Sample JSON response - + ```json { @@ -1351,13 +1351,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method adds cron job by the given note id. + This ```POST``` method adds cron job by the given note id. Default value of ```releaseResource``` is ```false```. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[noteId]``` Success code @@ -1369,7 +1369,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json {"cron": "cron expression of note", "releaseResource": "false"} @@ -1378,7 +1378,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} @@ -1394,12 +1394,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```DELETE``` method removes cron job by the given note id. + This ```DELETE``` method removes cron job by the given note id. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[noteId]``` Success code @@ -1411,7 +1411,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json {"status": "OK"} @@ -1427,13 +1427,13 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method gets cron job expression of given note id. + This ```GET``` method gets cron job expression of given note id. The body field of the returned JSON contains the cron expression and ```releaseResource``` flag. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[noteId]``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[noteId]``` Success code @@ -1445,7 +1445,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1470,12 +1470,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method gets a note authorization information. + This ```GET``` method gets a note authorization information. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/permissions``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/permissions``` Success code @@ -1491,7 +1491,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1523,12 +1523,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```PUT``` method set note authorization information. + This ```PUT``` method set note authorization information. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/permissions``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/permissions``` Success code @@ -1544,7 +1544,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json { @@ -1566,7 +1566,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1588,12 +1588,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method gets the revisions of a note. + This ```GET``` method gets the revisions of a note. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision``` Success code @@ -1605,7 +1605,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1634,12 +1634,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```POST``` method saves a revision for a note. + This ```POST``` method saves a revision for a note. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision``` Success code @@ -1655,7 +1655,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON input - + ```json { @@ -1666,7 +1666,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1683,12 +1683,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```GET``` method gets a revision of a note. + This ```GET``` method gets a revision of a note. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision/{revisionId}``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision/{revisionId}``` Success code @@ -1700,7 +1700,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1787,12 +1787,12 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, Description - This ```PUT``` method reverts a note to a specified version + This ```PUT``` method reverts a note to a specified version URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision/{revisionId}``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook/[noteId]/revision/{revisionId}``` Success code @@ -1804,7 +1804,7 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, sample JSON response - + ```json { @@ -1815,4 +1815,3 @@ Notebooks REST API supports the following operations: List, Create, Get, Delete, - diff --git a/docs/usage/rest_api/notebook_repository.md b/docs/usage/rest_api/notebook_repository.md index 2536d61b253..9bba0e336d3 100644 --- a/docs/usage/rest_api/notebook_repository.md +++ b/docs/usage/rest_api/notebook_repository.md @@ -38,11 +38,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns all the available notebook repositories. + This ```GET``` method returns all the available notebook repositories. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook-repositories``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook-repositories``` Success code @@ -54,7 +54,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -88,11 +88,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method triggers reloading and broadcasting of the note list. + This ```GET``` method triggers reloading and broadcasting of the note list. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook-repositories/reload``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook-repositories/reload``` Success code @@ -104,7 +104,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { @@ -124,11 +124,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```PUT``` method updates a specific notebook repository. + This ```PUT``` method updates a specific notebook repository. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/notebook-repositories``` + ```http://[zeppelin-server]:[zeppelin-port]/api/notebook-repositories``` Success code @@ -144,7 +144,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON input - + ```json { @@ -158,7 +158,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Sample JSON response - + ```json { diff --git a/docs/usage/rest_api/zeppelin_server.md b/docs/usage/rest_api/zeppelin_server.md index 67ae96c0339..562db52a6dd 100644 --- a/docs/usage/rest_api/zeppelin_server.md +++ b/docs/usage/rest_api/zeppelin_server.md @@ -38,11 +38,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```GET``` method returns Zeppelin version + This ```GET``` method returns Zeppelin version URL - ```http://[zeppelin-server]:[zeppelin-port]/api/version``` + ```http://[zeppelin-server]:[zeppelin-port]/api/version``` Success code @@ -54,7 +54,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple sample JSON response - + ```json { @@ -78,11 +78,11 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple Description - This ```PUT``` method is used to update the root logger's log level of the server. + This ```PUT``` method is used to update the root logger's log level of the server. URL - ```http://[zeppelin-server]:[zeppelin-port]/api/log/level/``` + ```http://[zeppelin-server]:[zeppelin-port]/api/log/level/``` Success code @@ -94,7 +94,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple sample JSON response - + ```json { @@ -105,7 +105,7 @@ If you work with Apache Zeppelin and find a need for an additional REST API, ple sample error JSON response - + ```json { From 9f7092b4a82e0fb42641cb9fc55eda463ee6dff3 Mon Sep 17 00:00:00 2001 From: Jongyoul Lee Date: Fri, 14 Aug 2026 14:55:29 +0900 Subject: [PATCH 175/179] [MINOR] Add daily npm audit remediation workflow ### What is this PR for? Add a daily and manually triggered workflow that detects high/critical `npm audit` failures in `zeppelin-react`. When a lockfile-only fix is available, the workflow: - changes only `zeppelin-react/package-lock.json`; - validates audit, lint, tests, and production build; - creates or updates one Draft PR from a fixed automation branch; - skips creating a duplicate when the lockfile content is unchanged. It never uses `npm audit fix --force`, pushes directly to `master`, or merges automatically. ### What type of PR is it? Improvement ### What is the Jira issue? N/A ### How should this be tested? - The workflow's `prepare` job passed on this PR. - The end-to-end remediation path passed audit, lint, 14 tests, and production build locally. Closes #5390 from jongyoul/codex/daily-npm-audit-fix-pr. Signed-off-by: Jongyoul Lee --- .github/workflows/npm-audit-remediation.yml | 291 ++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 .github/workflows/npm-audit-remediation.yml diff --git a/.github/workflows/npm-audit-remediation.yml b/.github/workflows/npm-audit-remediation.yml new file mode 100644 index 00000000000..841bf3aab2a --- /dev/null +++ b/.github/workflows/npm-audit-remediation.yml @@ -0,0 +1,291 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: npm audit remediation + +on: + schedule: + - cron: '23 2 * * *' + workflow_dispatch: + pull_request: + paths: + - '.github/workflows/npm-audit-remediation.yml' + +concurrency: + group: npm-audit-remediation + cancel-in-progress: false + +env: + FRONTEND_DIRECTORY: zeppelin-web-angular + PACKAGE_DIRECTORY: zeppelin-web-angular/projects/zeppelin-react + LOCKFILE: zeppelin-web-angular/projects/zeppelin-react/package-lock.json + REMEDIATION_BRANCH: automation/npm-audit-fix-zeppelin-react + PR_TITLE: '[HOTFIX] Refresh zeppelin-react lockfile for npm audit' + +jobs: + prepare: + runs-on: ubuntu-24.04 + timeout-minutes: 30 + permissions: + contents: read + outputs: + audited_sha: ${{ steps.revision.outputs.sha }} + needs_remediation: ${{ steps.audit.outputs.needs_remediation }} + steps: + - name: Checkout + uses: actions/checkout@v5 + with: + fetch-depth: 0 + persist-credentials: false + ref: ${{ github.event_name == 'pull_request' && github.sha || 'master' }} + + - id: revision + name: Record audited revision + shell: bash + run: echo "sha=$(git rev-parse HEAD)" >> "${GITHUB_OUTPUT}" + + - name: Set up Node.js + uses: actions/setup-node@v5 + with: + node-version-file: 'zeppelin-web-angular/.nvmrc' + + - id: audit + name: Check npm audit + working-directory: ${{ env.PACKAGE_DIRECTORY }} + shell: bash + run: | + set +e + npm audit --package-lock-only --audit-level=high --json \ + > "${RUNNER_TEMP}/npm-audit-before.json" + audit_status=$? + set -e + + if [[ ${audit_status} -eq 0 ]]; then + echo "needs_remediation=false" >> "${GITHUB_OUTPUT}" + exit 0 + fi + + vulnerable_count=$(node - "${RUNNER_TEMP}/npm-audit-before.json" <<'NODE' + const fs = require('fs'); + const report = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')); + const counts = report.metadata && report.metadata.vulnerabilities; + if (!counts) { + process.exit(2); + } + console.log((counts.high || 0) + (counts.critical || 0)); + NODE + ) || { + cat "${RUNNER_TEMP}/npm-audit-before.json" + echo "::error::npm audit failed without a valid vulnerability report" + exit "${audit_status}" + } + + if [[ ${vulnerable_count} -eq 0 ]]; then + cat "${RUNNER_TEMP}/npm-audit-before.json" + echo "::error::npm audit failed without a high or critical vulnerability" + exit "${audit_status}" + fi + + echo "needs_remediation=true" >> "${GITHUB_OUTPUT}" + echo "Found ${vulnerable_count} high or critical vulnerabilities" + + - name: Generate a lockfile-only fix + if: steps.audit.outputs.needs_remediation == 'true' + working-directory: ${{ env.PACKAGE_DIRECTORY }} + run: npm audit fix --package-lock-only --ignore-scripts --audit-level=high + + - name: Verify the generated diff + if: steps.audit.outputs.needs_remediation == 'true' + shell: bash + run: | + changed_files=$(git diff --name-only) + if [[ "${changed_files}" != "${LOCKFILE}" ]]; then + echo "::error::Expected only ${LOCKFILE} to change, got:" + printf '%s\n' "${changed_files}" + exit 1 + fi + git diff --check + + - name: Install frontend dependencies + if: steps.audit.outputs.needs_remediation == 'true' + working-directory: ${{ env.FRONTEND_DIRECTORY }} + run: npm ci --ignore-scripts --no-audit + + - name: Validate the fix + if: steps.audit.outputs.needs_remediation == 'true' + working-directory: ${{ env.PACKAGE_DIRECTORY }} + run: | + npm ci --ignore-scripts --no-audit + npm audit --audit-level=high + npm run lint + npm test + npm run build + + - name: Create remediation artifact + if: steps.audit.outputs.needs_remediation == 'true' + shell: bash + run: | + artifact_directory="${RUNNER_TEMP}/npm-audit-remediation" + mkdir -p "${artifact_directory}" + git diff --binary -- "${LOCKFILE}" > "${artifact_directory}/fix.patch" + cp "${RUNNER_TEMP}/npm-audit-before.json" "${artifact_directory}/audit-before.json" + test -s "${artifact_directory}/fix.patch" + + - name: Upload remediation artifact + if: steps.audit.outputs.needs_remediation == 'true' + uses: actions/upload-artifact@v6 + with: + name: npm-audit-remediation + path: ${{ runner.temp }}/npm-audit-remediation + retention-days: 1 + + publish: + needs: prepare + if: >- + needs.prepare.outputs.needs_remediation == 'true' && + github.event_name != 'pull_request' && + github.repository == 'apache/zeppelin' + runs-on: ubuntu-24.04 + timeout-minutes: 10 + permissions: + actions: read + contents: write + pull-requests: write + steps: + - name: Checkout audited revision + uses: actions/checkout@v5 + with: + fetch-depth: 0 + ref: ${{ needs.prepare.outputs.audited_sha }} + + - name: Download remediation artifact + uses: actions/download-artifact@v7 + with: + name: npm-audit-remediation + path: ${{ runner.temp }}/npm-audit-remediation + + - name: Create or update remediation pull request + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + git apply "${RUNNER_TEMP}/npm-audit-remediation/fix.patch" + + changed_files=$(git diff --name-only) + if [[ "${changed_files}" != "${LOCKFILE}" ]]; then + echo "::error::Artifact changed unexpected files:" + printf '%s\n' "${changed_files}" + exit 1 + fi + + desired_blob=$(git hash-object "${LOCKFILE}") + # Include closed PRs so a maintainer's decision is not undone every day. + # The REST head filter includes the repository owner, avoiding a fork + # PR with the same predictable branch name. + latest_pr=$(gh api --method GET \ + "repos/${GITHUB_REPOSITORY}/pulls" \ + -f state=all \ + -f base=master \ + -f head="${GITHUB_REPOSITORY_OWNER}:${REMEDIATION_BRANCH}" \ + -f per_page=1 \ + --jq '.[0] // empty | {number: .number, state: (.state | ascii_upcase)}') + + latest_pr_number=$(jq -r '.number // empty' <<< "${latest_pr}") + latest_pr_state=$(jq -r '.state // empty' <<< "${latest_pr}") + + if [[ -n "${latest_pr_number}" ]]; then + unexpected_files=$(gh pr view "${latest_pr_number}" \ + --repo "${GITHUB_REPOSITORY}" \ + --json files \ + --jq '.files[].path' | grep -vx "${LOCKFILE}" || true) + + if [[ "${latest_pr_state}" == "OPEN" && -n "${unexpected_files}" ]]; then + echo "::error::Existing remediation PR contains unexpected files:" + printf '%s\n' "${unexpected_files}" + exit 1 + fi + + git fetch --no-tags origin \ + "refs/pull/${latest_pr_number}/head:refs/remotes/origin/npm-audit-pr-head" + previous_blob=$(git rev-parse \ + "refs/remotes/origin/npm-audit-pr-head:${LOCKFILE}" 2>/dev/null || true) + + if [[ -z "${unexpected_files}" && "${desired_blob}" == "${previous_blob}" ]]; then + echo "PR #${latest_pr_number} (${latest_pr_state}) already contains this lockfile." + echo "Suppressing an identical replacement PR." + exit 0 + fi + + if [[ "${latest_pr_state}" == "OPEN" ]]; then + open_pr_number="${latest_pr_number}" + fi + fi + + remote_sha=$(git ls-remote --heads origin \ + "refs/heads/${REMEDIATION_BRANCH}" | cut -f1) + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git switch -C "${REMEDIATION_BRANCH}" + git add "${LOCKFILE}" + git commit -m "${PR_TITLE}" + + if [[ -n "${remote_sha}" ]]; then + git push \ + --force-with-lease="refs/heads/${REMEDIATION_BRANCH}:${remote_sha}" \ + origin "HEAD:refs/heads/${REMEDIATION_BRANCH}" + else + git push origin "HEAD:refs/heads/${REMEDIATION_BRANCH}" + fi + + if [[ -n "${open_pr_number:-}" ]]; then + echo "Updated existing PR #${open_pr_number}." + exit 0 + fi + + pr_body="${RUNNER_TEMP}/npm-audit-pr-body.md" + { + echo '### What is this PR for?' + echo + echo 'Refresh the zeppelin-react lockfile with compatible updates suggested by `npm audit fix`.' + echo 'The daily audit remediation workflow generated this change after the required high-severity audit began failing.' + echo + echo '### What type of PR is it?' + echo + echo 'Hot Fix' + echo + echo '### What is the Jira issue?' + echo + echo 'N/A - automated dependency maintenance.' + echo + echo '### How should this be tested?' + echo + echo '- `npm ci --ignore-scripts --no-audit` in `zeppelin-web-angular`' + echo '- `npm ci --ignore-scripts --no-audit` in `zeppelin-web-angular/projects/zeppelin-react`' + echo '- `npm audit --audit-level=high`' + echo '- `npm run lint`' + echo '- `npm test`' + echo '- `npm run build`' + echo + echo 'All commands passed before this PR was created.' + } > "${pr_body}" + + gh pr create \ + --repo "${GITHUB_REPOSITORY}" \ + --base master \ + --head "${REMEDIATION_BRANCH}" \ + --title "${PR_TITLE}" \ + --body-file "${pr_body}" \ + --draft From e5b698701a6fefe71cb5489015b104b1412c34ec Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 13:02:37 +0900 Subject: [PATCH 176/179] [HOTFIX] Refresh zeppelin-react lockfile for npm audit ### What is this PR for? Refresh the zeppelin-react lockfile with compatible updates suggested by `npm audit fix`. The daily audit remediation workflow generated this change after the required high-severity audit began failing. ### What type of PR is it? Hot Fix ### What is the Jira issue? N/A - automated dependency maintenance. ### How should this be tested? - `npm ci --ignore-scripts --no-audit` in `zeppelin-web-angular` - `npm ci --ignore-scripts --no-audit` in `zeppelin-web-angular/projects/zeppelin-react` - `npm audit --audit-level=high` - `npm run lint` - `npm test` - `npm run build` All commands passed before this PR was created. Closes #5422 from github-actions[bot]/automation/npm-audit-fix-zeppelin-react. Signed-off-by: YONGJAE LEE --- .../projects/zeppelin-react/package-lock.json | 60 +++++-------------- 1 file changed, 15 insertions(+), 45 deletions(-) diff --git a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json index 4fa79386ebe..53b1f40349e 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/package-lock.json +++ b/zeppelin-web-angular/projects/zeppelin-react/package-lock.json @@ -1628,9 +1628,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1648,9 +1645,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1668,9 +1662,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1688,9 +1679,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1708,9 +1696,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1728,9 +1713,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3283,9 +3265,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.8.tgz", - "integrity": "sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { @@ -4958,9 +4940,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", - "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "dev": true, "funding": [ { @@ -6331,9 +6313,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.0.tgz", - "integrity": "sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, "funding": [ { @@ -6635,9 +6617,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -6659,9 +6638,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -6683,9 +6659,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -6707,9 +6680,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MPL-2.0", "optional": true, "os": [ @@ -7045,9 +7015,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", - "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -10222,9 +10192,9 @@ } }, "node_modules/undici": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", - "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", "dev": true, "license": "MIT", "engines": { From d64897a0abdb4c9f720cf26faf95861c0e117ef1 Mon Sep 17 00:00:00 2001 From: Minho Jang <166613620+miinhho@users.noreply.github.com> Date: Sat, 15 Aug 2026 17:58:32 +0900 Subject: [PATCH 177/179] [ZEPPELIN-6565] Re-enter Angular zone for React remote callbacks ### What is this PR for? This PR fixes `ReactMountDirective` so callbacks invoked by a mounted React remote re-enter the Angular zone before calling back into the Angular host. `ReactMountDirective` mounts and updates React remotes inside `ngZone.runOutsideAngular()`. The directive already used `ngZone.run()` for errors reported through its own `reportError()` path, but props were passed to the remote unchanged. As a result, a remote such as the React paragraph footer could call `props.onError()` directly from outside the Angular zone. For an Angular `OnPush` host component, that can mark the component dirty without scheduling change detection, delaying the fallback UI until some later zone-scheduled work occurs. This change wraps host callbacks as props enter `ReactMountDirective`, while keeping the original props (`latestRawProps`) available for directive-internal error reporting. The wrapped props (`latestProps`) are passed to both `mount()` and `update()`, so React remote callbacks consistently run through the Angular zone boundary. ### What type of PR is it? Bug Fix ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6565 ### How should this be tested? Run the shell unit tests: ```sh cd zeppelin-web-angular npm run test:shell ``` ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5417 from miinhho/fix/react-lifecycle-outside. Signed-off-by: ChanHo Lee --- .../react-mount/react-mount.directive.spec.ts | 58 ++++++++++++++++++- .../react-mount/react-mount.directive.ts | 25 +++++++- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts index 7a9862707f2..71c5e64e30b 100644 --- a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts +++ b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.spec.ts @@ -14,7 +14,7 @@ import { ElementRef, NgZone, SimpleChange } from '@angular/core'; import { describe, expect, it, vi } from 'vitest'; import { ReactRemoteLoaderService } from './react-remote-loader.service'; -import { ReactExposedModule, ReactMountHandle, ReactProps } from './react-mount-handle'; +import { ReactExposedModule, ReactHostCallbacks, ReactMountHandle, ReactProps } from './react-mount-handle'; import { ReactMountDirective } from './react-mount.directive'; describe('ReactMountDirective', () => { @@ -62,4 +62,60 @@ describe('ReactMountDirective', () => { expect(unmount).toHaveBeenCalledOnce(); }); + + it('re-enters the Angular zone for callbacks invoked by the React remote', async () => { + const host = new ElementRef(document.createElement('div')); + const ngZone = new NgZone({}); + let mountedProps: (ReactProps & ReactHostCallbacks) | undefined; + let updatedProps: (ReactProps & ReactHostCallbacks) | undefined; + const update = vi.fn((props: ReactProps & ReactHostCallbacks) => { + updatedProps = props; + }); + const mountHandle: ReactMountHandle = { + update, + unmount: vi.fn() + }; + const remote: ReactExposedModule = { + mount: (_element: HTMLElement, props: ReactProps & ReactHostCallbacks) => { + mountedProps = props; + return mountHandle; + } + }; + const loadModule = vi.fn(async (): Promise => remote as T); + const loader = { loadModule } as Pick; + const zoneStates: boolean[] = []; + const onMountError = vi.fn(() => { + zoneStates.push(NgZone.isInAngularZone()); + }); + const onUpdateError = vi.fn(() => { + zoneStates.push(NgZone.isInAngularZone()); + }); + const directive = new ReactMountDirective(host, ngZone, loader as ReactRemoteLoaderService); + + directive.module = 'paragraph-footer'; + directive.reactProps = { onError: onMountError }; + directive.ngOnChanges({ + module: new SimpleChange(undefined, directive.module, true), + reactProps: new SimpleChange(undefined, directive.reactProps, true) + }); + await vi.waitFor(() => expect(mountedProps).toBeDefined()); + + ngZone.runOutsideAngular(() => { + mountedProps!.onError!(new Error('mount remote failed')); + }); + + directive.reactProps = { onError: onUpdateError }; + directive.ngOnChanges({ + reactProps: new SimpleChange({ onError: onMountError }, directive.reactProps, false) + }); + + ngZone.runOutsideAngular(() => { + updatedProps!.onError!(new Error('update remote failed')); + }); + + expect(onMountError).toHaveBeenCalledOnce(); + expect(onUpdateError).toHaveBeenCalledOnce(); + expect(update).toHaveBeenCalledOnce(); + expect(zoneStates).toEqual([true, true]); + }); }); diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts index c93c168001b..a28a575b7ef 100644 --- a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts +++ b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts @@ -40,6 +40,7 @@ export class ReactMountDirective implements OnChanges, OnDestroy { @Input('zeppelin-react-mount') module!: string; @Input() reactProps: ReactProps & ReactHostCallbacks = {}; + private latestRawProps: ReactProps & ReactHostCallbacks = {}; private latestProps: ReactProps & ReactHostCallbacks = {}; private destroyed = false; private loading = false; @@ -53,7 +54,8 @@ export class ReactMountDirective implements OnChanges, OnDestroy { ) {} ngOnChanges(changes: SimpleChanges): void { - this.latestProps = this.reactProps ?? {}; + this.latestRawProps = this.reactProps ?? {}; + this.latestProps = this.withHostCallbacks(this.latestRawProps); if (changes.module && !changes.module.firstChange && this.mountedModule) { // Module swap after first mount is unsupported. Report via onError @@ -128,7 +130,7 @@ export class ReactMountDirective implements OnChanges, OnDestroy { } private reportError(error: unknown): void { - const onError = this.latestProps.onError; + const onError = this.latestRawProps.onError; if (typeof onError === 'function') { // Re-enter the Angular zone so onError handlers can safely mutate // host state and trigger change detection. React lifecycle callbacks @@ -146,4 +148,23 @@ export class ReactMountDirective implements OnChanges, OnDestroy { console.error('[ReactMountDirective]', error); } } + + private withHostCallbacks(props: ReactProps & ReactHostCallbacks): ReactProps & ReactHostCallbacks { + const onError = props.onError; + if (typeof onError !== 'function') { + return props; + } + return { + ...props, + onError: (error: unknown): void => { + this.ngZone.run(() => { + try { + onError(error); + } catch { + /* swallow callback errors; they shouldn't loop */ + } + }); + } + }; + } } From cd700db60e01e9def588a64696ffde17125b6263 Mon Sep 17 00:00:00 2001 From: ChanHo Lee Date: Sat, 15 Aug 2026 19:34:09 +0900 Subject: [PATCH 178/179] [ZEPPELIN-6641] Fix stale rationale in the reportError comment ### What is this PR for? The `reportError` comment in `ReactMountDirective` claimed that a `markForCheck()` issued from outside the Angular zone has nothing to flush it. Since Angular 18 that is not accurate: hybrid scheduling notifies `ChangeDetectionSchedulerImpl`, and a tick is scheduled for exactly that case (measured at 1 to 4 ms on a running dev server, see the ZEPPELIN-6565 comment). This states a rationale that does not depend on internal scheduling behavior. Comment only, no behavior change. ### What type of PR is it? Improvement ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6641 ### How should this be tested? Comment-only change, nothing to test. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5424 from tbonelee/ZEPPELIN-6641. Signed-off-by: YONGJAE LEE --- .../src/app/share/react-mount/react-mount.directive.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts index a28a575b7ef..96ff0ee7d04 100644 --- a/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts +++ b/zeppelin-web-angular/src/app/share/react-mount/react-mount.directive.ts @@ -132,11 +132,10 @@ export class ReactMountDirective implements OnChanges, OnDestroy { private reportError(error: unknown): void { const onError = this.latestRawProps.onError; if (typeof onError === 'function') { - // Re-enter the Angular zone so onError handlers can safely mutate - // host state and trigger change detection. React lifecycle callbacks - // (e.g. error boundaries) run outside the zone because we mounted - // there; calling back into the host without ngZone.run would leave - // markForCheck() with nothing to flush. + // Re-enter the Angular zone before calling back into the host. We mount + // the remote outside the zone, so React lifecycle callbacks (e.g. error + // boundaries) run outside it as well, and any async work the handler + // starts from there (timers, HTTP) would stay untracked by NgZone. this.ngZone.run(() => { try { onError(error); From 14cdf8437224adff08864de05b810f7149a82119 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:34:02 +0900 Subject: [PATCH 179/179] [ZEPPELIN-6640] Theme the React remote from the host instead of the shell's CSS ### What is this PR for? The React remote never learns which theme the shell is in. `PublishedParagraph` wraps its tree in antd's `ConfigProvider` but only sets `token.fontFamily`, so antd always builds its styles from the default (light) algorithm. Dark mode still looks correct today, but not for a reason either side declares. `ThemeService` writes `data-theme` and a `dark` class onto the document root, and the shell's global ng-zorro-antd stylesheet targets the same `.ant-*` class names the remote's markup happens to use, so the shell's dark rules land on top of the remote's own light CSS-in-JS. In the published paragraph with `?react=true` in dark mode, `.ant-table` computes to `rgb(31, 31, 31)`. Disable every stylesheet except the remote's own injected `style[data-css-hash]` tags and the same element becomes `rgb(255, 255, 255)` on the dark page. Anything the shell's CSS cannot reach stays light. The charts in `TableVisualization` are drawn on a canvas, and no chart config sets axis, grid or legend colors, so chart.js v4 defaults apply (`#666` text, `rgba(0, 0, 0, 0.1)` grid). Against the dark page background (`#141414`) the tick and category labels sit at about 3.2:1, below the 4.5:1 WCAG AA threshold for text, and the grid lines are effectively invisible. This gives the remote the theme as an input instead of letting it inherit one by accident. `src/theme/hostTheme.ts` reads the theme the shell already publishes on the document root and follows it while mounted, `ZeppelinThemeProvider` selects antd's dark or default algorithm from it and exposes the resolved value through context for code that draws outside antd, and `chartTheme.ts` sets the two chart.js globals that ticks, legend labels and grid lines resolve from. The theme is read from the DOM rather than passed in through `reactProps`. The published paragraph still mounts through its own `window.reactApp` path, so a props based version would have to be wired into that path as well as the directive, and the two host files it would touch are the ones ZEPPELIN-6564 and ZEPPELIN-6565 are currently changing. Reading the attribute the shell already publishes for its own CSS covers both mount paths and needs no host change, and a theme toggle then re-renders the remote without going through change detection. If you would rather keep host state flowing in through props, having the provider take an explicit `theme` prop is a small follow-up. Matching the shell pixel for pixel is not the goal. antd's dark container token is `#141414` where ng-zorro's is `#1f1f1f`, and where the shell's global rules still win, they win. ### What type of PR is it? Bug Fix ### Todos None ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6640 ### How should this be tested? * New vitest specs under `projects/zeppelin-react/src/theme/`: theme resolution from the document root and its fallbacks, live updates when the shell toggles the theme, antd algorithm selection asserted through `theme.useToken()`, and the chart.js defaults. The project's suite is green at 29 specs. Note that unit tests do not gate CI yet (ZEPPELIN-6566). * Manual check in both modes on the published paragraph with `?react=true`, on a paragraph with a TABLE result. Switch to Bar Chart in dark mode: the axis labels, legend and grid lines are readable where they were not. The table view and light mode are unchanged. * To see the cause rather than the symptom, disable the host's stylesheets in devtools. On master the remote's table turns white on the dark page. Here it stays dark, and the rule the remote injects reads `color: rgba(255, 255, 255, 0.85)`. * A production build of the remote (`npm run build`). ### Screenshots (if appropriate) before 1-before-chart-dark after 2-after-chart-dark ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? Yes, `projects/zeppelin-react/README.md` gains the provider step in "Adding a new React module" Closes #5420 from kimyenac/ZEPPELIN-6640. Signed-off-by: YONGJAE LEE --- .../projects/zeppelin-react/README.md | 15 ++- .../visualizations/TableVisualization.tsx | 8 +- .../src/pages/PublishedParagraph.tsx | 30 ++--- .../src/theme/ZeppelinThemeProvider.spec.tsx | 93 +++++++++++++ .../src/theme/ZeppelinThemeProvider.tsx | 47 +++++++ .../src/theme/chartTheme.spec.ts | 51 ++++++++ .../zeppelin-react/src/theme/chartTheme.ts | 37 ++++++ .../src/theme/hostTheme.spec.tsx | 122 ++++++++++++++++++ .../zeppelin-react/src/theme/hostTheme.ts | 78 +++++++++++ .../zeppelin-react/src/theme/index.ts | 15 +++ 10 files changed, 474 insertions(+), 22 deletions(-) create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.spec.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.spec.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.spec.tsx create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.ts create mode 100644 zeppelin-web-angular/projects/zeppelin-react/src/theme/index.ts diff --git a/zeppelin-web-angular/projects/zeppelin-react/README.md b/zeppelin-web-angular/projects/zeppelin-react/README.md index a32e90643f3..f9d1b1d6317 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/README.md +++ b/zeppelin-web-angular/projects/zeppelin-react/README.md @@ -89,6 +89,7 @@ src/ │ └── PublishedParagraph.tsx # entry component + mount() ├── templates/ │ └── SingleResultRenderer.tsx # routes result types to renderers +├── theme/ # host theme detection, antd + chart.js theming ├── utils/ # tableUtils, textUtils, exportFile └── main.ts # re-exports for Module Federation ``` @@ -109,12 +110,18 @@ export function mount(element: HTMLElement, props: Props): ReactMountHandle; 1. Create a component (e.g. `src/components//ExampleFeature.tsx`). 2. Wrap its render tree in ``. -3. Export a `mount(element, props)` function that: +3. Wrap it in `` as well (see `src/theme/`), otherwise + antd builds its styles from the default light algorithm and the module only + looks right in dark mode while the shell's global `.ant-*` rules happen to + cover the components in use. Pass surface specific tokens through its + `token` prop, and read `useHostThemeMode()` when you draw outside antd, as + a canvas chart does. +4. Export a `mount(element, props)` function that: - Creates a single `Root` via `createRoot(element)`. - Calls `root.render()` on initial mount AND on every `update(newProps)` call. React's reconciler preserves state. - Returns `{ update, unmount }`. `unmount` calls `root.unmount()`. -4. Register in `webpack.config.js` under `exposes`: +5. Register in `webpack.config.js` under `exposes`: ```js exposes: { './PublishedParagraph': './src/pages/PublishedParagraph', @@ -122,14 +129,14 @@ export function mount(element: HTMLElement, props: Props): ReactMountHandle; './ExampleFeature': './src/components//ExampleFeature' } ``` -5. Re-export from `main.ts`: +6. Re-export from `main.ts`: ```ts export { ExampleFeature, mount as mountExampleFeature } from './components//ExampleFeature'; ``` -6. Use from Angular by adding the directive to your template: +7. Use from Angular by adding the directive to your template: ```html
      { const [currentMode, setCurrentMode] = useState(config?.graph.mode || 'table'); const chartRef = useRef(null); + const themeMode = useHostThemeMode(); const tableData = useMemo(() => parseTableData(result.data), [result.data]); @@ -86,6 +88,10 @@ export const TableVisualization = ({ result, config }: TableVisualizationProps) const ChartConstructor = module.Chart || module.default; + // Ticks, legend labels and grid lines all resolve from these two + // globals, and a canvas is out of reach of the shell's stylesheets. + applyChartTheme(ChartConstructor, themeMode); + const canvas = document.createElement('canvas'); canvas.style.width = '100%'; canvas.style.height = '100%'; @@ -222,7 +228,7 @@ export const TableVisualization = ({ result, config }: TableVisualizationProps) container.innerHTML = ''; } }; - }, [currentMode, tableData]); + }, [currentMode, tableData, themeMode]); return (
      diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx index 2d48314d5c1..04ea1024b78 100644 --- a/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx +++ b/zeppelin-web-angular/projects/zeppelin-react/src/pages/PublishedParagraph.tsx @@ -11,30 +11,26 @@ */ import { createRoot } from 'react-dom/client'; -import { ConfigProvider } from 'antd'; import { Empty } from '@/components'; import { SingleResultRenderer } from '@/templates'; +import { ZeppelinThemeProvider } from '@/theme'; import type { ParagraphConfigResults, ParagraphIResultsMsgItem } from '@zeppelin/sdk'; +const RESULT_FONT_FAMILY = "'Lucida Console', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace"; + export interface PublishedParagraphProps { paragraphId: string; results?: ParagraphIResultsMsgItem[]; config?: ParagraphConfigResults; } -export const PublishedParagraph = ({ results, config }: PublishedParagraphProps) => { - if (!results || results.length === 0) { - return ; - } - - return ( - +export const PublishedParagraph = ({ results, config }: PublishedParagraphProps) => ( + // The empty state is inside the provider too: antd's Empty illustration is + // themed, so leaving it outside would leak a light widget into a dark page. + + {!results || results.length === 0 ? ( + + ) : (
      {results.map((result, index) => (
      @@ -42,9 +38,9 @@ export const PublishedParagraph = ({ results, config }: PublishedParagraphProps)
      ))}
      -
      - ); -}; + )} + +); export const mount = (element: HTMLElement, props?: PublishedParagraphProps) => { if (!element) { diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.spec.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.spec.tsx new file mode 100644 index 00000000000..d70daee60a2 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.spec.tsx @@ -0,0 +1,93 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { act } from 'react'; +import { render, screen } from '@testing-library/react'; +import { theme as antdTheme } from 'antd'; +import { afterEach, describe, expect, it } from 'vitest'; +import { useHostThemeMode, ZeppelinThemeProvider } from './ZeppelinThemeProvider'; +import { HostThemeMode } from './hostTheme'; + +const Probe = () => { + const { token } = antdTheme.useToken(); + return ( + <> + {token.colorBgContainer} + {token.fontFamily} + {useHostThemeMode()} + + ); +}; + +const setHostTheme = (mode: HostThemeMode) => { + document.documentElement.setAttribute('data-theme', mode); +}; + +describe('ZeppelinThemeProvider', () => { + afterEach(() => { + document.documentElement.removeAttribute('data-theme'); + }); + + it('builds antd tokens from the dark algorithm when the shell is dark', () => { + setHostTheme('dark'); + render( + + + + ); + + // Light tokens would put a white container on the shell's dark page; today + // that only goes unnoticed because the shell's global .ant-* rules cover it. + expect(screen.getByTestId('container-bg').textContent).toBe('#141414'); + expect(screen.getByTestId('mode').textContent).toBe('dark'); + }); + + it('builds antd tokens from the default algorithm when the shell is light', () => { + setHostTheme('light'); + render( + + + + ); + + expect(screen.getByTestId('container-bg').textContent).toBe('#ffffff'); + expect(screen.getByTestId('mode').textContent).toBe('light'); + }); + + it('re-themes in place when the shell toggles the theme', async () => { + setHostTheme('light'); + render( + + + + ); + expect(screen.getByTestId('container-bg').textContent).toBe('#ffffff'); + + await act(async () => { + setHostTheme('dark'); + }); + + expect(screen.getByTestId('container-bg').textContent).toBe('#141414'); + }); + + it('keeps surface tokens while switching algorithms', () => { + setHostTheme('dark'); + render( + + + + ); + + expect(screen.getByTestId('font').textContent).toBe('Consolas'); + expect(screen.getByTestId('container-bg').textContent).toBe('#141414'); + }); +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.tsx new file mode 100644 index 00000000000..1ee2181aaae --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/ZeppelinThemeProvider.tsx @@ -0,0 +1,47 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createContext, ReactNode, useContext } from 'react'; +import { ConfigProvider, theme as antdTheme, ThemeConfig } from 'antd'; +import { HostThemeMode, useHostTheme } from './hostTheme'; + +const HostThemeContext = createContext('light'); + +/** Resolved host theme for code that draws outside antd, such as canvas charts. */ +export const useHostThemeMode = (): HostThemeMode => useContext(HostThemeContext); + +export interface ZeppelinThemeProviderProps { + children: ReactNode; + /** Extra tokens for a single surface, e.g. a monospace result font. */ + token?: ThemeConfig['token']; +} + +/** + * Every exposed module should render inside this provider. Without it antd + * builds its styles from the default (light) algorithm, and the remote looks + * dark only for as long as the shell's global `.ant-*` rules happen to cover + * the components in use. + */ +export const ZeppelinThemeProvider = ({ children, token }: ZeppelinThemeProviderProps) => { + const mode = useHostTheme(); + + return ( + + {children} + + ); +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.spec.ts b/zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.spec.ts new file mode 100644 index 00000000000..973bacdcdad --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.spec.ts @@ -0,0 +1,51 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, expect, it } from 'vitest'; +import { applyChartTheme, CHART_THEME } from './chartTheme'; + +// chart.js ships '#666' text and 'rgba(0, 0, 0, 0.1)' grid lines, both of +// which are meant for a light canvas. +const chartJsDefaults = () => ({ defaults: { color: '#666', borderColor: 'rgba(0, 0, 0, 0.1)' } }); + +describe('applyChartTheme', () => { + it('replaces the chart.js defaults with the dark palette', () => { + const chart = chartJsDefaults(); + + applyChartTheme(chart, 'dark'); + + expect(chart.defaults.color).toBe(CHART_THEME.dark.text); + expect(chart.defaults.borderColor).toBe(CHART_THEME.dark.grid); + }); + + it('replaces the chart.js defaults with the light palette', () => { + const chart = chartJsDefaults(); + + applyChartTheme(chart, 'light'); + + expect(chart.defaults.color).toBe(CHART_THEME.light.text); + expect(chart.defaults.borderColor).toBe(CHART_THEME.light.grid); + }); + + it('leaves no chart.js default in place for either mode', () => { + // The point of the issue: axis labels at '#666' sit at about 3.2:1 against + // the shell's dark background, below the 4.5:1 the rest of the UI meets. + const untouched = chartJsDefaults().defaults; + + for (const mode of ['light', 'dark'] as const) { + const chart = chartJsDefaults(); + applyChartTheme(chart, mode); + expect(chart.defaults.color).not.toBe(untouched.color); + expect(chart.defaults.borderColor).not.toBe(untouched.borderColor); + } + }); +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.ts b/zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.ts new file mode 100644 index 00000000000..01b563f95c2 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/chartTheme.ts @@ -0,0 +1,37 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { HostThemeMode } from './hostTheme'; + +/** + * Charts are painted on a canvas, so no stylesheet reaches them. chart.js + * defaults to '#666' text and 'rgba(0, 0, 0, 0.1)' grid lines, which leaves + * axis labels at roughly 3.2:1 against the dark background and the grid + * invisible. These values follow antd's secondary text and split tokens. + */ +export const CHART_THEME: Record = { + light: { text: 'rgba(0, 0, 0, 0.65)', grid: 'rgba(0, 0, 0, 0.06)' }, + dark: { text: 'rgba(255, 255, 255, 0.65)', grid: 'rgba(255, 255, 255, 0.12)' } +}; + +/** The two globals chart.js resolves ticks, legend labels and grid lines from. */ +export interface ChartThemeTarget { + defaults: { + color: unknown; + borderColor: unknown; + }; +} + +export const applyChartTheme = (chart: ChartThemeTarget, mode: HostThemeMode): void => { + chart.defaults.color = CHART_THEME[mode].text; + chart.defaults.borderColor = CHART_THEME[mode].grid; +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.spec.tsx b/zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.spec.tsx new file mode 100644 index 00000000000..4661daff283 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.spec.tsx @@ -0,0 +1,122 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { act } from 'react'; +import { render, screen } from '@testing-library/react'; +import { afterEach, describe, expect, it } from 'vitest'; +import { HostThemeMode, readHostTheme, useHostTheme } from './hostTheme'; + +const Probe = () => {useHostTheme()}; + +const setHostTheme = (mode: HostThemeMode) => { + document.documentElement.setAttribute('data-theme', mode); + document.documentElement.classList.remove('light', 'dark'); + document.documentElement.classList.add(mode); +}; + +const stubMatchMedia = (matches: boolean) => { + const listeners = new Set<() => void>(); + const mql = { + matches, + addEventListener: (_: string, cb: () => void) => listeners.add(cb), + removeEventListener: (_: string, cb: () => void) => listeners.delete(cb) + }; + (window as unknown as { matchMedia?: unknown }).matchMedia = () => mql; + return { + set: (next: boolean) => { + mql.matches = next; + listeners.forEach(cb => cb()); + }, + listenerCount: () => listeners.size + }; +}; + +describe('readHostTheme', () => { + afterEach(() => { + document.documentElement.removeAttribute('data-theme'); + document.documentElement.classList.remove('light', 'dark'); + delete (window as unknown as { matchMedia?: unknown }).matchMedia; + }); + + it('reads the theme the shell writes to the document root', () => { + setHostTheme('dark'); + expect(readHostTheme()).toBe('dark'); + + setHostTheme('light'); + expect(readHostTheme()).toBe('light'); + }); + + it('falls back to the root class when the attribute is missing', () => { + document.documentElement.classList.add('dark'); + expect(readHostTheme()).toBe('dark'); + }); + + it('falls back to the OS preference when the shell declares nothing', () => { + stubMatchMedia(true); + expect(readHostTheme()).toBe('dark'); + }); + + it('defaults to light when neither the shell nor matchMedia is available', () => { + expect(readHostTheme()).toBe('light'); + }); +}); + +describe('useHostTheme', () => { + afterEach(() => { + document.documentElement.removeAttribute('data-theme'); + document.documentElement.classList.remove('light', 'dark'); + delete (window as unknown as { matchMedia?: unknown }).matchMedia; + }); + + it('starts from the declared theme', () => { + setHostTheme('dark'); + render(); + + expect(screen.getByTestId('mode').textContent).toBe('dark'); + }); + + it('follows the shell when the user toggles the theme while mounted', async () => { + setHostTheme('light'); + render(); + expect(screen.getByTestId('mode').textContent).toBe('light'); + + await act(async () => { + setHostTheme('dark'); + }); + + expect(screen.getByTestId('mode').textContent).toBe('dark'); + }); + + it('follows the OS only while the shell has declared nothing', () => { + const media = stubMatchMedia(false); + render(); + expect(screen.getByTestId('mode').textContent).toBe('light'); + expect(media.listenerCount()).toBe(1); + + act(() => { + media.set(true); + }); + + expect(screen.getByTestId('mode').textContent).toBe('dark'); + }); + + it('does not subscribe to the OS when the shell declares a theme', () => { + const media = stubMatchMedia(true); + setHostTheme('light'); + render(); + + // The shell already resolved 'system' for us, so a second source would + // let the OS override an explicit light/dark choice. + expect(screen.getByTestId('mode').textContent).toBe('light'); + expect(media.listenerCount()).toBe(0); + }); +}); diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.ts b/zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.ts new file mode 100644 index 00000000000..36368c6e5d0 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/hostTheme.ts @@ -0,0 +1,78 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useEffect, useState } from 'react'; + +export type HostThemeMode = 'light' | 'dark'; + +/** + * The Angular shell's ThemeService resolves 'system' for us and writes the + * result to the document root as `data-theme` plus a `dark`/`light` class. + * Reading that is what keeps the remote in step with the host without the + * host having to thread a prop through every mount point. + */ +export const readHostTheme = (): HostThemeMode => { + const root = document.documentElement; + const declared = root.getAttribute('data-theme'); + if (declared === 'dark' || declared === 'light') { + return declared; + } + if (root.classList.contains('dark')) { + return 'dark'; + } + if (root.classList.contains('light')) { + return 'light'; + } + + // Standalone dev server (port 3001) has no shell, so fall back to the OS + // preference the shell would have resolved itself. + if (typeof window.matchMedia === 'function') { + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + + return 'light'; +}; + +const hostDeclaresTheme = (): boolean => { + const root = document.documentElement; + return root.hasAttribute('data-theme') || root.classList.contains('dark') || root.classList.contains('light'); +}; + +/** Resolved host theme, kept up to date while mounted. */ +export const useHostTheme = (): HostThemeMode => { + const [mode, setMode] = useState(readHostTheme); + + useEffect(() => { + // The shell can apply its theme after the remote mounts, so re-read once + // the subscription is in place rather than trusting the initial render. + setMode(readHostTheme()); + const sync = () => setMode(readHostTheme()); + + const observer = new MutationObserver(sync); + observer.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme', 'class'] }); + + // Only follow the OS while the shell has not declared a theme; once it + // has, its value already accounts for the 'system' setting. + let media: MediaQueryList | undefined; + if (!hostDeclaresTheme() && typeof window.matchMedia === 'function') { + media = window.matchMedia('(prefers-color-scheme: dark)'); + media.addEventListener('change', sync); + } + + return () => { + observer.disconnect(); + media?.removeEventListener('change', sync); + }; + }, []); + + return mode; +}; diff --git a/zeppelin-web-angular/projects/zeppelin-react/src/theme/index.ts b/zeppelin-web-angular/projects/zeppelin-react/src/theme/index.ts new file mode 100644 index 00000000000..a9c900c9e28 --- /dev/null +++ b/zeppelin-web-angular/projects/zeppelin-react/src/theme/index.ts @@ -0,0 +1,15 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export type { HostThemeMode } from './hostTheme'; +export { ZeppelinThemeProvider, useHostThemeMode } from './ZeppelinThemeProvider'; +export { applyChartTheme } from './chartTheme';

    Spelled out here rather than read back from IdHashes so that changing the dictionary + * has to be a deliberate act that updates this test too. + */ + private static final String EXPECTED_CHARACTERS = "123456789ABCDEFGHJKMNPQRSTUVWXYZ"; + + /** + * IDs are derived from {@code currentTimeMillis() + SecureRandom.nextInt()}, so uniqueness + * can only be asserted probabilistically. The random term spans 2^32 values, which puts the + * chance of a collision within one sample of this size on the order of 1e-4. + */ + private static final int SAMPLE_SIZE = 1000; + + @Test + void generatedIdsContainOnlyDictionaryCharacters() { + for (int i = 0; i < SAMPLE_SIZE; i++) { + String id = IdHashes.generateId(); + for (char c : id.toCharArray()) { + assertTrue(EXPECTED_CHARACTERS.indexOf(c) >= 0, + "generated id '" + id + "' contains '" + c + "', which is not in the dictionary"); + } + } + } + + @Test + void generatedIdsAreNeverEmpty() { + for (int i = 0; i < SAMPLE_SIZE; i++) { + assertFalse(IdHashes.generateId().isEmpty(), "generateId() returned an empty id"); + } + } + + @Test + void generatedIdsAreDistinctAcrossManyCalls() { + Set ids = new HashSet<>(); + for (int i = 0; i < SAMPLE_SIZE; i++) { + ids.add(IdHashes.generateId()); + } + assertEquals(SAMPLE_SIZE, ids.size(), "generateId() produced duplicate ids"); + } +} diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Note.java index 8b7622e1ef1..278fa43ecc6 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -36,11 +36,11 @@ import org.apache.zeppelin.interpreter.remote.RemoteAngularObject; import org.apache.zeppelin.interpreter.remote.RemoteAngularObjectRegistry; import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion; -import org.apache.zeppelin.notebook.utility.IdHashes; import org.apache.zeppelin.scheduler.ExecutorFactory; import org.apache.zeppelin.scheduler.Job.Status; import org.apache.zeppelin.user.AuthenticationInfo; import org.apache.zeppelin.user.Credentials; +import org.apache.zeppelin.util.IdHashes; import org.apache.zeppelin.util.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/utility/IdHashes.java b/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/utility/IdHashes.java deleted file mode 100644 index 7b0d804de94..00000000000 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/notebook/utility/IdHashes.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.zeppelin.notebook.utility; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.List; - -/** - * Generate Tiny ID. - */ -public class IdHashes { - private static final char[] DICTIONARY = new char[] {'1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z'}; - - /** - * encodes the given string into the base of the dictionary provided in the constructor. - * - * @param value the number to encode. - * @return the encoded string. - */ - private static String encode(Long value) { - - List result = new ArrayList<>(); - BigInteger base = new BigInteger("" + DICTIONARY.length); - int exponent = 1; - BigInteger remaining = new BigInteger(value.toString()); - while (true) { - BigInteger a = base.pow(exponent); // 16^1 = 16 - BigInteger b = remaining.mod(a); // 119 % 16 = 7 | 112 % 256 = 112 - BigInteger c = base.pow(exponent - 1); - BigInteger d = b.divide(c); - - // if d > dictionary.length, we have a problem. but BigInteger doesnt have - // a greater than method :-( hope for the best. theoretically, d is always - // an index of the dictionary! - result.add(DICTIONARY[d.intValue()]); - remaining = remaining.subtract(b); // 119 - 7 = 112 | 112 - 112 = 0 - - // finished? - if (remaining.equals(BigInteger.ZERO)) { - break; - } - - exponent++; - } - - // need to reverse it, since the start of the list contains the least significant values - StringBuffer sb = new StringBuffer(); - for (int i = result.size() - 1; i >= 0; i--) { - sb.append(result.get(i)); - } - return sb.toString(); - } - - public static String generateId() { - return encode(System.currentTimeMillis() + new SecureRandom().nextInt()); - } -} From 8a2b306bbcc26d1cffa7737d304f72dbc1924944 Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Thu, 6 Aug 2026 11:10:23 +0900 Subject: [PATCH 142/179] [ZEPPELIN-6463] Close the package.json reader in HeliumBundleFactory with try-with-resources ### What is this PR for? `HeliumBundleFactory.downloadPackage()` stages a Helium package into its bundle directory, either by copying a local directory or by unpacking an npm tarball, and then reads the `package.json` it finds there to pull out the `dependencies` and `main` entries: ```java JsonReader reader = new JsonReader(new FileReader(existingPackageJson)); Map packageJson = gson.fromJson(reader, new TypeToken>(){}.getType()); ``` The reader is never closed. There is no `close()`, no `finally` and no try-with-resources, and Gson does not close a reader handed to it. Ownership stays with the caller. The descriptor is therefore released only once the garbage collector reclaims the `FileReader`, because `FileInputStream` registers itself for cleanup. So this is not an unbounded leak, but the release is not deterministic: the descriptor stays open for as long as the `FileReader` goes unreclaimed, which has nothing to do with the point where the parse finishes and the reader stops being useful. The same holds when parsing fails, since a malformed `package.json` makes Gson raise `JsonSyntaxException` and the method exits without closing. This PR wraps the reader in a try-with-resources so the descriptor is released as soon as parsing finishes. Only `JsonReader` is declared as a resource, since closing it closes the `FileReader` it wraps, which avoids a redundant second close. `packageJson` is declared ahead of the block so the parsed result remains available to the rest of the method. Parsing behaviour and the resulting bundle setup are unchanged, and no signatures or access modifiers change. ### What type of PR is it? Bug Fix ### Todos * [x] Close the `package.json` reader opened in `downloadPackage` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6463 ### How should this be tested? ```bash ./mvnw package -pl zeppelin-server --am \ -Dtest='HeliumBundleFactoryTest,HeliumTest,HeliumLocalRegistryTest' \ -DfailIfNoTests=false ``` `Tests run: 9, Failures: 0, Errors: 0, Skipped: 0`, and `zeppelin-server` builds. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5380 from big-cir/ZEPPELIN-6463. Signed-off-by: ChanHo Lee --- .../org/apache/zeppelin/helium/HeliumBundleFactory.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumBundleFactory.java b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumBundleFactory.java index d17906343b9..f6e9389633f 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumBundleFactory.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/helium/HeliumBundleFactory.java @@ -305,9 +305,11 @@ public boolean accept(File pathname) { // 1. setup package.json File existingPackageJson = new File(bundleDir, "package.json"); - JsonReader reader = new JsonReader(new FileReader(existingPackageJson)); - Map packageJson = gson.fromJson(reader, - new TypeToken>(){}.getType()); + Map packageJson; + try (JsonReader reader = new JsonReader(new FileReader(existingPackageJson))) { + packageJson = gson.fromJson(reader, + new TypeToken>(){}.getType()); + } Map existingDeps = (Map) packageJson.get("dependencies"); String mainFileName = (String) packageJson.get("main"); From 460a2e4a6d124365a159d7733164febb1fb42801 Mon Sep 17 00:00:00 2001 From: huiseong29 Date: Thu, 6 Aug 2026 11:11:40 +0900 Subject: [PATCH 143/179] [ZEPPELIN-6486] Rename the mislabeled "Set up JDK 8" CI step to JDK 11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? The JDK setup step in the `flink-test-and-flink-integration-test` job of `.github/workflows/core.yml` was named "Set up JDK 8" while its `java-version` was already set to `11`. The name was the only thing wrong; anyone reading the workflow or the CI logs would think the job runs on JDK 8. This renames the step to "Set up JDK 11", matching the correctly labeled step elsewhere in the same file. Only the display name changes — `java-version` and every other key stay exactly as they are. A grep across `.github/workflows/` confirms this was the only static JDK setup step whose name disagreed with its configured `java-version`; every other step either pins 11 with a matching name or derives the version from the build matrix. ### What type of PR is it? Improvement ### Todos - [x] - Rename the step to "Set up JDK 11" ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6486 ### How should this be tested? `grep -rn "Set up JDK 8" .github/workflows/` returns no matches. The renamed step still has `java-version: 11` and no other keys changed. The workflow YAML still parses. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5382 from huiseong29/ZEPPELIN-6486. Signed-off-by: ChanHo Lee --- .github/workflows/core.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 0051ce98844..816d9f7be90 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -243,7 +243,7 @@ jobs: uses: actions/checkout@v5 - name: Tune Runner VM uses: ./.github/actions/tune-runner-vm - - name: Set up JDK 8 + - name: Set up JDK 11 uses: actions/setup-java@v5 with: distribution: 'temurin' From 07cf67087516e16c3d1c6e31716c956f6654f33e Mon Sep 17 00:00:00 2001 From: dae won <99483390+big-cir@users.noreply.github.com> Date: Thu, 6 Aug 2026 16:57:06 +0900 Subject: [PATCH 144/179] [ZEPPELIN-6012] Fix NPE when the run-note request body carries no params ### What is this PR for? `POST /api/notebook/job/{noteId}` accepts an optional request body carrying form parameters. Sending a body that supplies no parameters, either `{}` or `{"params":null}`, returns HTTP 500. `ParametersRequest` declares its `params` field as `final` and assigns it in the constructor, but Gson never invokes that constructor. It allocates the instance and fills the fields reflectively, so a body without a `"params"` entry leaves the field at its default value of `null`. `NotebookRestApi.runNoteJobs` then hands that `null` straight to `HashMap.putAll`: ```java Map params = new HashMap<>(); if (!StringUtils.isEmpty(message)) { ParametersRequest request = GSON.fromJson(message, ParametersRequest.class); params.putAll(request.getParams()); } ``` `{}` is not an empty string, so the guard passes and the call throws: ``` java.lang.NullPointerException: Cannot invoke "java.util.Map.size()" because "m" is null at java.util.HashMap.putMapEntries(HashMap.java:495) at java.util.HashMap.putAll(HashMap.java:783) at org.apache.zeppelin.rest.NotebookRestApi.runNoteJobs(NotebookRestApi.java:850) ``` Nothing catches it, so `WebApplicationExceptionMapper` turns it into a generic `Internal server error` with status 500. Running a note without form parameters is a legitimate request, and an empty body already works, so both spellings should behave the same. This PR makes `ParametersRequest.getParams()` return an empty map instead of `null`, which covers both an absent key and an explicit null value. Scope note: two other call sites parse the same request object, at `NotebookRestApi` lines 979 and 1018. Both assign the result to a local variable rather than calling `putAll`, so they do not throw, and their consumers already guard against null (`Note.runAllSync` and `NotebookService.runParagraph` each check `params != null && !params.isEmpty()`). Fixing the accessor covers all three call sites without changing their behavior. ### What type of PR is it? Bug Fix ### Todos * [x] - Return an empty map from `ParametersRequest.getParams()` when no parameters were supplied * [x] - Add a regression test covering both `{}` and `{"params":null}` * [x] - Confirm the test fails without the fix and passes with it ### What is the Jira issue? * [ZEPPELIN-6012](https://issues.apache.org/jira/browse/ZEPPELIN-6012) ### How should this be tested? New test `NotebookRestApiTest#testRunNoteWithoutParamsInBody` creates a note and posts both bodies to the run-note endpoint, asserting that each returns status `OK`. ```bash ./mvnw package -pl zeppelin-server --am \ -Dtest='NotebookRestApiTest#testRunNoteWithoutParamsInBody' -DfailIfNoTests=false ``` Reverting only the production change makes the new test fail with `Expected: HTTP response <200> but: got <500>`, and the server log shows the stack trace above. With the fix it passes. Also verified by hand against a locally running server, posting each body to `/api/notebook/job/{noteId}`: | Request body | Before | After | |---|---|---| | `{}` | HTTP 500 | HTTP 200 | | `{"params":null}` | HTTP 500 | HTTP 200 | | empty body | HTTP 200 | HTTP 200 | | `{"params":{"name":"zeppelin"}}` | HTTP 200 | HTTP 200 | ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5385 from big-cir/ZEPPELIN-6012. Signed-off-by: Jongyoul Lee --- .../rest/message/ParametersRequest.java | 8 +++++- .../zeppelin/rest/NotebookRestApiTest.java | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParametersRequest.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParametersRequest.java index 04e19a3772b..828c36c4749 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParametersRequest.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/ParametersRequest.java @@ -16,6 +16,7 @@ */ package org.apache.zeppelin.rest.message; +import java.util.Collections; import java.util.Map; /** @@ -29,7 +30,12 @@ public ParametersRequest(Map params) { this.params = params; } + /** + * Gson bypasses the constructor, so this field is null when the body carries no "params" entry. + * + * @return the parameters, or an empty map when none were supplied + */ public Map getParams() { - return params; + return params == null ? Collections.emptyMap() : params; } } diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java index c93cc610d58..0257f8a69ef 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java @@ -890,6 +890,33 @@ void testRunNoteWithParams() throws IOException, InterruptedException { } } + @Test + void testRunNoteWithoutParamsInBody() throws IOException { + LOGGER.info("Running testRunNoteWithoutParamsInBody"); + String note1Id = null; + try { + note1Id = notebook.createNote("note1", anonymous); + + // Running a note without form parameters is valid. Gson leaves ParametersRequest#params + // null both when the key is absent and when it is an explicit null, so neither body may fail. + for (String body : new String[] {"{}", "{\"params\":null}"}) { + CloseableHttpResponse post = + httpPost("/notebook/job/" + note1Id + "?blocking=true&isolated=true", body); + assertThat(post, isAllowed()); + Map resp = gson.fromJson( + EntityUtils.toString(post.getEntity(), StandardCharsets.UTF_8), + new TypeToken>() {}.getType()); + assertEquals("OK", resp.get("status"), "Failed for request body: " + body); + post.close(); + } + } finally { + // cleanup + if (null != note1Id) { + notebook.removeNote(note1Id, anonymous); + } + } + } + @Test void testRunAllParagraph_FirstFailed() throws IOException { LOGGER.info("Running testRunAllParagraph_FirstFailed"); From b90e68634b0f2b6e389a84925ea0657457253a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Thu, 6 Aug 2026 17:12:05 +0900 Subject: [PATCH 145/179] [ZEPPELIN-6599] Stop treating the user list search text as LDAP filter and regex syntax ### What is this PR for? `GET /api/security/userlist/{searchText}` interprets the client-supplied search text as syntax in two places. This PR fixes both. **1. LDAP search filters** `ShiroAuthenticationService` builds the LDAP search filter by string concatenation, in `getUserList(DefaultLdapRealm, String, int)` and `getUserList(LdapRealm, String, int)`. The filter metacharacters `(`, `)`, `*`, `\` and NUL are therefore interpreted as filter syntax instead of literal text. Both sites now go through `LdapFilterEncoder.escapeFilterValue`, the RFC 4515 escape utility that `ActiveDirectoryGroupRealm` already uses. The filter building is extracted into two small helpers so the rendered filter can be asserted directly in unit tests, following the `expandFilterTemplate` approach already used in `LdapRealm`. The wildcards that Zeppelin adds around the search text stay outside the escaped value, so substring matching behaves exactly as before. Only an asterisk typed by the user becomes a literal character. The configured attribute name and object class are escaped as well for defense in depth, while the raw attribute name is still used for `setReturningAttributes`. The remaining realm branches of `getMatchedUsers` are already safe: `ActiveDirectoryGroupRealm` escapes the value in `searchForUserName`, and the `JdbcRealm` branch uses a `PreparedStatement` with a validated identifier. **2. Regular expression in the sorting comparator** `SecurityRestApi` sorted the matched users with `o1.matches(searchText + "(.*)")`, which compiles the search text as a regular expression. A search text of `*` therefore fails with `PatternSyntaxException: Dangling meta character '*'` and the endpoint responds with HTTP 500. That comparator only wants to list the users whose name starts with the search text first, which `startsWith` does without compiling anything. The replacement is a consistent comparator as well, and the alphabetical order within each group is preserved because the sort is stable. ### What type of PR is it? Improvement ### Todos * [x] Escape the search text at both LDAP filter building sites * [x] Unit tests for the rendered filters (16) * [x] Sort the user list without compiling the search text as a regular expression * [x] Endpoint test for search texts containing regex metacharacters ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-6599 ### How should this be tested? ``` ./mvnw test -pl zeppelin-server -Dtest=ShiroAuthenticationServiceFilterInjectionTest,SecurityRestApiTest ``` `SecurityRestApiTest.testGetUserListWithRegexMetacharacters` returns HTTP 500 without the comparator change and HTTP 200 with it. The existing LDAP realm and Shiro service tests keep passing. The LDAP part was also verified manually against an in-memory LDAP server. With the search text `*)(cn=Bob`, the directory server received `(&(objectclass=person)(uid=*)(cn=Bob*))` before this change, so the `uid` condition was neutralized and an extra condition was appended. After this change the same input arrives as `(&(objectclass=person)(uid=*\2a\29\28cn=Bob*))`, while a normal search text produces exactly the same filter and the same results as before. Worth noting that the entries matched by an injected filter are not disclosed in the REST response today, because `SecurityRestApi` filters the returned list once more with `containsIgnoreCase(user, searchText)`. So the LDAP part is hardening of the filter building rather than a fix for an information leak. ### Screenshots (if appropriate) Not applicable. ### Questions * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5384 from kimyenac/ZEPPELIN-6599. Signed-off-by: Jongyoul Lee --- .../apache/zeppelin/rest/SecurityRestApi.java | 15 +- .../service/ShiroAuthenticationService.java | 34 +++- .../zeppelin/rest/SecurityRestApiTest.java | 17 ++ ...henticationServiceFilterInjectionTest.java | 170 ++++++++++++++++++ 4 files changed, 218 insertions(+), 18 deletions(-) create mode 100644 zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceFilterInjectionTest.java diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java index 89bc317734d..5eec6e7713f 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/SecurityRestApi.java @@ -18,6 +18,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -102,16 +103,10 @@ public Response getUserList(@PathParam("searchText") final String searchText) { List autoSuggestRoleList = new ArrayList<>(); Collections.sort(usersList); Collections.sort(rolesList); - Collections.sort( - usersList, - (o1, o2) -> { - if (o1.matches(searchText + "(.*)") && o2.matches(searchText + "(.*)")) { - return 0; - } else if (o1.matches(searchText + "(.*)")) { - return -1; - } - return 0; - }); + // List the users whose name starts with the search text first, keeping the alphabetical order + // within each group. The search text comes from the client, so it must not be compiled as a + // regular expression here. + usersList.sort(Comparator.comparing((String user) -> !user.startsWith(searchText))); int maxLength = 0; for (String user : usersList) { if (StringUtils.containsIgnoreCase(user, searchText)) { diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/service/ShiroAuthenticationService.java b/zeppelin-server/src/main/java/org/apache/zeppelin/service/ShiroAuthenticationService.java index 21219c6e2e5..3797624a01a 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/service/ShiroAuthenticationService.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/service/ShiroAuthenticationService.java @@ -53,6 +53,7 @@ import org.apache.shiro.util.ThreadContext; import org.apache.zeppelin.conf.ZeppelinConfiguration; import org.apache.zeppelin.realm.ActiveDirectoryGroupRealm; +import org.apache.zeppelin.realm.LdapFilterEncoder; import org.apache.zeppelin.realm.LdapRealm; import org.apache.zeppelin.realm.jwt.KnoxJwtRealm; import org.slf4j.Logger; @@ -315,7 +316,7 @@ private List getUserList(DefaultLdapRealm r, String searchText, int numU String[] attrIDs = {userDnPrefix}; constraints.setReturningAttributes(attrIDs); NamingEnumeration result = - ctx.search(userDnSuffix, "(" + userDnPrefix + "=*" + searchText + "*)", constraints); + ctx.search(userDnSuffix, buildUserSearchFilter(userDnPrefix, searchText), constraints); while (result.hasMore()) { Attributes attrs = result.next().getAttributes(); if (attrs.get(userDnPrefix) != null) { @@ -330,6 +331,17 @@ private List getUserList(DefaultLdapRealm r, String searchText, int numU return userList; } + /** + * Builds the user search filter for {@link DefaultLdapRealm}. The attribute name and the search + * text are escaped per RFC 4515; the wildcards Zeppelin adds around the search text stay outside + * the escaped value so that substring matching keeps working. + */ + static String buildUserSearchFilter(String userDnPrefix, String searchText) { + return String.format("(%s=*%s*)", + LdapFilterEncoder.escapeFilterValue(userDnPrefix), + LdapFilterEncoder.escapeFilterValue(searchText)); + } + /** Function to extract users from Zeppelin LdapRealm. */ private List getUserList(LdapRealm r, String searchText, int numUsersToFetch) { List userList = new ArrayList<>(); @@ -348,13 +360,7 @@ private List getUserList(LdapRealm r, String searchText, int numUsersToF NamingEnumeration result = ctx.search( userSearchRealm, - "(&(objectclass=" - + userObjectClass - + ")(" - + userAttribute - + "=*" - + searchText - + "*))", + buildUserSearchFilterWithObjectClass(userObjectClass, userAttribute, searchText), constraints); while (result.hasMore()) { Attributes attrs = result.next().getAttributes(); @@ -377,6 +383,18 @@ private List getUserList(LdapRealm r, String searchText, int numUsersToF return userList; } + /** + * Builds the user search filter for Zeppelin {@link LdapRealm}. Follows the same escaping rules + * as {@link #buildUserSearchFilter(String, String)}, with the user object class escaped as well. + */ + static String buildUserSearchFilterWithObjectClass(String userObjectClass, String userAttribute, + String searchText) { + return String.format("(&(objectclass=%s)(%s=*%s*))", + LdapFilterEncoder.escapeFilterValue(userObjectClass), + LdapFilterEncoder.escapeFilterValue(userAttribute), + LdapFilterEncoder.escapeFilterValue(searchText)); + } + /** * * Get user roles from shiro.ini for Zeppelin LdapRealm. * diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java index b7e01b1fec7..25912b063f3 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/SecurityRestApiTest.java @@ -91,6 +91,23 @@ void testGetUserList() throws IOException { notUser.close(); } + @Test + void testGetUserListWithRegexMetacharacters() throws IOException { + // The search text is not a regular expression. Metacharacters must not break the endpoint. + for (String searchText : new String[] {"%2A", "%28", "%2B"}) { + CloseableHttpResponse get = httpGet("/security/userlist/" + searchText, "admin", "password1"); + assertThat("Status code for search text " + searchText, + get.getStatusLine().getStatusCode(), CoreMatchers.equalTo(200)); + Map resp = gson.fromJson( + EntityUtils.toString(get.getEntity(), StandardCharsets.UTF_8), + new TypeToken>(){}.getType()); + List userList = (List) ((Map) resp.get("body")).get("users"); + assertThat("Search result size for search text " + searchText, userList.size(), + CoreMatchers.equalTo(0)); + get.close(); + } + } + @Test void testRolesEscaped() throws IOException { CloseableHttpResponse get = httpGet("/security/ticket", "admin", "password1"); diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceFilterInjectionTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceFilterInjectionTest.java new file mode 100644 index 00000000000..14dca43b90a --- /dev/null +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/service/ShiroAuthenticationServiceFilterInjectionTest.java @@ -0,0 +1,170 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zeppelin.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * Tests verifying that the search text supplied to + * {@code GET /api/security/userlist/{searchText}} cannot inject LDAP filter metacharacters into + * the filters that {@link ShiroAuthenticationService} builds for the LDAP realms. The rendered + * filter must never contain unescaped {@code (}, {@code )} or {@code *} characters that + * originated in the search text. + */ +class ShiroAuthenticationServiceFilterInjectionTest { + + private static final String USER_ATTRIBUTE = "uid"; + private static final String USER_OBJECT_CLASS = "person"; + + // "(uid=*%s*)" contributes 1 '(', 1 ')' and the 2 wildcards Zeppelin adds itself. + private static final int DEFAULT_LDAP_OPEN_PARENS = 1; + private static final int DEFAULT_LDAP_CLOSE_PARENS = 1; + private static final int DEFAULT_LDAP_ASTERISKS = 2; + + // "(&(objectclass=person)(uid=*%s*))" contributes 3 '(', 3 ')' and the same 2 wildcards. + private static final int LDAP_REALM_OPEN_PARENS = 3; + private static final int LDAP_REALM_CLOSE_PARENS = 3; + private static final int LDAP_REALM_ASTERISKS = 2; + + static Stream injectionPayloads() { + return Stream.of( + ")(uid=*", + "admin)(|(uid=*", + "*", + "admin)(cn=a*", + ")(mail=*@corp.com", + "alice)(userPassword=*", + "alice\\", + "alice\\2a", + "alice\\29\\28uid=\\2a", + "\\", + "\0"); + } + + @ParameterizedTest + @MethodSource("injectionPayloads") + void defaultLdapRealmFilterNeutralizesPayload(String payload) { + String rendered = ShiroAuthenticationService.buildUserSearchFilter(USER_ATTRIBUTE, payload); + + assertMetacharacterCounts(rendered, payload, + DEFAULT_LDAP_OPEN_PARENS, DEFAULT_LDAP_CLOSE_PARENS, DEFAULT_LDAP_ASTERISKS); + } + + @ParameterizedTest + @MethodSource("injectionPayloads") + void ldapRealmFilterNeutralizesPayload(String payload) { + String rendered = ShiroAuthenticationService.buildUserSearchFilterWithObjectClass( + USER_OBJECT_CLASS, USER_ATTRIBUTE, payload); + + assertMetacharacterCounts(rendered, payload, + LDAP_REALM_OPEN_PARENS, LDAP_REALM_CLOSE_PARENS, LDAP_REALM_ASTERISKS); + } + + @Test + void normalSearchTextKeepsSubstringMatching() { + assertEquals("(uid=*alice*)", + ShiroAuthenticationService.buildUserSearchFilter(USER_ATTRIBUTE, "alice")); + assertEquals("(&(objectclass=person)(uid=*alice*))", + ShiroAuthenticationService.buildUserSearchFilterWithObjectClass( + USER_OBJECT_CLASS, USER_ATTRIBUTE, "alice")); + } + + @Test + void asteriskInSearchTextBecomesLiteral() { + // The wildcards Zeppelin adds stay wildcards, the one typed by the user does not. + assertEquals("(uid=*a\\2ab*)", + ShiroAuthenticationService.buildUserSearchFilter(USER_ATTRIBUTE, "a*b")); + assertEquals("(&(objectclass=person)(uid=*a\\2ab*))", + ShiroAuthenticationService.buildUserSearchFilterWithObjectClass( + USER_OBJECT_CLASS, USER_ATTRIBUTE, "a*b")); + } + + @Test + void emptySearchTextKeepsExistingBehaviour() { + assertEquals("(uid=**)", + ShiroAuthenticationService.buildUserSearchFilter(USER_ATTRIBUTE, "")); + assertEquals("(&(objectclass=person)(uid=**))", + ShiroAuthenticationService.buildUserSearchFilterWithObjectClass( + USER_OBJECT_CLASS, USER_ATTRIBUTE, "")); + } + + @Test + void configuredAttributeNamesAreEscapedAsWell() { + assertEquals("(&(objectclass=per\\29son)(u\\28id=*alice*))", + ShiroAuthenticationService.buildUserSearchFilterWithObjectClass("per)son", "u(id", + "alice")); + } + + @Test + void backslashAndNulInSearchTextAreEscaped() { + assertEquals("(uid=*alice\\5c*)", + ShiroAuthenticationService.buildUserSearchFilter(USER_ATTRIBUTE, "alice\\")); + assertEquals("(uid=*alice\\00*)", + ShiroAuthenticationService.buildUserSearchFilter(USER_ATTRIBUTE, "alice\0")); + assertEquals("(&(objectclass=person)(uid=*alice\\5c\\00*))", + ShiroAuthenticationService.buildUserSearchFilterWithObjectClass( + USER_OBJECT_CLASS, USER_ATTRIBUTE, "alice\\\0")); + } + + private static void assertMetacharacterCounts(String rendered, String payload, + int expectedOpenParens, int expectedCloseParens, int expectedAsterisks) { + assertEquals(expectedOpenParens, count(rendered, '('), + "extra unescaped '(' from payload: " + rendered); + assertEquals(expectedCloseParens, count(rendered, ')'), + "extra unescaped ')' from payload: " + rendered); + assertEquals(expectedAsterisks, count(rendered, '*'), + "extra unescaped '*' from payload: " + rendered); + + if (payload.indexOf('(') >= 0) { + assertTrue(rendered.contains("\\28"), "missing \\28 in: " + rendered); + } + if (payload.indexOf(')') >= 0) { + assertTrue(rendered.contains("\\29"), "missing \\29 in: " + rendered); + } + if (payload.indexOf('*') >= 0) { + assertTrue(rendered.contains("\\2a"), "missing \\2a in: " + rendered); + } + if (payload.indexOf('\\') >= 0) { + assertTrue(rendered.contains("\\5c"), "missing \\5c in: " + rendered); + } + if (payload.indexOf('\0') >= 0) { + assertTrue(rendered.contains("\\00"), "missing \\00 in: " + rendered); + } + } + + /** + * Counts occurrences of {@code ch} in the rendered filter. {@code LdapFilterEncoder} replaces + * every metacharacter with a hex escape such as {@code \2a}, so a metacharacter that is still + * present as itself is by definition an unescaped one. + */ + private static int count(String s, char ch) { + int count = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == ch) { + count++; + } + } + return count; + } +} From 3faf553a532df600f4d9b7544e833b3390d1c51c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:22:23 +0900 Subject: [PATCH 146/179] [ZEPPELIN-6533] Apply the notebook search term after the paragraph views exist ### What is this PR for? The notebook component reads the `term` query param in `ngOnInit`, which runs before `ViewChildren` resolves and before the note arrives over the WebSocket. The initial term was applied to a paragraph query list that did not exist yet, and nothing re-applied it once the paragraphs rendered, so opening a note through a `?term=...` deep link (for example clicking a notebook search result) never highlighted the matching text. This keeps the term on the notebook component and re-applies it in `ngAfterViewInit` and whenever the paragraph query list changes. The code editor keeps the term as well, because Monaco loads asynchronously and would otherwise ignore a term that arrived before the editor was ready. The guard suggested in the issue (`listOfNotebookParagraphComponent?.forEach(...)`) is already on master, so `onParagraphSearch` does not throw today. The access stays guarded here. ### What type of PR is it? Bug Fix ### Todos * [x] - Apply the search term once the paragraph views exist * [x] - Apply the search term once the Monaco editor is ready * [x] - Add an e2e regression test for the `term` deep link ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6533 ### How should this be tested? * Automated: `e2e/tests/notebook/search/editor-search.spec.ts` gains "highlights the term carried by a deep link when the notebook opens". Run it with `npm run e2e:fast -- tests/notebook/search/editor-search.spec.ts` in `zeppelin-web-angular`. The new test fails on master (0 highlights) and passes with this change; the rest of the spec and the notebook keyboard spec stay green. * Manual: create a note, put `alpha target beta target gamma target` in a paragraph, then open `/#/notebook/?term=target` coming from another page. Every occurrence of `target` is highlighted. The same applies when clicking a result on the notebook search page, which navigates with `paragraph` and `term` query params. ### Screenshots (if appropriate) Before: nothing is highlighted when the note opens through the deep link. After: the three `target` occurrences are highlighted. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5378 from kimyenac/ZEPPELIN-6533. Signed-off-by: YONGJAE LEE --- .../e2e/models/editor-search-page.ts | 24 ++++++++++++ .../notebook/search/editor-search.spec.ts | 37 +++++++++++++++++++ zeppelin-web-angular/e2e/utils.ts | 30 +++++++++++++++ .../workspace/notebook/notebook.component.ts | 21 ++++++++++- .../code-editor/code-editor.component.ts | 4 ++ .../notebook/paragraph/paragraph.component.ts | 14 ++++++- 6 files changed, 126 insertions(+), 4 deletions(-) diff --git a/zeppelin-web-angular/e2e/models/editor-search-page.ts b/zeppelin-web-angular/e2e/models/editor-search-page.ts index d47ba32fc47..a7fbc2d60c8 100644 --- a/zeppelin-web-angular/e2e/models/editor-search-page.ts +++ b/zeppelin-web-angular/e2e/models/editor-search-page.ts @@ -22,6 +22,8 @@ export class EditorSearchPage extends BasePage { readonly replaceInput: Locator; readonly matchesCount: Locator; readonly matchHighlights: Locator; + readonly termHighlights: Locator; + readonly showHideCodeButton: Locator; readonly nextMatchButton: Locator; readonly previousMatchButton: Locator; readonly toggleReplaceButton: Locator; @@ -42,6 +44,11 @@ export class EditorSearchPage extends BasePage { this.matchesCount = this.findWidget.locator('.matchesCount').first(); // Monaco decorates every match with .findMatch and the active one with .currentFindMatch. this.matchHighlights = this.editor.locator('.findMatch, .currentFindMatch'); + // The `term` query param highlights through Zeppelin's own decoration class, not Monaco's find widget. + this.termHighlights = this.editor.locator('.editor-search-highlight'); + this.showHideCodeButton = page + .locator('zeppelin-notebook-paragraph-control a[nzTooltipTitle="Show/hide the code"]') + .first(); this.nextMatchButton = this.findWidget.locator('.button.next, [title^="Next Match"]').first(); this.previousMatchButton = this.findWidget.locator('.button.previous, [title^="Previous Match"]').first(); this.toggleReplaceButton = this.findWidget.locator('.button.toggle, [title^="Toggle Replace"]').first(); @@ -54,6 +61,23 @@ export class EditorSearchPage extends BasePage { await expect(this.editor).toBeVisible({ timeout: 15000 }); } + async openNotebookWithSearchTerm(noteId: string, term: string): Promise { + await this.navigateToNotebookWithSearchTerm(noteId, term); + await expect(this.editor).toBeVisible({ timeout: 15000 }); + } + + // Separate from openNotebookWithSearchTerm: a paragraph whose editor starts hidden renders no + // Monaco instance, so the caller cannot wait for the editor before acting. + async navigateToNotebookWithSearchTerm(noteId: string, term: string): Promise { + await this.page.goto(`/#/notebook/${noteId}?term=${encodeURIComponent(term)}`); + await waitForZeppelinReady(this.page); + } + + async showCode(): Promise { + await this.showHideCodeButton.click(); + await expect(this.editor).toBeVisible({ timeout: 15000 }); + } + async setEditorContent(content: string): Promise { await this.editor.click(); // Key off the browser, not the host: Monaco follows the browser UA's keymap, and diff --git a/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts b/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts index a7420914f1c..3960559c1ff 100644 --- a/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts +++ b/zeppelin-web-angular/e2e/tests/notebook/search/editor-search.spec.ts @@ -17,6 +17,8 @@ import { createTestNotebook, PAGES, performLoginIfRequired, + setParagraphEditorHidden, + setParagraphText, skipWhenAuthenticationIsStillRequired, waitForNotebookLinks, waitForZeppelinReady @@ -77,6 +79,41 @@ test.describe('Notebook editor search', () => { await expect(editorSearchPage.matchHighlights).toHaveCount(3); }); + test('highlights the term carried by a deep link when the notebook opens', async ({ page }) => { + const { noteId, paragraphId } = await createTestNotebook(page); + + await test.step('Given a paragraph containing the term three times', async () => { + await setParagraphText(page, noteId, paragraphId, 'alpha target beta target gamma target'); + }); + + await test.step('When the notebook is opened with the term in the query string', async () => { + await editorSearchPage.openNotebookWithSearchTerm(noteId, 'target'); + }); + + await test.step('Then every occurrence is highlighted', async () => { + await expect(editorSearchPage.termHighlights).toHaveCount(3); + }); + }); + + test('highlights the term carried by a deep link when a hidden editor is shown', async ({ page }) => { + const { noteId, paragraphId } = await createTestNotebook(page); + + await test.step('Given a paragraph whose editor is hidden and contains the term three times', async () => { + await setParagraphText(page, noteId, paragraphId, 'alpha target beta target gamma target'); + await setParagraphEditorHidden(page, noteId, paragraphId, true); + }); + + await test.step('When the notebook is opened with the term and the code is shown again', async () => { + await editorSearchPage.navigateToNotebookWithSearchTerm(noteId, 'target'); + await expect(editorSearchPage.editor).toHaveCount(0); + await editorSearchPage.showCode(); + }); + + await test.step('Then every occurrence is highlighted', async () => { + await expect(editorSearchPage.termHighlights).toHaveCount(3); + }); + }); + test('replaces all matches in the editor search widget', async ({ page }) => { const { noteId } = await createTestNotebook(page); diff --git a/zeppelin-web-angular/e2e/utils.ts b/zeppelin-web-angular/e2e/utils.ts index cfc3c110e17..d4500d3f6e3 100644 --- a/zeppelin-web-angular/e2e/utils.ts +++ b/zeppelin-web-angular/e2e/utils.ts @@ -482,6 +482,36 @@ const createNotebookViaRest = async ( return { noteId, paragraphId }; }; +export const setParagraphText = async ( + page: Page, + noteId: string, + paragraphId: string, + text: string +): Promise => { + const response = await page.request.put(`/api/notebook/${noteId}/paragraph/${paragraphId}`, { + data: { text }, + failOnStatusCode: false + }); + if (!response.ok()) { + throw new Error(`Update paragraph REST request failed: ${response.status()} ${await response.text()}`); + } +}; + +export const setParagraphEditorHidden = async ( + page: Page, + noteId: string, + paragraphId: string, + editorHide: boolean +): Promise => { + const response = await page.request.put(`/api/notebook/${noteId}/paragraph/${paragraphId}/config`, { + data: { editorHide }, + failOnStatusCode: false + }); + if (!response.ok()) { + throw new Error(`Update paragraph config REST request failed: ${response.status()} ${await response.text()}`); + } +}; + interface CreateTestNotebookWithNameOptions { folderPath?: string | null; namePrefix?: string; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts index 408ca1af281..552e0f8c8d4 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts @@ -11,6 +11,7 @@ */ import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -57,9 +58,10 @@ import { NotebookParagraphComponent } from './paragraph/paragraph.component'; changeDetection: ChangeDetectionStrategy.OnPush, standalone: false }) -export class NotebookComponent extends MessageListenersManager implements OnInit, OnDestroy { +export class NotebookComponent extends MessageListenersManager implements OnInit, AfterViewInit, OnDestroy { @ViewChildren(NotebookParagraphComponent) listOfNotebookParagraphComponent!: QueryList; private destroy$ = new Subject(); + private searchTerm = ''; note?: Exclude; permissions?: Permissions; selectId: string | null = null; @@ -272,7 +274,8 @@ export class NotebookComponent extends MessageListenersManager implements OnInit } onParagraphSearch(term: string) { - this.listOfNotebookParagraphComponent?.forEach(comp => comp.highlightMatches(term || '')); + this.searchTerm = term || ''; + this.highlightSearchTerm(); } saveParagraph(id: string) { @@ -485,6 +488,13 @@ export class NotebookComponent extends MessageListenersManager implements OnInit }); } + ngAfterViewInit(): void { + this.highlightSearchTerm(); + this.listOfNotebookParagraphComponent.changes.pipe(takeUntil(this.destroy$)).subscribe(() => { + this.highlightSearchTerm(); + }); + } + removeParagraphFromNgZ(): void { if (this.note && Array.isArray(this.note.paragraphs)) { this.note.paragraphs.forEach(p => { @@ -501,4 +511,11 @@ export class NotebookComponent extends MessageListenersManager implements OnInit this.destroy$.complete(); this.titleService.setTitle('Zeppelin'); } + + // The term can arrive before the paragraphs exist: the query param subscription emits during + // ngOnInit, and the paragraphs themselves are only rendered once the note arrives over the + // WebSocket. Keep the term and (re)apply it whenever the paragraph views change. + private highlightSearchTerm(): void { + this.listOfNotebookParagraphComponent?.forEach(comp => comp.highlightMatches(this.searchTerm)); + } } diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts index 093a34e11cc..ccb1a1669b7 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts @@ -66,6 +66,7 @@ export class NotebookParagraphCodeEditorComponent private editor?: IStandaloneCodeEditor; private monacoDisposables: IDisposable[] = []; private highlightDecorations: DecorationIdentifier[] = []; + private searchTerm = ''; height = 18; interpreterName?: string; @@ -217,6 +218,8 @@ export class NotebookParagraphCodeEditorComponent this.initEditorFocus(); this.initCompletionService(this.editor); this.setEditorValue(this.editor); + // A term requested before Monaco finished loading was only stored, not applied yet. + this.highlightMatches(this.searchTerm); setTimeout(() => { this.autoAdjustEditorHeight(); }); @@ -356,6 +359,7 @@ export class NotebookParagraphCodeEditorComponent } highlightMatches(term: string) { + this.searchTerm = term; if (!this.editor || !term) { // Remove previous highlights if term is empty this.highlightDecorations = this.editor?.deltaDecorations(this.highlightDecorations, []) || []; diff --git a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts index 8f72c2bbf3d..186b4c595c8 100644 --- a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts +++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts @@ -84,8 +84,6 @@ export class NotebookParagraphComponent implements OnInit, OnChanges, OnDestroy, AfterViewInit, AngularKeyboardEventHandler { @HostBinding('attr.tabindex') tabindex = '-1'; - @ViewChild(NotebookParagraphCodeEditorComponent, { static: false }) - notebookParagraphCodeEditorComponent?: NotebookParagraphCodeEditorComponent; @ViewChildren(NotebookParagraphResultComponent) notebookParagraphResultComponents!: QueryList; @Input() paragraph!: ParagraphItem; @@ -145,9 +143,11 @@ export class NotebookParagraphComponent @Output() readonly openSearchMenu = new EventEmitter(); private destroy$ = new Subject(); + private searchTerm = ''; private mode: Mode = 'command'; waitConfirmFromEdit = false; + notebookParagraphCodeEditorComponent?: NotebookParagraphCodeEditorComponent; private keyBinderService: KeyBinder; @@ -170,7 +170,17 @@ export class NotebookParagraphComponent } } + // The code editor sits behind an @if on `config.editorHide`, so it can mount long after the + // search term arrived, and it mounts as a fresh instance that knows nothing about the term. + // Setter injection replays the retained term the moment the editor becomes available. + @ViewChild(NotebookParagraphCodeEditorComponent, { static: false }) + set codeEditorComponent(component: NotebookParagraphCodeEditorComponent | undefined) { + this.notebookParagraphCodeEditorComponent = component; + component?.highlightMatches(this.searchTerm); + } + highlightMatches(searchText: string) { + this.searchTerm = searchText; this.notebookParagraphCodeEditorComponent?.highlightMatches(searchText); } From 4998576589b94d6236ed156c049371ad902ef184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=98=88=EB=82=98?= <101786858+kimyenac@users.noreply.github.com> Date: Fri, 7 Aug 2026 12:42:26 +0900 Subject: [PATCH 147/179] [ZEPPELIN-3798] Fix wrong link to Dynamic Form docs on Zeppelin Context webpage ### What is this PR for? The two "Dynamic Form" links on the Zeppelin Context page point to `../usage/dynamic_form/intro.html`. The page itself is served from `/usage/other_features/`, so that relative path resolves to `/usage/usage/dynamic_form/intro.html` and returns 404. This is still reproducible on the published docs (see the link below). The fix is `../dynamic_form/intro.html`, which is how sibling pages such as `other_features/customizing_homepage.md` link to `../display_system/`. While I was there I audited every relative `.html` link in `docs/` and in the navigation sidebar and found three more broken targets, fixed in the second commit: * `index.md` and `_navigation.html` link the Notebook Storage entries to `setup/storage/storage.html`, but the file is `notebook_storage.md`. The fragments were wrong too: the docs are rendered with redcarpet, which does not emit heading ids, so the only usable anchors on that page are its explicit `` tags (`Git`, `S3`, `Azure`, `GCS`, `OSS`, `MongoDB`). This one is visible on every docs page because it is in the sidebar. * `usage/interpreter/overview.md` links to `../development/writing_zeppelin_interpreter.html`, which resolves to `/usage/development/`. It needs one more level up. * `pleasecontribute.md` links to `development/howtocontributewebsite.html`, which is now `development/contribution/how_to_contribute_website.html`. After this change every relative `.html` link in `docs/` and in the navigation sidebar resolves to an existing page. Happy to split the second commit out into its own JIRA if you prefer to keep this PR to the reported issue only. ### What type of PR is it? Bug Fix / Documentation ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-3798 ### How should this be tested? Docs only, no code change. The broken link can be seen on the published docs at https://zeppelin.apache.org/docs/0.12.0/usage/other_features/zeppelin_context.html (the "Dynamic Form" links in the body, not the sidebar one), and the Notebook Storage entries in the left sidebar of any docs page 404 as well. I verified the fix by resolving every relative link in `docs/` against the file tree and confirming each target file exists, and by checking that the anchors used for `notebook_storage.html` are present in that page. ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Closes #5387 from kimyenac/ZEPPELIN-3798. Signed-off-by: Jongyoul Lee --- docs/_includes/themes/zeppelin/_navigation.html | 12 ++++++------ docs/index.md | 10 +++++----- docs/pleasecontribute.md | 2 +- docs/usage/interpreter/overview.md | 2 +- docs/usage/other_features/zeppelin_context.md | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/_includes/themes/zeppelin/_navigation.html b/docs/_includes/themes/zeppelin/_navigation.html index cc2d63ebb5f..9554b48a75c 100644 --- a/docs/_includes/themes/zeppelin/_navigation.html +++ b/docs/_includes/themes/zeppelin/_navigation.html @@ -110,12 +110,12 @@