From 64c19dcd4f716ea631425a199b2b89ce5b0d9480 Mon Sep 17 00:00:00 2001 From: erKam Date: Tue, 13 Oct 2026 03:46:51 +0000 Subject: [PATCH 1/9] feat(overlay): explain change detection, leaks and common errors Phase 4 diagnosis: each recorded cycle says what started it, with wasted checks, inputs that break OnPush and zone.js dependents; components destroyed but still retained, open subscriptions and live effects are listed; and NG0100, hydration mismatches and NullInjectorError get explainers, with a new explain-injection tool. Refs #343. --- app/src/__tests__/cd-diagnosis.test.ts | 141 +++ app/src/__tests__/error-explain.test.ts | 238 +++++ app/src/__tests__/leaks-section.test.ts | 159 ++++ app/src/app.ts | 1 + app/src/pages/cd-diagnosis.ts | 227 +++++ app/src/pages/cd-recording.ts | 24 +- app/src/pages/component-tree.ts | 29 + app/src/pages/error-explain.ts | 486 ++++++++++ app/src/pages/errors-inspector.ts | 14 +- app/src/pages/errors-types.ts | 60 ++ app/src/pages/leaks-section.ts | 472 ++++++++++ apps/docs/src/content/agents/mcp-server.md | 3 +- apps/docs/src/content/agents/resources.md | 19 +- apps/docs/src/content/agents/tools.md | 93 +- .../content/getting-started/configuration.md | 10 +- .../content/getting-started/installation.md | 4 +- .../docs/src/content/inspectors/components.md | 105 ++- apps/docs/src/content/inspectors/errors.md | 41 +- apps/docs/src/content/inspectors/injectors.md | 18 +- docs/angular-compat.md | 30 +- .../src/__tests__/cd-diagnosis-real.test.ts | 203 +++++ .../src/__tests__/cd-diagnosis-tool.test.ts | 265 ++++++ .../src/__tests__/cd-diagnosis.test.ts | 411 +++++++++ .../devtools/src/__tests__/config.test.ts | 2 + .../src/__tests__/docs-tool-count.test.ts | 4 + .../devtools/src/__tests__/dom-diff.test.ts | 48 + .../src/__tests__/error-explain.test.ts | 370 ++++++++ .../__tests__/errors-explain-tools.test.ts | 137 +++ .../src/__tests__/explainers-real.test.ts | 177 ++++ .../src/__tests__/hydration-agent.test.ts | 4 +- .../src/__tests__/injector-tree.test.ts | 22 + .../src/__tests__/leaks-collector.test.ts | 624 +++++++++++++ .../devtools/src/__tests__/leaks-real.test.ts | 136 +++ .../src/__tests__/leaks-tools.test.ts | 225 +++++ packages/devtools/src/cd-data.ts | 247 +++++ packages/devtools/src/cd-diagnosis.ts | 808 +++++++++++++++++ packages/devtools/src/cd-overlay.ts | 28 +- packages/devtools/src/cd-recorder.ts | 6 + packages/devtools/src/config.ts | 135 +++ packages/devtools/src/devframe.ts | 61 ++ packages/devtools/src/dom-diff.ts | 75 ++ packages/devtools/src/error-explain.ts | 344 +++++++ packages/devtools/src/errors-collector.ts | 38 +- packages/devtools/src/injector-tree.ts | 29 + packages/devtools/src/leaks-collector.ts | 843 ++++++++++++++++++ packages/devtools/src/overlay.ts | 22 +- .../rpc/__tests__/injection-explain.test.ts | 282 ++++++ .../src/rpc/__tests__/injector-report.test.ts | 12 +- .../devtools/src/rpc/cd-diagnosis-tools.ts | 134 +++ packages/devtools/src/rpc/cd-export-tools.ts | 30 +- packages/devtools/src/rpc/cd-redact.ts | 70 ++ packages/devtools/src/rpc/cd-tools.ts | 17 +- .../devtools/src/rpc/error-explain-tools.ts | 252 ++++++ packages/devtools/src/rpc/errors-register.ts | 2 +- packages/devtools/src/rpc/errors-tools.ts | 10 + packages/devtools/src/rpc/hydration-tools.ts | 16 +- .../devtools/src/rpc/injection-explain.ts | 500 +++++++++++ packages/devtools/src/rpc/injector-report.ts | 1 + packages/devtools/src/rpc/leaks-register.ts | 186 ++++ packages/devtools/src/rpc/leaks-tools.ts | 406 +++++++++ packages/devtools/src/types.ts | 6 + packages/devtools/vitest.compat.config.ts | 2 + 62 files changed, 9243 insertions(+), 121 deletions(-) create mode 100644 app/src/__tests__/cd-diagnosis.test.ts create mode 100644 app/src/__tests__/error-explain.test.ts create mode 100644 app/src/__tests__/leaks-section.test.ts create mode 100644 app/src/pages/cd-diagnosis.ts create mode 100644 app/src/pages/error-explain.ts create mode 100644 app/src/pages/leaks-section.ts create mode 100644 packages/devtools/src/__tests__/cd-diagnosis-real.test.ts create mode 100644 packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts create mode 100644 packages/devtools/src/__tests__/cd-diagnosis.test.ts create mode 100644 packages/devtools/src/__tests__/dom-diff.test.ts create mode 100644 packages/devtools/src/__tests__/error-explain.test.ts create mode 100644 packages/devtools/src/__tests__/errors-explain-tools.test.ts create mode 100644 packages/devtools/src/__tests__/explainers-real.test.ts create mode 100644 packages/devtools/src/__tests__/leaks-collector.test.ts create mode 100644 packages/devtools/src/__tests__/leaks-real.test.ts create mode 100644 packages/devtools/src/__tests__/leaks-tools.test.ts create mode 100644 packages/devtools/src/cd-diagnosis.ts create mode 100644 packages/devtools/src/dom-diff.ts create mode 100644 packages/devtools/src/error-explain.ts create mode 100644 packages/devtools/src/leaks-collector.ts create mode 100644 packages/devtools/src/rpc/__tests__/injection-explain.test.ts create mode 100644 packages/devtools/src/rpc/cd-diagnosis-tools.ts create mode 100644 packages/devtools/src/rpc/cd-redact.ts create mode 100644 packages/devtools/src/rpc/error-explain-tools.ts create mode 100644 packages/devtools/src/rpc/injection-explain.ts create mode 100644 packages/devtools/src/rpc/leaks-register.ts create mode 100644 packages/devtools/src/rpc/leaks-tools.ts diff --git a/app/src/__tests__/cd-diagnosis.test.ts b/app/src/__tests__/cd-diagnosis.test.ts new file mode 100644 index 00000000..298845db --- /dev/null +++ b/app/src/__tests__/cd-diagnosis.test.ts @@ -0,0 +1,141 @@ +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import type { CdDiagnosis as Diagnosis } from '@pangular-inspector/devtools/config'; +import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import { CdDiagnosis } from '../pages/cd-diagnosis'; +import { CdRecording, type CdPage } from '../pages/cd-recording'; + +const diagnosis: Diagnosis = { + triggers: true, + waste: true, + major: 22, + causes: { signal: 4, event: 2, zone: 1 }, + components: [ + { name: 'Banner', refreshed: 20, unchanged: 19, strategy: 'Eager' }, + { name: 'Cart', refreshed: 5, unchanged: 0, strategy: 'OnPush' }, + ], + inputs: [{ name: 'Row', input: 'items', parent: 'List', inPlace: 3, sameContents: 1 }], + zone: [{ name: 'Clock', ticks: 1, tasks: ['setTimeout'] }], +}; + +function page(extra: Partial = {}): CdPage { + return { + pageId: 'p1', + supported: true, + recording: false, + startedAt: 1000, + dropped: 0, + cycles: [ + { + id: 1, + at: 1001, + ms: 1, + passes: 1, + checks: 2, + components: [{ name: 'Cart', checks: 1, ms: 0.5 }], + trigger: 'Cart (add)', + cause: { + kind: 'event', + event: 'click', + target: 'button', + component: 'Cart', + listener: 'add', + }, + refreshed: 2, + unchanged: 1, + }, + ], + components: [{ name: 'Cart', checks: 2, ms: 1, maxMs: 1, cycles: 1 }], + hosts: {}, + diagnosis, + ...extra, + }; +} + +const text = (el: Element | null) => el?.textContent?.replace(/\s+/g, ' ').trim() ?? ''; +/** A table row's cells, joined with spaces. */ +const cells = (row: Element | null) => + [...(row?.querySelectorAll('td') ?? [])].map((cell) => text(cell)).join(' '); + +describe('CdDiagnosis', () => { + let fixture: ComponentFixture; + const host = () => fixture.nativeElement as HTMLElement; + const section = (heading: string) => + [...host().querySelectorAll('h4')].find((h) => text(h) === heading)?.nextElementSibling ?? null; + + beforeEach(() => { + fixture = TestBed.createComponent(CdDiagnosis); + }); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + async function show(value: CdPage | null) { + fixture.componentRef.setInput('page', value); + await fixture.whenStable(); + } + + it('shows nothing for a recording without a diagnosis', async () => { + await show(page({ diagnosis: undefined })); + expect(host().querySelector('section')).toBeNull(); + }); + + it('lists causes in a fixed order, zone.js dependents, wasted checks, inputs and hints', async () => { + await show(page()); + const heading = host().querySelector('section')!.getAttribute('aria-labelledby')!; + expect(text(host().querySelector(`#${heading}`))).toBe('Why it ran and what it wasted'); + const causes = [...section('What started the cycles')!.querySelectorAll('tbody tr')].map(cells); + expect(causes).toEqual(['Event 2', 'Signal write 4', 'zone.js only 1']); + expect(cells(section('Depends on zone.js')!.querySelector('tbody tr'))).toBe( + 'Clock 1 setTimeout', + ); + const wasted = [...section('Wasted checks')!.querySelectorAll('tbody tr')].map(cells); + expect(wasted).toEqual(['Banner 20 19 (95%) Eager']); + expect(cells(section('Inputs that break OnPush')!.querySelector('tbody tr'))).toBe( + 'Row.items List 3 1', + ); + const hints = [...section('Hints')!.querySelectorAll('li')].map(text); + expect(hints[0]).toContain('Banner was refreshed 20 times and changed something in 1'); + expect(hints[0]).toContain('default from Angular 22'); + expect( + hints.some((h) => h.includes('Input items of Row set by List changed in place 3 times')), + ).toBe(true); + expect( + hints.some((h) => h.startsWith('Clock changed in 1 tick that only zone.js started')), + ).toBe(true); + }); + + it('says why causes or wasted checks are missing', async () => { + await show( + page({ diagnosis: { ...diagnosis, triggers: false, waste: false, zone: undefined } }), + ); + expect(text(section('What started the cycles'))).toContain('needs Angular 18 or later'); + expect(text(section('Wasted checks'))).toContain("can't watch DOM updates"); + expect(section('Depends on zone.js')).toBeNull(); + }); + + it('says when zone.js ticks changed nothing', async () => { + await show(page({ diagnosis: { ...diagnosis, zone: undefined } })); + expect(text(section('Depends on zone.js'))).toBe( + '1 tick came from zone.js alone, and no component changed in them.', + ); + }); +}); + +describe('CdRecording latest cycles', () => { + it('names what started a cycle and how many checks changed nothing', async () => { + const fixture = TestBed.createComponent(CdRecording); + fixture.componentRef.setInput('page', page()); + await fixture.whenStable(); + const row = (fixture.nativeElement as HTMLElement).querySelector('.cycles li'); + expect(text(row)).toContain('from click on button in Cart (add)'); + expect(text(row)).toContain('1 changed nothing'); + expect(text(row)).not.toContain('after Cart (add)'); + expect( + (fixture.nativeElement as HTMLElement).querySelector('app-cd-diagnosis section'), + ).not.toBeNull(); + fixture.destroy(); + TestBed.resetTestingModule(); + }); +}); diff --git a/app/src/__tests__/error-explain.test.ts b/app/src/__tests__/error-explain.test.ts new file mode 100644 index 00000000..fbfe253b --- /dev/null +++ b/app/src/__tests__/error-explain.test.ts @@ -0,0 +1,238 @@ +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import type { DevframeRpcClient } from 'devframe/client'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import type { ErrorGroup, InjectionExplanation } from '../pages/errors-types'; + +vi.mock('devframe/client', () => ({ connectDevframe: () => new Promise(() => {}) })); + +const { ErrorsInspector } = await import('../pages/errors-inspector'); +const { codeSegments } = await import('../pages/errors-types'); + +const group = (extra: Partial): ErrorGroup => ({ + id: 'e1', + message: 'Error: something', + count: 1, + firstAt: 1_000, + lastAt: 2_000, + sources: ['handler'], + owner: { id: 'c1-7', name: 'TripList' }, + ...extra, +}); + +type RpcCall = (name: string, args?: unknown) => Promise; + +function client(errors: ErrorGroup[], call: RpcCall = vi.fn()) { + const value = { + pages: { + p1: { + pageId: 'p1', + url: '/p1', + title: 'Trips', + reportedAt: 5_000, + handler: 'wrapped', + errors: Object.fromEntries(errors.map((e) => [e.id, e])), + console: {}, + dropped: { errors: 0, console: 0 }, + }, + }, + }; + const rpc = { + call, + callEvent: () => Promise.resolve(), + sharedState: () => Promise.resolve({ value: () => value, on: () => () => {} }), + }; + return { scope: () => ({ rpc }), events: { on: () => () => {} } } as unknown as DevframeRpcClient; +} + +async function settle(fixture: ComponentFixture) { + for (let i = 0; i < 4; i++) { + await new Promise((resolve) => setTimeout(resolve)); + await fixture.whenStable(); + } +} + +async function mount(errors: ErrorGroup[], options: { call?: RpcCall; injectors?: boolean } = {}) { + const fixture = TestBed.createComponent(ErrorsInspector); + fixture.componentRef.setInput('rpc', client(errors, options.call)); + fixture.componentRef.setInput('canExplainInjection', options.injectors ?? true); + document.body.append(fixture.nativeElement); + await settle(fixture); + return fixture; +} + +const host = (fixture: ComponentFixture) => fixture.nativeElement as HTMLElement; +const text = (fixture: ComponentFixture) => + (host(fixture).textContent ?? '').replace(/\s+/g, ' '); + +afterEach(() => { + document.body.innerHTML = ''; +}); + +describe('the Errors tab explainers', () => { + it('shows what changed for an NG0100: binding, both values, fields and the signal write', async () => { + const fixture = await mount([ + group({ + code: 'NG0100', + explain: { + kind: 'expression-changed', + binding: 'title', + template: 'TripList_Template', + previous: 'Trips', + current: 'Trips (3)', + members: ['title'], + writes: [ + { + signal: 'heading', + at: 4_000, + stack: ['TripList.ngAfterViewInit (trip-list.ts:22:5)'], + }, + ], + writesKnown: true, + }, + }), + ]); + const explain = host(fixture).querySelector('app-error-explain')!; + expect(explain.querySelector('h3')?.textContent).toBe('What changed'); + const facts = [...explain.querySelectorAll('dt')].map((dt) => [ + dt.textContent?.trim(), + dt.nextElementSibling?.textContent?.replace(/\s+/g, ' ').trim(), + ]); + expect(facts).toEqual([ + ['Binding', 'title in TripList_Template'], + ['Previous', 'Trips'], + ['Current', 'Trips (3)'], + ['Held by', 'title'], + ]); + expect(text(fixture)).toContain('Signal heading at'); + expect(explain.querySelector('.frames code')?.textContent).toBe( + 'TripList.ngAfterViewInit (trip-list.ts:22:5)', + ); + }); + + it('says how to find the writer when no signal matched', async () => { + const fixture = await mount([ + group({ + explain: { kind: 'expression-changed', previous: 'a', current: 'b', writesKnown: true }, + }), + ]); + expect(text(fixture)).toContain("A text interpolation (Angular doesn't name it)"); + expect(text(fixture)).toContain('No named signal was written with this value'); + }); + + it('shows the server vs client DOM diff with signs a screen reader can tell apart', async () => { + const fixture = await mount([ + group({ + code: 'NG0500', + explain: { + kind: 'hydration-mismatch', + summary: 'During hydration Angular expected
but found .', + diff: [ + { op: 'same', text: '

' }, + { op: 'expected', text: '

…
' }, + { op: 'actual', text: ' …' }, + ], + external: true, + }, + }), + ]); + const region = host(fixture).querySelector('[role="region"]')!; + expect(region.getAttribute('aria-label')).toBe('Server vs client DOM diff'); + expect(region.getAttribute('tabindex')).toBe('0'); + const lines = [...region.querySelectorAll('li')].map((li) => ({ + op: li.getAttribute('data-op'), + label: li.querySelector('.sr-only')?.textContent ?? '', + code: li.querySelector('code')?.textContent, + })); + expect(lines).toEqual([ + { op: 'same', label: '', code: '

' }, + { op: 'expected', label: 'Server only:', code: '

…
' }, + { op: 'actual', label: 'Client only:', code: ' …' }, + ]); + expect(text(fixture)).toContain('During hydration Angular expected
but found .'); + expect(text(fixture)).toContain('browser extension or third-party script'); + }); + + it('walks the lookup of a missing provider through explain-injection', async () => { + const answer: InjectionExplanation = { + pageId: 'p1', + token: 'TripApi', + flags: [], + outcome: 'error', + summary: 'No injector Angular asks provides `TripApi`, so it throws NG0201.', + steps: [ + { + id: 'el-list', + name: '', + type: 'element', + component: 'TripList', + status: 'missing', + reason: 'Not in its providers.', + }, + { + id: 'env-r', + name: 'Root', + type: 'environment', + status: 'missing', + reason: "An `@Injectable({ providedIn: 'root' })` class would be created here.", + }, + ], + }; + const call = vi.fn().mockResolvedValue(answer); + const fixture = await mount( + [ + group({ + code: 'NG0201', + explain: { kind: 'missing-provider', token: 'TripApi', path: ['TripList', 'TripApi'] }, + }), + ], + { call }, + ); + expect(text(fixture)).toContain('TokenTripApi'); + expect(text(fixture)).toContain('PathTripList → TripApi'); + const button = [...host(fixture).querySelectorAll('button')].find( + (b) => b.textContent?.trim() === 'Explain lookup', + )!; + button.click(); + await settle(fixture); + expect(call).toHaveBeenCalledWith('explain-injection', { + selector: 'c1-7', + token: 'TripApi', + pageId: 'p1', + }); + const steps = [...host(fixture).querySelectorAll('ol.steps > li')]; + expect(steps).toHaveLength(2); + expect(steps[0]!.querySelector('.chip')?.textContent?.trim()).toBe('Not provided'); + // Code spans in reasons render as , not as backticks. + expect(steps[1]!.querySelector('.reason code')?.textContent).toBe( + "@Injectable({ providedIn: 'root' })", + ); + expect(host(fixture).querySelector('.summary code')?.textContent).toBe('TripApi'); + }); + + it('shows why the lookup failed, and hides the button without the Injectors tab', async () => { + const call = vi.fn().mockResolvedValue({ error: 'No injector data available.' }); + const errors = [group({ explain: { kind: 'missing-provider', token: 'TripApi' } })]; + const fixture = await mount(errors, { call }); + [...host(fixture).querySelectorAll('button')] + .find((b) => b.textContent?.trim() === 'Explain lookup')! + .click(); + await settle(fixture); + expect(host(fixture).querySelector('[role="alert"]')?.textContent).toContain( + 'No injector data available.', + ); + const off = await mount(errors, { injectors: false }); + expect( + [...host(off).querySelectorAll('button')].some((b) => + b.textContent?.includes('Explain lookup'), + ), + ).toBe(false); + }); + + it('splits code spans out of text', () => { + expect(codeSegments('a `b` c')).toEqual([ + { code: false, text: 'a ' }, + { code: true, text: 'b' }, + { code: false, text: ' c' }, + ]); + }); +}); diff --git a/app/src/__tests__/leaks-section.test.ts b/app/src/__tests__/leaks-section.test.ts new file mode 100644 index 00000000..d13ebaa6 --- /dev/null +++ b/app/src/__tests__/leaks-section.test.ts @@ -0,0 +1,159 @@ +import { TestBed, type ComponentFixture } from '@angular/core/testing'; +import type { DevframeRpcClient } from 'devframe/client'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { LeaksSection, type LeaksPage } from '../pages/leaks-section'; + +const NOW = 1_000_000; + +function page(extra: Partial = {}): LeaksPage { + return { + pageId: 'p1', + url: '/trips', + title: 'Trips', + at: NOW, + reportedAt: NOW, + support: { retention: true, effects: true, subscriptions: 'off', detached: true }, + navigations: 5, + totals: { components: 3, effects: 3, subscriptions: 0, destroyed: 3, collected: 4, dropped: 0 }, + components: [ + { id: 'c1', name: 'TripList', effects: 2, subscriptions: 0 }, + { id: 'c2', name: 'Banner', effects: 0, sharedEffects: 1, subscriptions: 0 }, + ], + destroyed: [ + { id: 'c9', name: 'TripCard', route: '/trips/7', destroyedAt: NOW - 60_000, navigations: 3 }, + { id: 'c10', name: 'TripMap', route: '/trips/8', destroyedAt: NOW - 1000, navigations: 0 }, + { + id: 'c11', + name: 'Cached', + route: '/a', + destroyedAt: NOW - 90_000, + navigations: 4, + detached: true, + }, + ], + subscriptions: [], + ...extra, + }; +} + +let fixture: ComponentFixture; +let rpcCall: ReturnType; +const host = () => fixture.nativeElement as HTMLElement; +const text = () => host().textContent!.replace(/\s+/g, ' '); +const button = (label: string) => + [...host().querySelectorAll('button')].find((b) => b.textContent?.trim().startsWith(label))!; + +async function show(report: LeaksPage | null) { + fixture.componentRef.setInput('report', report); + await fixture.whenStable(); +} + +describe('LeaksSection', () => { + beforeEach(() => { + rpcCall = vi.fn(() => Promise.resolve({ pages: 1 })); + const client = { scope: () => ({ rpc: { call: rpcCall } }) }; + fixture = TestBed.createComponent(LeaksSection); + fixture.componentRef.setInput('pageId', 'p1'); + fixture.componentRef.setInput('rpc', client as unknown as DevframeRpcClient); + fixture.componentRef.setInput('now', () => NOW); + }); + + afterEach(() => { + fixture?.destroy(); + TestBed.resetTestingModule(); + }); + + it('says when the page has not reported yet, with the track button disabled', async () => { + await show(null); + expect(text()).toContain('No leak data from this page yet'); + expect(button('Track subscriptions').disabled).toBe(true); + }); + + it('lists retained instances apart from recent and detached ones, and says it is a hint', async () => { + await show(page()); + const retained = host().querySelectorAll('.rows')[0]!; + expect(retained.textContent).toContain('TripCard'); + expect(retained.textContent).toContain('/trips/7'); + expect(retained.textContent).toContain('3 navigations ago'); + expect(retained.textContent).toContain('60 s old'); + expect(retained.textContent).not.toContain('TripMap'); + expect(text()).toContain('destroyed recently and not collected yet: TripMap'); + expect(text()).toContain('not destroyed (detached views, such as a route reuse cache): Cached'); + expect(text()).toContain('Memory panel'); + expect(text()).toContain('5 navigations · 1 still retained · 4 instances collected'); + // h2 then h3, never skipping a level. + expect(host().querySelector('h2')!.textContent).toContain('Leaks'); + expect(host().querySelectorAll('h3')).toHaveLength(3); + }); + + it('lists live effects, with the shared note, and selects or highlights a component', async () => { + await show(page()); + const shown: string[] = []; + const lit: (string | null)[] = []; + fixture.componentInstance.showComponent.subscribe((id) => shown.push(id)); + fixture.componentInstance.highlight.subscribe((id) => lit.push(id)); + const row = button('TripList'); + expect(row.textContent).toContain('2 effects'); + expect(button('Banner').textContent).toContain('0 effects, 1 shared'); + expect(text()).toContain('show as shared'); + row.dispatchEvent(new Event('mouseenter')); + row.click(); + row.dispatchEvent(new Event('mouseleave')); + expect(shown).toEqual(['c1']); + expect(lit).toEqual(['c1', null]); + }); + + it('starts and stops subscription tracking for its page and announces it', async () => { + await show(page()); + expect(text()).toContain('Off. Track subscriptions wraps Observable.prototype.subscribe'); + const track = button('Track subscriptions'); + expect(track.getAttribute('aria-pressed')).toBe('false'); + track.click(); + await fixture.whenStable(); + expect(rpcCall).toHaveBeenLastCalledWith('request-leak-tracking', { pageId: 'p1', on: true }); + expect(host().querySelector('[role="status"]')!.textContent).toContain( + 'Tracking subscriptions', + ); + + await show( + page({ + support: { retention: true, effects: true, subscriptions: 'on', instances: true }, + subscriptions: [ + { + name: 'TripCard', + instanceId: 'c9', + count: 2, + source: 'TripCard.ngOnInit (trip-card.ts:12:7)', + route: '/trips/7', + openedAt: NOW - 70_000, + reason: 'instance-destroyed', + }, + ], + }), + ); + expect(text()).toMatch(/TripCard\s*2 open\s*instance destroyed\s*TripCard\.ngOnInit/); + expect(text()).toContain('takeUntilDestroyed()'); + const stop = button('Stop tracking subscriptions'); + expect(stop.getAttribute('aria-pressed')).toBe('true'); + stop.click(); + await fixture.whenStable(); + expect(rpcCall).toHaveBeenLastCalledWith('request-leak-tracking', { pageId: 'p1', on: false }); + }); + + it('shows the unavailable states', async () => { + await show( + page({ + support: { retention: false, effects: false, subscriptions: 'unavailable' }, + components: [], + }), + ); + expect(text()).toContain('cannot track destroyed components'); + expect(text()).toContain('no RxJS the overlay can load'); + fixture.componentRef.setInput('angular', { + version: '19.2.0', + capabilities: { signalGraph: true }, + }); + await fixture.whenStable(); + expect(text()).toContain('The live signal graph needs Angular 20.1 or later'); + }); +}); diff --git a/app/src/app.ts b/app/src/app.ts index 6f7dfb40..5ed2728b 100644 --- a/app/src/app.ts +++ b/app/src/app.ts @@ -559,6 +559,7 @@ function readView(): View | null { } diff --git a/app/src/pages/cd-diagnosis.ts b/app/src/pages/cd-diagnosis.ts new file mode 100644 index 00000000..de11d85d --- /dev/null +++ b/app/src/pages/cd-diagnosis.ts @@ -0,0 +1,227 @@ +import { Component, computed, input } from '@angular/core'; +import { CD_CAUSE_KINDS, CD_CAUSE_LABEL, cdHints } from '@pangular-inspector/devtools/cd-data'; +import type { CdReport } from '@pangular-inspector/devtools/config'; + +const SHOWN = 10; + +/** What started a recording's cycles, zone.js dependents, wasted checks, inputs that break OnPush and hints. */ +@Component({ + selector: 'app-cd-diagnosis', + template: ` + @if (diagnosis(); as d) { +
+

Why it ran and what it wasted

+
+
+

What started the cycles

+ @if (!d.triggers) { +

+ The page has no Angular change detection scheduler the overlay could find (it needs + Angular 18 or later), so cycles have no cause. +

+ } @else if (causes().length) { + + + + + + + + + @for (row of causes(); track row.kind) { + + + + + } + +
TriggerCycles
{{ row.label }}{{ row.count }}
+ } @else { +

No cycle has a cause yet.

+ } +
+
+

Depends on zone.js

+ @if (zone().length) { + + + + + + + + + + @for (z of zone(); track z.name) { + + + + + + } + +
ComponentZone-only ticksAfter
{{ z.name }}{{ z.ticks }}{{ z.tasks?.join(', ') }}
+ } @else if (d.triggers) { +

{{ zoneNote() }}

+ } +
+
+

Wasted checks

+ @if (!d.waste) { +

The page can't watch DOM updates, so wasted checks are not counted.

+ } @else if (wasted().length) { + + + + + + + + + + + @for (c of wasted(); track c.name) { + + + + + + + } + +
ComponentRefreshedChanged nothingStrategy
{{ c.name }}{{ c.refreshed }}{{ c.unchanged }} ({{ share(c.unchanged, c.refreshed) }}){{ c.strategy ?? 'Unknown' }}
+ } @else { +

Every refreshed check changed something.

+ } + @if (inputs().length) { +

Inputs that break OnPush

+ + + + + + + + + + + @for (i of inputs(); track i.name + '.' + i.input) { + + + + + + + } + +
InputSet byChanged in placeSame contents, new reference
{{ i.name }}.{{ i.input }}{{ i.parent ?? 'Unknown' }}{{ i.inPlace }}{{ i.sameContents }}
+ } + @if (hints().length) { +

Hints

+
    + @for (hint of hints(); track $index) { +
  • {{ hint.text }}
  • + } +
+ } +
+ } + `, + styles: ` + @use 'mixins' as m; + + :host { + display: block; + } + h3 { + @include m.label; + margin: 16px 0 6px; + } + h4 { + margin: 12px 0 6px; + color: var(--text-2); + font-size: 12px; + font-weight: 600; + } + .grid { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 0 16px; + } + @media (min-width: 880px) { + .grid { + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + } + } + table { + width: 100%; + border-collapse: collapse; + font-size: 12px; + } + th, + td { + padding: 4px 6px; + border-bottom: 1px solid var(--border); + text-align: left; + } + th { + color: var(--text-2); + font-weight: 500; + } + td.mono { + overflow-wrap: anywhere; + } + .num { + text-align: right; + font-variant-numeric: tabular-nums; + } + .mono { + font-family: var(--font-mono); + } + .note { + margin: 4px 0 8px; + color: var(--text-2); + font-size: 12px; + line-height: 1.5; + } + .hints { + margin: 0; + padding-left: 18px; + color: var(--text); + font-size: 12px; + line-height: 1.5; + } + .hints li + li { + margin-top: 4px; + } + `, +}) +export class CdDiagnosis { + readonly page = input(null); + + readonly diagnosis = computed(() => this.page()?.diagnosis ?? null); + readonly causes = computed(() => { + const counts = this.diagnosis()?.causes ?? {}; + return CD_CAUSE_KINDS.filter((kind) => counts[kind]).map((kind) => ({ + kind, + label: CD_CAUSE_LABEL[kind], + count: counts[kind]!, + })); + }); + readonly zone = computed(() => (this.diagnosis()?.zone ?? []).slice(0, SHOWN)); + readonly zoneNote = computed(() => { + const ticks = this.diagnosis()?.causes.zone ?? 0; + return ticks + ? `${ticks} ${ticks === 1 ? 'tick' : 'ticks'} came from zone.js alone, and no component changed in them.` + : 'No component changed in a tick only zone.js started.'; + }); + readonly wasted = computed(() => + (this.diagnosis()?.components ?? []).filter((c) => c.unchanged > 0).slice(0, SHOWN), + ); + readonly inputs = computed(() => (this.diagnosis()?.inputs ?? []).slice(0, SHOWN)); + readonly hints = computed(() => cdHints(this.diagnosis() ?? undefined).slice(0, SHOWN)); + + protected share(part: number, whole: number): string { + return whole ? `${Math.round((part / whole) * 100)}%` : '0%'; + } +} diff --git a/app/src/pages/cd-recording.ts b/app/src/pages/cd-recording.ts index 838e8fdd..63c5d716 100644 --- a/app/src/pages/cd-recording.ts +++ b/app/src/pages/cd-recording.ts @@ -7,7 +7,10 @@ import { rpcCall as call } from '../rpc'; import { LimitNote } from '../ui/limit-note'; import { AngularUnavailable } from '../ui/angular-unavailable'; import { angularPageFor, injectAngularPages } from '../angular-pages'; +import { cdCauseText } from '@pangular-inspector/devtools/cd-data'; +import type { CdCause } from '@pangular-inspector/devtools/config'; import { aggregateComponents, cyclesInRange, type CdRange } from './cd-chart-data'; +import { CdDiagnosis } from './cd-diagnosis'; import { CdCycleChart } from './cd-cycle-chart'; import { CdFlameGraph } from './cd-flame-graph'; import { CdTiming } from './cd-timing'; @@ -28,6 +31,7 @@ const SHOWN_CYCLES = 30; AngularUnavailable, LimitNote, CdTiming, + CdDiagnosis, CdTransfer, CdCycleChart, CdFlameGraph, @@ -63,8 +67,10 @@ const SHOWN_CYCLES = 30; }

Records each change detection cycle with Angular's profiler: how long it took, how many - components it checked and the output that ran before it. Tree rows show how often each - instance was checked. Times come from a development build. + components it checked, what started it and which checks changed nothing. Tree rows show how + often each instance was checked. Times come from a development build. While it records, the + page also wraps Angular's scheduler, adds a signal write hook and watches DOM updates; all + of it stops with the recording.

@if (page()?.supported === false) { @@ -200,11 +206,18 @@ const SHOWN_CYCLES = 30; {{ cycle.passes }} {{ cycle.passes === 1 ? 'pass' : 'passes' }}
- @if (cycle.trigger) { + @if (cycle.cause; as cause) { + from {{ causeText(cause) }} + } @else if (cycle.trigger) { after {{ cycle.trigger }} } + @if (cycle.unchanged) { + {{ cycle.unchanged }} changed nothing + } @if (cycle.hookMs) { hooks {{ ms(cycle.hookMs) }} } @@ -222,6 +235,7 @@ const SHOWN_CYCLES = 30;
+ } @else if (recording()) {

Use the app. Cycles show up here as Angular runs change detection.

} @@ -488,6 +502,10 @@ export class CdRecording { return time(at); } + protected causeText(cause: CdCause): string { + return cdCauseText(cause); + } + async toggle() { if (this.recording()) { await this.send({ on: false }, '', () => { diff --git a/app/src/pages/component-tree.ts b/app/src/pages/component-tree.ts index 024dac0c..4beed86c 100644 --- a/app/src/pages/component-tree.ts +++ b/app/src/pages/component-tree.ts @@ -48,6 +48,7 @@ import { ValueStore } from './component-value-store'; import { nestedMatches } from './component-value-state'; import { StoreGlobal } from '../ui/store-global'; import { ForBlocksSection, type ForBlock } from './for-blocks-section'; +import { LeaksSection, type LeaksPage } from './leaks-section'; import { VirtualWindow } from '../ui/virtual-window'; interface SourceComponent { @@ -201,6 +202,7 @@ function storedDirectiveHosts(): boolean { StoreGlobal, ForBlocksSection, HydrationSection, + LeaksSection, AngularUnavailable, ], host: { '(keydown.escape)': 'cancelPick()' }, @@ -807,6 +809,14 @@ function storedDirectiveHosts(): boolean { [rpc]="rpc()" (showComponent)="showCdComponent($event)" /> + } } @else { @if (page()) { @@ -1787,6 +1797,13 @@ export class ComponentTree { }); readonly cdHosts = computed(() => this.cdPage()?.hosts ?? {}); + private readonly leaksPages = signal>({}); + /** The shown page's leak report, from the `leaks` shared state. */ + readonly leaksPage = computed(() => { + const pageId = this.page()?.pageId; + return pageId ? (this.leaksPages()[pageId] ?? null) : null; + }); + /** The page's tree, without directive hosts when this viewer hid them. */ private readonly visibleRoots = computed(() => { const roots = this.page()?.roots ?? []; @@ -2128,6 +2145,18 @@ export class ComponentTree { } catch { this.cdPages.set({}); } + try { + const leaks = await my.rpc.sharedState('leaks'); + if (this.destroyRef.destroyed) return; + const applyLeaks = (value: unknown) => { + const pages = (value as { pages?: Record } | null)?.pages; + this.leaksPages.set(pages && typeof pages === 'object' ? pages : {}); + }; + applyLeaks(leaks.value()); + this.cleanups.push(leaks.on('updated', applyLeaks)); + } catch { + this.leaksPages.set({}); + } try { const router = await my.rpc.sharedState('router'); if (this.destroyRef.destroyed) return; diff --git a/app/src/pages/error-explain.ts b/app/src/pages/error-explain.ts new file mode 100644 index 00000000..baaeb2a6 --- /dev/null +++ b/app/src/pages/error-explain.ts @@ -0,0 +1,486 @@ +import { Component, computed, input, signal } from '@angular/core'; +import type { DevframeRpcClient } from 'devframe/client'; +import { time } from '../format'; +import { + codeSegments, + type ErrorExplain, + type ErrorOwner, + type InjectionExplanation, + type InjectionStep, +} from './errors-types'; + +const STEP_LABEL: Record = { + provides: 'Provides it', + missing: 'Not provided', + hidden: 'Hidden', + skipped: 'Skipped', + 'not-asked': 'Not asked', + unknown: 'Unknown', +}; + +const STEP_TONE: Record = { + provides: 'ok', + missing: 'plain', + hidden: 'warn', + skipped: 'plain', + 'not-asked': 'plain', + unknown: 'warn', +}; + +/** + * The explainer under an error in the Errors tab: what changed for an NG0100, + * the server vs client DOM diff of a hydration mismatch, and the token of a + * missing provider with an Explain lookup button that walks its injectors. + */ +@Component({ + selector: 'app-error-explain', + template: ` + @switch (explain().kind) { + @case ('expression-changed') { + @if (changed(); as e) { +

What changed

+
+
Binding
+
+ @if (e.binding) { + {{ e.binding }} + } @else { + A text interpolation (Angular doesn't name it) + } + @if (e.template) { + in {{ e.template }} + } +
+
Previous
+
+ {{ e.previous }} +
+
Current
+
+ {{ e.current }} +
+ @if (e.members?.length) { +
Held by
+
+ @for (member of e.members; track member; let last = $last) { + {{ member }}{{ last ? '' : ', ' }} + } +
+ } +
+ @if (e.masked) { +

+ Values are hidden: the binding or a field that holds them has a secret-looking name. +

+ } + @if (e.creation) { +

+ Angular says this view was created after its parent was checked, so a change detection + hook such as ngAfterViewInit created it. +

+ } + @if (e.writes?.length) { +

Written by

+
    + @for (write of e.writes; track write.signal + write.at) { +
  • + Signal {{ write.signal }} at {{ time(write.at) }} + @if (write.stack?.length) { +
      + @for (frame of write.stack; track $index) { +
    1. + {{ frame }} +
    2. + } +
    + } @else { + + (turn on write stacks in the Signals tab and reproduce to see the code) + } +
  • + } +
+ } @else if (e.writesKnown) { +

+ No named signal was written with this value just before the check. Look for code that + sets a field the template reads during change detection, such as + ngAfterViewInit, a getter that returns a new value each time, or a child + that changes its parent. +

+ } @else { +

+ Where it was written is unknown: the page doesn't report signal writes (the Signals + inspector is off, or Angular is older than 17). +

+ } + } + } + @case ('hydration-mismatch') { + @if (mismatch(); as m) { +

Server vs client DOM

+ @if (m.summary) { +

{{ m.summary }}

+ } + @if (m.diff?.length) { +

+ server HTML Angular expected + client DOM it found +

+
+
    + @for (line of m.diff; track $index) { +
  1. + + @if (line.op !== 'same') { + {{ + line.op === 'expected' ? 'Server only:' : 'Client only:' + }} + } + {{ line.text }} +
  2. + } +
+
+ } @else { +

Angular described neither side of the mismatch.

+ } + @if (m.external) { +

+ Angular thinks a browser extension or third-party script changed the DOM before + hydration. Try a clean browser profile, or add ngSkipHydration to the + host. +

+ } + } + } + @case ('missing-provider') { + @if (missing(); as p) { +

Missing provider

+
+
Token
+
+ {{ p.token }} +
+ @if (p.path?.length) { +
Path
+
+ @for (name of p.path; track $index; let last = $last) { + {{ name }}{{ last ? '' : ' → ' }} + } +
+ } + @if (p.source) { +
Source
+
+ {{ p.source }} +
+ } +
+ @if (canExplain() && owner()) { + + } @else if (!owner()) { +

+ The component that asked for it wasn't found on the page, so the lookup can't be + walked from here. +

+ } +
+ @if (loading()) { +

Walking the lookup…

+ } @else if (lookupError(); as error) { + + } @else if (lookup(); as l) { +

+ @for (part of segments(l.summary); track $index) { + @if (part.code) { + {{ part.text }} + } @else { + {{ part.text }} + } + } +

+
    + @for (step of l.steps; track step.id + $index) { +
  1. + + {{ step.name }} + @if (step.component) { + {{ step.component }} + } + + {{ + stepLabel[step.status] + }} + + @for (part of segments(step.reason); track $index) { + @if (part.code) { + {{ part.text }} + } @else { + {{ part.text }} + } + } + +
  2. + } +
+

+ Read from the injector tree the page reported, assuming no self, + skipSelf, host or optional. Agents can pass + those to explain-injection. + @if (l.approximate) { + This Angular version has no resolution path, so the path follows the rendered + tree. + } +

+ } +
+ } + } + } + `, + styles: ` + @use 'mixins' as m; + :host { + display: grid; + gap: 6px; + min-width: 0; + padding: 8px 10px; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--bg); + font-size: 12px; + } + .label { + @include m.label; + margin: 0; + } + code { + font-family: var(--font-mono); + font-size: 12px; + overflow-wrap: anywhere; + } + .muted { + color: var(--text-2); + } + .facts { + display: grid; + grid-template-columns: max-content minmax(0, 1fr); + gap: 4px 12px; + margin: 0; + } + dt { + color: var(--text-2); + } + dd { + min-width: 0; + margin: 0; + } + .value { + white-space: pre-wrap; + } + .note, + .summary, + .legend { + margin: 0; + color: var(--text-2); + line-height: 1.5; + } + .summary { + color: var(--text); + } + .writes, + .frames { + margin: 0; + padding-left: 18px; + } + .diff-wrap { + max-height: 280px; + overflow: auto; + border-radius: var(--radius-sm); + border: 1px solid var(--border); + } + .diff-wrap:focus-visible { + @include m.focus-ring(-2px); + } + .diff { + min-width: max-content; + margin: 0; + padding: 4px 0; + list-style: none; + } + .diff li { + display: flex; + gap: 8px; + padding: 0 8px; + white-space: pre; + } + .diff code { + overflow-wrap: normal; + } + .diff li[data-op='expected'] { + @include m.tint(danger); + } + .diff li[data-op='actual'] { + @include m.tint(ok); + } + .sign { + flex-shrink: 0; + width: 1ch; + font-family: var(--font-mono); + font-weight: 700; + } + .legend .sign { + display: inline-block; + text-align: center; + } + .legend .sign.expected { + color: var(--danger-text); + } + .legend .sign.actual { + color: var(--ok-text); + } + .small { + justify-self: start; + height: var(--control-h); + padding: 0 12px; + border: 1px solid var(--border-strong); + border-radius: var(--radius-sm); + background: var(--surface-2); + color: var(--text); + font: inherit; + cursor: pointer; + } + .small:hover { + background: var(--surface-3); + } + .small:disabled { + cursor: progress; + } + .small:focus-visible { + @include m.focus-ring; + } + .steps { + display: grid; + gap: 4px; + margin: 0; + padding-left: 22px; + } + .steps li { + padding: 2px 0; + } + .step-name { + display: inline-flex; + flex-wrap: wrap; + gap: 6px; + margin-right: 6px; + } + .reason { + display: block; + color: var(--text-2); + line-height: 1.5; + } + .chip { + display: inline-flex; + align-items: center; + padding: 0 8px; + border: 1px solid transparent; + border-radius: 99px; + font-size: 11px; + font-weight: 600; + } + .chip[data-tone='ok'] { + @include m.tint(ok); + } + .chip[data-tone='warn'] { + @include m.tint(warn); + } + .chip[data-tone='plain'] { + border-color: var(--border); + background: var(--surface-2); + color: var(--text-2); + } + `, +}) +export class ErrorExplainView { + readonly explain = input.required(); + readonly owner = input(undefined); + readonly pageId = input(''); + readonly rpc = input(null); + /** Whether the Injectors inspector is on, so the lookup can be walked. */ + readonly canExplain = input(false); + + protected readonly time = time; + protected readonly segments = codeSegments; + protected readonly stepLabel = STEP_LABEL; + protected readonly stepTone = STEP_TONE; + + protected readonly changed = computed(() => { + const e = this.explain(); + return e.kind === 'expression-changed' ? e : null; + }); + protected readonly mismatch = computed(() => { + const e = this.explain(); + return e.kind === 'hydration-mismatch' ? e : null; + }); + protected readonly missing = computed(() => { + const e = this.explain(); + return e.kind === 'missing-provider' ? e : null; + }); + + readonly loading = signal(false); + readonly lookup = signal(null); + readonly lookupError = signal(null); + + signOf(op: 'same' | 'expected' | 'actual'): string { + return op === 'expected' ? '−' : op === 'actual' ? '+' : ' '; + } + + async explainLookup(token: string) { + const client = this.rpc(); + const owner = this.owner(); + if (!client || !owner) return; + this.loading.set(true); + this.lookupError.set(null); + try { + const answer = (await client.scope('pangular').rpc.call('explain-injection', { + selector: owner.id, + token, + pageId: this.pageId(), + } as never)) as InjectionExplanation | { error: string } | null; + if (!answer || 'error' in answer) { + this.lookup.set(null); + this.lookupError.set(answer?.error ?? "The server didn't answer."); + } else { + this.lookup.set(answer); + } + } catch { + this.lookup.set(null); + this.lookupError.set("Can't reach the devtools server. Try again."); + } finally { + this.loading.set(false); + } + } +} diff --git a/app/src/pages/errors-inspector.ts b/app/src/pages/errors-inspector.ts index 81245867..82c0f7e6 100644 --- a/app/src/pages/errors-inspector.ts +++ b/app/src/pages/errors-inspector.ts @@ -13,6 +13,7 @@ import type { DevframeRpcClient } from 'devframe/client'; import { time } from '../format'; import { hostPageId } from '../page-id'; import { Select, type SelectOption } from '../ui/select'; +import { ErrorExplainView } from './error-explain'; import type { ComponentFocus } from '../types/component-focus.types'; import { ALL_PAGES, @@ -39,7 +40,7 @@ const LEVEL_TONE: Record = { @Component({ selector: 'app-errors-inspector', - imports: [Select], + imports: [Select, ErrorExplainView], template: ` @if (!loaded()) {

Loading errors…

@@ -193,6 +194,15 @@ const LEVEL_TONE: Record = { } } + @if (error.explain; as explain) { + + } @if (error.stack) {
Stack @@ -537,6 +547,8 @@ export class ErrorsInspector { readonly rpc = input(null); /** Whether the Components tab is on, so "Show component" has somewhere to go. */ readonly canShowComponent = input(true); + /** Whether the Injectors tab is on, so a missing provider can walk its lookup. */ + readonly canExplainInjection = input(false); readonly showComponent = output(); private readonly destroyRef = inject(DestroyRef); diff --git a/app/src/pages/errors-types.ts b/app/src/pages/errors-types.ts index 52268ca6..559d4793 100644 --- a/app/src/pages/errors-types.ts +++ b/app/src/pages/errors-types.ts @@ -10,6 +10,65 @@ export interface ErrorOwner { name: string; } +/** One line of the server vs client DOM diff the server builds for a hydration mismatch. */ +export interface DiffLine { + op: 'same' | 'expected' | 'actual'; + text: string; +} + +/** What the page read about an NG0100, a hydration mismatch or a missing provider. */ +export type ErrorExplain = + | { + kind: 'expression-changed'; + binding?: string; + template?: string; + previous: string; + current: string; + masked?: boolean; + creation?: boolean; + members?: string[]; + writes?: { signal: string; at: number; stack?: string[] }[]; + writesKnown?: boolean; + } + | { + kind: 'hydration-mismatch'; + summary?: string; + expected?: string; + actual?: string; + external?: boolean; + diff?: DiffLine[]; + } + | { kind: 'missing-provider'; token: string; path?: string[]; source?: string }; + +/** One injector of an `explain-injection` answer. */ +export interface InjectionStep { + id: string; + name: string; + type: 'element' | 'environment' | 'null'; + component?: string; + status: 'provides' | 'missing' | 'hidden' | 'skipped' | 'not-asked' | 'unknown'; + reason: string; +} + +/** The `explain-injection` RPC answer: the lookup path of a token, step by step. */ +export interface InjectionExplanation { + pageId: string; + token: string; + flags: string[]; + steps: InjectionStep[]; + outcome: 'resolved' | 'null' | 'error' | 'unknown'; + summary: string; + approximate?: boolean; +} + +/** Text with `code` spans, split so a template can render them as ``. */ +export function codeSegments(text: string): { code: boolean; text: string }[] { + return text + .split('`') + .map((part, index) => ({ code: index % 2 === 1, text: part })) + .filter((part) => part.text); +} + export interface ErrorGroup { id: string; message: string; @@ -22,6 +81,7 @@ export interface ErrorGroup { sources: ('handler' | 'window' | 'promise')[]; stack?: string; owner?: ErrorOwner; + explain?: ErrorExplain; } export interface ConsoleEntry { diff --git a/app/src/pages/leaks-section.ts b/app/src/pages/leaks-section.ts new file mode 100644 index 00000000..76fef687 --- /dev/null +++ b/app/src/pages/leaks-section.ts @@ -0,0 +1,472 @@ +import { Component, computed, input, output, signal } from '@angular/core'; +import { + RETAINED_AFTER_MS, + RETAINED_AFTER_NAVIGATIONS, + type AngularPageInfo, +} from '@pangular-inspector/devtools/config'; +import type { DevframeRpcClient } from 'devframe/client'; +import { rpcCall } from '../rpc'; +import { AngularUnavailable } from '../ui/angular-unavailable'; + +/** A component on the page with its live effects and tracked subscriptions. */ +export interface LeakComponent { + id: string; + name: string; + effects: number; + sharedEffects?: number; + subscriptions: number; +} + +/** A component instance that left the page and was not collected yet. */ +export interface LeakDestroyed { + id: string; + name: string; + route: string; + destroyedAt: number; + navigations: number; + detached?: boolean; + subscriptions?: number; +} + +/** Subscriptions still open after the component that made them went away. */ +export interface LeakSubscription { + name: string; + instanceId?: string; + count: number; + source?: string; + route: string; + openedAt: number; + reason: 'instance-destroyed' | 'no-live-instance'; +} + +/** One page's leak report, as the `leaks` shared state holds it. */ +export interface LeaksPage { + pageId: string; + url: string; + title: string; + at: number; + reportedAt: number; + support: { + retention: boolean; + effects: boolean; + subscriptions: 'off' | 'on' | 'unavailable'; + instances?: boolean; + detached?: boolean; + }; + navigations: number; + totals: { + components: number; + effects: number; + subscriptions: number; + destroyed: number; + collected: number; + dropped: number; + }; + components: LeakComponent[]; + destroyed: LeakDestroyed[]; + subscriptions: LeakSubscription[]; +} + +const SHOWN = 20; + +function age(ms: number): string { + const seconds = Math.max(0, Math.round(ms / 1000)); + if (seconds < 120) return `${seconds} s`; + const minutes = Math.round(seconds / 60); + return minutes < 120 ? `${minutes} min` : `${Math.round(minutes / 60)} h`; +} + +const plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`; + +/** + * Leak hints on the Components page: instances destroyed but still in memory + * after a few navigations, subscriptions still open after their component went + * away (while tracking is on), and live effects and subscriptions per component. + */ +@Component({ + selector: 'app-leaks-section', + imports: [AngularUnavailable], + template: ` +
+
+

Leaks

+ +

{{ announcement() }}

+
+

+ Components that left the page but are still in memory, and the live effects and RxJS + subscriptions of each component. The browser collects garbage when it decides, so a retained + instance is a hint: check what holds it in the Chrome DevTools Memory panel. +

+ + @if (report(); as page) { + @if (!page.support.retention) { +

+ This page cannot track destroyed components. It needs WeakRef, FinalizationRegistry and + the Angular debug API of a development build. +

+ } +

+ {{ plural(page.navigations, 'navigation') }} · {{ retained().length }} still retained · + {{ plural(page.totals.collected, 'instance') }} collected +

+ +

+ Still retained + {{ retained().length }} +

+ @if (retained().length) { +

+ Destroyed, yet still in memory after at least {{ minNavigations }} navigations and + {{ minSeconds }} seconds. Take a heap snapshot, search for the class and read its + retainers. +

+
    + @for (item of retained().slice(0, shown); track item.id) { +
  • + {{ item.name }} + {{ item.route || '/' }} + {{ plural(item.navigations, 'navigation') }} ago + {{ ageOf(item) }} + @if (item.subscriptions) { + {{ + plural(item.subscriptions, 'open subscription') + }} + } +
  • + } +
+ } @else { +

No destroyed component is still in memory after a few navigations.

+ } + @if (recent().length) { +

+ {{ plural(recent().length, 'instance') }} destroyed recently and not collected yet: + {{ names(recent()) }}. Navigate a few times to see whether they stay. +

+ } + @if (detached().length) { +

+ Off the page but not destroyed (detached views, such as a route reuse cache): + {{ names(detached()) }}. +

+ } + +

+ Open subscriptions after destroy + @if (page.support.subscriptions === 'on') { + {{ page.subscriptions.length }} + } +

+ @switch (page.support.subscriptions) { + @case ('on') { + @if (page.subscriptions.length) { +

+ Still open although the component that made them is gone. Tear them down with + takeUntilDestroyed(), DestroyRef.onDestroy or the async pipe. +

+
    + @for (sub of page.subscriptions.slice(0, shown); track $index) { +
  • + {{ sub.name }} + {{ sub.count }} open + + {{ + sub.reason === 'instance-destroyed' + ? 'instance destroyed' + : 'no instance left' + }} + + @if (sub.source) { + {{ sub.source }} + } +
  • + } +
+ } @else { +

No subscription is still open after its component went away.

+ } + @if (!page.support.instances) { +

+ Subscriptions are tied to component classes only; Angular 20 profiler hooks tie them + to instances. +

+ } + } + @case ('unavailable') { +

+ Tracking could not start: the page has no RxJS the overlay can load. +

+ } + @default { +

+ Off. Track subscriptions wraps Observable.prototype.subscribe on the page to record + which component makes each subscription, until you stop it. Subscriptions made before + you start are not seen, so reload or navigate again after starting. +

+ } + } + +

+ Live effects and subscriptions + {{ page.components.length }} +

+ @if (!page.support.effects) { + + } + @if (page.components.length) { +
    + @for (item of page.components.slice(0, shown); track item.id) { +
  • + +
  • + } +
+ @if (page.components.some(hasShared)) { +

+ Angular files a component's effects under the template its host sits in, so effects of + components side by side in one template show as shared. +

+ } + } @else { +

No component on the page has a live effect or a tracked subscription.

+ } + } @else { +

No leak data from this page yet. It comes with the next report.

+ } +
+ `, + styles: ` + @use 'mixins' as m; + + :host { + display: block; + } + .leaks { + margin-top: 16px; + } + .head { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + } + h2 { + @include m.label; + margin: 0; + } + .track { + height: var(--control-h); + } + .track[aria-pressed='true'] { + @include m.tint(accent); + } + .track:focus-visible { + @include m.focus-ring; + } + .hint, + .note, + .stats { + margin: 8px 0; + color: var(--text-2); + font-size: 12px; + line-height: 1.5; + } + .stats { + color: var(--text); + } + .sub { + display: flex; + align-items: center; + gap: 6px; + margin: 14px 0 6px; + color: var(--text-strong); + font-size: 12px; + font-weight: 600; + } + .pill { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 18px; + height: 16px; + padding: 0 5px; + border-radius: 99px; + background: var(--surface-3); + color: var(--text-2); + font-size: 10px; + font-weight: 600; + } + .rows { + display: grid; + gap: 6px; + margin: 0; + padding: 0; + list-style: none; + } + .row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; + min-height: var(--control-h); + padding: 6px 12px; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--surface); + font-size: 12px; + } + .row.live { + justify-content: flex-start; + width: 100%; + height: auto; + text-align: left; + } + .row.live:focus-visible { + @include m.focus-ring; + } + .name { + min-width: 0; + color: var(--text-strong); + font-weight: 600; + @include m.truncate; + } + .mono { + font-family: var(--font-mono); + } + .meta { + min-width: 0; + color: var(--text-2); + @include m.truncate; + } + .count { + padding: 0 8px; + border-radius: 99px; + background: var(--surface-3); + color: var(--text-2); + font-size: 11px; + line-height: 18px; + } + .flag { + padding: 0 6px; + border-radius: 5px; + font-size: 11px; + line-height: 18px; + } + .flag.warn { + @include m.tint(warn); + } + `, +}) +export class LeaksSection { + /** The page's leak report, or `null` before its first one. */ + readonly report = input(null); + readonly pageId = input(null); + readonly rpc = input(null); + /** The page's Angular version, which the unavailable note names. */ + readonly angular = input(null); + /** Clock for ages; a test passes its own. */ + readonly now = input<() => number>(() => Date.now()); + /** Selects a component in the tree, by its id. */ + readonly showComponent = output(); + /** The element to highlight in the app, or `null` to clear it. */ + readonly highlight = output(); + + protected readonly shown = SHOWN; + protected readonly minNavigations = RETAINED_AFTER_NAVIGATIONS; + protected readonly minSeconds = RETAINED_AFTER_MS / 1000; + protected readonly plural = plural; + protected readonly busy = signal(false); + protected readonly announcement = signal(''); + + protected readonly tracking = computed(() => this.report()?.support.subscriptions === 'on'); + + private readonly split = computed(() => { + const page = this.report(); + const retained: LeakDestroyed[] = []; + const recent: LeakDestroyed[] = []; + const detached: LeakDestroyed[] = []; + if (!page) return { retained, recent, detached }; + for (const item of page.destroyed) { + if (item.detached) detached.push(item); + else if (this.isRetained(page, item)) retained.push(item); + else recent.push(item); + } + return { retained, recent, detached }; + }); + protected readonly retained = computed(() => this.split().retained); + protected readonly recent = computed(() => this.split().recent); + protected readonly detached = computed(() => this.split().detached); + + private ageMs(page: LeaksPage, item: LeakDestroyed): number { + return Math.max(0, this.now()() - page.reportedAt + (page.at - item.destroyedAt)); + } + + private isRetained(page: LeaksPage, item: LeakDestroyed): boolean { + return ( + item.navigations >= RETAINED_AFTER_NAVIGATIONS && this.ageMs(page, item) >= RETAINED_AFTER_MS + ); + } + + protected ageOf(item: LeakDestroyed): string { + const page = this.report(); + return page ? `${age(this.ageMs(page, item))} old` : ''; + } + + protected names(items: LeakDestroyed[]): string { + const names = [...new Set(items.map((item) => item.name))]; + return names.length > 6 ? `${names.slice(0, 6).join(', ')} and more` : names.join(', '); + } + + protected hasShared(item: LeakComponent): boolean { + return !!item.sharedEffects; + } + + protected effectsText(item: LeakComponent): string { + const own = plural(item.effects, 'effect'); + return item.sharedEffects ? `${own}, ${item.sharedEffects} shared` : own; + } + + async toggle() { + const pageId = this.pageId(); + if (!pageId || this.busy()) return; + const on = !this.tracking(); + this.busy.set(true); + try { + await rpcCall(this.rpc(), 'request-leak-tracking', { pageId, on }); + this.announcement.set( + on + ? 'Tracking subscriptions. Reload or navigate to see subscriptions made at start.' + : 'Stopped tracking subscriptions.', + ); + } catch { + this.announcement.set('Could not reach the page. Try again.'); + } finally { + this.busy.set(false); + } + } +} diff --git a/apps/docs/src/content/agents/mcp-server.md b/apps/docs/src/content/agents/mcp-server.md index 4d39a43b..5358a06d 100644 --- a/apps/docs/src/content/agents/mcp-server.md +++ b/apps/docs/src/content/agents/mcp-server.md @@ -247,7 +247,7 @@ The server registers tools with a colon, as `pangular:get-routes`. MCP clients s ### Read and action tools -Each tool has a safety tier: `read`, `action` or `destructive`. The server marks `read` tools as read-only for your client, and `destructive` tools as destructive. Thirteen tools act on the app, so the server does not mark them read-only: +Each tool has a safety tier: `read`, `action` or `destructive`. The server marks `read` tools as read-only for your client, and `destructive` tools as destructive. Fourteen tools act on the app, so the server does not mark them read-only: | Tool | Tier | Reference | | ------------------------ | ------------- | ----------------------------------------------------- | @@ -261,6 +261,7 @@ Each tool has a safety tier: `read`, `action` or `destructive`. The server marks | `set-signal` | `action` | [Edit a component](./tools.md#edit-a-component) | | `watch-signal` | `action` | [watch-signal](./tools.md#watch-signal) | | `record-pipes` | `action` | [Record pipe calls](./tools.md#record-pipe-calls) | +| `track-subscriptions` | `action` | [Track subscriptions](./tools.md#track-subscriptions) | | `change-detection` | `action` | [change-detection](./tools.md#change-detection) | | `clear-recordings` | `destructive` | [Clear recordings](./tools.md#clear-recordings) | | `analog-call-api` | `destructive` | [Call a server route](./tools.md#call-a-server-route) | diff --git a/apps/docs/src/content/agents/resources.md b/apps/docs/src/content/agents/resources.md index a68346db..9b444703 100644 --- a/apps/docs/src/content/agents/resources.md +++ b/apps/docs/src/content/agents/resources.md @@ -88,15 +88,16 @@ The HTTP endpoint leaves out the keys of an inspector whose agent tools are hidd This table covers the data that has no resource of its own. -| Key | Content | -| --------------------------- | --------------------------------------------------------------------- | -| `pangular:http` | The SSR & HTTP timeline, SSR requests, fault rules and hydration data | -| `pangular:http-payloads` | The TransferState payload of each page, by page id | -| `pangular:change-detection` | Change detection recordings, by page id | -| `pangular:pipe-usage` | Live pipe instances and recorded calls | -| `pangular:errors` | Error groups and console calls, by page id | -| `pangular:analog` | Analog page data and the server call log | -| `pangular:routes` | Declared but not filled. Use `get-routes` or `list-routes` instead. | +| Key | Content | +| --------------------------- | ----------------------------------------------------------------------- | +| `pangular:http` | The SSR & HTTP timeline, SSR requests, fault rules and hydration data | +| `pangular:http-payloads` | The TransferState payload of each page, by page id | +| `pangular:change-detection` | Change detection recordings, by page id | +| `pangular:pipe-usage` | Live pipe instances and recorded calls | +| `pangular:errors` | Error groups and console calls, by page id | +| `pangular:leaks` | Leak hints: retained instances, open subscriptions, effects, by page id | +| `pangular:analog` | Analog page data and the server call log | +| `pangular:routes` | Declared but not filled. Use `get-routes` or `list-routes` instead. | The list also includes the keys behind the six resources above (`pangular:component-tree`, `pangular:forms`, and so on). diff --git a/apps/docs/src/content/agents/tools.md b/apps/docs/src/content/agents/tools.md index 72d3b0ff..5702b4ac 100644 --- a/apps/docs/src/content/agents/tools.md +++ b/apps/docs/src/content/agents/tools.md @@ -4,7 +4,7 @@ description: Every agent tool the devtools expose, grouped by inspector, with wh --- - Seventy-one tools, grouped by inspector. Each one answers a question you would otherwise answer by clicking through the panel. + Seventy-five tools, grouped by inspector. Each one answers a question you would otherwise answer by clicking through the panel. # Tools @@ -41,7 +41,7 @@ If `page` names a tab that doesn't report that data, the tool answers `No page < ### Older Angular versions -When the page's Angular lacks the debug API a tool needs, the tool answers **Unsupported on this Angular version** with the version the feature needs and the version the page runs, instead of an empty list. `inspect-signals`, `watch-signal`, `defer-blocks`, `for-blocks` and `change-detection` answer this way. `inspect-providers` puts the same note before a reduced tree. See [Supported Angular versions](../getting-started/installation.md#supported-angular-versions). +When the page's Angular lacks the debug API a tool needs, the tool answers **Unsupported on this Angular version** with the version the feature needs and the version the page runs, instead of an empty list. `inspect-signals`, `watch-signal`, `defer-blocks`, `for-blocks`, `change-detection` and `diagnose-change-detection` answer this way. `inspect-providers` puts the same note before a reduced tree. See [Supported Angular versions](../getting-started/installation.md#supported-angular-versions). ### list-pages @@ -65,11 +65,11 @@ The answer is a full URL, such as `http://localhost:4200/__devframes/pangular/#t Every tool has one of three safety tiers. The server sends the tier to your client as the tool's read-only and destructive hints. -| Tier | What the tool can do | Tools | -| ------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `read` | Reads your source, the page or the server. `highlight` only shows and selects a component. | Every other tool, and every resource | -| `action` | Changes the running page, the server's fault rules or what the page records. A reload or the next call undoes it. | `navigate`, `dispatch-ngrx-action`, `form-action`, `fill-form`, `set-http-rule`, `remove-http-rule`, `set-component-property`, `set-signal`, `watch-signal`, `record-pipes`, `change-detection` and `hydration` | -| `destructive` | Can lose data: it erases recordings, or sends writes to your own API routes. | `clear-recordings` and `analog-call-api` | +| Tier | What the tool can do | Tools | +| ------------- | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `read` | Reads your source, the page or the server. `highlight` only shows and selects a component. | Every other tool, and every resource | +| `action` | Changes the running page, the server's fault rules or what the page records. A reload or the next call undoes it. | `navigate`, `dispatch-ngrx-action`, `form-action`, `fill-form`, `set-http-rule`, `remove-http-rule`, `set-component-property`, `set-signal`, `watch-signal`, `record-pipes`, `track-subscriptions`, `change-detection` and `hydration` | +| `destructive` | Can lose data: it erases recordings, or sends writes to your own API routes. | `clear-recordings` and `analog-call-api` | The fourteen action and destructive tools act on the app. Your client can ask you before it runs them. @@ -182,7 +182,7 @@ Each page lists at most 50 blocks, with a note on how many more are not shown, a ### hydration Action -Hydration of each page that was rendered on the server: how many component hosts were hydrated, skipped with `ngSkipHydration`, mismatched or created on the client, and how many `@defer` blocks are still dehydrated. It names the skipped and client-created hosts and the dehydrated blocks, at most 30 of each, and each mismatch with what Angular expected and what it found. Reads: page. +Hydration of each page that was rendered on the server: how many component hosts were hydrated, skipped with `ngSkipHydration`, mismatched or created on the client, and how many `@defer` blocks are still dehydrated. It names the skipped and client-created hosts and the dehydrated blocks, at most 30 of each, and each mismatch with a line diff of the server HTML Angular expected (`-`) and the client DOM it found (`+`). Reads: page. | Argument | Required | Value | | --------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | @@ -210,6 +210,28 @@ Without `page`, it reads the page that is recording, and `record` goes to every `export` only reads, so it stays available with `agent.readOnly`. The file is masked like other answers (JWTs, bearer tokens and secret names), has no instance check counts, and comes in a `json` code block to save as a `.json` file. An export over 100,000 characters is not returned, because cut JSON doesn't parse. The answer gives its size and the counts of cycles, timed spans, component classes, hook rows and output rows instead. Export it from the panel then, or clear the recording and record a shorter session. See [Export and import a recording](../inspectors/components.md#export-and-import-a-recording). +Each cycle line also names what started the cycle and how many of its refreshed checks changed nothing, when the page reports them. See [diagnose-change-detection](#diagnose-change-detection). + +### diagnose-change-detection + +Why change detection ran and what it wasted, from the recording that `change-detection` or the panel started. Reads: page. Needs Angular 20 or later. + +| Argument | Required | Value | +| -------- | -------- | -------------------------------------- | +| `limit` | no | Rows per list. Default 10, at most 50. | + +Without `page`, it reads the page that is recording, like `change-detection`. The answer starts with the page's change detection mode, then has these parts: + +| Part | What it lists | +| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **What started the cycles** | Cycles per cause, then the latest causes: a DOM event with its type, target and listener component, a signal write with the signal's `debugName`, an HTTP response, a timer, `markForCheck`, `setInput`, an effect, a view change, `ApplicationRef.tick()` from app code, or a zone.js tick that nothing in Angular asked for. Causes from app code carry its first app frames. | +| **Components that depend on zone.js** | Components that changed in ticks only zone.js started, with the zone.js tasks behind them, such as `setTimeout`. Without zone.js these components would not update. | +| **Wasted checks** | Per component class, the refreshed checks where nothing it renders changed, and its change detection strategy. | +| **Inputs that break OnPush** | Inputs mutated in place (same reference, other contents) and inputs given a new reference with the same contents, with the component that set them. | +| **Hints** | OnPush for a class refreshed at least 10 times that changed something in under 20% of them, or a note that it is already OnPush, plus a line per input and per zone.js dependent above. | + +It only reads, so it stays with `agent.readOnly`. With no recording yet, it says to start one with `change-detection`. See [Why it ran and what it wasted](../inspectors/components.md#why-it-ran-and-what-it-wasted) for how the page finds causes and wasted checks. + ### Edit a component Action `set-component-property` and `set-signal` write a JSON value to one live component instance, in development only, and answer with the value it now holds, redacted like the component detail. Reads: page. @@ -235,6 +257,34 @@ Both tools refuse, and write nothing, when: A parent binding sets a bound input again the next time its own value changes. Only signals held as component properties can be set; the signals that `inspect-signals` lists elsewhere cannot. Set [`actions.components`](../getting-started/configuration.md#actions) to `false` to drop both tools. +### find-leaks + +Leak hints for one page, in three parts. Reads: page. + +| Part | What it lists | +| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Still retained** | Component instances destroyed but still in memory after at least 2 navigations and 10 seconds: class, instance id, the route they lived on, age, navigations since and open subscriptions. Detached views are named apart. | +| **Open subscriptions after destroy** | Subscriptions still open after the component that made them went away, grouped by class, instance and call site, with why each is flagged. Only while subscription tracking is on. | +| **Live effects and subscriptions** | Components with live effects (from `ng.ɵgetSignalGraph`, Angular 20.1 and later) or tracked open subscriptions, with instance ids for `inspect-component`. | + +| Argument | Required | Value | +| ----------- | -------- | -------------------------------------------------------- | +| `component` | no | Only classes whose name contains this text, in any case. | +| `limit` | no | Rows per table, 1 to 200. Defaults to 20. | + +Garbage collection runs when the browser decides, so the answer says "still retained" and points to the retainers in the Chrome Memory panel rather than calling it a leak. It also says what the page can't report: no `WeakRef` or debug API, no signal graph, or tracking off. Routes and call sites are masked like other live values. See [Leaks](../inspectors/components.md#leaks). + +### Track subscriptions Action + +`track-subscriptions` starts or stops subscription tracking on a page, the same switch as **Track subscriptions** in the Components panel. Reads: page. + +| Argument | Required | Value | +| -------- | -------- | ------------------------------------------------------------------------------------------ | +| `action` | yes | `start` or `stop`. | +| `page` | no | The tab to track. Defaults to the most recent page for `start`, and every page for `stop`. | + +While on, the overlay wraps `Observable.prototype.subscribe` and records which component made each subscription. `stop` puts `subscribe` back. Subscriptions made before tracking started are not seen, so reload the tab or go to the screen again after `start`, then call `find-leaks`. Tracking patches the page, so `track-subscriptions` is an `action` tool and `agent.readOnly` drops it. No action covers it, so `actions` leaves it in place. `agent.tools.components: false` hides both tools. + ### inspect-signals The signal graph the page reported: nodes (`signal`, `computed`, `linkedSignal`, `effect`), dependency edges, the component or injector they belong to, and recent value history per node. Reads: page. @@ -297,6 +347,21 @@ An element injector that belongs to a component carries `componentId`, the insta Without `selector` or `token`, the answer is the whole tree and says which change detection mode the page runs. The answer stays within 20,000 characters and its JSON always parses. A larger tree shows element injectors as an outline (id, name, type, component, and provider and dependency counts), and when that is still too long it leaves out the deepest injectors and says how many. The environment injectors are always there, as an outline when they are large, and without their deepest injectors when even that outline is too long. A `selector` or `token` answer that is too long keeps whole entries and says how many it shows. `selector` and `token` take at most 500 characters each. When the page reported only part of its injector tree (it keeps at most 2000 element injectors and 2500 in all, and leaves out injectors nested more than 1000 levels deep), the answer says so. +### explain-injection + +How Angular resolves one token for one component, element or environment injector: each injector on the lookup path in order, whether it provides the token and why the lookup stops. It reads the injector tree the page reported, so nothing is created or injected. See [Explain a lookup with flags](../inspectors/injectors.md#explain-a-lookup-with-flags). Reads: page. + +| Argument | Required | Value | +| ---------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `selector` | yes | Where the injection happens: a component or directive class name, a tag, a component instance id like `c12` (an error's owner id works), an injector id, or an environment injector name like `Root`. | +| `token` | yes | The token as the Injectors tab names it: a class name like `HttpClient` or an `InjectionToken` description like `API_URL`. | +| `self` | no | `true` asks only the first injector. | +| `skipSelf` | no | `true` starts at the parent injector. | +| `host` | no | `true` stops at the host element of the component that declares the start, where only its `viewProviders` and the component count. | +| `optional` | no | `true` ends in `null` instead of NG0201. | + +The answer is a table of steps: **provides it**, **not provided**, **hidden** (a `viewProviders` entry the lookup can't see), **skipped**, **not asked** or **unknown**. A `providedIn: 'root'` service counts as provided once something on the page got it. When a selector matches several injectors, the answer uses the first and lists the others. Before Angular 16.2 the path is rebuilt from the rendered tree and providers are unknown, and the answer says so. `selector` and `token` take at most 500 characters each. + ## NgRx Two tools read the live `@ngrx/signals` and `@ngrx/store` state a page reported. Reads: page. @@ -555,11 +620,13 @@ These tools read what a Capacitor app reported: its platform, its plugins and th These tools read what a page captured: errors from Angular's `ErrorHandler`, uncaught errors, unhandled promise rejections and console calls. See [Errors](../inspectors/errors.md). Reads: page. -| Tool | What it answers | Arguments | -| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | -| `list-errors` | Error groups, most recent first: id, count, when last seen, the Angular error code linked to its reference page, the message, the owning component with its instance id, and the source (`handler`, `window` or `promise`). | `code`, `limit` | -| `explain-error` | One error by `id`: message, count, sources, the owning component, the stack of the first occurrence, and for an Angular code its reference page and a short known cause. With `code` instead, the reference entry and the errors that carry it. | `id`, `code` | -| `list-console` | Console calls, newest first: when, level, the text of the arguments and the Angular code it mentions. Calls repeated in a row show once with a count. | `level`, `search`, `limit` | +| Tool | What it answers | Arguments | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | +| `list-errors` | Error groups, most recent first: id, count, when last seen, the Angular error code linked to its reference page, the message, the owning component with its instance id, and the source (`handler`, `window` or `promise`). | `code`, `limit` | +| `explain-error` | One error by `id`: message, count, sources, the owning component, the stack of the first occurrence, and for an Angular code its reference page and a short known cause. With `code` instead, the reference entry and the errors that carry it. An NG0100, a hydration mismatch or a missing provider adds its explainer. | `id`, `code` | +| `list-console` | Console calls, newest first: when, level, the text of the arguments and the Angular code it mentions. Calls repeated in a row show once with a count. | `level`, `search`, `limit` | + +The explainers are the ones the [Errors](../inspectors/errors.md#explainers) tab shows. For NG0100: the binding, the template function, the previous and current value, the component fields that hold the new value, and the named signals written with it just before the check, with the code that wrote them when write stacks are on. For NG0500 to NG0503: a diff of the server HTML Angular expected and the client DOM it found. For NG0201 and `NullInjectorError`: the token and Angular's dependency path, to pass to `explain-injection`. `code` accepts `NG0100`, `ng100` or `NG01203`. `explain-error` says so when Angular's error reference has no page for a code, and gives no known cause then. Pass the owner's instance id to `inspect-component` for its inputs and state. `list-errors` takes `limit` up to 100 (default 30), and `list-console` up to 200 (default 50). Messages, stacks and console text are masked like other live values. diff --git a/apps/docs/src/content/getting-started/configuration.md b/apps/docs/src/content/getting-started/configuration.md index b1574dac..555c3c43 100644 --- a/apps/docs/src/content/getting-started/configuration.md +++ b/apps/docs/src/content/getting-started/configuration.md @@ -125,11 +125,11 @@ interface PangularConfig { ### Inspectors and agent tools -| Option | Default | What it does | -| -------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `inspectors.` | `true` | `false` removes the inspector: no tab or dock, no page collector, no RPC functions, and no agent tools or resources. Its actions are blocked too. | -| `agent.readOnly` | `false` | `true` keeps only the agent tools in the `read` [safety tier](../agents/tools.md#action-tools). It drops `form-action`, `fill-form`, `navigate`, `dispatch-ngrx-action`, `set-http-rule`, `remove-http-rule`, `set-component-property`, `set-signal`, `record-pipes`, `analog-call-api` and `clear-recordings`. `change-detection` stays without its `record` argument. | -| `agent.tools.` | `true` | `false` hides one inspector's agent tools and resources, and its [shared-state keys](../agents/resources.md#shared-state) over HTTP MCP. The tab stays. | +| Option | Default | What it does | +| -------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `inspectors.` | `true` | `false` removes the inspector: no tab or dock, no page collector, no RPC functions, and no agent tools or resources. Its actions are blocked too. | +| `agent.readOnly` | `false` | `true` keeps only the agent tools in the `read` [safety tier](../agents/tools.md#action-tools). It drops `form-action`, `fill-form`, `navigate`, `dispatch-ngrx-action`, `set-http-rule`, `remove-http-rule`, `set-component-property`, `set-signal`, `record-pipes`, `track-subscriptions`, `analog-call-api` and `clear-recordings`. `change-detection` stays without its `record` argument. | +| `agent.tools.` | `true` | `false` hides one inspector's agent tools and resources, and its [shared-state keys](../agents/resources.md#shared-state) over HTTP MCP. The tab stays. | `agent.tools` has the same keys as `inspectors`. An inspector that is off has no agent tools, whatever `agent.tools` says. diff --git a/apps/docs/src/content/getting-started/installation.md b/apps/docs/src/content/getting-started/installation.md index 219c5073..f51632ce 100644 --- a/apps/docs/src/content/getting-started/installation.md +++ b/apps/docs/src/content/getting-started/installation.md @@ -38,6 +38,7 @@ When a tab needs a debug API the page doesn't have, it says which Angular versio | Feature | Needs Angular | | ------------------------------------------------------ | ------------- | | Live component tree, detail and values | 12.0 | +| Telling detached components from destroyed ones | 14.0 | | Injected services, providers and environment injectors | 16.2 | | Full injector tree with lookup paths | 17.0 | | Signal values in the component detail (`ng.isSignal`) | 17.1 | @@ -45,7 +46,8 @@ When a tab needs a debug API the page doesn't have, it says which Angular versio | The `@pangular-inspector/devtools/http` entry | 19.0 | | **Defer blocks** list | 19.1 | | Change detection recording and Angular profiling | 20.0 | -| Live signal graph | 20.1 | +| Subscriptions tied to component instances | 20.0 | +| Live signal graph and effect counts in **Leaks** | 20.1 | | **@for blocks** list | 22.0 | All of them need a development build, since production builds leave out `window.ng`. diff --git a/apps/docs/src/content/inspectors/components.md b/apps/docs/src/content/inspectors/components.md index f8fd5e47..8409a658 100644 --- a/apps/docs/src/content/inspectors/components.md +++ b/apps/docs/src/content/inspectors/components.md @@ -158,7 +158,7 @@ The **Hydration** section shows how Angular hydrated a page that was rendered on Click a mismatch to select its component in the tree. **Outline on page** draws an outline on the page over each region: hydrated (solid), skipped (dashed), mismatched (double) and dehydrated `@defer` blocks (dotted), each with a label and a legend in the corner. Only the top of each hydrated region gets an outline, so nested components don't stack boxes. The outline is drawn in its own layer, ignores the pointer and changes nothing in the app. Click the button again to remove it. -A page that was not rendered on the server shows that there is nothing to hydrate. A page with server HTML and no hydrated component says that client hydration is off. Hydration status comes from what Angular records in development builds, so a production build shows the same note. The [`hydration`](../agents/tools.md#hydration) tool returns the same data. +A page that was not rendered on the server shows that there is nothing to hydrate. A page with server HTML and no hydrated component says that client hydration is off. Hydration status comes from what Angular records in development builds, so a production build shows the same note. The [`hydration`](../agents/tools.md#hydration) tool returns the same data, with a line diff of the server HTML and the client DOM for each mismatch. The NG05xx error itself shows the same diff in the [Errors](./errors.md#server-vs-client-dom-ng0500-to-ng0503) tab. ### For blocks @@ -182,11 +182,12 @@ Below the tree and the defer blocks, the **Change detection** section records ch - **Spans in the picked cycles**: when the page reports timed spans, a flame graph of the picked cycles. Time runs left to right, cycle after cycle with the idle time between them left out, and a span nested in another sits one row lower. Each span is a component check (solid), a lifecycle hook (stripes), an `afterRender` callback (dots) or the output listener that triggered the cycle (lines, drawn before the cycle's start), with a key under the graph. Hover or focus a span to read its total and self time. The arrow keys move along a row, **Up** goes to the enclosing span and **Down** to the first nested one. **Enter** or a click on a component, hook or output selects that component in the tree. **Show the spans as a table** lists the same spans. The graph shows at most 30 cycles; pick a smaller range when more are picked. - **Self time by component**: a treemap of each component class's self time in the picked cycles, largest first. The recording has no parent links between components, so the cells are not nested. Click a cell, or press **Enter** on it, to select an instance of that class in the tree (the one checked most often). - **Slowest components**: each component class with its check count, its self time (its own template and hooks, children excluded) and its slowest single check. -- **Latest cycles**, newest first: the start time, the duration, how many components Angular checked, how many sync passes it ran, the output listener that ran just before the cycle (an output that ended more than 50 ms before the cycle is not counted), the time in lifecycle hooks and in `afterRender` callbacks, and the slowest component in it. +- **Latest cycles**, newest first: the start time, the duration, how many components Angular checked, how many sync passes it ran, what started the cycle (see [Why it ran and what it wasted](#why-it-ran-and-what-it-wasted)), how many refreshed checks changed nothing, the time in lifecycle hooks and in `afterRender` callbacks, and the slowest component in it. A recording without causes shows the output listener that ran just before the cycle instead (an output that ended more than 50 ms before the cycle is not counted). - **Lifecycle hooks**: time per class and hook (`ngOnChanges`, `ngOnInit`, `ngDoCheck`, `ngAfterContentChecked`, `ngAfterViewChecked` and the others Angular calls), with call count and slowest call. A hook's time is also part of the self time of the component whose view runs it. - **Output listeners**: time per class and listener, without the time of outputs the listener emitted, with call count and slowest call. - A line with how often Angular ran the `afterEveryRender` and `afterNextRender` callbacks, and how long they took. - Tree rows show how many times each instance was checked while recording. +- **Why it ran and what it wasted**: what started the cycles, the components that depend on zone.js, wasted checks, inputs that break OnPush, and hints. See [Why it ran and what it wasted](#why-it-ran-and-what-it-wasted). **Lifecycle hooks** and **Output listeners** show their 10 slowest rows. A recording keeps the 100 slowest of each among the first 1000 it times, and a note says how many it left out. @@ -196,6 +197,22 @@ Each cycle keeps its 40 longest timed spans, and the flame graph says how many s Recording is off by default. While it is off, the page registers no profiler for it. The page keeps the last 200 cycles, set with [`limits.cdCycles`](../getting-started/configuration.md#limits). Recording needs Angular 20 or later. On older versions, the section says so. Times come from a development build, so they are higher than in production. +#### Why it ran and what it wasted + +While a recording runs, the page also finds what started each cycle and which checks changed nothing. It wraps the `notify` method of Angular's change detection scheduler, adds a signal write hook and watches DOM updates with a `MutationObserver`. All three stop when the recording stops, and none of them changes what the app does. + +| Table | What it shows | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **What started the cycles** | Cycles per cause. A cause is the first thing that told Angular to run after the previous cycle: a template listener (**Event**, with the DOM event type, its target and the listener's component), a signal a template reads (**Signal write**, with the signal's `debugName`), an effect, `markForCheck`, `setInput`, a view change, `ApplicationRef.tick()` from app code, or nothing at all (**zone.js only**). | +| **Depends on zone.js** | Components that changed in a tick zone.js started with no Angular notification before it, with the zone.js tasks behind those ticks. Such a component changes state in a callback that only a zone.js tick picks up, such as a field set in `setTimeout` or a promise without a signal or `markForCheck`. | +| **Wasted checks** | Per component class, how often Angular ran its template and how often nothing it renders changed: no DOM update and no new input reference for a child. The development checkNoChanges pass and checks that only passed through to a child are left out. The strategy column is `OnPush` or `Eager`. | +| **Inputs that break OnPush** | Inputs changed in place (same object or array, other contents), which an OnPush child does not see, and inputs given a new reference with the same contents, which refresh it for nothing. Each row names the component whose template set the input. | +| **Hints** | OnPush for a class refreshed at least 10 times that changed something in under 20% of them. On Angular 22, where OnPush is the default, the hint says to remove `ChangeDetectionStrategy.Eager`; on a class that is already OnPush it says what keeps marking it. Each input and zone.js dependent above gets a line too. | + +The latest cycles name each cause in one line, such as `click on button in Cart (add), wrote signal count`. Code that ran on an HTTP response counts as **HTTP response**, from the XHR `load` event or the frames of Angular's fetch backend. A timer counts as **Timer** only when zone.js is loaded and reports the task. Without zone.js, a write in a timer or a promise shows as a signal write or `markForCheck` with the app frames that did it. + +The first check of each instance in a recording is the baseline its inputs are compared with, so a change shows from its second check on. Causes need Angular's zoneless-capable scheduler (Angular 18 and later); recording itself needs 20.0. If the page has no scheduler the overlay can find, the section says so and still counts wasted checks. + #### Pick a range of cycles Drag across the bars to pick a range of cycles, or type cycle numbers in **Start** and **End**. With the chart focused, the arrow keys move between cycles, **Shift** with an arrow key extends the range, **Enter** picks one cycle and **Escape** shows all cycles again. **Show all cycles** does the same. The flame graph, the treemap and **Slowest components** then cover only the picked cycles. Each cycle lists its 10 slowest components, so totals for a range leave out the components a cycle did not list. **Show the cycles as a table** lists the picked cycles with their duration, budget, checks, passes, trigger and slowest component. @@ -224,6 +241,38 @@ The **Live views** toggles below **Record** show change detection as it happens, The flash boxes are drawn on a canvas in a shadow root that the overlay adds to the page. It doesn't take clicks, and the overlay never changes the app's own elements. The page measures the checked hosts once per animation frame and draws at most 150 boxes at a time. +### Leaks + +Below **Change detection**, the **Leaks** section looks for components that stay in memory after they leave the page, and for what keeps them there. It has three lists: + +| List | What it shows | +| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Still retained** | Component instances that were destroyed but are still in memory after at least 2 navigations and 10 seconds: class, the route they lived on, how many navigations ago they went, their age and their open subscriptions. | +| **Open subscriptions after destroy** | RxJS subscriptions a component made that are still open after it went away, with the class, the count and the line that made them. Only while **Track subscriptions** is on. | +| **Live effects and subscriptions** | Components on the page that hold live effects or tracked open subscriptions. Hover or focus a row to highlight the component in the page, and click it to select it in the tree. | + +A line above the lists counts the navigations, the retained instances and the destroyed instances the browser has collected. Instances destroyed fewer than 2 navigations or 10 seconds ago are named under **Still retained**, and instances that left the page without being destroyed (detached views, such as a `RouteReuseStrategy` cache) are named apart. + + + The browser collects garbage when it decides, so an instance in Still retained is not proof of a leak. Take a heap snapshot in the Chrome DevTools Memory panel, search for the class name and read its Retainers to see what holds it. + + +#### How destroyed components are found + +The page walks the component tree when elements come or go, and every 30 seconds otherwise. A component whose host left the page counts as destroyed when Angular has dropped its view (`ng.getInjector` gives Angular's null injector for the host). If Angular still holds the view, the component counts as detached. The page holds each instance through a `WeakRef` only, and a `FinalizationRegistry` tells it when the browser collected one, so the devtools keep nothing alive themselves. The page tracks up to 500 destroyed instances, and the section lists the oldest 100. + +#### Effects + +The effect counts come from the signal graph Angular keeps for each component injector (`ng.ɵgetSignalGraph`). Angular files a component's effects under the template its host sits in, so components side by side in one template list each other's effects. Those show as **shared**. A routed component, or one inside its own `@if` or `@for` block, gets its own count. + +#### Track subscriptions + +Subscription tracking is off by default. **Track subscriptions** turns it on for the page: the overlay wraps `Observable.prototype.subscribe` of the app's RxJS and reads the call stack of each subscription to find the component class whose code made it. On Angular 20 and later, a subscription made in a lifecycle hook, the template or an event listener is tied to the instance through Angular's profiler. A subscription made in a constructor is tied to the class. + +A subscription is flagged when it is still open and either its instance was destroyed, or no instance of its class is left on the page and one was destroyed after it opened. Fix it with `takeUntilDestroyed()`, `DestroyRef.onDestroy` or the `async` pipe. + +**Stop tracking subscriptions** puts `subscribe` back. Subscriptions made before tracking started are not seen, so reload the page or go to the screen again after you start. Tracking stays on across a reload of the tab. The [`track-subscriptions`](../agents/tools.md#track-subscriptions) tool is the same switch. + ### Source mode Without live data, the tab lists the `@Component` and `@Directive` classes in your source. Expand a row to see its class, file, standalone flag, change detection, inputs and outputs. Click **Refresh** to scan again. @@ -347,6 +396,23 @@ To go the other way, select a component and click **Reveal in Elements** in its +### Find a component that stays in memory + + + + In the Leaks section, click Track subscriptions, then reload the page so the first screen is tracked too. + + + Open the screen you suspect, then navigate away and around a few times. + + + An instance under Still retained with open subscriptions points at a missing teardown. Open subscriptions after destroy shows the line that subscribed. + + + Take a heap snapshot in Chrome DevTools, search for the class and read its retainers. + + + ### Console handles When you select a component in the panel, the page sets `$ng0` in its console to that instance. The previous selections move to `$ng1` through `$ng4`, newest first, so the last five stay at hand. Selecting the same instance again keeps the order, and an earlier one moves back to `$ng0`. **Pick component on page** sets `$ng0` too. Selections made by an agent tool don't. @@ -375,19 +441,22 @@ Press Escape in the filter box to clear it. When the filter matches nothing, **C ## Agent tools -| Tool or resource | Kind | What it does | -| --------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `pangular:get-components` | tool | Lists components and directives from source, with selector, kind, inputs, outputs, change detection, file and line. | -| `pangular:highlight` | tool | Highlights a component in the page and selects it. Takes an instance id, class name, host tag or CSS selector. Also retargets the Signals graph. Lists every instance a name matches. | -| `pangular:inspect-component` | tool | Selects one instance and returns its live detail: inputs, outputs, properties, listeners, directives and injected services. With `path`, reads one nested value instead, with `depth` and `limit`. | -| `pangular:list-components` | tool | Returns the live tree of one page as an indented outline with routed, directive host and hydration markers. Takes a `filter` with the search syntax, a `depth` and `directiveHosts`. | -| `pangular:defer-blocks` | tool | Lists the `@defer` blocks of each page, and flags blocks that failed, blocks stuck on their placeholder and blocks still dehydrated. | -| `pangular:for-blocks` | tool | Lists the `@for` blocks of each page with their item count, track kind and `@empty` block. | -| `pangular:hydration` | tool | Returns the hydration status of each page rendered on the server, and turns the outline on the page on or off. An action when it turns the outline on or off. | -| `pangular:change-detection` | tool | Starts, stops or clears a change detection recording, turns the live views on or off, and returns the slowest and most often checked components, hook, output and afterRender time, the latest cycles, or an export. | -| `pangular:set-component-property` | tool | Writes an input or property of one instance and runs change detection. An action. | -| `pangular:set-signal` | tool | Sets a writable signal that one instance holds as a property. An action. | -| `pangular:component-tree` | resource | The live tree per page, with the detail of the selected instance and the defer blocks. | +| Tool or resource | Kind | What it does | +| ------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `pangular:get-components` | tool | Lists components and directives from source, with selector, kind, inputs, outputs, change detection, file and line. | +| `pangular:highlight` | tool | Highlights a component in the page and selects it. Takes an instance id, class name, host tag or CSS selector. Also retargets the Signals graph. Lists every instance a name matches. | +| `pangular:inspect-component` | tool | Selects one instance and returns its live detail: inputs, outputs, properties, listeners, directives and injected services. With `path`, reads one nested value instead, with `depth` and `limit`. | +| `pangular:list-components` | tool | Returns the live tree of one page as an indented outline with routed, directive host and hydration markers. Takes a `filter` with the search syntax, a `depth` and `directiveHosts`. | +| `pangular:defer-blocks` | tool | Lists the `@defer` blocks of each page, and flags blocks that failed, blocks stuck on their placeholder and blocks still dehydrated. | +| `pangular:for-blocks` | tool | Lists the `@for` blocks of each page with their item count, track kind and `@empty` block. | +| `pangular:hydration` | tool | Returns the hydration status of each page rendered on the server, and turns the outline on the page on or off. An action when it turns the outline on or off. | +| `pangular:change-detection` | tool | Starts, stops or clears a change detection recording, turns the live views on or off, and returns the slowest and most often checked components, hook, output and afterRender time, the latest cycles, or an export. | +| `pangular:diagnose-change-detection` | tool | What started the recorded cycles, components that depend on zone.js, wasted checks, inputs that break OnPush, and OnPush hints. | +| `pangular:set-component-property` | tool | Writes an input or property of one instance and runs change detection. An action. | +| `pangular:set-signal` | tool | Sets a writable signal that one instance holds as a property. An action. | +| `pangular:find-leaks` | tool | Lists retained destroyed instances, subscriptions still open after their component went away, and live effects and subscriptions per component. | +| `pangular:track-subscriptions` | tool | Starts or stops subscription tracking on a page, like **Track subscriptions**. An action. | +| `pangular:component-tree` | resource | The live tree per page, with the detail of the selected instance and the defer blocks. | See [Tools](../agents/tools.md) and [Resources](../agents/resources.md). @@ -395,7 +464,7 @@ See [Tools](../agents/tools.md) and [Resources](../agents/resources.md). ### On older Angular -The tree, the detail and component values work from Angular 12. Before 17.1 the detail leaves out signal values, since `ng.isSignal` is missing, and before 16.2 it lists no injected services. The **Defer blocks** list needs 19.1, the **@for blocks** list 22.0 and change detection recording 20.0. On Angular 17.0 and later, where `@defer` and `@for` exist, the tab names the version each list needs and the version the page runs. See [Supported Angular versions](../getting-started/installation.md#supported-angular-versions). +The tree, the detail and component values work from Angular 12. Before 17.1 the detail leaves out signal values, since `ng.isSignal` is missing, and before 16.2 it lists no injected services. The **Defer blocks** list needs 19.1, the **@for blocks** list 22.0 and change detection recording 20.0. In the **Leaks** section, effect counts need 20.1, tying subscriptions to instances needs 20.0, and telling detached views from destroyed ones needs 14.0 (before, every component that leaves the page counts as destroyed). On Angular 17.0 and later, where `@defer` and `@for` exist, the tab names the version each list needs and the version the page runs. See [Supported Angular versions](../getting-started/installation.md#supported-angular-versions). ### Development builds only @@ -413,6 +482,10 @@ The page sends the first level of each input and property, with 30 keys or items The devtools replace inputs and properties with secret-looking names with `[redacted]`. They also redact JWTs and `Bearer` values inside strings. See [what the devtools redact](../security.md). +### Selected components stay in memory + +The console handles `$ng0` to `$ng4`, a component stored as a global, and values you logged in the browser console keep their component in memory. A component you selected or logged can then show under **Still retained**. Select other components, or clear the console, before you judge the list. + ### Instance ids change on reload Instance ids change on every page load. Don't store them between sessions. diff --git a/apps/docs/src/content/inspectors/errors.md b/apps/docs/src/content/inspectors/errors.md index 7da07e9e..67514277 100644 --- a/apps/docs/src/content/inspectors/errors.md +++ b/apps/docs/src/content/inspectors/errors.md @@ -28,9 +28,37 @@ Each row is one message with: | Time | When the page last hit it. | | **Show component** | Opens the [Components](./components.md) tab with the owning component selected. | | **Stack** | The stack of the first occurrence, collapsed until you open it. | +| Explainer | For NG0100, hydration mismatches and missing providers, what the page read about the error. See [Explainers](#explainers). | The list is newest first. Search by message, code or component name, and press `Escape` to clear the search. +### Explainers + +Three kinds of Angular error get a box under the message with what the overlay read about them. + +#### What changed (NG0100) + +For `ExpressionChangedAfterItHasBeenCheckedError`, the box shows: + +| Row | What it shows | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **Binding** | The property Angular names, such as `title`, and the compiled template function on the stack, such as `TripList_Template`. A text interpolation has no name. | +| **Previous** | The value of the first check, as Angular prints it. | +| **Current** | The value of the second check. | +| **Held by** | The fields of the component that hold the current value now, signals included. Getters and `computed` signals don't run. | + +**Written by** lists the named signals written with the current value in the 2 seconds before the error. With write stacks on (see [Signals](./signals.md)), each one shows the app frames that wrote it. Without a match, the box says where to look instead. The overlay hears signal writes only while the Signals inspector is on, on Angular 17.0 or later, and only for signals with a `debugName`. + +When the binding or a field that holds the value has a secret-looking name, both values show as `[redacted]`. + +#### Server vs client DOM (NG0500 to NG0503) + +For a hydration mismatch, the box shows Angular's first sentence and a line diff of the server HTML Angular expected (`−`) and the client DOM it found (`+`). Angular marks the node it means with `<-- AT THIS LOCATION`. The diff comes from the error message. When the message has no DOM, it comes from what Angular recorded on the component host instead, the same data as the [Hydration](./components.md#hydration) section. When Angular suspects a browser extension or a third-party script, the box says so. + +#### Missing provider (NG0201) + +For `NullInjectorError` and NG0201, the box shows the token, Angular's dependency path and the source injector. **Explain lookup** walks the lookup of that token from the component that asked for it: each injector Angular asks, in order, whether it provides the token, and why the lookup stops. It reads the tree the [Injectors](./injectors.md) tab shows, so it needs that tab on, and it assumes no `self`, `skipSelf`, `host` or `optional` flag. The `explain-injection` agent tool takes those flags. + ### Console Click **Console** to see the page's `console.log`, `info`, `warn`, `error` and `debug` calls, newest first. Pick a level in **Console level**, or search the text. A call repeated in a row shows once with a count. A call that mentions an Angular code gets a code chip too. @@ -71,11 +99,12 @@ A `RuntimeError` carries its code, and other errors carry it in the message. The ## Agent tools -| Tool | What it does | -| ------------------------ | -------------------------------------------------------------------------------------------------------------------- | -| `pangular:list-errors` | The error groups, with count, code link, owning component and source. | -| `pangular:explain-error` | One error by `id`, or an Angular `code`: the message, the owning component, the stack, the reference page and cause. | -| `pangular:list-console` | The console calls, by `level` or `search`. | +| Tool | What it does | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `pangular:list-errors` | The error groups, with count, code link, owning component and source. | +| `pangular:explain-error` | One error by `id`, or an Angular `code`: the message, the owning component, the stack, the reference page and cause, and the explainer of an NG0100, a hydration mismatch or a missing provider. | +| `pangular:list-console` | The console calls, by `level` or `search`. | +| `pangular:explain-injection` | Walks the lookup of a token from a component, with `self`, `skipSelf`, `host` and `optional`. Belongs to the [Injectors](./injectors.md#agent-tools) inspector. | The known causes come from Angular's error reference, in a sentence or two. For a code without a reference page, `explain-error` says so. See [Tools](../agents/tools.md#errors). @@ -92,6 +121,8 @@ The known causes come from Angular's error reference, in a sentence or two. For | Error groups | 100. The least recent one goes first. | | Console calls | 200. The oldest one goes first. | | Message, console text | 500 characters. | +| Explainer values | 200 characters each. | +| Explainer DOM | 3,000 characters and 80 lines a side. | | Stack | 40 lines and 4,000 characters. | The tab says how many groups or calls a page dropped. diff --git a/apps/docs/src/content/inspectors/injectors.md b/apps/docs/src/content/inspectors/injectors.md index 4ecd6ec0..f0a8b180 100644 --- a/apps/docs/src/content/inspectors/injectors.md +++ b/apps/docs/src/content/inspectors/injectors.md @@ -143,6 +143,21 @@ The source-mode notice says to connect the overlay to a development build for th +When the error reached the page, the [Errors](./errors.md#missing-provider-ng0201) tab has an **Explain lookup** button on it. It walks the same path for the missing token and says at each injector whether it provides the token and why the lookup stops. An agent does the same with `explain-injection`, flags included. + +### Explain a lookup with flags + +`pangular:explain-injection` follows Angular's own lookup for a token from one component, element or environment injector, without creating anything: + +| Flag | What changes | +| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `self` | Only the first injector is asked. | +| `skipSelf` | The lookup starts at the parent injector. | +| `host` | The lookup stops at the host element of the component whose template declares the start. There, only its `viewProviders` and the component itself count. Environment injectors are never asked. | +| `optional` | A token nobody provides gives `null` instead of NG0201. | + +Each step says **provides it**, **not provided**, **hidden** (only in `viewProviders`, which projected content can't see), **skipped**, **not asked** or **unknown**. A service created on demand, such as `providedIn: 'root'`, counts as provided by the injector that gave it to something else on the page. Before anything injects it, the root injector's step says the tool can't tell from the token name. + ### Find which instance a component gets @@ -167,6 +182,7 @@ If the selected injector leaves the page because its component or directive was | Tool or resource | Kind | What it does | | ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `pangular:get-providers` | tool | DI providers from source: `@Injectable` services, `inject()` calls, constructor parameters and `providers` arrays. | +| `pangular:explain-injection` | tool | The lookup of one token from a component, element or environment injector, step by step, with `self`, `skipSelf`, `host` and `optional`. Says at each injector whether it provides the token and why the lookup stops. See [Explain a lookup with flags](#explain-a-lookup-with-flags). | | `pangular:inspect-providers` | tool | The injector tree a page reported, with what components and created services inject. `selector` narrows it to matching element or environment injectors (`Root`, `Platform`, `Route: admin`) or a component instance id, `token` to where a token is provided and injected. `componentId` and `framework` mark the owning component and Angular's own injectors and providers. | | `pangular:injector-tree` | resource | The live tree last reported by a page. | @@ -183,7 +199,7 @@ The full tree needs Angular 17.0 or later. On older versions the tab shows a not | 16.2 to 16.x | Element and environment injectors with providers and dependencies. Lookup paths list only the environment injectors. | | 12.0 to 16.1 | Element injectors with their components and directives, without providers or environment injectors. | -`inspect-providers` starts its answer with the same note. See [Supported Angular versions](../getting-started/installation.md#supported-angular-versions). +`inspect-providers` starts its answer with the same note. Before 16.2, `explain-injection` rebuilds the lookup path from the rendered tree and answers **unknown** where it can't see providers, and says so. See [Supported Angular versions](../getting-started/installation.md#supported-angular-versions). ### Up to 2000 element injectors diff --git a/docs/angular-compat.md b/docs/angular-compat.md index 466f68f2..d8034002 100644 --- a/docs/angular-compat.md +++ b/docs/angular-compat.md @@ -8,30 +8,30 @@ The `@angular/core` and `@angular/router` packages of these versions were packed ## Public debug API on `window.ng` -| API | Used by | First version | Shape changes up to 22 | Fallback | -| ---------------------- | ---------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | -| `getComponent` | `component-tree.ts`, `injector-tree.ts`, `router.ts`, `signal-graph.ts`, forms, pipes and NgRx | 12.0 | None. | None needed. Without it (a production build) the page reports no live data. | -| `getDirectives` | `component-tree.ts`, `injector-tree.ts`, `forms.ts`, `router-fallback.ts` | 12.0 | None. | As above. | -| `getInjector` | `injector-tree.ts`, `router.ts`, `signal-graph.ts`, `ngrx-collector.ts` | 12.0 | None. Before 15.0 `injector.get(token, notFound, flags)` takes a number for `flags`, not an options object; the collectors only pass an options object on paths that need 16.2 or later. | As above. | -| `getHostElement` | `component-tree.ts`, `pipes-collector.ts` | 12.0 | None. | As above. | -| `getOwningComponent` | `pipes-runtime.ts`, `component-tree.ts` | 12.0 | None. | Falls back to `getComponent`. | -| `getDirectiveMetadata` | `component-tree.ts` | 12.0 | Input values are the property name (a string) in every version. From 17.1 Angular unwraps the `[name, flags]` form signal inputs store. 22 names `ChangeDetectionStrategy` 1 `Eager` instead of `Default`; the numbers are the same. | Reads both forms. | -| `getListeners` | `component-tree.ts` | 12.0 | None. | Empty list when missing. | -| `getRootComponents` | `overlay-nativescript-views.ts` | 12.0 | None. | None needed. | -| `applyChanges` | `forms-actions.ts`, `component-edit.ts` | 12.0 | None. | None needed. | -| `isSignal` | `component-tree.ts`, `component-values.ts`, `component-edit.ts`, `signal-graph.ts` | 17.1 | Not on `ng` in 16.x or 17.0, although signals exist from 16.0. | Values that are functions are left out of the component detail. | -| `enableProfiling` | `cd-live.ts` | 20.0 | None. | The Angular profiling switch says it is unavailable (`angularProfiling`). | +| API | Used by | First version | Shape changes up to 22 | Fallback | +| ---------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | +| `getComponent` | `component-tree.ts`, `injector-tree.ts`, `router.ts`, `signal-graph.ts`, `leaks-collector.ts`, forms, pipes and NgRx | 12.0 | None. | None needed. Without it (a production build) the page reports no live data. | +| `getDirectives` | `component-tree.ts`, `injector-tree.ts`, `forms.ts`, `router-fallback.ts` | 12.0 | None. | As above. | +| `getInjector` | `injector-tree.ts`, `router.ts`, `signal-graph.ts`, `ngrx-collector.ts`, `leaks-collector.ts` | 12.0 | None. Before 15.0 `injector.get(token, notFound, flags)` takes a number for `flags`, not an options object; the collectors only pass an options object on paths that need 16.2 or later. From 14.0 an element keeps its view's id rather than the view, so the host of a destroyed view gives `Injector.NULL`, which `leaks-collector.ts` uses to tell destroyed from detached. Before 14.0 the view stays reachable, so every host that left the page counts as destroyed. | As above. | +| `getHostElement` | `component-tree.ts`, `pipes-collector.ts` | 12.0 | None. | As above. | +| `getOwningComponent` | `pipes-runtime.ts`, `component-tree.ts` | 12.0 | None. | Falls back to `getComponent`. | +| `getDirectiveMetadata` | `component-tree.ts` | 12.0 | Input values are the property name (a string) in every version. From 17.1 Angular unwraps the `[name, flags]` form signal inputs store. 22 names `ChangeDetectionStrategy` 1 `Eager` instead of `Default`; the numbers are the same. | Reads both forms. | +| `getListeners` | `component-tree.ts` | 12.0 | None. | Empty list when missing. | +| `getRootComponents` | `overlay-nativescript-views.ts` | 12.0 | None. | None needed. | +| `applyChanges` | `forms-actions.ts`, `component-edit.ts` | 12.0 | None. | None needed. | +| `isSignal` | `component-tree.ts`, `component-values.ts`, `component-edit.ts`, `signal-graph.ts` | 17.1 | Not on `ng` in 16.x or 17.0, although signals exist from 16.0. | Values that are functions are left out of the component detail. | +| `enableProfiling` | `cd-live.ts` | 20.0 | None. | The Angular profiling switch says it is unavailable (`angularProfiling`). | ## Private debug API on `window.ng` | API | Used by | First version | Shape changes up to 22 | Fallback | | -------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ɵsetProfiler` | `change-detection.ts`, `cd-overlay.ts`, `forms-instrument.ts` | 12.0 | Up to 19.2 it holds one profiler and returns nothing; setting it would evict another profiler (the Angular DevTools extension) with no way to give the slot back. From 20.0 it keeps a list and returns a remover. | Not used before 20.0: the refresh falls back to polling and change detection recording is unavailable (`profiler`). This is the one check made from the version, since trying the util would take the slot. | +| `ɵsetProfiler` | `change-detection.ts`, `cd-overlay.ts`, `forms-instrument.ts`, `leaks-collector.ts` | 12.0 | Up to 19.2 it holds one profiler and returns nothing; setting it would evict another profiler (the Angular DevTools extension) with no way to give the slot back. From 20.0 it keeps a list and returns a remover. | Not used before 20.0: the refresh falls back to polling and change detection recording is unavailable (`profiler`). This is the one check made from the version, since trying the util would take the slot. | | `ɵgetInjectorProviders` | `injector-tree.ts`, `router.ts`, `router-setup.ts`, `ngrx-collector.ts`, `forms-webmcp.ts`, `router-config-tools.ts` | 16.2 | None. | Element injectors are listed without providers. The router is found through `router-fallback.ts`. The `@ngrx/store` Store and signal stores provided by components are not found (`injectorProviders`). | | `ɵgetInjectorResolutionPath` | `injector-tree.ts`, `router.ts`, `router-setup.ts`, `signal-graph.ts`, `ngrx-collector.ts`, `forms-webmcp.ts` | 16.2 | None. | No environment injectors and no lookup path. | | `ɵgetDependenciesFromInjectable` | `injector-tree.ts`, `component-tree.ts` | 16.2 | None. | No dependencies listed. | | `ɵgetInjectorMetadata` | `injector-tree.ts`, `ngrx-collector.ts`, `signal-graph.ts` | 17.0 | None. | `injectorMetadata()` in `injector-tree.ts` tells an environment injector by its `records` map and `source` (an `R3Injector` in every Ivy version) and the null injector by its class. Element injectors on a lookup path can't be named and are left out. | -| `ɵgetSignalGraph` | `signal-graph.ts`, `signal-peek.ts` | 19.1 | Nodes carry `id` and `epoch` (and `debuggableFn`) from 20.1. Before that the collector reports `unsupported: true`. | The Signals page shows the source scan and the unavailable note; `inspect-signals` and `watch-signal` answer "unsupported" (`signalGraph`, named as 20.1). | +| `ɵgetSignalGraph` | `signal-graph.ts`, `signal-peek.ts`, `leaks-collector.ts` | 19.1 | Nodes carry `id` and `epoch` (and `debuggableFn`) from 20.1. Before that the collector reports `unsupported: true`. | The Signals page shows the source scan and the unavailable note; `inspect-signals` and `watch-signal` answer "unsupported" (`signalGraph`, named as 20.1). | | `ɵgetDeferBlocks` | `defer-blocks.ts` | 19.1 (removed in 22.0) | Replaced by `ɵgetControlFlowBlocks` in 22.0. | `deferBlocks` is true when either util exists. `@defer` itself exists from 17.0, so pages on 17.0 to 19.0 get the unavailable note. | | `ɵgetControlFlowBlocks` | `defer-blocks.ts`, `for-blocks.ts`, `rpc/for-blocks-tools.ts` | 22.0 | None. | `@for` blocks unavailable (`forBlocks`). | | `ɵgetRouterInstance` | `router.ts`, `router-setup.ts`, `analog-runtime.ts`, `ssr-navigation.ts` | 20.3.5 (`provideRouter`) | Published by `@angular/router`, not core: present in 21.0.9, absent in 20.0.7. 20.3.5 comes from the router changelog and `private-api-canary.test.ts`. | `providerOf()` looks the Router up through `ɵgetInjectorProviders` (16.2+). Before 16.2 `router-fallback.ts` reads the Router a `RouterLink`, `RouterLinkActive` or component holds in a field, then asks the root injector for that class. Nothing holds it: no router data. | diff --git a/packages/devtools/src/__tests__/cd-diagnosis-real.test.ts b/packages/devtools/src/__tests__/cd-diagnosis-real.test.ts new file mode 100644 index 00000000..827be14a --- /dev/null +++ b/packages/devtools/src/__tests__/cd-diagnosis-real.test.ts @@ -0,0 +1,203 @@ +// @vitest-environment jsdom +import '@angular/compiler'; +import * as core from '@angular/core'; +import { Component } from '@angular/core'; +import { afterEach, describe, expect, it } from 'vitest'; +import { attachChangeDetection, type CdReport } from '../cd-overlay.ts'; +import { findCdScheduler } from '../cd-diagnosis.ts'; +import { angularAtLeast, bootstrapRoot, STANDALONE, type BootedApp } from './angular-version.ts'; + +const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +const ngOf = () => (globalThis as { ng?: unknown }).ng; +const supported = angularAtLeast('20.0'); +const signal = (value: T, debugName: string) => + (core.signal as (v: T, o: { debugName: string }) => core.WritableSignal)(value, { + debugName, + }); + +class StaticNote {} +Component({ + ...STANDALONE, + selector: 'app-static-note', + changeDetection: core.ChangeDetectionStrategy.Default, + template: '

Static

', +})(StaticNote); + +class ItemCount { + items: number[] = []; +} +Component({ + ...STANDALONE, + selector: 'app-item-count', + inputs: ['items'], + template: '{{ items.length }} items', +})(ItemCount); + +class Options { + options: { size: number } = { size: 0 }; +} +Component({ + ...STANDALONE, + selector: 'app-options', + inputs: ['options'], + template: 'size {{ options.size }}', +})(Options); + +class Counter { + readonly count = signal(0, 'count'); + bump() { + this.count.update((n) => n + 1); + } +} +Component({ + ...STANDALONE, + selector: 'app-counter', + template: ' {{ count() }}', +})(Counter); + +class Shell { + readonly items = [1, 2]; + readonly ticks = signal(0, 'ticks'); + options() { + return { size: 1 }; + } + addInPlace() { + this.items.push(this.items.length + 1); + this.ticks.update((n) => n + 1); + } +} +Component({ + ...STANDALONE, + selector: 'app-root', + imports: [StaticNote, ItemCount, Options, Counter], + changeDetection: core.ChangeDetectionStrategy.Default, + template: ` + + + + `, +})(Shell); + +function fakeRpc() { + const handlers = new Map unknown>(); + const reports: CdReport[] = []; + const my = { + rpc: { + call: async (name: string, ...args: unknown[]) => { + if (name === 'push-change-detection') reports.push(args[0] as CdReport); + return undefined; + }, + register: (definition: { name: string; handler: (...args: unknown[]) => unknown }) => { + handlers.set(definition.name, definition.handler); + }, + }, + }; + return { my, handlers, reports }; +} + +describe.skipIf(!supported)('change detection diagnosis with a real app', () => { + let app: BootedApp | null = null; + let stop: (() => void) | null = null; + afterEach(() => { + stop?.(); + stop = null; + app?.destroy(); + app = null; + document.body.innerHTML = ''; + }); + + async function record() { + document.body.innerHTML = ''; + app = await bootstrapRoot(Shell); + app.appRef.tick(); + await wait(20); + const { my, handlers, reports } = fakeRpc(); + const cd = attachChangeDetection(my, 'p1', ngOf, 50); + stop = cd.stop; + handlers.get('change-detection-record')!({ pageId: 'p1', on: true }); + // The signal write hook loads with a dynamic import. + await wait(20); + return { + async report() { + await cd.push(true); + return reports.at(-1)!; + }, + }; + } + + it("finds Angular's scheduler through the root injector", async () => { + document.body.innerHTML = ''; + app = await bootstrapRoot(Shell); + const scheduler = findCdScheduler(ngOf(), document.querySelectorAll('[ng-version]')); + expect(typeof scheduler?.notify).toBe('function'); + }); + + it('credits a click to its event, target and listener component, with the signal it wrote', async () => { + const recording = await record(); + (document.querySelector('app-counter button') as HTMLButtonElement).click(); + await wait(40); + const report = await recording.report(); + const cycle = report.cycles.find((c) => c.cause?.kind === 'event'); + expect(cycle?.cause).toMatchObject({ + kind: 'event', + event: 'click', + target: 'button', + component: 'Counter', + signal: 'count', + }); + expect(report.diagnosis?.triggers).toBe(true); + expect(report.diagnosis?.causes.event).toBeGreaterThanOrEqual(1); + }); + + it('credits a signal written in a timer to the signal and the app frame that wrote it', async () => { + const recording = await record(); + const counter = (ngOf() as { getComponent(el: Element): Counter }).getComponent( + document.querySelector('app-counter')!, + ); + setTimeout(() => counter.bump(), 0); + await wait(60); + const report = await recording.report(); + const cause = report.cycles.find((c) => c.cause?.signal === 'count')?.cause; + expect(cause?.kind).toBe('signal'); + expect(cause?.signal).toBe('count'); + expect(cause?.stack?.[0]).toMatch(/Counter\.bump/); + expect(cause?.component).toBe('Counter'); + }); + + it('counts unchanged checks, an input mutated in place and an equal new reference', async () => { + const recording = await record(); + for (let i = 0; i < 3; i++) { + (document.getElementById('add') as HTMLButtonElement).click(); + await wait(40); + } + const report = await recording.report(); + const diagnosis = report.diagnosis!; + expect(diagnosis.waste).toBe(true); + const note = diagnosis.components.find((c) => c.name === 'StaticNote'); + expect(note).toMatchObject({ refreshed: 3, unchanged: 3, strategy: 'Eager' }); + // The first check of an instance in a recording is the baseline its inputs are compared with. + const inPlace = diagnosis.inputs?.find((i) => i.name === 'ItemCount'); + expect(inPlace).toMatchObject({ input: 'items', parent: 'Shell', inPlace: 2, sameContents: 0 }); + const renewed = diagnosis.inputs?.find((i) => i.name === 'Options'); + expect(renewed).toMatchObject({ + input: 'options', + parent: 'Shell', + inPlace: 0, + sameContents: 2, + }); + // The new reference means the Shell's check did something, from the second check on. + const shell = diagnosis.components.find((c) => c.name === 'Shell'); + expect(shell).toMatchObject({ refreshed: 3, unchanged: 1, strategy: 'Eager' }); + expect(report.cycles.at(-1)?.unchanged).toBeGreaterThanOrEqual(1); + }); + + it('unwraps the scheduler when the recording stops', async () => { + const recording = await record(); + const scheduler = findCdScheduler(ngOf(), document.querySelectorAll('[ng-version]'))!; + expect(Object.prototype.hasOwnProperty.call(scheduler, 'notify')).toBe(true); + stop!(); + stop = null; + expect(Object.prototype.hasOwnProperty.call(scheduler, 'notify')).toBe(false); + await recording.report(); + }); +}); diff --git a/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts b/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts new file mode 100644 index 00000000..3fd2e731 --- /dev/null +++ b/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts @@ -0,0 +1,265 @@ +import { createHostContext } from 'devframe/node'; +import { describe, expect, it } from 'vitest'; +import pangular from '../devframe.ts'; +import { + cdCauseText, + cdHints, + cdTraceFile, + parseCdImport, + sanitizeCdDiagnosis, + sanitizeCdRecording, +} from '../cd-data.ts'; +import { AGENT_INSPECTOR, AGENT_SAFETY, PAGE_AGENT_ENTRIES, type CdDiagnosis } from '../config.ts'; +import { cdDiagnosisText } from '../rpc/cd-diagnosis-tools.ts'; +import { toCdPage, type CdState } from '../rpc/cd-tools.ts'; + +const JWT = + 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U'; + +const diagnosis: CdDiagnosis = { + triggers: true, + waste: true, + major: 22, + causes: { event: 3, zone: 2 }, + components: [ + { name: 'Banner', refreshed: 20, unchanged: 19, strategy: 'Eager' }, + { name: 'Row', refreshed: 12, unchanged: 11, strategy: 'OnPush' }, + { name: 'Cart', refreshed: 12, unchanged: 2, strategy: 'Eager' }, + { name: 'Rare', refreshed: 3, unchanged: 3, strategy: 'Eager' }, + ], + inputs: [{ name: 'Row', input: 'items', parent: 'List', inPlace: 4, sameContents: 0 }], + zone: [{ name: 'Clock', ticks: 2, tasks: ['setTimeout'] }], +}; + +const report = (pageId: string, extra: Record = {}) => ({ + pageId, + supported: true, + recording: true, + startedAt: 1, + dropped: 0, + cycles: [ + { + id: 1, + at: 2, + ms: 1, + passes: 1, + checks: 2, + components: [], + cause: { + kind: 'event', + event: 'click', + target: 'button', + component: 'Cart', + listener: 'add', + }, + refreshed: 2, + unchanged: 1, + }, + ], + components: [{ name: 'Cart', checks: 2, ms: 1, maxMs: 1, cycles: 1 }], + hosts: {}, + diagnosis, + ...extra, +}); + +async function boot() { + const host = { + mountStatic: () => {}, + resolveOrigin: () => 'http://localhost', + getStorageDir: () => '', + }; + const ctx = await createHostContext({ cwd: process.cwd(), mode: 'dev', host: host as never }); + await pangular.setup(ctx as never); + const push = (name: string, payload: unknown) => + ctx.rpc.invokeLocal(`pangular:${name}` as never, ...([payload] as never)); + const call = async (args: Record) => + ((await ctx.agent.invoke('pangular:diagnose-change-detection', args)) as { markdown: string }) + .markdown; + return { push, call, ctx }; +} + +describe('change detection diagnosis data', () => { + it('keeps known cause fields and drops unknown kinds, fields and extra frames', () => { + const clean = sanitizeCdRecording( + report('p1', { + cycles: [ + { + id: 1, + at: 1, + ms: 1, + passes: 1, + checks: 0, + components: [], + cause: { + kind: 'signal', + via: 'nonsense', + signal: 'count', + extra: 'x', + stack: ['a', 'b', 'c', 'd'], + zone: 'yes', + more: -1, + }, + refreshed: 'x', + }, + { id: 2, at: 1, ms: 1, passes: 1, checks: 0, components: [], cause: { kind: 'made-up' } }, + ], + }), + 10, + )!; + expect(clean.cycles[0]!.cause).toEqual({ + kind: 'signal', + signal: 'count', + stack: ['a', 'b', 'c'], + }); + expect(clean.cycles[0]!.refreshed).toBeUndefined(); + expect(clean.cycles[1]!.cause).toBeUndefined(); + }); + + it('checks a diagnosis: known kinds, numbers, strategies and capped lists', () => { + expect(sanitizeCdDiagnosis(null)).toBeUndefined(); + const clean = sanitizeCdDiagnosis({ + triggers: true, + waste: 'yes', + major: 1e9, + causes: { event: 2, bogus: 5, zone: -1 }, + components: [{ name: 'A', refreshed: 3, unchanged: 1, strategy: 'Weird' }, { name: '' }], + inputs: Array.from({ length: 60 }, (_, i) => ({ name: `C${i}`, input: 'x', inPlace: 1 })), + zone: [{ name: 'Z', ticks: 1, tasks: ['a', 'b', 'c', 'd'] }], + })!; + expect(clean.triggers).toBe(true); + expect(clean.waste).toBe(false); + expect(clean.major).toBeUndefined(); + expect(clean.causes).toEqual({ event: 2 }); + expect(clean.components).toEqual([{ name: 'A', refreshed: 3, unchanged: 1 }]); + expect(clean.inputs).toHaveLength(50); + expect(clean.inputs![0]).toEqual({ name: 'C0', input: 'x', inPlace: 1, sameContents: 0 }); + expect(clean.zone).toEqual([{ name: 'Z', ticks: 1, tasks: ['a', 'b', 'c'] }]); + }); + + it('keeps the diagnosis through an export and an import, and names the cause in a trace', () => { + const clean = sanitizeCdRecording(report('p1'), 10)!; + const imported = parseCdImport(JSON.stringify({ recording: clean }), 10); + expect(imported.ok && imported.recording.diagnosis?.zone).toEqual(diagnosis.zone); + const trace = cdTraceFile(clean, 'p1'); + const cycle = trace.traceEvents.find((e) => e.name === 'Change detection #1'); + expect(cycle?.args?.['cause']).toBe('click on button in Cart (add)'); + }); + + it('describes causes in one line', () => { + expect( + cdCauseText({ + kind: 'event', + event: 'click', + target: 'button', + component: 'Cart', + listener: 'add', + signal: 'count', + }), + ).toBe('click on button in Cart (add), wrote signal count'); + expect(cdCauseText({ kind: 'http', via: 'markForCheck', component: 'Users', more: 2 })).toBe( + 'HTTP response in Users, via markForCheck, 2 more notifications', + ); + expect(cdCauseText({ kind: 'zone', zone: true, task: 'setTimeout' })).toBe( + 'zone.js tick with no Angular notification after setTimeout', + ); + expect(cdCauseText({ kind: 'markForCheck', zone: true })).toBe('markForCheck, run by zone.js'); + expect(cdCauseText({ kind: 'tick', component: 'Poller' })).toBe( + 'ApplicationRef.tick() in Poller', + ); + }); + + it('suggests OnPush by version, notes classes already OnPush, and flags inputs and zone.js', () => { + const hints = cdHints(diagnosis); + expect(hints.map((h) => [h.name, h.kind])).toEqual([ + ['Banner', 'on-push'], + ['Row', 'already-on-push'], + ['Row', 'in-place'], + ['Clock', 'zone'], + ]); + expect(hints[0]!.text).toContain('default from Angular 22'); + expect(hints[0]!.text).toContain('ChangeDetectionStrategy.Eager'); + const older = cdHints({ ...diagnosis, major: 19 }); + expect(older[0]!.text).toContain('Add `changeDetection: ChangeDetectionStrategy.OnPush`'); + expect(older[1]!.text).not.toContain('Angular 22'); + expect(hints[2]!.text).toContain('Input items of Row set by List changed in place 4 times'); + expect(cdHints(undefined)).toEqual([]); + }); + + it('masks secrets the page put in causes and names', () => { + const page = toCdPage( + report('p1', { + cycles: [ + { + id: 1, + at: 1, + ms: 1, + passes: 1, + checks: 0, + components: [], + cause: { kind: 'signal', signal: JWT, stack: [`load (src/a.ts?token=${JWT}:1:1)`] }, + }, + ], + diagnosis: { ...diagnosis, zone: [{ name: 'Clock', ticks: 1, tasks: [`Bearer ${JWT}`] }] }, + }), + 10, + )!; + const text = JSON.stringify(page); + expect(text).not.toContain(JWT); + }); +}); + +describe('diagnose-change-detection tool', () => { + it('is a read tool of the components inspector that needs a page', () => { + expect(AGENT_INSPECTOR['diagnose-change-detection']).toBe('components'); + expect(AGENT_SAFETY['diagnose-change-detection']).toBeUndefined(); + expect(PAGE_AGENT_ENTRIES).toContain('diagnose-change-detection'); + }); + + it('answers with causes, zone.js dependents, wasted checks, inputs and hints', async () => { + const { push, call } = await boot(); + await push('push-change-detection', report('p1')); + const text = await call({}); + expect(text).toContain('**What started the cycles**'); + expect(text).toContain('Event (`event`): 3 cycle(s)'); + expect(text).toContain('`click on button in Cart (add)`'); + expect(text).toContain('**Components that depend on zone.js**'); + expect(text).toContain('- `Clock`: 2 tick(s), after `setTimeout`'); + expect(text).toContain('- `Banner`: 19 of 20 refreshed check(s) changed nothing (95%), Eager'); + expect(text).toContain('- `Row.items` (set by `List`): 4 change(s) in place'); + expect(text).toContain('remove `changeDetection: ChangeDetectionStrategy.Eager`'); + }); + + it('says what to do with no recording, an unknown page and a page without the scheduler', async () => { + const { push, call } = await boot(); + expect(await call({})).toMatch(/^No change detection recording yet/); + await push( + 'push-change-detection', + report('p1', { diagnosis: { ...diagnosis, triggers: false } }), + ); + expect(await call({ page: 'gone' })).toMatch(/^No page `gone`/); + expect(await call({ page: 'p1' })).toContain('cycles carry no cause'); + }); + + it('explains a page that cannot record and one that sent no diagnosis', () => { + const state = (page: Record): CdState => + ({ pages: { p1: { ...report('p1'), reportedAt: 1, ...page } } }) as unknown as CdState; + expect(cdDiagnosisText(state({ supported: false }))).toContain('needs Angular 20 or later'); + expect(cdDiagnosisText(state({ diagnosis: undefined }))).toContain('reported no diagnosis'); + expect( + cdDiagnosisText(state({ supported: false }), {}, () => ({ + version: '19.2.0', + capabilities: { profiler: false }, + })), + ).toContain('Unsupported on this Angular version'); + }); + + it('adds the cause and unchanged checks to the change-detection cycle lines', async () => { + const { push, ctx } = await boot(); + await push('push-change-detection', report('p1')); + const text = ((await ctx.agent.invoke('pangular:change-detection', {})) as { markdown: string }) + .markdown; + expect(text).toContain( + 'started by `click on button in Cart (add)`, 1 of 2 refreshed check(s) changed nothing', + ); + }); +}); diff --git a/packages/devtools/src/__tests__/cd-diagnosis.test.ts b/packages/devtools/src/__tests__/cd-diagnosis.test.ts new file mode 100644 index 00000000..301c22e6 --- /dev/null +++ b/packages/devtools/src/__tests__/cd-diagnosis.test.ts @@ -0,0 +1,411 @@ +// @vitest-environment jsdom +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { callerStack, createCdDiagnosis, findCdScheduler, NOTIFY } from '../cd-diagnosis.ts'; +import { PROFILER_EVENT as E } from '../cd-recorder.ts'; +import type { RawSignalNode } from '../signal-history.ts'; + +class Shell {} +class Row { + items: number[] = []; +} +(Shell as unknown as { ɵcmp: object }).ɵcmp = {}; +(Row as unknown as { ɵcmp: object }).ɵcmp = {}; + +const APP_STACK = 'Error\n at Cart.add (http://localhost:4200/src/app/cart.ts:12:5)'; +const HTTP_STACK = + 'Error\n at Users.load (http://localhost:4200/src/app/users.ts:8:3)\n at _FetchBackend.doRequest (http://localhost:4200/@fs/node_modules/@angular/common/fesm2022/http.mjs:1:1)'; + +/** A fake app: an `ng` whose root injector holds a scheduler, and a root element. */ +function fakePage( + meta: Record; changeDetection?: number }> = {}, +) { + document.body.innerHTML = ''; + const notified: number[] = []; + const scheduler = { + appRef: {}, + runningTick: false, + notify(source: number) { + notified.push(source); + }, + }; + const env = { + records: new Map([[class X {}, { value: scheduler }]]), + }; + const ng = { + getInjector: () => ({ node: true }), + ɵgetInjectorResolutionPath: () => [{ node: true }, env], + getDirectiveMetadata: (instance: object) => meta[instance.constructor.name] ?? null, + }; + return { ng, scheduler, notified }; +} + +function setup( + options: { + meta?: Parameters[0]; + global?: Record; + stack?: string; + clock?: () => number; + } = {}, +) { + const page = fakePage(options.meta); + let onWrite: ((node: RawSignalNode) => void) | null = null; + const removeHook = vi.fn(); + const diagnosis = createCdDiagnosis({ + getNg: () => page.ng, + maxCycles: 5, + // Spreading `globalThis` would lose its non-enumerable classes, such as MutationObserver. + ...(options.global + ? { + global: () => + new Proxy(globalThis as unknown as Record, { + get: (target, key: string) => + key in options.global! ? options.global![key] : target[key], + }), + } + : {}), + stack: () => options.stack, + ...(options.clock ? { now: options.clock } : {}), + writeHook: async (fn) => { + onWrite = fn; + return removeHook; + }, + }); + let id = 0; + const cycle = (body: () => void = () => {}) => { + diagnosis.onEvent(E.ChangeDetectionStart, undefined, undefined, ++id); + diagnosis.onEvent(E.ChangeDetectionSyncStart, undefined, undefined, id); + body(); + diagnosis.onEvent(E.ChangeDetectionSyncEnd, undefined, undefined, id); + diagnosis.onEvent(E.ChangeDetectionEnd, undefined, undefined, null); + return id; + }; + /** A component check; `refresh` runs its template, `dom` changes the page while it runs. */ + const check = (instance: object, { refresh = true, dom = false, children = () => {} } = {}) => { + diagnosis.onEvent(E.ComponentStart, undefined, undefined, id); + if (refresh) diagnosis.onEvent(E.TemplateUpdateStart, instance, undefined, id); + if (dom) document.body.append(document.createElement('span')); + children(); + diagnosis.onEvent(E.ComponentEnd, instance, undefined, id); + }; + return { + ...page, + diagnosis, + cycle, + check, + removeHook, + write: (debugName?: string) => onWrite?.({ debugName }), + }; +} + +afterEach(() => { + document.body.innerHTML = ''; +}); + +describe('change detection diagnosis', () => { + it('finds the scheduler among the values the root injector holds, and nothing on a bare page', () => { + const { ng, scheduler } = fakePage(); + expect(findCdScheduler(ng, document.querySelectorAll('[ng-version]'))).toBe(scheduler); + expect(findCdScheduler({}, document.querySelectorAll('[ng-version]'))).toBeNull(); + expect(findCdScheduler(null, [])).toBeNull(); + }); + + it('wraps notify only while it records, and forwards every call', async () => { + const t = setup(); + const original = t.scheduler.notify; + t.diagnosis.start(); + expect(t.scheduler.notify).not.toBe(original); + t.scheduler.notify(NOTIFY.MarkForCheck); + expect(t.notified).toEqual([4]); + await Promise.resolve(); + t.diagnosis.stop(); + expect(t.scheduler.notify).toBe(original); + expect(t.removeHook).toHaveBeenCalled(); + t.scheduler.notify(NOTIFY.MarkForCheck); + expect(t.notified).toEqual([4, 4]); + }); + + it('removes a write hook that finishes loading after the recording stopped', async () => { + const t = setup(); + t.diagnosis.start(); + t.diagnosis.stop(); + await Promise.resolve(); + await Promise.resolve(); + expect(t.removeHook).toHaveBeenCalledTimes(1); + }); + + it('credits a tick to the signal written and the app frame that wrote it', async () => { + const t = setup({ stack: APP_STACK }); + t.diagnosis.start(); + await Promise.resolve(); + t.scheduler.notify(NOTIFY.MarkAncestorsForTraversal); + t.write('count'); + t.scheduler.notify(NOTIFY.RootEffect); + const id = t.cycle(); + expect(t.diagnosis.cycle(id).cause).toEqual({ + kind: 'signal', + component: 'Cart', + signal: 'count', + stack: ['Cart.add (src/app/cart.ts:12:5)'], + more: 1, + }); + }); + + it('names a template listener by its DOM event, target and owner', () => { + const t = setup(); + t.diagnosis.start(); + const button = document.createElement('button'); + document.body.append(button); + const listener = function Cart_Template_button_click_0_listener() {}; + let id = 0; + button.addEventListener('click', () => { + t.scheduler.notify(NOTIFY.Listener); + t.diagnosis.onEvent(E.OutputStart, new Row(), listener, null); + t.diagnosis.onEvent(E.OutputEnd, new Row(), listener, null); + }); + button.click(); + id = t.cycle(); + expect(t.diagnosis.cycle(id).cause).toEqual({ + kind: 'event', + event: 'click', + target: 'button', + component: 'Row', + listener: 'Cart_Template_button_click_0_listener', + }); + }); + + it('calls code on an HTTP response http, from the XHR load event or the fetch backend frames', () => { + const t = setup({ stack: HTTP_STACK }); + t.diagnosis.start(); + t.scheduler.notify(NOTIFY.MarkForCheck); + const id = t.cycle(); + expect(t.diagnosis.cycle(id).cause).toMatchObject({ + kind: 'http', + via: 'markForCheck', + component: 'Users', + }); + + const xhr = new XMLHttpRequest(); + xhr.addEventListener('load', () => t.scheduler.notify(NOTIFY.MarkAncestorsForTraversal)); + xhr.dispatchEvent(new Event('load')); + const next = t.cycle(); + expect(t.diagnosis.cycle(next).cause).toMatchObject({ kind: 'http', via: 'signal' }); + expect(t.diagnosis.cycle(next).cause?.event).toBeUndefined(); + }); + + it('reads zone.js tasks: a timer, a zone-only tick and the components that changed in it', () => { + const zone = { + current: { get: (key: string) => key === 'isAngularZone' }, + currentTask: { type: 'macroTask', source: 'setTimeout' } as { + type: string; + source: string; + } | null, + }; + const t = setup({ global: { Zone: zone }, meta: { Row: { changeDetection: 1 } } }); + t.diagnosis.start(); + t.scheduler.notify(NOTIFY.MarkForCheck); + const timer = t.cycle(); + expect(t.diagnosis.cycle(timer).cause).toMatchObject({ + kind: 'timer', + via: 'markForCheck', + task: 'setTimeout', + zone: true, + }); + + const row = new Row(); + const zoneOnly = t.cycle(() => t.check(row, { dom: true })); + expect(t.diagnosis.cycle(zoneOnly).cause).toEqual({ + kind: 'zone', + zone: true, + task: 'setTimeout', + }); + zone.currentTask = { type: 'macroTask', source: 'XMLHttpRequest.send' }; + t.cycle(() => t.check(row, { dom: true })); + expect(t.diagnosis.snapshot()?.zone).toEqual([ + { name: 'Row', ticks: 2, tasks: ['setTimeout', 'XMLHttpRequest.send'] }, + ]); + expect(t.diagnosis.snapshot()?.causes).toEqual({ timer: 1, zone: 2 }); + }); + + it('marks a tick the scheduler ran without a seen notification unknown, and one app code ran tick', () => { + const t = setup({ stack: APP_STACK }); + t.diagnosis.start(); + t.scheduler.runningTick = true; + const scheduled = t.cycle(); + expect(t.diagnosis.cycle(scheduled).cause).toEqual({ kind: 'unknown' }); + t.scheduler.runningTick = false; + const manual = t.cycle(); + expect(t.diagnosis.cycle(manual).cause).toEqual({ + kind: 'tick', + component: 'Cart', + stack: ['Cart.add (src/app/cart.ts:12:5)'], + }); + }); + + it('lets a refreshing notification replace one that only runs afterRender, and drops a stale one', () => { + let now = 0; + const t = setup({ clock: () => now }); + t.diagnosis.start(); + t.scheduler.notify(NOTIFY.PendingTaskRemoved); + t.scheduler.notify(NOTIFY.MarkForCheck); + expect(t.diagnosis.cycle(t.cycle()).cause).toEqual({ kind: 'markForCheck', more: 1 }); + + t.scheduler.notify(NOTIFY.PendingTaskRemoved); + now = 500; + t.scheduler.runningTick = true; + expect(t.diagnosis.cycle(t.cycle()).cause).toMatchObject({ kind: 'unknown' }); + }); + + it('ignores notifications Angular sends while a tick runs', () => { + const t = setup(); + t.diagnosis.start(); + t.scheduler.notify(NOTIFY.SetInput); + const id = t.cycle(() => t.scheduler.notify(NOTIFY.MarkForCheck)); + expect(t.diagnosis.cycle(id).cause).toEqual({ kind: 'input' }); + t.scheduler.runningTick = true; + expect(t.diagnosis.cycle(t.cycle()).cause).toEqual({ kind: 'unknown' }); + }); + + it('counts refreshed checks without DOM updates, and leaves out traversals and the checkNoChanges pass', () => { + const t = setup({ meta: { Shell: { changeDetection: 0 }, Row: { changeDetection: 1 } } }); + t.diagnosis.start(); + const shell = new Shell(); + const row = new Row(); + const id = t.cycle(() => { + t.check(shell, { dom: false, children: () => t.check(row, { dom: true }) }); + // Visited without running its template: not a refresh. + t.check(new Shell(), { refresh: false }); + }); + // The development checkNoChanges pass runs after the last sync pass. + t.diagnosis.onEvent(E.ChangeDetectionStart, undefined, undefined, 99); + t.check(row); + t.diagnosis.onEvent(E.ChangeDetectionEnd, undefined, undefined, null); + + expect(t.diagnosis.cycle(id)).toMatchObject({ refreshed: 2, unchanged: 1 }); + const snap = t.diagnosis.snapshot(22)!; + expect(snap.components).toEqual([ + { name: 'Shell', refreshed: 1, unchanged: 1, strategy: 'OnPush' }, + { name: 'Row', refreshed: 1, unchanged: 0, strategy: 'Eager' }, + ]); + expect(snap.major).toBe(22); + expect(snap.waste).toBe(true); + expect(snap.triggers).toBe(true); + }); + + it('finds inputs mutated in place and new references with equal contents, crediting the parent', () => { + const t = setup({ meta: { Row: { inputs: { items: 'items' } } } }); + t.diagnosis.start(); + const shell = new Shell(); + const row = new Row(); + const pass = () => t.cycle(() => t.check(shell, { children: () => t.check(row) })); + row.items = [1]; + pass(); + row.items.push(2); + pass(); + row.items = [...row.items]; + const renewed = pass(); + expect(t.diagnosis.snapshot()?.inputs).toEqual([ + { name: 'Row', input: 'items', parent: 'Shell', inPlace: 1, sameContents: 1 }, + ]); + // The new reference counts as a change of the parent's check. + expect(t.diagnosis.cycle(renewed)).toMatchObject({ refreshed: 2, unchanged: 1 }); + }); + + it("reads a signal input's stored value without calling it", () => { + const t = setup({ meta: { Row: { inputs: { items: 'items' } } } }); + t.diagnosis.start(); + const node = { value: [1] as number[] }; + const read = vi.fn(() => node.value); + const SIGNAL = Symbol('SIGNAL'); + const items = Object.assign(read, { [SIGNAL]: node }); + const row = Object.assign(new Row(), { items }) as unknown as Row; + t.cycle(() => t.check(row)); + node.value.push(2); + t.cycle(() => t.check(row)); + expect(read).not.toHaveBeenCalled(); + expect(t.diagnosis.snapshot()?.inputs?.[0]).toMatchObject({ input: 'items', inPlace: 1 }); + }); + + it('cuts the overlay and Angular frames a bundled build shares chunk files with', () => { + const bundled = [ + 'Error', + ' at captureStack (chunk-IPR3QYBB.js:12111:12)', + ' at onNotify (chunk-IPR3QYBB.js:15893:55)', + ' at ChangeDetectionSchedulerImpl.wrapper [as notify] (chunk-IPR3QYBB.js:16105:9)', + ' at markViewDirty (chunk-IPR3QYBB.js:900:3)', + ' at _ViewRef.markForCheck (chunk-IPR3QYBB.js:950:5)', + ' at _EagerClock.tick (chunk-APP.js:20:7)', + ].join('\n'); + const t = setup({ stack: bundled }); + t.diagnosis.start(); + t.scheduler.notify(NOTIFY.MarkForCheck); + expect(t.diagnosis.cycle(t.cycle()).cause).toEqual({ + kind: 'markForCheck', + component: 'EagerClock', + stack: ['EagerClock.tick (chunk-APP.js:20:7)'], + }); + const firefox = 'wrapper@chunk.js:1:1\nmarkViewDirty@chunk.js:2:2\nPoller.poll@app.js:3:3'; + expect( + callerStack(firefox, (line) => line.startsWith('wrapper@'), { skip: /^markViewDirty$/ }), + ).toBe('Error\nPoller.poll@app.js:3:3'); + expect(callerStack('no marker here', () => false)).toBe('no marker here'); + }); + + it('credits ApplicationRef.tick to the app frame below it', () => { + const t = setup({ + stack: [ + 'Error', + ' at captureStack (chunk.js:1:1)', + ' at dispatch (chunk.js:2:2)', + ' at _ApplicationRef._tick (chunk.js:3:3)', + ' at _ApplicationRef.tick (chunk.js:4:4)', + ' at _Poller.refresh (chunk-APP.js:5:5)', + ].join('\n'), + }); + t.diagnosis.start(); + expect(t.diagnosis.cycle(t.cycle()).cause).toEqual({ + kind: 'tick', + component: 'Poller', + stack: ['Poller.refresh (chunk-APP.js:5:5)'], + }); + }); + + it('marks every tick unknown when the page has no scheduler, never zone.js only', () => { + const zone = { + current: { get: (key: string) => key === 'isAngularZone' }, + currentTask: { type: 'macroTask', source: 'setTimeout' }, + }; + const t = setup({ global: { Zone: zone } }); + t.ng.ɵgetInjectorResolutionPath = () => []; + t.diagnosis.start(); + const id = t.cycle(() => t.check(new Row(), { dom: true })); + expect(t.diagnosis.cycle(id).cause).toEqual({ + kind: 'unknown', + zone: true, + task: 'setTimeout', + }); + expect(t.diagnosis.snapshot()).toMatchObject({ triggers: false, waste: true }); + expect(t.diagnosis.snapshot()?.zone).toBeUndefined(); + }); + + it('keeps per-cycle data for the ids the recorder still holds, and empties on clear', () => { + const t = setup(); + t.diagnosis.start(); + for (let i = 0; i < 8; i++) t.cycle(); + expect(t.diagnosis.cycle(1)).toEqual({}); + expect(t.diagnosis.cycle(8).cause).toEqual({ kind: 'tick' }); + t.diagnosis.clear(); + expect(t.diagnosis.cycle(8)).toEqual({}); + expect(t.diagnosis.snapshot()?.causes).toEqual({}); + }); + + it('reports nothing before the first start, and what it could hook after a stop', () => { + const t = setup(); + expect(t.diagnosis.snapshot()).toBeUndefined(); + t.diagnosis.onEvent(E.ChangeDetectionStart, undefined, undefined, 1); + t.diagnosis.onEvent(E.ChangeDetectionEnd, undefined, undefined, null); + expect(t.diagnosis.cycle(1)).toEqual({}); + t.diagnosis.start(); + t.diagnosis.stop(); + expect(t.diagnosis.snapshot()).toMatchObject({ triggers: true, waste: true }); + }); +}); diff --git a/packages/devtools/src/__tests__/config.test.ts b/packages/devtools/src/__tests__/config.test.ts index 0f538f40..8e9851d8 100644 --- a/packages/devtools/src/__tests__/config.test.ts +++ b/packages/devtools/src/__tests__/config.test.ts @@ -265,6 +265,7 @@ describe('agent tool and RPC registration', () => { 'set-component-property', 'set-http-rule', 'set-signal', + 'track-subscriptions', 'watch-signal', ].sort(), ); @@ -372,6 +373,7 @@ describe('agent tool and RPC registration', () => { 'set-component-property', 'set-http-rule', 'set-signal', + 'track-subscriptions', 'watch-signal', ].sort(), ); diff --git a/packages/devtools/src/__tests__/docs-tool-count.test.ts b/packages/devtools/src/__tests__/docs-tool-count.test.ts index 12b6a452..6081d207 100644 --- a/packages/devtools/src/__tests__/docs-tool-count.test.ts +++ b/packages/devtools/src/__tests__/docs-tool-count.test.ts @@ -29,6 +29,10 @@ const WORDS = [ 'Sixty-nine', 'Seventy', 'Seventy-one', + 'Seventy-two', + 'Seventy-three', + 'Seventy-four', + 'Seventy-five', ]; it('states on the tools page how many tools the server registers', async () => { diff --git a/packages/devtools/src/__tests__/dom-diff.test.ts b/packages/devtools/src/__tests__/dom-diff.test.ts new file mode 100644 index 00000000..ff4243c0 --- /dev/null +++ b/packages/devtools/src/__tests__/dom-diff.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, it } from 'vitest'; +import { MAX_DIFF_LINES, diffDom, diffText } from '../dom-diff.ts'; + +const EXPECTED = ` + … +
…
<-- AT THIS LOCATION + … +
`; + +const ACTUAL = ` + … + … <-- AT THIS LOCATION + … +`; + +describe('diffDom', () => { + it('keeps the shared lines and marks what only the server or the client has', () => { + expect(diffDom(EXPECTED, ACTUAL)).toEqual([ + { op: 'same', text: '' }, + { op: 'same', text: ' …' }, + { op: 'expected', text: '
…
<-- AT THIS LOCATION' }, + { op: 'actual', text: ' … <-- AT THIS LOCATION' }, + { op: 'same', text: ' …' }, + { op: 'same', text: '
' }, + ]); + }); + + it("matches a line with Angular's location marker to the same line without it", () => { + const diff = diffDom('

\n … <-- AT THIS LOCATION\n

', '

\n …\n

'); + expect(diff.every((line) => line.op === 'same')).toBe(true); + // The marked line is kept, so the reader still sees where Angular looked. + expect(diff[1]!.text).toContain('AT THIS LOCATION'); + }); + + it('lists only one side when Angular found no node at all', () => { + expect(diffDom('
…
', '')).toEqual([{ op: 'expected', text: '
…
' }]); + expect(diffDom(undefined, '')).toEqual([{ op: 'actual', text: '' }]); + }); + + it('caps each side so a huge description stays small', () => { + const many = Array.from({ length: 500 }, (_, i) => `
  • ${i}
  • `).join('\n'); + expect(diffDom(many, many)).toHaveLength(MAX_DIFF_LINES); + }); + + it('writes the diff as unified text', () => { + expect(diffText(diffDom('\n', '\n'))).toBe(' \n- \n+ '); + }); +}); diff --git a/packages/devtools/src/__tests__/error-explain.test.ts b/packages/devtools/src/__tests__/error-explain.test.ts new file mode 100644 index 00000000..7754f0f8 --- /dev/null +++ b/packages/devtools/src/__tests__/error-explain.test.ts @@ -0,0 +1,370 @@ +// @vitest-environment jsdom +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { elementId } from '../element-id.ts'; +import { + WRITE_WINDOW_MS, + createRecentWrites, + explainError, + formatLikeAngular, + membersHolding, + parseExpressionChanged, + parseHydrationMismatch, + parseMissingProvider, + templateOf, +} from '../error-explain.ts'; +import { attachErrors, ownerCandidates, type ErrorsDebugNg } from '../errors-collector.ts'; +import { HYDRATION_INFO_KEY } from '../hydration.ts'; +import type { ErrorsReport } from '../rpc/errors-tools.ts'; + +const JWT = ['eyJhbGciOiJIUzI1NiJ9', 'eyJzdWIiOiIxMjM0NSJ9', 'c2lnbmF0dXJlc2ln'].join('.'); + +/** Angular's NG0100 message, as `throwErrorIfNoChangesMode` builds it. */ +const NG0100 = + "NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'title': 'Trips'. Current value: 'Trips (3)'. Expression location: TripList component. Find more at https://angular.dev/errors/NG0100"; + +const NG0100_STACK = `Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError + at throwErrorIfNoChangesMode (http://localhost:4200/@fs/node_modules/.vite/deps/@angular_core.js:100:11) + at bindingUpdated (http://localhost:4200/@fs/node_modules/.vite/deps/@angular_core.js:200:7) + at TripList_Conditional_2_Template (http://localhost:4200/src/app/trip-list.ts:40:9) + at executeTemplate (http://localhost:4200/@fs/node_modules/.vite/deps/@angular_core.js:300:5)`; + +/** Angular's NG0500 message, as `validateMatchingNode` builds it. */ +const NG0500 = `NG0500: During hydration Angular expected
    but found . + +Angular expected this DOM: + + + … +
    …
    <-- AT THIS LOCATION + … +
    + +Actual DOM is: + + + … + … <-- AT THIS LOCATION + … + + +Note: attributes are only displayed to better represent the DOM but have no effect on hydration mismatches. + +To fix this problem: + * check the "Price" component for hydration-related issues + * check to see if your template has valid HTML structure + * or skip hydration by adding the \`ngSkipHydration\` attribute to its host node in a template + +Find more at https://angular.dev/errors/NG0500`; + +class RuntimeError extends Error { + constructor( + readonly code: number, + message: string, + stack?: string, + ) { + super(message); + if (stack) this.stack = stack; + } +} + +describe('reading Angular error messages', () => { + it('reads the binding, both values and the creation hint of an NG0100', () => { + expect(parseExpressionChanged(NG0100)).toEqual({ + binding: 'title', + previous: 'Trips', + current: 'Trips (3)', + creation: false, + }); + expect( + parseExpressionChanged( + "Expression has changed after it was checked. Previous value: 'false'. Current value: 'true'. It seems like the view has been created after its parent and its children have been dirty checked.", + ), + ).toEqual({ previous: 'false', current: 'true', creation: true }); + expect(parseExpressionChanged('NG0100: something else')).toBeNull(); + }); + + it('finds the template function the binding sits in, not a listener', () => { + expect(templateOf(NG0100_STACK)).toBe('TripList_Conditional_2_Template'); + expect(templateOf(' at App_Template_button_click_0_listener (main.ts:3:1)')).toBeUndefined(); + expect(templateOf('App_Template@http://localhost/main.js:1:1')).toBe('App_Template'); + }); + + it('splits a hydration message into its sentence, the expected DOM and the actual DOM', () => { + const parts = parseHydrationMismatch(NG0500); + expect(parts.summary).toBe('During hydration Angular expected
    but found .'); + expect(parts.expected).toContain('
    …
    <-- AT THIS LOCATION'); + expect(parts.expected).not.toContain('Actual DOM'); + expect(parts.actual).toContain('…'); + expect(parts.actual).not.toContain('Note:'); + expect(parts.external).toBe(false); + }); + + it('reads the expected DOM of NG0502, which has no label', () => { + const parts = parseHydrationMismatch( + 'NG0502: During hydration, Angular expected an element to be present at this location.\n\n
      \n
    • …
    • <-- AT THIS LOCATION\n
    \n\nTo fix this problem:\n * check', + ); + expect(parts.expected).toBe('
      \n
    • …
    • <-- AT THIS LOCATION\n
    '); + expect(parts.actual).toBeUndefined(); + }); + + it('reads the token, path and source of every missing provider message shape', () => { + expect( + parseMissingProvider( + 'NG0201: No provider found for `TripApi`. Source: Standalone[App]. Path: TripList -> TripApi. Find more at https://angular.dev/errors/NG0201', + ), + ).toEqual({ token: 'TripApi', path: ['TripList', 'TripApi'], source: 'Standalone[App]' }); + expect( + parseMissingProvider( + 'R3InjectorError(AppModule)[TripApi -> InjectionToken API_URL -> InjectionToken API_URL]: \n NullInjectorError: No provider for InjectionToken API_URL!', + ), + ).toEqual({ + token: 'API_URL', + path: ['TripApi', 'API_URL', 'API_URL'], + source: 'AppModule', + }); + expect(parseMissingProvider('NG0201: No provider for Tooltip found in NodeInjector.')).toEqual({ + token: 'Tooltip', + source: 'NodeInjector', + }); + expect(parseMissingProvider('NG0201: something unexpected')).toBeNull(); + }); + + it('masks NG0100 values when the binding has a secret name, and tokens in any value', () => { + const secret = explainError( + 'NG0100', + "Previous value for 'password': 'hunter2'. Current value: 'hunter3'.", + undefined, + ); + expect(secret).toMatchObject({ previous: '[redacted]', current: '[redacted]', masked: true }); + const token = explainError( + 'NG0100', + `Previous value for 'title': 'none'. Current value: 'Bearer ${JWT}'.`, + undefined, + ); + expect(JSON.stringify(token)).not.toContain(JWT); + }); + + it('names the requester of a missing provider as an owner candidate, and the hydration footer component', () => { + expect( + ownerCandidates('NG0201: No provider found for `TripApi`. Path: TripList -> TripApi.', ''), + ).toEqual(['TripList']); + expect(ownerCandidates(NG0500, '')).toEqual(['Price']); + }); +}); + +describe('membersHolding', () => { + it('names plain fields and signals holding the value, without running getters or computeds', () => { + const getter = vi.fn(() => 'Trips (3)'); + const signalNode = { value: 'Trips (3)' }; + const sig = Object.assign(() => 'never called', { [Symbol('SIGNAL')]: signalNode }); + const component = Object.defineProperties( + { heading: 'Trips (3)', count: 3, other: 'x', label: sig }, + { computedTitle: { get: getter, enumerable: true } }, + ); + expect(membersHolding(component, 'Trips (3)')).toEqual(['heading', 'label']); + expect(membersHolding(component, '3')).toEqual(['count']); + expect(getter).not.toHaveBeenCalled(); + }); + + it('prints values the way Angular does in NG0100', () => { + expect(formatLikeAngular({ a: 1 })).toBe('{"a":1}'); + expect(formatLikeAngular([1, 2])).toBe('[1,2]'); + expect(formatLikeAngular(null)).toBe('null'); + expect(formatLikeAngular('x'.repeat(300))).toHaveLength(201); + }); +}); + +describe('recent signal writes', () => { + it('matches writes of the current value in the window before the error, newest first', () => { + const writes = createRecentWrites(); + writes.add('n1', 'title', { epoch: 1, value: 'Trips (3)', at: 1000, source: 'write' }); + writes.add('n1', 'title', { + epoch: 2, + value: 'Trips (3)', + at: 1500, + source: 'write', + stack: ['TripList.ngAfterViewInit (src/app/trip-list.ts:22:5)'], + }); + writes.add('n2', 'other', { epoch: 1, value: 'nope', at: 1500, source: 'write' }); + writes.add('n1', 'title', { epoch: 3, value: 'Trips (3)', at: 1600, source: 'sample' }); + expect(writes.matching(1700, 'Trips (3)')).toEqual([ + { + signal: 'title', + at: 1500, + stack: ['TripList.ngAfterViewInit (src/app/trip-list.ts:22:5)'], + }, + { signal: 'title', at: 1000 }, + ]); + expect(writes.matching(1500 + WRITE_WINDOW_MS + 1, 'Trips (3)')).toEqual([]); + }); + + it('keeps a bounded number of writes', () => { + const writes = createRecentWrites(3); + for (let i = 0; i < 10; i++) { + writes.add(undefined, `s${i}`, { epoch: i, value: 'v', at: 100, source: 'write' }); + } + expect(writes.matching(100, 'v').map((w) => w.signal)).toEqual(['s9', 's8', 's7']); + }); +}); + +describe('the errors collector explainers', () => { + const stops: (() => void)[] = []; + afterEach(() => { + for (const stop of stops.splice(0)) stop(); + document.body.innerHTML = ''; + vi.useRealTimers(); + }); + + class TripList { + title = 'Trips (3)'; + password = 'Trips (3)'; + } + class Price {} + + function setup(component: object, writes = createRecentWrites()) { + document.body.innerHTML = + ''; + const host = document.querySelector('app-trip-list')!; + const ng: ErrorsDebugNg = { + getComponent: (el) => (el === host ? component : null), + }; + const reports: ErrorsReport[] = []; + const my = { + rpc: { + call: async (name: string, report: unknown) => { + if (name === 'push-errors') reports.push(structuredClone(report) as ErrorsReport); + return { known: true }; + }, + }, + }; + const target = new EventTarget(); + const collector = attachErrors(my, 'page-1', () => ng, { + target: target as never, + now: () => 5000, + writes, + }); + stops.push(collector.stop); + const fire = (error: unknown) => { + const event = new Event('error') as ErrorEvent; + Object.defineProperty(event, 'error', { value: error }); + target.dispatchEvent(event); + }; + return { reports, collector, host, fire }; + } + + it('sends an NG0100 with its component, binding, values, matching fields and the signal write behind it', async () => { + const writes = createRecentWrites(); + writes.listening(); + writes.add('n1', 'heading', { + epoch: 4, + value: 'Trips (3)', + at: 4900, + source: 'write', + stack: ['TripList.ngAfterViewInit (src/app/trip-list.ts:22:5)'], + }); + const component = new (class TripList { + title = 'Trips (3)'; + })(); + const { reports, collector, host, fire } = setup(component, writes); + fire(new RuntimeError(-100, NG0100, NG0100_STACK)); + await collector.push(); + const [group] = reports.at(-1)!.errors; + expect(group!.owner).toEqual({ id: elementId(host), name: 'TripList' }); + expect(group!.explain).toEqual({ + kind: 'expression-changed', + binding: 'title', + template: 'TripList_Conditional_2_Template', + previous: 'Trips', + current: 'Trips (3)', + members: ['title'], + writes: [ + { + signal: 'heading', + at: 4900, + stack: ['TripList.ngAfterViewInit (src/app/trip-list.ts:22:5)'], + }, + ], + writesKnown: true, + }); + }); + + it('hides NG0100 values when a component field holding them has a secret name', async () => { + const { reports, collector, fire } = setup(new TripList()); + fire(new RuntimeError(-100, NG0100)); + await collector.push(); + const explain = reports.at(-1)!.errors[0]!.explain; + expect(explain).toMatchObject({ + kind: 'expression-changed', + previous: '[redacted]', + current: '[redacted]', + masked: true, + members: ['title', 'password'], + writesKnown: false, + }); + expect(explain).not.toHaveProperty('writes'); + }); + + it('sends the expected and actual DOM of a hydration mismatch with the component Angular names', async () => { + document.body.innerHTML = ''; + const { reports, collector, fire } = setup(new Price()); + // The footer names Price, so the owner search looks for that class. + document.body.innerHTML = ''; + fire(new RuntimeError(-500, NG0500)); + await collector.push(); + const explain = reports.at(-1)!.errors[0]!.explain; + expect(explain).toMatchObject({ + kind: 'hydration-mismatch', + summary: 'During hydration Angular expected
    but found .', + }); + expect(explain && 'expected' in explain && explain.expected).toContain('
    '); + expect(explain && 'actual' in explain && explain.actual).toContain(''); + }); + + it('falls back to the hydration info Angular left on the host when the message has no DOM', async () => { + const component = new TripList(); + const { reports, collector, host, fire } = setup(component); + (host as unknown as Record)[HYDRATION_INFO_KEY] = { + status: 'mismatched', + expectedNodeDetails: '\n
      …
    \n
    ', + actualNodeDetails: '\n
      …
    \n
    ', + }; + fire( + new RuntimeError( + -502, + 'NG0502: During hydration Angular was unable to locate a node using the "firstChild" path. To fix this problem:\n * check the "TripList" component', + ), + ); + await collector.push(); + expect(reports.at(-1)!.errors[0]!.explain).toMatchObject({ + kind: 'hydration-mismatch', + expected: '\n
      …
    \n
    ', + actual: '\n
      …
    \n
    ', + }); + }); + + it('sends the missing token and path of an NG0201 and finds the requesting component', async () => { + const { reports, collector, host, fire } = setup(new TripList()); + fire( + new RuntimeError( + -201, + 'NG0201: No provider found for `TripApi`. Source: Standalone[App]. Path: TripList -> TripApi. Find more at https://angular.dev/errors/NG0201', + ), + ); + await collector.push(); + const [group] = reports.at(-1)!.errors; + expect(group!.owner).toEqual({ id: elementId(host), name: 'TripList' }); + expect(group!.explain).toEqual({ + kind: 'missing-provider', + token: 'TripApi', + path: ['TripList', 'TripApi'], + source: 'Standalone[App]', + }); + }); + + it('adds no explainer to other errors', async () => { + const { reports, collector, fire } = setup(new TripList()); + fire(new Error('No seats left')); + await collector.push(); + expect(reports.at(-1)!.errors[0]).not.toHaveProperty('explain'); + }); +}); diff --git a/packages/devtools/src/__tests__/errors-explain-tools.test.ts b/packages/devtools/src/__tests__/errors-explain-tools.test.ts new file mode 100644 index 00000000..690966f9 --- /dev/null +++ b/packages/devtools/src/__tests__/errors-explain-tools.test.ts @@ -0,0 +1,137 @@ +import { describe, expect, it } from 'vitest'; +import { explainSection, toErrorExplain } from '../rpc/error-explain-tools.ts'; +import { + explainErrorText, + mergeErrorsReport, + toErrorsReport, + type ErrorsState, +} from '../rpc/errors-tools.ts'; + +const JWT = ['eyJhbGciOiJIUzI1NiJ9', 'eyJzdWIiOiIxMjM0NSJ9', 'c2lnbmF0dXJlc2ln'].join('.'); + +function stateWith(group: Record): ErrorsState { + const state: ErrorsState = { pages: {} }; + const report = toErrorsReport({ + pageId: 'p1', + full: true, + url: '/', + title: 'Trips', + handler: 'wrapped', + errors: [{ id: 'e1', message: 'x', count: 1, firstAt: 1, lastAt: 1, sources: [], ...group }], + console: [], + dropped: { errors: 0, console: 0 }, + })!; + mergeErrorsReport(state, report, 10); + return state; +} + +describe('toErrorExplain', () => { + it('builds the hydration diff on the server and ignores one the page sent', () => { + const explain = toErrorExplain({ + kind: 'hydration-mismatch', + expected: '

    \n

    …
    ', + actual: '

    \n …', + diff: [{ op: 'same', text: 'forged' }], + external: true, + }); + expect(explain).toEqual({ + kind: 'hydration-mismatch', + expected: '

    \n

    …
    ', + actual: '

    \n …', + external: true, + diff: [ + { op: 'same', text: '

    ' }, + { op: 'expected', text: '

    …
    ' }, + { op: 'actual', text: ' …' }, + ], + }); + }); + + it('masks values again and keeps masked values hidden', () => { + const explain = toErrorExplain({ + kind: 'expression-changed', + previous: `Bearer ${JWT}`, + current: 'ok', + writes: [{ signal: 'token', at: 1, stack: [`f (${JWT})`] }, { signal: 3 }], + }); + expect(JSON.stringify(explain)).not.toContain(JWT); + expect(explain).toMatchObject({ writes: [{ signal: 'token', at: 1 }] }); + expect( + toErrorExplain({ kind: 'expression-changed', masked: true, previous: 'a', current: 'b' }), + ).toMatchObject({ previous: '[redacted]', current: '[redacted]', masked: true }); + }); + + it('drops an unknown kind and a missing provider without a token', () => { + expect(toErrorExplain({ kind: 'other' })).toBeUndefined(); + expect(toErrorExplain({ kind: 'missing-provider' })).toBeUndefined(); + expect(toErrorExplain('x')).toBeUndefined(); + }); +}); + +describe('explain-error with an explainer', () => { + it('shows the NG0100 binding, values, fields and the signal write with its stack', () => { + const text = explainErrorText( + stateWith({ + code: 'NG0100', + owner: { id: 'c4', name: 'TripList' }, + explain: { + kind: 'expression-changed', + binding: 'title', + template: 'TripList_Template', + previous: 'Trips', + current: 'Trips (3)', + members: ['title'], + writes: [{ signal: 'heading', at: 1, stack: ['TripList.ngAfterViewInit (a.ts:1:1)'] }], + writesKnown: true, + }, + }), + { id: 'e1' }, + 10, + ); + expect(text).toContain('**What changed** (NG0100 explainer)'); + expect(text).toContain('- Component: `TripList` (instance `c4`).'); + expect(text).toContain('the `title` property, in the template function `TripList_Template`'); + expect(text).toContain('Previous value: `Trips`. Current value: `Trips (3)`.'); + expect(text).toContain( + 'Signal `heading` was written with this value just before the check, from `TripList.ngAfterViewInit (a.ts:1:1)`.', + ); + }); + + it('says how to find the writer when no signal write matched or none is heard', () => { + const base = { kind: 'expression-changed', previous: 'a', current: 'b' }; + expect( + explainErrorText(stateWith({ explain: { ...base, writesKnown: true } }), { id: 'e1' }), + ).toContain('No named signal was written with this value'); + expect(explainErrorText(stateWith({ explain: base }), { id: 'e1' })).toContain( + 'the page does not report signal writes', + ); + }); + + it('shows the hydration diff as a fenced block', () => { + const text = explainErrorText( + stateWith({ + code: 'NG0500', + explain: { + kind: 'hydration-mismatch', + summary: 'During hydration Angular expected
    but found .', + expected: '

    \n

    …
    ', + actual: '

    \n …', + }, + }), + { id: 'e1' }, + ); + expect(text).toContain('**Server vs client DOM**'); + expect(text).toContain('```text\n

    \n-

    …
    \n+ …\n```'); + }); + + it('points a missing provider at explain-injection with the owner and token', () => { + const section = explainSection( + { kind: 'missing-provider', token: 'TripApi', path: ['TripList', 'TripApi'] }, + { id: 'c4', name: 'TripList' }, + ); + expect(section).toContain('`TripList` -> `TripApi`'); + expect(section).toContain( + 'pangular:explain-injection with `selector` `c4` and `token` `TripApi`', + ); + }); +}); diff --git a/packages/devtools/src/__tests__/explainers-real.test.ts b/packages/devtools/src/__tests__/explainers-real.test.ts new file mode 100644 index 00000000..d1e2d942 --- /dev/null +++ b/packages/devtools/src/__tests__/explainers-real.test.ts @@ -0,0 +1,177 @@ +// @vitest-environment jsdom +import '@angular/compiler'; +import { Component, ErrorHandler, Injectable, Injector } from '@angular/core'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { elementById } from '../element-id.ts'; +import { createRecentWrites } from '../error-explain.ts'; +import { attachErrors, type ErrorsDebugNg } from '../errors-collector.ts'; +import { collectInjectorTree, type DebugNg } from '../injector-tree.ts'; +import { explainInjection, type InjectionExplanation } from '../rpc/injection-explain.ts'; +import type { ErrorsReport } from '../rpc/errors-tools.ts'; +import type { InjectorPage, InjectorTreeNode } from '../types.ts'; +import { angularAtLeast, bootstrapRoot, STANDALONE, type BootedApp } from './angular-version.ts'; + +/** `ChangeDetectionStrategy.Default` (`Eager` from 22.0): checked again after each tick, so NG0100 fires. */ +const EAGER = 1; + +class Headline { + label = 'Trips'; + ngAfterViewInit(): void { + this.label = 'Trips (3)'; + } +} +Component({ + ...STANDALONE, + selector: 'app-headline', + template: '

    Hello

    ', + changeDetection: EAGER, +})(Headline); + +class Missing {} +Injectable()(Missing); +class CardState {} +Injectable()(CardState); +class Hint {} +Injectable()(Hint); + +class TripCard { + constructor(readonly injector: Injector) {} + open(): void { + this.injector.get(Missing); + } +} +(TripCard as unknown as { ctorParameters: () => unknown[] }).ctorParameters = () => [ + { type: Injector }, +]; +Component({ + ...STANDALONE, + selector: 'app-trip-card', + template: '', + providers: [CardState], +})(TripCard); + +class TripPage {} +Component({ + ...STANDALONE, + selector: 'app-root', + imports: [TripCard, Headline], + template: '', + viewProviders: [Hint], + // An OnPush parent that is not dirty skips its children in the second check. + changeDetection: EAGER, +})(TripPage); + +const flatten = (nodes: InjectorTreeNode[]): InjectorTreeNode[] => + nodes.flatMap((node) => [node, ...flatten(node.children)]); + +function harness() { + const reports: ErrorsReport[] = []; + const my = { + rpc: { + call: async (name: string, report: unknown) => { + if (name === 'push-errors') reports.push(report as ErrorsReport); + return { known: true }; + }, + }, + }; + const ng = () => (globalThis as { ng?: ErrorsDebugNg }).ng; + const writes = createRecentWrites(); + writes.listening(); + return { reports, collector: attachErrors(my, 'real-page', ng, { writes }) }; +} + +describe('the explainers with a real app', () => { + let app: BootedApp | null = null; + let stop = () => {}; + afterEach(() => { + stop(); + app?.destroy(); + app = null; + document.body.innerHTML = ''; + vi.restoreAllMocks(); + }); + + async function boot() { + vi.spyOn(console, 'error').mockImplementation(() => {}); + document.body.innerHTML = ''; + const { reports, collector } = harness(); + stop = collector.stop; + app = await bootstrapRoot(TripPage, { declarations: [TripCard, Headline] }); + for (let i = 0; i < 2; i++) { + await new Promise((resolve) => setTimeout(resolve, 0)); + try { + app.appRef.tick(); + } catch (error) { + // A direct tick throws; the app's scheduler hands the error to the ErrorHandler. + app.injector.get(ErrorHandler).handleError(error); + } + } + return { reports, collector }; + } + + it("explains Angular's own NG0100 with the binding, both values and the field that holds the new one", async () => { + const { reports, collector } = await boot(); + await collector.push(); + const group = reports + .flatMap((report) => report.errors) + .find((error) => /ExpressionChanged/.test(error.message)); + expect(group).toBeDefined(); + expect(group!.owner?.name).toBe('Headline'); + expect(group!.explain).toMatchObject({ + kind: 'expression-changed', + previous: 'Trips', + current: 'Trips (3)', + members: ['label'], + writesKnown: true, + }); + if (angularAtLeast('12.0')) { + expect(group!.explain).toMatchObject({ binding: 'title' }); + } + }); + + it("explains a real missing provider and walks the real injector tree's lookup for it", async () => { + const { reports, collector } = await boot(); + document.querySelector('button')!.click(); + await collector.push(); + const group = reports + .flatMap((report) => report.errors) + .find((error) => error.explain?.kind === 'missing-provider'); + expect(group?.explain).toMatchObject({ kind: 'missing-provider', token: 'Missing' }); + expect(group?.owner?.name).toBe('TripCard'); + expect(elementById(group!.owner!.id)).toBe(document.querySelector('app-trip-card')); + + const ng = (globalThis as { ng?: DebugNg }).ng!; + const tree = collectInjectorTree(ng); + const page: InjectorPage = { pageId: 'real-page', reportedAt: 1, ...tree }; + const nodes = flatten(tree.roots); + const card = nodes.find((n) => n.injector.component === 'TripCard')!; + const root = nodes.find((n) => n.injector.component === 'TripPage')!; + // TripCard is declared in TripPage's template, so a `host` lookup stops at TripPage. + expect(card.injector.host).toBe(root.injector.id); + expect(root.injector.host).toBeUndefined(); + + const reduced = !angularAtLeast('16.2'); + const missing = explainInjection( + page, + { selector: group!.owner!.id, token: 'Missing' }, + reduced, + ) as InjectionExplanation; + expect(missing.outcome).toBe(reduced ? 'unknown' : 'error'); + expect(missing.steps.at(-1)?.type).toBe('null'); + if (reduced) return; + expect(missing.approximate).toBeUndefined(); + + const own = explainInjection(page, { + selector: 'TripCard', + token: 'CardState', + }) as InjectionExplanation; + expect(own.resolvedBy).toBe(card.injector.id); + // TripPage's viewProviders reach TripCard, which sits in TripPage's view. + const hint = explainInjection(page, { + selector: 'TripCard', + token: 'Hint', + host: true, + }) as InjectionExplanation; + expect(hint.resolvedBy).toBe(root.injector.id); + }); +}); diff --git a/packages/devtools/src/__tests__/hydration-agent.test.ts b/packages/devtools/src/__tests__/hydration-agent.test.ts index a3b54eaa..ee548ba2 100644 --- a/packages/devtools/src/__tests__/hydration-agent.test.ts +++ b/packages/devtools/src/__tests__/hydration-agent.test.ts @@ -110,7 +110,9 @@ describe('hydration tool', () => { expect(text).toContain('Page `p1` (`http://localhost:4000/trips`): hydrated from server HTML.'); expect(text).toContain('| Skipped (ngSkipHydration) | 1 |'); expect(text).toContain('Skipped: `TripMap` `` `c3`'); - expect(text).toContain('- `Price` `` `c5`: expected `
    `, found ``'); + expect(text).toContain('- `Price` `` `c5`'); + // The server HTML Angular expected against the client DOM it found, as a diff. + expect(text).toContain(' ```diff\n -
    \n + \n ```'); expect(text).toContain( 'Created on the client (after hydration, or inside a skipped host): `Toast`', ); diff --git a/packages/devtools/src/__tests__/injector-tree.test.ts b/packages/devtools/src/__tests__/injector-tree.test.ts index 3f9b2094..feaebcca 100644 --- a/packages/devtools/src/__tests__/injector-tree.test.ts +++ b/packages/devtools/src/__tests__/injector-tree.test.ts @@ -147,6 +147,28 @@ describe('collectInjectorTree', () => { ]); }); + it('names where a host lookup stops: the host of the component whose template declares the element', () => { + const { ng, root, card } = fakeNg(); + const app = ng.getComponent(root); + const withOwners = { + ...ng, + // Each call returns a new App, so the owner is matched by its host instead. + getOwningComponent: (el: Element) => (el === card ? app : null), + getHostElement: (component: unknown) => (component === app ? root : null), + }; + const report = collectInjectorTree(withOwners); + const [rootNode] = report.roots; + expect(rootNode!.children[0]!.injector.host).toBe(rootNode!.injector.id); + // The root component is declared by no template. + expect(rootNode!.injector).not.toHaveProperty('host'); + }); + + it('leaves the host out when the page has no getOwningComponent', () => { + const { ng } = fakeNg(); + const card = collectInjectorTree(ng).roots[0].children[0]; + expect(card.injector).not.toHaveProperty('host'); + }); + it('keeps ids stable between collections and gives each element a selector', () => { const { ng, card } = fakeNg(); const first = collectInjectorTree(ng).roots[0].children[0].injector; diff --git a/packages/devtools/src/__tests__/leaks-collector.test.ts b/packages/devtools/src/__tests__/leaks-collector.test.ts new file mode 100644 index 00000000..7bd34a43 --- /dev/null +++ b/packages/devtools/src/__tests__/leaks-collector.test.ts @@ -0,0 +1,624 @@ +// @vitest-environment jsdom +import { afterEach, describe, expect, it } from 'vitest'; +import { elementId } from '../element-id.ts'; +import { + MAX_TRACKED_DESTROYED, + TRACKING_KEY, + attachLeaks, + stackClasses, + type LeaksDebugNg, + type LeaksOptions, +} from '../leaks-collector.ts'; +import type { Profiler } from '../change-detection.ts'; +import type { LeaksReport } from '../rpc/leaks-tools.ts'; + +const JWT = ['eyJhbGciOiJIUzI1NiJ9', 'eyJzdWIiOiIxMjM0NSJ9', 'c2lnbmF0dXJlc2ln'].join('.'); + +/** A `WeakRef` a test can clear, standing in for the garbage collector. */ +class FakeWeakRef { + static all: FakeWeakRef[] = []; + private target: T | undefined; + constructor(target: T) { + this.target = target; + FakeWeakRef.all.push(this as FakeWeakRef); + } + deref() { + return this.target; + } + /** Collects `target` everywhere a fake ref points at it. */ + static collect(target: object) { + for (const ref of FakeWeakRef.all) if (ref.target === target) ref.target = undefined; + } +} + +class FakeRegistry { + static last: FakeRegistry | null = null; + readonly entries: { target: object; held: T; token?: object }[] = []; + constructor(readonly callback: (held: T) => void) { + FakeRegistry.last = this as FakeRegistry; + } + register(target: object, held: T, token?: object) { + this.entries.push({ target, held, token }); + } + unregister(token: object) { + const at = this.entries.findIndex((entry) => entry.token === token); + if (at >= 0) this.entries.splice(at, 1); + return at >= 0; + } + /** Runs the cleanup of every collected target, as the engine would after a GC. */ + finalize() { + for (const entry of this.entries.splice(0)) { + FakeWeakRef.collect(entry.target); + this.callback(entry.held); + } + } +} + +class TripList {} +interface Subscribable { + subscribe(): { closed: boolean; unsubscribe(): void }; +} + +class TripCard { + sub?: { closed: boolean; unsubscribe(): void }; + constructor( + readonly trip: number, + source?: Subscribable, + ) { + // A subscription made in the constructor, with no teardown. + if (source) this.sub = source.subscribe(); + } + listen(source: Subscribable) { + return source.subscribe(); + } +} + +/** Fake `ng`: components by host element, a null injector for unknown elements. */ +function fakeNg(components: Map, extra: Partial = {}) { + const NULL = { name: 'NullInjector' }; + const alive = new Set(); + const ng: LeaksDebugNg & { NULL: object; alive: Set } = { + NULL, + alive, + getComponent: (el: Element) => components.get(el) ?? null, + getInjector: (el: Element) => (el.isConnected || alive.has(el) ? { el } : NULL), + ...extra, + }; + return ng; +} + +interface Harness { + reports: LeaksReport[]; + calls: { name: string; args: unknown[] }[]; + collector: ReturnType; + route: { value: string }; + registry: () => FakeRegistry; + handlers: Map unknown>; +} + +const stops: (() => void)[] = []; +afterEach(() => { + for (const stop of stops.splice(0)) stop(); + document.body.innerHTML = ''; + FakeWeakRef.all = []; +}); + +function harness(ng: () => LeaksDebugNg | undefined, options: Partial = {}): Harness { + const reports: LeaksReport[] = []; + const calls: { name: string; args: unknown[] }[] = []; + const handlers = new Map unknown>(); + const route = { value: '/trips' }; + const my = { + rpc: { + call: async (name: string, ...args: unknown[]) => { + calls.push({ name, args }); + if (name === 'push-leaks') reports.push(structuredClone(args[0]) as LeaksReport); + return { known: true }; + }, + register: (definition: { name: string; handler: (...args: unknown[]) => unknown }) => { + handlers.set(definition.name, definition.handler); + }, + }, + }; + const collector = attachLeaks(my, 'page-1', ng, { + route: () => route.value, + weak: { WeakRef: FakeWeakRef as never, FinalizationRegistry: FakeRegistry as never }, + dirty: null, + storage: null, + target: null, + angularMajor: () => 22, + addProfiler: () => null, + ...options, + }); + stops.push(collector.stop); + return { + reports, + calls, + collector, + route, + registry: () => FakeRegistry.last!, + handlers, + }; +} + +function page(cards: number) { + document.body.innerHTML = `
    ${''.repeat(cards)}
    `; + const root = document.querySelector('app-root')!; + const components = new Map([[root, new TripList()]]); + document + .querySelectorAll('app-trip-card') + .forEach((el, i) => components.set(el, new TripCard(i))); + return { root, components, cards: [...document.querySelectorAll('app-trip-card')] }; +} + +describe('attachLeaks: destroyed but alive', () => { + it('moves a component that left the page to the destroyed list, keyed by its stable id', async () => { + const { components, cards } = page(2); + const ng = fakeNg(components); + const h = harness(() => ng); + await h.collector.push(); + expect(h.reports.at(-1)!.totals.components).toBe(3); + expect(h.reports.at(-1)!.destroyed).toEqual([]); + + const id = elementId(cards[1]!); + cards[1]!.remove(); + await h.collector.push(); + const gone = h.reports.at(-1)!.destroyed; + expect(gone).toEqual([ + expect.objectContaining({ id, name: 'TripCard', route: '/trips', navigations: 0 }), + ]); + expect(gone[0]!.detached).toBeUndefined(); + expect(h.reports.at(-1)!.totals.components).toBe(2); + expect(h.reports.at(-1)!.pageId).toBe('page-1'); + }); + + it('counts navigations since the destroy, and forgets an instance once it is collected', async () => { + const { components, cards } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng); + await h.collector.push(); + cards[0]!.remove(); + await h.collector.push(); + h.route.value = '/trips/2'; + await h.collector.push(); + h.route.value = '/about'; + await h.collector.push(); + const report = h.reports.at(-1)!; + expect(report.navigations).toBe(2); + expect(report.destroyed[0]).toMatchObject({ + name: 'TripCard', + route: '/trips', + navigations: 2, + }); + + h.registry().finalize(); + await h.collector.push(); + expect(h.reports.at(-1)!.destroyed).toEqual([]); + expect(h.reports.at(-1)!.totals).toMatchObject({ destroyed: 0, collected: 1 }); + }); + + it('reports a host that left while Angular still holds its view as detached, not destroyed', async () => { + const { components, cards } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng); + await h.collector.push(); + ng.alive.add(cards[0]!); + cards[0]!.remove(); + await h.collector.push(); + expect(h.reports.at(-1)!.destroyed[0]).toMatchObject({ name: 'TripCard', detached: true }); + expect(h.reports.at(-1)!.support.detached).toBe(true); + + // Angular drops the view later: now it is destroyed. + ng.alive.delete(cards[0]!); + await h.collector.push(); + expect(h.reports.at(-1)!.destroyed[0]!.detached).toBeUndefined(); + }); + + it('takes a detached view back when it returns to the page (route reuse)', async () => { + const { components, cards } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng); + await h.collector.push(); + const card = cards[0]!; + const parent = card.parentElement!; + ng.alive.add(card); + card.remove(); + await h.collector.push(); + expect(h.reports.at(-1)!.destroyed).toHaveLength(1); + parent.append(card); + await h.collector.push(); + expect(h.reports.at(-1)!.destroyed).toEqual([]); + expect(h.registry().entries).toEqual([]); + }); + + it('cannot tell detached from destroyed before Angular 14, so it calls both destroyed', async () => { + const { components, cards } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng, { angularMajor: () => 13 }); + await h.collector.push(); + ng.alive.add(cards[0]!); + cards[0]!.remove(); + await h.collector.push(); + expect(h.reports.at(-1)!.destroyed[0]!.detached).toBeUndefined(); + expect(h.reports.at(-1)!.support.detached).toBeUndefined(); + }); + + it('keeps no more than its cap of destroyed instances, oldest first out', async () => { + const { components } = page(0); + const main = document.querySelector('main')!; + const ng = fakeNg(components); + const h = harness(() => ng); + for (let round = 0; round < 3; round++) { + const batch: Element[] = []; + for (let i = 0; i < 250; i++) { + const el = document.createElement('app-trip-card'); + components.set(el, new TripCard(i)); + main.append(el); + batch.push(el); + } + h.collector.scan(); + for (const el of batch) el.remove(); + h.collector.scan(); + } + const report = h.collector.report(); + expect(report.totals.destroyed).toBe(MAX_TRACKED_DESTROYED); + expect(report.totals.dropped).toBe(750 - MAX_TRACKED_DESTROYED); + expect(report.destroyed.length).toBeLessThanOrEqual(100); + }); + + it('says retention is unavailable without WeakRef or the debug API', async () => { + page(1); + const h = harness(() => undefined, { weak: {} }); + await h.collector.push(); + expect(h.reports.at(-1)!.support.retention).toBe(false); + expect(h.reports.at(-1)!.totals.components).toBe(0); + }); + + it('masks secrets in routes and titles', async () => { + const { components, cards } = page(1); + document.title = `Trip ${JWT}`; + const ng = fakeNg(components); + const h = harness(() => ng); + h.route.value = `/trips?token=${JWT}`; + await h.collector.push(); + cards[0]!.remove(); + await h.collector.push(); + const text = JSON.stringify(h.reports.at(-1)); + expect(text).not.toContain(JWT); + document.title = ''; + }); + + it('never changes the app DOM', async () => { + const { components, cards } = page(2); + const ng = fakeNg(components); + const h = harness(() => ng); + const before = document.documentElement.outerHTML; + const changes: MutationRecord[] = []; + const observer = new MutationObserver((records) => changes.push(...records)); + observer.observe(document.documentElement, { + subtree: true, + attributes: true, + childList: true, + }); + await h.collector.push(); + await h.collector.push(true); + observer.disconnect(); + expect(changes.concat(observer.takeRecords())).toEqual([]); + expect(document.documentElement.outerHTML).toBe(before); + expect(cards).toHaveLength(2); + }); +}); + +describe('attachLeaks: effects', () => { + it('counts the effects of each component from the signal graph, and shares those siblings both list', async () => { + const { root, components, cards } = page(2); + const graphs = new Map([ + [ + root, + [ + { id: 'r1', kind: 'effect' }, + { id: 't0', kind: 'template' }, + ], + ], + [ + cards[0]!, + [ + { id: 's1', kind: 'effect' }, + { id: 's2', kind: 'effect' }, + { id: 'x', kind: 'signal' }, + ], + ], + [ + cards[1]!, + [ + { id: 's1', kind: 'effect' }, + { id: 's2', kind: 'effect' }, + { id: 'c3', kind: 'effect' }, + ], + ], + ]); + const ng = fakeNg(components, { + ɵgetSignalGraph: (injector) => ({ + nodes: graphs.get((injector as { el: Element }).el) ?? [], + }), + }); + const h = harness(() => ng); + await h.collector.push(); + const report = h.reports.at(-1)!; + expect(report.support.effects).toBe(true); + expect(report.totals.effects).toBe(4); + const byId = new Map(report.components.map((c) => [c.id, c])); + expect(byId.get(elementId(root))).toMatchObject({ effects: 1 }); + expect(byId.get(elementId(cards[0]!))).toMatchObject({ effects: 0, sharedEffects: 2 }); + expect(byId.get(elementId(cards[1]!))).toMatchObject({ effects: 1, sharedEffects: 2 }); + }); + + it('says effects are unavailable without ɵgetSignalGraph, or when its nodes carry no ids (before 20.1)', async () => { + const { components } = page(1); + const h = harness(() => fakeNg(components)); + await h.collector.push(); + expect(h.reports.at(-1)!.support.effects).toBe(false); + + const old = fakeNg(components, { ɵgetSignalGraph: () => ({ nodes: [{ kind: 'effect' }] }) }); + const h2 = harness(() => old); + await h2.collector.push(); + expect(h2.reports.at(-1)!.support.effects).toBe(false); + expect(h2.reports.at(-1)!.totals.effects).toBe(0); + }); +}); + +/** A small stand-in for RxJS: `subscribe` returns a subscription that can close. */ +function fakeRxjs() { + class Subscription { + closed = false; + unsubscribe() { + this.closed = true; + } + } + class Observable { + constructor(private readonly onSubscribe?: () => void) {} + subscribe(): Subscription { + this.onSubscribe?.(); + return new Subscription(); + } + } + const original = Observable.prototype.subscribe; + return { module: { Observable }, Observable, original }; +} + +describe('attachLeaks: subscriptions', () => { + it('stays off until asked, then wraps subscribe and restores it when turned off', async () => { + const rx = fakeRxjs(); + const { components } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng, { loadRxjs: async () => rx.module as never }); + await h.collector.push(); + expect(h.reports.at(-1)!.support.subscriptions).toBe('off'); + expect(rx.Observable.prototype.subscribe).toBe(rx.original); + + expect(await h.collector.setTracking(true)).toMatchObject({ ok: true }); + expect(rx.Observable.prototype.subscribe).not.toBe(rx.original); + await h.collector.push(); + expect(h.reports.at(-1)!.support.subscriptions).toBe('on'); + + await h.collector.setTracking(false); + expect(rx.Observable.prototype.subscribe).toBe(rx.original); + expect(Object.prototype.hasOwnProperty.call(rx.Observable.prototype, 'subscribe')).toBe(true); + }); + + it('leaves a wrapper someone added after it in place, and goes quiet', async () => { + const rx = fakeRxjs(); + page(0); + const h = harness(() => fakeNg(new Map()), { loadRxjs: async () => rx.module as never }); + await h.collector.setTracking(true); + const ours = rx.Observable.prototype.subscribe; + const theirs = function (this: unknown) { + return ours.call(this); + }; + rx.Observable.prototype.subscribe = theirs; + await h.collector.setTracking(false); + expect(rx.Observable.prototype.subscribe).toBe(theirs); + }); + + it('flags a subscription still open after the instance that made it was destroyed', async () => { + const rx = fakeRxjs(); + let listener: Profiler | null = null; + const { components, cards } = page(1); + const card = components.get(cards[0]!) as TripCard; + const ng = fakeNg(components); + const h = harness(() => ng, { + loadRxjs: async () => rx.module as never, + addProfiler: (fn) => { + listener = fn; + return () => (listener = null); + }, + }); + await h.collector.push(); + await h.collector.setTracking(true); + + const source = new rx.Observable(); + // Subscriptions made inside a lifecycle hook, between Angular's profiler events. + listener!(4, card, 'ngOnInit'); + const subs = { open: card.listen(source), closed: card.listen(source) }; + listener!(5, card, 'ngOnInit'); + subs.closed.unsubscribe(); + + await h.collector.push(); + let report = h.reports.at(-1)!; + expect(report.support.instances).toBe(true); + expect(report.components.find((c) => c.name === 'TripCard')).toMatchObject({ + subscriptions: 1, + }); + expect(report.subscriptions).toEqual([]); + + cards[0]!.remove(); + await h.collector.push(); + report = h.reports.at(-1)!; + expect(report.subscriptions).toEqual([ + expect.objectContaining({ + name: 'TripCard', + instanceId: elementId(cards[0]!), + count: 1, + reason: 'instance-destroyed', + route: '/trips', + }), + ]); + expect(report.subscriptions[0]!.source).toMatch(/TripCard/); + expect(report.destroyed[0]).toMatchObject({ subscriptions: 1 }); + + subs.open.unsubscribe(); + await h.collector.push(); + expect(h.reports.at(-1)!.subscriptions).toEqual([]); + }); + + it('without the profiler, flags subscriptions of a class that has no instance left', async () => { + const rx = fakeRxjs(); + const { components, cards } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng, { loadRxjs: async () => rx.module as never }); + await h.collector.push(); + await h.collector.setTracking(true); + const source = new rx.Observable(); + const made = new TripCard(9, source); + await h.collector.push(); + expect(h.reports.at(-1)!.subscriptions).toEqual([]); + expect(h.reports.at(-1)!.support.instances).toBeUndefined(); + + cards[0]!.remove(); + await h.collector.push(); + expect(h.reports.at(-1)!.subscriptions).toEqual([ + expect.objectContaining({ name: 'TripCard', count: 1, reason: 'no-live-instance' }), + ]); + expect(h.reports.at(-1)!.subscriptions[0]!.instanceId).toBeUndefined(); + made.sub!.unsubscribe(); + }); + + it("does not give a child's constructor subscription to the parent whose template builds it", async () => { + const rx = fakeRxjs(); + let listener: Profiler | null = null; + const { root, components } = page(1); + const list = components.get(root)!; + const h = harness(() => fakeNg(components), { + loadRxjs: async () => rx.module as never, + addProfiler: (fn) => { + listener = fn; + return () => (listener = null); + }, + }); + await h.collector.push(); + await h.collector.setTracking(true); + listener!(0, list); + const made = new TripCard(7, new rx.Observable()); + listener!(1, list); + await h.collector.push(); + const report = h.reports.at(-1)!; + expect(report.components.find((c) => c.name === 'TripList')?.subscriptions ?? 0).toBe(0); + expect(report.totals.subscriptions).toBe(1); + made.sub!.unsubscribe(); + }); + + it('counts one subscription for an operator chain, not one per inner subscribe', async () => { + const rx = fakeRxjs(); + const { components, cards } = page(1); + const card = components.get(cards[0]!) as TripCard; + const h = harness(() => fakeNg(components), { loadRxjs: async () => rx.module as never }); + await h.collector.push(); + await h.collector.setTracking(true); + const inner = new rx.Observable(); + // An operator subscribes to its source inside the outer subscribe. + const outer = new rx.Observable(() => inner.subscribe()); + card.listen(outer); + await h.collector.push(); + expect(h.reports.at(-1)!.totals.subscriptions).toBe(1); + }); + + it('reports tracking as unavailable when RxJS cannot be loaded', async () => { + page(0); + const h = harness(() => fakeNg(new Map()), { + loadRxjs: () => Promise.reject(new Error('no rxjs')), + }); + expect(await h.collector.setTracking(true)).toMatchObject({ ok: false }); + await h.collector.push(); + expect(h.reports.at(-1)!.support.subscriptions).toBe('unavailable'); + }); + + it('starts tracking again after a reload when it was on, and forgets the choice when off', async () => { + const rx = fakeRxjs(); + page(0); + const store = new Map([[TRACKING_KEY, '1']]); + const storage = { + getItem: (key: string) => store.get(key) ?? null, + setItem: (key: string, value: string) => void store.set(key, value), + removeItem: (key: string) => void store.delete(key), + }; + const h = harness(() => fakeNg(new Map()), { + loadRxjs: async () => rx.module as never, + storage, + }); + await new Promise((resolve) => setTimeout(resolve, 0)); + await h.collector.push(); + expect(h.reports.at(-1)!.support.subscriptions).toBe('on'); + await h.collector.setTracking(false); + expect(store.has(TRACKING_KEY)).toBe(false); + }); + + it('answers the leak-tracking event only for its own page', async () => { + const rx = fakeRxjs(); + page(0); + const h = harness(() => fakeNg(new Map()), { loadRxjs: async () => rx.module as never }); + const handler = h.handlers.get('leak-tracking')!; + handler({ pageId: 'other', on: true }); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(rx.Observable.prototype.subscribe).toBe(rx.original); + handler({ pageId: 'page-1', on: true }); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(rx.Observable.prototype.subscribe).not.toBe(rx.original); + }); +}); + +describe('attachLeaks: pushes', () => { + it('skips an unchanged report, sends a keepalive when one is due, and forgets the page on leave', async () => { + let now = 1000; + const { components } = page(1); + const ng = fakeNg(components); + const h = harness(() => ng, { now: () => now, tickMs: () => 3000 }); + await h.collector.push(); + await h.collector.push(); + expect(h.reports).toHaveLength(1); + now += 6000; + await h.collector.push(); + expect(h.reports).toHaveLength(2); + + h.collector.leave(); + await h.collector.push(true); + expect(h.reports).toHaveLength(2); + expect(h.calls.at(-1)).toEqual({ name: 'forget-leaks-page', args: ['page-1'] }); + h.collector.resume(); + await h.collector.push(); + expect(h.reports).toHaveLength(3); + }); +}); + +describe('stackClasses', () => { + it('reads constructors, methods and compiled template functions, innermost first', () => { + const stack = [ + 'Error', + ' at Observable.subscribe (http://localhost:4200/node_modules/rxjs/index.js:10:5)', + ' at new _TripCard (http://localhost:4200/src/app/trip-card.ts?t=1:12:7)', + ' at TripList_Conditional_2_Template (http://localhost:4200/src/app/trip-list.ts:30:1)', + ' at executeTemplate (http://localhost:4200/node_modules/core.js:1:1)', + ].join('\n'); + const { names, frames } = stackClasses(stack); + expect(names.slice(0, 2)).toEqual(['Observable', 'TripCard']); + expect(names).toContain('TripList'); + expect(frames[1]).toContain('new _TripCard'); + }); + + it('reads Firefox and Safari frames', () => { + const { names } = stackClasses( + 'Error\nngOnInit@http://x/a.js:1:1\nTripCard.prototype.ngOnInit@x', + ); + expect(names).toEqual(['TripCard']); + expect(stackClasses('Error\nTripCard.ngOnInit@http://x/a.js:1:1').names).toEqual(['TripCard']); + }); +}); diff --git a/packages/devtools/src/__tests__/leaks-real.test.ts b/packages/devtools/src/__tests__/leaks-real.test.ts new file mode 100644 index 00000000..39a66f94 --- /dev/null +++ b/packages/devtools/src/__tests__/leaks-real.test.ts @@ -0,0 +1,136 @@ +// @vitest-environment jsdom +import '@angular/compiler'; +import * as core from '@angular/core'; +import { Component } from '@angular/core'; +import { Observable, Subject } from 'rxjs'; +import { afterEach, describe, expect, it } from 'vitest'; +import { attachLeaks, type LeaksDebugNg } from '../leaks-collector.ts'; +import type { LeaksReport } from '../rpc/leaks-tools.ts'; +import { + angularAtLeast, + bootstrapRoot, + writableSignal, + STANDALONE, + type BootedApp, +} from './angular-version.ts'; + +/** A long-lived source, like a store or a service's Subject. */ +const updates = new Subject(); + +const effect = (core as unknown as Record)['effect'] as + ((fn: () => void) => unknown) | undefined; + +class LeakyCard { + readonly seats = writableSignal(3); + // Subscribed in the constructor with no teardown. + readonly sub = updates.subscribe(() => {}); + hooked?: { unsubscribe(): void }; + constructor() { + effect?.(() => void this.seats()); + } + ngOnInit() { + // Made inside a lifecycle hook, so the profiler names the instance (20.0+). + this.hooked = updates.subscribe(() => {}); + } +} +Component({ ...STANDALONE, selector: 'app-leaky-card', template: `{{ seats() }}` })(LeakyCard); + +class Trips { + readonly show = writableSignal(false); +} +Component({ + ...STANDALONE, + selector: 'app-root', + imports: [LeakyCard], + template: `@if (show()) {}`, +})(Trips); + +const settle = async (app: BootedApp) => { + for (let i = 0; i < 3; i++) { + await new Promise((resolve) => setTimeout(resolve, 0)); + app.appRef.tick(); + } +}; + +// `@if` and standalone imports need 17.0. +describe.runIf(angularAtLeast('17.0'))('the leaks collector with a real app', () => { + let app: BootedApp | null = null; + let stop = () => {}; + afterEach(() => { + stop(); + app?.destroy(); + app = null; + document.body.innerHTML = ''; + }); + + it('sees a destroyed component through the null injector, its effect, and its open subscription', async () => { + document.body.innerHTML = ''; + app = await bootstrapRoot(Trips); + await settle(app); + const reports: LeaksReport[] = []; + const route = { value: '/trips' }; + const my = { + rpc: { + call: async (name: string, report: unknown) => { + if (name === 'push-leaks') reports.push(report as LeaksReport); + return { known: true }; + }, + }, + }; + const ng = () => (globalThis as { ng?: LeaksDebugNg }).ng; + const collector = attachLeaks(my, 'real-page', ng, { + route: () => route.value, + dirty: null, + storage: null, + target: null, + }); + stop = collector.stop; + await collector.push(); + const subscribe = Observable.prototype.subscribe; + // The real RxJS, loaded the way the overlay loads it. + expect(await collector.setTracking(true)).toMatchObject({ ok: true }); + + const root = app.injector.get(core.ApplicationRef).components[0]!.instance as Trips; + root.show.set(true); + await settle(app); + await collector.push(); + let report = reports.at(-1)!; + const card = report.components.find((c) => c.name === 'LeakyCard'); + if (angularAtLeast('20.1')) { + expect(report.support.effects).toBe(true); + expect(card).toMatchObject({ effects: 1 }); + } + expect(report.totals.subscriptions).toBe(2); + // From 20.0 the profiler ties the ngOnInit subscription to the instance. + const profiler = angularAtLeast('20.0'); + if (profiler) expect(card).toMatchObject({ subscriptions: 1 }); + + root.show.set(false); + await settle(app); + route.value = '/about'; + await collector.push(); + report = reports.at(-1)!; + expect(report.support.detached).toBe(true); + expect(report.destroyed).toEqual([ + expect.objectContaining({ name: 'LeakyCard', route: '/trips', navigations: 1 }), + ]); + // Destroyed, not detached: Angular dropped its view. + expect(report.destroyed[0]!.detached).toBeUndefined(); + const reasons = report.subscriptions.map((s) => [s.name, s.reason, s.count]); + expect(reasons).toEqual( + expect.arrayContaining( + profiler + ? [ + ['LeakyCard', 'no-live-instance', 1], + ['LeakyCard', 'instance-destroyed', 1], + ] + : [['LeakyCard', 'no-live-instance', 2]], + ), + ); + for (const sub of report.subscriptions) expect(sub.source).toMatch(/LeakyCard/); + + expect(Observable.prototype.subscribe).not.toBe(subscribe); + await collector.setTracking(false); + expect(Observable.prototype.subscribe).toBe(subscribe); + }); +}); diff --git a/packages/devtools/src/__tests__/leaks-tools.test.ts b/packages/devtools/src/__tests__/leaks-tools.test.ts new file mode 100644 index 00000000..2f94a302 --- /dev/null +++ b/packages/devtools/src/__tests__/leaks-tools.test.ts @@ -0,0 +1,225 @@ +import { createHostContext } from 'devframe/node'; +import { describe, expect, it, vi } from 'vitest'; +import pangular, { createPangular } from '../devframe.ts'; +import { + AGENT_INSPECTOR, + AGENT_SAFETY, + PAGE_AGENT_ENTRIES, + RPC_INSPECTOR, + SHARED_STATE_INSPECTOR, + agentAllowed, + resolvePangularConfig, +} from '../config.ts'; +import { + RETAINED_AFTER_MS, + findLeaksText, + isRetained, + staleLeakPages, + toLeaksReport, + type LeaksReport, + type LeaksState, +} from '../rpc/leaks-tools.ts'; + +const JWT = ['eyJhbGciOiJIUzI1NiJ9', 'eyJzdWIiOiIxMjM0NSJ9', 'c2lnbmF0dXJlc2ln'].join('.'); + +async function boot(definition = pangular) { + const host = { + mountStatic: () => {}, + resolveOrigin: () => 'http://localhost', + getStorageDir: () => '', + }; + const ctx = await createHostContext({ cwd: process.cwd(), mode: 'dev', host: host as never }); + await definition.setup(ctx as never); + const call = (name: string, payload: unknown) => + ctx.rpc.invokeLocal(`pangular:${name}` as never, ...([payload] as never)); + const invoke = async (id: string, args: Record = {}) => + ((await ctx.agent.invoke(`pangular:${id}`, args)) as { markdown: string }).markdown; + const state = async () => + ( + await ( + ctx.rpc as unknown as { + sharedState: { get: (key: string) => Promise<{ value: () => LeaksState }> }; + } + ).sharedState.get('pangular:leaks') + ).value(); + return { ctx, call, invoke, state }; +} + +const report = (extra: Partial = {}): LeaksReport => ({ + pageId: 'tab1', + url: '/trips', + title: 'Trips', + at: Date.now(), + support: { retention: true, effects: true, subscriptions: 'on', instances: true, detached: true }, + navigations: 4, + totals: { components: 3, effects: 2, subscriptions: 1, destroyed: 2, collected: 5, dropped: 0 }, + components: [ + { id: 'c1', name: 'TripList', effects: 2, subscriptions: 1 }, + { id: 'c2', name: 'Banner', effects: 0, subscriptions: 0, sharedEffects: 1 }, + ], + destroyed: [ + { + id: 'c9', + name: 'TripCard', + route: '/trips/7', + destroyedAt: Date.now() - RETAINED_AFTER_MS - 5000, + navigations: 3, + subscriptions: 1, + }, + { id: 'c10', name: 'TripMap', route: '/trips/8', destroyedAt: Date.now(), navigations: 0 }, + ], + subscriptions: [ + { + name: 'TripCard', + instanceId: 'c9', + count: 1, + source: 'TripCard.ngOnInit (trip-card.ts:12:7)', + route: '/trips/7', + openedAt: Date.now() - 60_000, + reason: 'instance-destroyed', + }, + ], + ...extra, +}); + +describe('toLeaksReport', () => { + it('masks routes, titles and call sites again on the server and drops what is not a report', () => { + const checked = toLeaksReport( + report({ + url: `/trips?token=${JWT}`, + title: `Bearer ${JWT}`, + destroyed: [ + { + id: 'c9', + name: 'TripCard', + route: `/trips?access_token=${JWT}`, + destroyedAt: 1, + navigations: 1, + }, + ], + subscriptions: [ + { + name: 'TripCard', + count: 1, + source: `load (api.ts?key=${JWT}:1:1)`, + route: '/x', + openedAt: 1, + reason: 'no-live-instance', + }, + ], + }), + )!; + expect(JSON.stringify(checked)).not.toContain(JWT); + expect(toLeaksReport({ url: '/x' })).toBeNull(); + expect(toLeaksReport(null)).toBeNull(); + expect( + toLeaksReport({ pageId: 'p', support: { subscriptions: 'weird' } })!.support.subscriptions, + ).toBe('off'); + }); +}); + +describe('isRetained', () => { + it('needs enough navigations and time, and never counts a detached view', () => { + const page = { ...report(), reportedAt: Date.now() }; + expect(isRetained(page, page.destroyed[0]!)).toBe(true); + expect(isRetained(page, page.destroyed[1]!)).toBe(false); + expect(isRetained(page, { ...page.destroyed[0]!, detached: true })).toBe(false); + expect(isRetained(page, { ...page.destroyed[0]!, navigations: 1 })).toBe(false); + }); +}); + +describe('the leaks registration', () => { + it('keeps one entry per page, forgets a page, and expires a silent one', async () => { + const { call, state } = await boot(); + await call('push-leaks', report()); + await call('push-leaks', report({ pageId: 'tab2', url: '/about' })); + expect(Object.keys((await state()).pages).sort()).toEqual(['tab1', 'tab2']); + expect((await state()).pages['tab1']!.url).toBe('/trips'); + await call('forget-leaks-page', 'tab2'); + expect(Object.keys((await state()).pages)).toEqual(['tab1']); + expect(staleLeakPages(await state(), Date.now() + 20_000, () => 15_000)).toEqual(['tab1']); + }); + + it('answers find-leaks with retained instances, open subscriptions and live effects', async () => { + const { call, invoke } = await boot(); + expect(await invoke('find-leaks')).toMatch(/No page reports leak data/); + await call('push-leaks', report()); + const text = await invoke('find-leaks'); + expect(text).toMatch(/## Still retained/); + expect(text).toMatch(/\| `TripCard` \| `c9` \| `\/trips\/7` \|/); + expect(text).toMatch(/not proof of a leak/); + expect(text).toMatch(/Memory panel/); + expect(text).toMatch(/destroyed recently and not collected yet: `TripMap`/); + expect(text).toMatch(/## Open subscriptions after destroy/); + expect(text).toMatch(/its instance is destroyed/); + expect(text).toMatch(/takeUntilDestroyed/); + expect(text).toMatch(/\| `TripList` \| `c1` \| 2 \| 1 \|/); + expect(text).toMatch(/\| `Banner` \| `c2` \| 0 \(\+1 shared\) \|/); + expect(await invoke('find-leaks', { component: 'map' })).not.toMatch(/`TripCard`/); + expect(await invoke('find-leaks', { page: 'nope' })).toMatch(/No page `nope`/); + }); + + it('says what is missing when tracking is off or the page lacks the APIs', () => { + const page = { + ...report({ + support: { retention: false, effects: false, subscriptions: 'off' }, + subscriptions: [], + }), + reportedAt: Date.now(), + }; + const text = findLeaksText({ pages: { tab1: page } }); + expect(text).toMatch(/cannot track destroyed components/); + expect(text).toMatch(/Subscription tracking is off/); + expect(text).toMatch(/Effects are not counted/); + }); + + it('turns tracking on for one page through the page-side event, and off for every page', async () => { + const { ctx, call, invoke } = await boot(); + expect(await invoke('track-subscriptions', { action: 'start' })).toMatch(/nothing to track/); + await call('push-leaks', report()); + await call('push-leaks', report({ pageId: 'tab2' })); + const broadcast = vi.spyOn(ctx.rpc, 'broadcast'); + expect(await invoke('track-subscriptions', { action: 'start', page: 'tab1' })).toMatch( + /Tracking subscriptions on page `tab1`/, + ); + expect(broadcast).toHaveBeenCalledWith( + expect.objectContaining({ + method: 'pangular:leak-tracking', + args: [{ pageId: 'tab1', on: true }], + }), + ); + broadcast.mockClear(); + expect(await invoke('track-subscriptions', { action: 'stop' })).toMatch(/every page/); + const args = broadcast.mock.calls.map(([options]) => (options as { args: unknown[] }).args[0]); + expect(args).toEqual( + expect.arrayContaining([ + { pageId: 'tab1', on: false }, + { pageId: 'tab2', on: false }, + ]), + ); + expect(await call('request-leak-tracking', { pageId: 'tab2', on: true })).toEqual({ + pages: 1, + }); + }); + + it('is part of the Components inspector, and track-subscriptions is an action', async () => { + for (const name of ['push-leaks', 'forget-leaks-page', 'request-leak-tracking']) { + expect(RPC_INSPECTOR[name]).toBe('components'); + } + expect(AGENT_INSPECTOR['find-leaks']).toBe('components'); + expect(AGENT_INSPECTOR['track-subscriptions']).toBe('components'); + expect(SHARED_STATE_INSPECTOR['leaks']).toBe('components'); + expect(AGENT_SAFETY['track-subscriptions']).toBe('action'); + expect(PAGE_AGENT_ENTRIES).toEqual( + expect.arrayContaining(['find-leaks', 'track-subscriptions']), + ); + const readOnly = resolvePangularConfig({ agent: { readOnly: true } }); + expect(agentAllowed({ id: 'pangular:find-leaks' }, readOnly)).toBe(true); + expect(agentAllowed({ id: 'pangular:track-subscriptions' }, readOnly)).toBe(false); + + const { ctx } = await boot(createPangular({ inspectors: { components: false } })); + const tools = ctx.agent.list().tools.map((tool: { id: string }) => tool.id); + expect(tools).not.toContain('pangular:find-leaks'); + expect(tools).not.toContain('pangular:track-subscriptions'); + }); +}); diff --git a/packages/devtools/src/cd-data.ts b/packages/devtools/src/cd-data.ts index 93489e86..28687834 100644 --- a/packages/devtools/src/cd-data.ts +++ b/packages/devtools/src/cd-data.ts @@ -1,6 +1,12 @@ import type { CdAfterRenderStat, + CdCause, + CdCauseKind, CdCheck, + CdDiagnosis, + CdInputStat, + CdWasteStat, + CdZoneStat, CdComponentStat, CdCycle, CdHookStat, @@ -31,6 +37,8 @@ const MAX_SPAN_NAMES = 4000; const MAX_DEPTH = 1000; const MAX_TIMINGS = 100; const MAX_PAGE_ID = 50; +const MAX_FRAMES = 3; +const MAX_DIAGNOSIS_ROWS = 50; /** What each {@link CdSpan} kind letter means. */ export const CD_SPAN_KIND = { @@ -91,6 +99,9 @@ function cycle(value: unknown, names: number): CdCycle | null { afterRenderMs: optional(value['afterRenderMs']), outputMs: optional(value['outputMs']), }; + const reason = cause(value['cause']); + const refreshed = optional(value['refreshed']); + const unchanged = optional(value['unchanged']); return { id: num(value['id']), at: num(value['at']), @@ -102,9 +113,241 @@ function cycle(value: unknown, names: number): CdCycle | null { ...Object.fromEntries(Object.entries(timing).filter(([, v]) => v !== undefined)), ...(spans.length ? { spans } : {}), ...(droppedSpans ? { droppedSpans } : {}), + ...(reason ? { cause: reason } : {}), + ...(refreshed ? { refreshed } : {}), + ...(unchanged ? { unchanged } : {}), }; } +/** Every cause kind, in the order the panel and the agent tool list them. */ +export const CD_CAUSE_KINDS: readonly CdCauseKind[] = [ + 'event', + 'http', + 'timer', + 'signal', + 'effect', + 'markForCheck', + 'input', + 'view', + 'tick', + 'zone', + 'unknown', +]; + +/** How the panel and the agent tool name each cause kind. */ +export const CD_CAUSE_LABEL: Record = { + event: 'Event', + http: 'HTTP response', + timer: 'Timer', + signal: 'Signal write', + effect: 'Effect', + markForCheck: 'markForCheck', + input: 'setInput', + view: 'View change', + tick: 'ApplicationRef.tick', + zone: 'zone.js only', + unknown: 'Unknown', +}; + +const isCauseKind = (value: unknown): value is CdCauseKind => + typeof value === 'string' && (CD_CAUSE_KINDS as readonly string[]).includes(value); + +function cause(value: unknown): CdCause | undefined { + if (!isRecord(value) || !isCauseKind(value['kind'])) return undefined; + const fields = ['component', 'listener', 'event', 'target', 'signal', 'task'] as const; + const out: CdCause = { kind: value['kind'] }; + if (isCauseKind(value['via'])) out.via = value['via']; + for (const field of fields) { + const each = text(value[field], MAX_NAME); + if (each) out[field] = each; + } + if (value['zone'] === true) out.zone = true; + const stack = list(value['stack'], MAX_FRAMES) + .map((frame) => text(frame, MAX_TRIGGER)) + .filter(Boolean); + if (stack.length) out.stack = stack; + const more = Math.floor(num(value['more'])); + if (more) out.more = more; + return out; +} + +function wasteStat(value: unknown): CdWasteStat | null { + if (!isRecord(value)) return null; + const name = text(value['name'], MAX_NAME); + if (!name) return null; + const strategy = value['strategy']; + return { + name, + refreshed: Math.floor(num(value['refreshed'])), + unchanged: Math.floor(num(value['unchanged'])), + ...(strategy === 'OnPush' || strategy === 'Eager' ? { strategy } : {}), + }; +} + +function inputStat(value: unknown): CdInputStat | null { + if (!isRecord(value)) return null; + const name = text(value['name'], MAX_NAME); + const input = text(value['input'], MAX_NAME); + if (!name || !input) return null; + const parent = text(value['parent'], MAX_NAME); + return { + name, + input, + ...(parent ? { parent } : {}), + inPlace: Math.floor(num(value['inPlace'])), + sameContents: Math.floor(num(value['sameContents'])), + }; +} + +function zoneStat(value: unknown): CdZoneStat | null { + if (!isRecord(value)) return null; + const name = text(value['name'], MAX_NAME); + if (!name) return null; + const tasks = list(value['tasks'], 3) + .map((task) => text(task, MAX_NAME)) + .filter(Boolean); + return { name, ticks: Math.floor(num(value['ticks'])), ...(tasks.length ? { tasks } : {}) }; +} + +/** Checks a recording's `diagnosis`; undefined when there is none. */ +export function sanitizeCdDiagnosis(value: unknown): CdDiagnosis | undefined { + if (!isRecord(value)) return undefined; + const causes: CdDiagnosis['causes'] = {}; + if (isRecord(value['causes'])) { + for (const kind of CD_CAUSE_KINDS) { + const count = Math.floor(num(value['causes'][kind])); + if (count) causes[kind] = count; + } + } + const components = list(value['components'], MAX_COMPONENTS) + .map(wasteStat) + .filter((c): c is CdWasteStat => !!c); + const inputs = list(value['inputs'], MAX_DIAGNOSIS_ROWS) + .map(inputStat) + .filter((c): c is CdInputStat => !!c); + const zone = list(value['zone'], MAX_DIAGNOSIS_ROWS) + .map(zoneStat) + .filter((c): c is CdZoneStat => !!c); + const major = Math.floor(num(value['major'])); + return { + triggers: value['triggers'] === true, + waste: value['waste'] === true, + ...(major && major < 1000 ? { major } : {}), + causes, + components, + ...(inputs.length ? { inputs } : {}), + ...(zone.length ? { zone } : {}), + }; +} + +/** One line on what started a cycle, such as `click on button in Cart (add), wrote count`. */ +export function cdCauseText(reason: CdCause): string { + const parts: string[] = []; + const where = reason.component + ? ` in ${reason.component}${reason.listener ? ` (${reason.listener})` : ''}` + : ''; + switch (reason.kind) { + case 'event': + parts.push( + `${reason.event ?? 'Template listener'}${reason.target ? ` on ${reason.target}` : ''}${where}`, + ); + break; + case 'http': + parts.push(`HTTP response${where}`); + break; + case 'timer': + parts.push(`${reason.task ?? 'Timer'}${where}`); + break; + case 'zone': + parts.push( + `zone.js tick with no Angular notification${reason.task ? ` after ${reason.task}` : ''}`, + ); + break; + case 'tick': + parts.push(`ApplicationRef.tick()${where}`); + break; + default: + parts.push(`${CD_CAUSE_LABEL[reason.kind]}${where}`); + } + if (reason.signal) parts.push(`wrote signal ${reason.signal}`); + else if (reason.via && reason.via !== reason.kind) + parts.push(`via ${CD_CAUSE_LABEL[reason.via]}`); + if (reason.zone && reason.kind !== 'zone') parts.push('run by zone.js'); + if (reason.more) parts.push(`${reason.more} more notification${reason.more === 1 ? '' : 's'}`); + return parts.join(', '); +} + +/** A suggestion from a recording's diagnosis. */ +export interface CdHint { + /** The component class it is about. */ + name: string; + kind: 'on-push' | 'already-on-push' | 'in-place' | 'same-contents' | 'zone'; + text: string; +} + +/** Refreshed checks a class needs before the OnPush hint looks at it. */ +export const CD_HINT_MIN_CHECKS = 10; +/** The share of refreshed checks that may change something for the OnPush hint. */ +export const CD_HINT_MAX_CHANGED = 0.2; + +/** + * Suggestions from a diagnosis: OnPush for classes refreshed often that + * rarely change, inputs mutated in place or renewed with equal contents, and + * components that only zone.js keeps up to date. + */ +export function cdHints(diagnosis: CdDiagnosis | undefined): CdHint[] { + if (!diagnosis) return []; + const hints: CdHint[] = []; + const defaultOnPush = (diagnosis.major ?? 0) >= 22; + for (const stat of diagnosis.components) { + if (stat.refreshed < CD_HINT_MIN_CHECKS) continue; + const changed = stat.refreshed - stat.unchanged; + if (changed / stat.refreshed > CD_HINT_MAX_CHANGED) continue; + const counts = `refreshed ${stat.refreshed} times and changed something in ${changed}`; + if (stat.strategy === 'Eager') { + hints.push({ + name: stat.name, + kind: 'on-push', + text: defaultOnPush + ? `${stat.name} was ${counts}. It opts out of OnPush, which is the default from Angular 22: remove \`changeDetection: ChangeDetectionStrategy.Eager\` (or \`Default\`) so Angular skips it until an input, event, signal or markForCheck marks it.` + : `${stat.name} was ${counts}. Add \`changeDetection: ChangeDetectionStrategy.OnPush\` so Angular skips it until an input, event, signal or markForCheck marks it.`, + }); + } else if (stat.strategy === 'OnPush') { + hints.push({ + name: stat.name, + kind: 'already-on-push', + text: `${stat.name} was ${counts}, and it is already OnPush${defaultOnPush ? ' (the default from Angular 22)' : ''}. Something keeps marking it: an input that gets a new reference each time, an event or output in it, markForCheck, or a signal it reads that is set to an equal value.`, + }); + } + } + for (const input of diagnosis.inputs ?? []) { + const from = input.parent ? ` set by ${input.parent}` : ''; + if (input.inPlace) { + hints.push({ + name: input.name, + kind: 'in-place', + text: `Input ${input.input} of ${input.name}${from} changed in place ${input.inPlace} time${input.inPlace === 1 ? '' : 's'}: same reference, different contents. OnPush components, computed and signal equality don't see that. Pass a new object or array instead of mutating it.`, + }); + } + if (input.sameContents) { + hints.push({ + name: input.name, + kind: 'same-contents', + text: `Input ${input.input} of ${input.name}${from} got a new reference with the same contents ${input.sameContents} time${input.sameContents === 1 ? '' : 's'}, so Angular refreshed ${input.name} for nothing. Keep the reference when nothing changed, for example with a computed instead of a method call in the template.`, + }); + } + } + for (const zone of diagnosis.zone ?? []) { + const tasks = zone.tasks?.length ? ` (after ${zone.tasks.join(', ')})` : ''; + hints.push({ + name: zone.name, + kind: 'zone', + text: `${zone.name} changed in ${zone.ticks} tick${zone.ticks === 1 ? '' : 's'} that only zone.js started${tasks}. Without zone.js it would not update: keep that state in a signal, or call markForCheck after changing it.`, + }); + } + return hints; +} + function stat(value: unknown): CdComponentStat | null { const base = check(value); if (!base || !isRecord(value)) return null; @@ -177,6 +420,7 @@ export function sanitizeCdRecording(value: unknown, maxCycles: number): CdRecord const droppedTimings = Math.floor(num(value['droppedTimings'])) + extraTimings; const afterRender = afterRenderStat(value['afterRender']); const used = cycles.some((c) => c.spans?.length); + const diagnosis = sanitizeCdDiagnosis(value['diagnosis']); return { recording: value['recording'] === true, startedAt: @@ -197,6 +441,7 @@ export function sanitizeCdRecording(value: unknown, maxCycles: number): CdRecord ...(droppedTimings ? { droppedTimings } : {}), ...(afterRender ? { afterRender } : {}), ...(used ? { spanNames } : {}), + ...(diagnosis ? { diagnosis } : {}), }; } @@ -345,6 +590,8 @@ export function cdTraceFile(recording: CdRecording, pageId: string): CdTraceFile ...(cycle.hookMs ? { hookMs: cycle.hookMs } : {}), ...(cycle.afterRenderMs ? { afterRenderMs: cycle.afterRenderMs } : {}), ...(cycle.outputMs ? { outputMs: cycle.outputMs } : {}), + ...(cycle.cause ? { cause: cdCauseText(cycle.cause) } : {}), + ...(cycle.unchanged ? { unchanged: cycle.unchanged } : {}), slowest: cycle.components.map((c) => `${c.name} ${c.checks}x ${c.ms}ms`), }, }); diff --git a/packages/devtools/src/cd-diagnosis.ts b/packages/devtools/src/cd-diagnosis.ts new file mode 100644 index 00000000..d520ea95 --- /dev/null +++ b/packages/devtools/src/cd-diagnosis.ts @@ -0,0 +1,808 @@ +import { PROFILER_EVENT } from './cd-recorder.ts'; +import { listenerName } from './cd-timing.ts'; +import type { + CdCause, + CdCauseKind, + CdDiagnosis, + CdInputStat, + CdWasteStat, + CdZoneStat, +} from './config.ts'; +import { className } from './injector-tree.ts'; +import { installSignalWriteHook, type RawSignalNode } from './signal-history.ts'; +import { rawNodeOf } from './signal-resources.ts'; +import { appFrames, captureStack } from './signal-stack.ts'; + +/** + * The `NotificationSource` values Angular passes to + * `ChangeDetectionSchedulerImpl.notify`, checked against the scheduler and + * its callers in `@angular/core/fesm2022/_debug_node-chunk.mjs` and + * `_pending_tasks-chunk.mjs` (Angular 22). The enum is `const`, so the + * numbers are all a build has. + */ +export const NOTIFY = { + /** `markAncestorsForTraversal`: a signal a template read changed. */ + MarkAncestorsForTraversal: 0, + SetInput: 1, + DeferBlockStateUpdate: 2, + DebugApplyChanges: 3, + MarkForCheck: 4, + /** `wrapListener`: a template listener runs. */ + Listener: 5, + CustomElement: 6, + RenderHook: 7, + ViewAttached: 8, + ViewDetachedFromDOM: 9, + AsyncAnimationsLoaded: 10, + PendingTaskRemoved: 11, + RootEffect: 12, + ViewEffect: 13, +} as const; + +/** What each notification says about the cause. Missing ones (11) don't make Angular refresh views. */ +const NOTIFY_KIND: Partial> = { + 0: 'signal', + 1: 'input', + 2: 'view', + 3: 'view', + 4: 'markForCheck', + 5: 'event', + 6: 'view', + 7: 'view', + 8: 'view', + 9: 'view', + 10: 'view', + 12: 'effect', + 13: 'effect', +}; + +/** Notifications that make Angular refresh views (`dirtyFlags` 1, 2, 4 or 16), not only run afterRender hooks. */ +const REFRESHING = new Set([0, 1, 2, 3, 4, 5, 6, 12, 13]); + +/** A notification that does not refresh views is dropped after this long without a tick. */ +const STALE_MS = 100; +/** Inputs compared per class, and items compared per input. */ +const MAX_INPUTS = 30; +const MAX_ITEMS = 50; +/** Classes and inputs the diagnosis keeps totals for. */ +const MAX_CLASSES = 1000; +const MAX_INPUT_ROWS = 500; +/** Rows a snapshot lists. */ +const LISTED_CLASSES = 100; +const LISTED_ROWS = 50; +const MAX_TASKS = 3; +const MAX_TEXT = 200; + +/** + * Frames of Angular's HTTP backends. The XHR backend answers in a `load` + * event, which the event target already shows; the fetch backend answers in + * a promise, so only the stack shows it. + */ +const HTTP_FRAME = + /\b_?(FetchBackend|HttpXhrBackend|HttpInterceptorHandler)\b|@angular[/_]common[/_]http/; +const TIMER_TASK = + /^(setTimeout|setInterval|setImmediate|requestAnimationFrame|webkitRequestAnimationFrame|mozRequestAnimationFrame)$/; +const HTTP_TASK = /XMLHttpRequest|fetch|JSONP/i; +/** Class names in stack frames that are not app classes. */ +const NOT_APP_CLASS = + /^(HTML|SVG|Window|Promise|Object|Array|Function|Timeout|XMLHttpRequest|EventTarget|Zone|Generator|AsyncGenerator|Map|Set)\b/; + +type Ctor = object; +type AnyRecord = Record; + +/** The fields of Angular's `ChangeDetectionSchedulerImpl` this module reads or wraps. */ +interface SchedulerLike { + notify(source: number): void; + runningTick?: boolean; +} + +interface ZoneTask { + type?: string; + source?: string; +} + +interface ZoneApi { + current?: { get?(key: string): unknown }; + currentTask?: ZoneTask | null; +} + +interface DebugNg { + getInjector?(el: Element): unknown; + ɵgetInjectorResolutionPath?(injector: unknown): unknown[]; + getDirectiveMetadata?(instance: unknown): { + inputs?: Record; + changeDetection?: number; + } | null; +} + +interface Pending { + source: number; + at: number; + event?: string; + target?: string; + http: boolean; + task?: string; + signal?: string; + stack?: string[]; + owner?: unknown; + listener?: unknown; + more: number; +} + +interface Frame { + /** The context of the first template Angular ran in this check: the component itself when it was refreshed. */ + first: unknown; + changed: boolean; +} + +interface CycleInfo { + cause: CdCause; + refreshed: number; + unchanged: number; +} + +interface ClassMeta { + inputs: [publicName: string, prop: string][]; + strategy?: 'OnPush' | 'Eager'; + component: boolean; +} + +interface Snap { + ref: unknown; + items?: unknown[]; +} + +const NONE = Symbol('none'); + +function read(fn: () => T, fallback: T): T { + try { + return fn(); + } catch { + return fallback; + } +} + +const ctorOf = (instance: unknown): Ctor | null => { + const ctor = (instance as { constructor?: unknown } | null)?.constructor; + return typeof ctor === 'function' ? ctor : null; +}; + +const nameOf = (instance: unknown): string => { + const ctor = ctorOf(instance); + return ctor ? className(ctor as { name?: string }) : '?'; +}; + +const cut = (value: string) => value.slice(0, MAX_TEXT); + +function isScheduler(value: unknown): value is SchedulerLike { + return ( + !!value && + typeof value === 'object' && + typeof (value as AnyRecord)['notify'] === 'function' && + 'runningTick' in value && + 'appRef' in value + ); +} + +/** + * Angular's change detection scheduler (`ChangeDetectionSchedulerImpl`), + * found among the values the app's environment injectors already hold, + * through `ng.getInjector` and `ng.ɵgetInjectorResolutionPath`. Nothing is + * created. Null when the page has no such scheduler (before Angular 18). + */ +export function findCdScheduler(ng: unknown, roots: Iterable): SchedulerLike | null { + const api = ng as DebugNg | null; + if (!api || typeof api.getInjector !== 'function') return null; + for (const root of roots) { + const injector = read(() => api.getInjector!(root), null); + if (!injector) continue; + const path = read(() => api.ɵgetInjectorResolutionPath?.(injector) ?? [], [] as unknown[]); + for (const each of path) { + const records = read(() => (each as { records?: unknown } | null)?.records, undefined); + if (!(records instanceof Map)) continue; + for (const record of records.values()) { + const value = read(() => (record as { value?: unknown } | null)?.value, undefined); + if (isScheduler(value)) return value; + } + } + } + return null; +} + +/** The items of an object input to compare by identity, or undefined for a primitive or function. */ +function itemsOf(value: unknown): unknown[] | undefined { + if (!value || typeof value !== 'object') return undefined; + return read(() => { + if (Array.isArray(value)) return [value.length, ...value.slice(0, MAX_ITEMS)]; + if (value instanceof Map) { + const items: unknown[] = [value.size]; + for (const [key, item] of value) { + if (items.length > MAX_ITEMS * 2) break; + items.push(key, item); + } + return items; + } + if (value instanceof Set) return [value.size, ...[...value].slice(0, MAX_ITEMS)]; + // Dates, elements and other class instances keep their state where a shallow look misses it. + const proto = Object.getPrototypeOf(value); + if (proto !== Object.prototype && proto !== null) return undefined; + const keys = Object.keys(value).slice(0, MAX_ITEMS); + return [keys.length, ...keys.flatMap((key) => [key, (value as AnyRecord)[key]])]; + }, undefined); +} + +function sameItems(a: unknown[], b: unknown[]): boolean { + if (a.length !== b.length) return false; + for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false; + return true; +} + +/** An input's value, without calling a signal: reading one inside a check would subscribe the running template to it. */ +function inputValue(instance: object, prop: string): unknown { + const value = read(() => (instance as AnyRecord)[prop], undefined); + if (typeof value !== 'function') return value; + const node = rawNodeOf(value) as { value?: unknown } | null; + const stored = node?.value; + return typeof stored === 'symbol' ? undefined : stored; +} + +/** + * Angular's functions between the code that changed something and `notify`, + * by name, from `markViewDirty`, `markAncestorsForTraversal`, the signal set + * path and `ComponentRef.setInput` in `@angular/core/fesm2022`. + */ +const ANGULAR_NOTIFY_PATH = + /^(markViewDirty|markForCheck|markAncestorsForTraversal|updateAncestorTraversalFlagsOnAttach|consumerMarkedDirty|producerNotifyConsumers|producerIncrementEpoch|signalValueChanged|signalSetFn|signalUpdateFn|linkedSignalSetFn|linkedSignalUpdateFn|runPostSignalSetFn|setInput|set|update|notify|addSequence|register|attachView|detachView|insertView)$/; + +/** A stack frame's function name without its class and alias: `markForCheck` for `ViewRef.markForCheck [as m]`. */ +function frameName(line: string): string { + const text = line.trim().replace(/^at\s+/, ''); + const match = text.match(/^(.*?)\s*\(/) ?? text.match(/^(.*?)@/); + const name = (match?.[1] ?? '').replace(/\s*\[as [^\]]+\]$/, '').replace(/^async\s+/, ''); + return name.split('.').pop() ?? ''; +} + +/** Frames of this module's `notify` wrapper, in V8 (`wrapper [as notify]`) and Firefox or Safari (`wrapper@`). */ +const isWrapperFrame = (line: string) => + /\[as notify\]/.test(line) || frameName(line) === 'wrapper'; +/** Frames of `ApplicationRef.tick`, `_tick` and `tickImpl`. */ +const isTickFrame = (line: string) => /^_?tick(Impl)?$/.test(frameName(line)); + +/** + * The frames below the `marker` frame near the top of `raw` (the first one, + * or the last with `last`): the code that called into Angular. In a bundled + * build the overlay and Angular share chunk files with the app, so their + * frames can't be told apart by file and are cut by position and name + * instead. A stack without the marker is kept. + */ +export function callerStack( + raw: string, + marker: (line: string) => boolean, + options: { skip?: RegExp; last?: boolean } = {}, +): string { + const { skip, last = false } = options; + const lines = raw.split('\n'); + let cut = -1; + for (let i = 0; i < Math.min(lines.length, 30); i++) { + if (!marker(lines[i]!)) continue; + cut = i; + if (!last) break; + } + if (cut < 0) return raw; + let rest = lines.slice(cut + 1); + if (skip) { + let i = 0; + while (i < rest.length && skip.test(frameName(rest[i]!))) i++; + rest = rest.slice(i); + } + return ['Error', ...rest].join('\n'); +} + +/** The class part of an app frame such as `Cart.add (src/app/cart.ts:12:5)`. */ +function frameClass(frame: string | undefined): string | undefined { + const match = frame?.match(/^([A-Z][\w$]*)\./); + return match && !NOT_APP_CLASS.test(match[1]!) ? match[1] : undefined; +} + +export interface CdDiagnosisOptions { + getNg: () => unknown; + maxCycles: number; + doc?: () => Document | undefined; + global?: () => AnyRecord; + now?: () => number; + stack?: () => string | undefined; + /** Adds a signal write hook and resolves to its remover, or null when the page has none. */ + writeHook?: (onWrite: (node: RawSignalNode) => void) => Promise<(() => void) | null>; +} + +/** + * Finds what started each change detection cycle and which checks changed + * nothing, while a recording runs. It wraps the scheduler's `notify`, adds a + * signal write hook and watches DOM updates with a `MutationObserver`, and + * undoes all three when the recording stops. `onEvent` gets the profiler + * events after the recorder, with the id the recorder gave the cycle. + */ +export function createCdDiagnosis(options: CdDiagnosisOptions) { + const doc = options.doc ?? (() => (typeof document === 'undefined' ? undefined : document)); + const global = options.global ?? (() => globalThis as unknown as AnyRecord); + const now = options.now ?? (() => performance.now()); + const stack = options.stack ?? captureStack; + const writeHook = options.writeHook ?? ((onWrite) => installSignalWriteHook(onWrite)); + + let active = false; + let started = false; + /** What the last start could hook, kept after a stop. */ + let hooked = { triggers: false, waste: false }; + let generation = 0; + let scheduler: SchedulerLike | null = null; + let unwrap: (() => void) | null = null; + let removeWriteHook: (() => void) | null = null; + let observer: MutationObserver | null = null; + + let pending: Pending | null = null; + let depth = 0; + let inSync = false; + let frames: Frame[] = []; + let cycleStack: { info: CycleInfo; frames: Frame[]; inSync: boolean }[] = []; + let current: CycleInfo | null = null; + + let cycles = new Map(); + let causes: Partial> = {}; + let classes = new Map< + Ctor, + { refreshed: number; unchanged: number; zone: number; tasks: string[] } + >(); + let untracked = 0; + let inputRows = new Map(); + let seen = new WeakMap>(); + const metas = new WeakMap(); + + const zoneApi = (): ZoneApi | undefined => + read(() => global()['Zone'] as ZoneApi | undefined, undefined); + + const zoneTask = (): string | undefined => { + const task = read(() => zoneApi()?.currentTask ?? null, null); + const source = read(() => task?.source, undefined); + return typeof source === 'string' && source ? cut(source) : undefined; + }; + + const inAngularZone = (): boolean => + read(() => zoneApi()?.current?.get?.('isAngularZone') === true, false); + + const domEvent = (): { type: string; target?: string; xhr: boolean } | null => { + const event = read(() => global()['event'] as Event | undefined, undefined); + if (!event || typeof event !== 'object' || typeof event.type !== 'string') return null; + const target = read(() => event.target, null); + const Xhr = read( + () => global()['XMLHttpRequest'] as typeof XMLHttpRequest | undefined, + undefined, + ); + const xhr = !!Xhr && read(() => target instanceof Xhr, false); + const tag = read( + () => (target && 'localName' in target ? String((target as Element).localName) : undefined), + undefined, + ); + return { type: cut(event.type), ...(tag ? { target: cut(tag) } : {}), xhr }; + }; + + const onNotify = (source: number) => { + if (!active || depth > 0) return; + const at = now(); + if (pending && !REFRESHING.has(pending.source) && at - pending.at > STALE_MS) pending = null; + if (pending && (REFRESHING.has(pending.source) || !REFRESHING.has(source))) { + pending.more++; + return; + } + const event = domEvent(); + const task = zoneTask(); + // A listener's own frames are Angular's; the app's run after this call. + const taken = source === NOTIFY.Listener ? undefined : stack(); + const raw = taken && callerStack(taken, isWrapperFrame, { skip: ANGULAR_NOTIFY_PATH }); + const http = + !!event?.xhr || (!!raw && HTTP_FRAME.test(raw)) || (!!task && HTTP_TASK.test(task)); + const appStack = raw ? appFrames(raw) : []; + pending = { + source, + at, + ...(event && !event.xhr ? { event: event.type } : {}), + ...(event?.target && !event.xhr ? { target: event.target } : {}), + http, + ...(task ? { task } : {}), + ...(appStack.length ? { stack: appStack } : {}), + more: pending ? pending.more + 1 : 0, + }; + }; + + const onWrite = (node: RawSignalNode) => { + if (!active || depth > 0 || !pending || pending.signal !== undefined) return; + pending.signal = cut(read(() => node.debugName, undefined) || '?'); + }; + + const causeOf = (): CdCause => { + const zone = inAngularZone(); + const running = read(() => scheduler?.runningTick === true, false); + const flag = zone && !running ? { zone: true } : {}; + const p = pending; + if (p) { + const base = NOTIFY_KIND[p.source] ?? 'unknown'; + const owner = p.owner !== undefined ? nameOf(p.owner) : undefined; + const listener = p.listener !== undefined ? listenerName(p.listener) : ''; + const timer = !!p.task && TIMER_TASK.test(p.task); + const kind: CdCauseKind = p.http + ? 'http' + : base !== 'event' && p.event + ? 'event' + : timer && base !== 'event' + ? 'timer' + : base; + const component = owner ?? frameClass(p.stack?.[0]); + return { + kind, + ...(kind !== base ? { via: base } : {}), + ...(component ? { component: cut(component) } : {}), + ...(listener ? { listener: cut(listener) } : {}), + ...(p.event ? { event: p.event } : {}), + ...(p.target ? { target: p.target } : {}), + ...(p.signal ? { signal: p.signal } : {}), + ...(p.task ? { task: p.task } : {}), + ...flag, + ...(p.stack ? { stack: p.stack } : {}), + ...(p.more ? { more: p.more } : {}), + }; + } + if (running) return { kind: 'unknown' }; + const task = zoneTask(); + // Without the scheduler no notification is seen, so a tick can't be told apart from one it ran. + if (!scheduler) return { kind: 'unknown', ...flag, ...(task && zone ? { task } : {}) }; + if (zone) return { kind: 'zone', zone: true, ...(task ? { task } : {}) }; + const taken = stack(); + const frames = taken ? appFrames(callerStack(taken, isTickFrame, { last: true })) : []; + const component = frameClass(frames[0]); + return { + kind: 'tick', + ...(component ? { component } : {}), + ...(frames.length ? { stack: frames } : {}), + }; + }; + + /** Credits DOM updates since the last call to the component being checked. */ + const credit = () => { + const records = observer ? read(() => observer!.takeRecords(), [] as MutationRecord[]) : []; + if (records.length && frames.length) frames.at(-1)!.changed = true; + }; + + const metaOf = (instance: object, ctor: Ctor): ClassMeta => { + const known = metas.get(ctor); + if (known) return known; + const ng = options.getNg() as DebugNg | undefined; + const meta = read(() => ng?.getDirectiveMetadata?.(instance) ?? null, null); + const inputs = Object.entries(meta?.inputs ?? {}) + .slice(0, MAX_INPUTS) + .map(([name, entry]): [string, string] => [ + name, + typeof entry === 'string' + ? entry + : Array.isArray(entry) && typeof entry[0] === 'string' + ? entry[0] + : name, + ]); + const strategy = + meta?.changeDetection === 0 ? 'OnPush' : meta?.changeDetection === 1 ? 'Eager' : undefined; + const value: ClassMeta = { + inputs, + ...(strategy ? { strategy } : {}), + component: read(() => 'ɵcmp' in (ctor as AnyRecord), false), + }; + metas.set(ctor, value); + return value; + }; + + const inputRow = (ctor: Ctor, input: string, parent: unknown): CdInputStat | null => { + const name = className(ctor as { name?: string }); + const key = `${name}\u0000${input}`; + let row = inputRows.get(key); + if (!row) { + if (inputRows.size >= MAX_INPUT_ROWS) return null; + const parentCtor = ctorOf(parent); + const parentMeta = + parentCtor && parent && typeof parent === 'object' ? metaOf(parent, parentCtor) : null; + row = { + name, + input: cut(input), + ...(parentMeta?.component ? { parent: nameOf(parent) } : {}), + inPlace: 0, + sameContents: 0, + }; + inputRows.set(key, row); + } + return row; + }; + + /** Compares the inputs with the last check; true when one got a new reference. */ + const compareInputs = (instance: object, ctor: Ctor, meta: ClassMeta, parent: unknown) => { + if (!meta.inputs.length) return false; + let before = seen.get(instance); + if (!before) { + before = new Map(); + seen.set(instance, before); + } + let renewed = false; + for (const [name, prop] of meta.inputs) { + const value = inputValue(instance, prop); + const items = itemsOf(value); + const old = before.get(prop); + before.set(prop, items ? { ref: value, items } : { ref: value }); + if (!old) continue; + if (!Object.is(old.ref, value)) { + renewed = true; + if (inSync && old.items && items && sameItems(old.items, items)) { + const row = inputRow(ctor, name, parent); + if (row) row.sameContents++; + } + } else if (inSync && old.items && items && !sameItems(old.items, items)) { + const row = inputRow(ctor, name, parent); + if (row) row.inPlace++; + } + } + return renewed; + }; + + const countClass = (ctor: Ctor) => { + let stat = classes.get(ctor); + if (!stat) { + if (classes.size >= MAX_CLASSES) { + untracked++; + return null; + } + stat = { refreshed: 0, unchanged: 0, zone: 0, tasks: [] }; + classes.set(ctor, stat); + } + return stat; + }; + + const onComponentEnd = (instance: unknown) => { + credit(); + const frame = frames.pop(); + if (!frame || !current || !instance || typeof instance !== 'object') return; + const ctor = ctorOf(instance); + if (!ctor) return; + const meta = metaOf(instance, ctor); + const parent = frames.at(-1); + const renewed = compareInputs(instance, ctor, meta, parent?.first); + // The parent's template set the new reference, so the parent's check did something. + if (renewed && parent) parent.changed = true; + if (!inSync || frame.first !== instance) return; + current.refreshed++; + const stat = countClass(ctor); + if (!frame.changed) { + current.unchanged++; + if (stat) stat.unchanged++; + } else if (stat && current.cause.kind === 'zone') { + stat.zone++; + const task = current.cause.task; + if (task && stat.tasks.length < MAX_TASKS && !stat.tasks.includes(task)) + stat.tasks.push(task); + } + if (stat) stat.refreshed++; + }; + + const onEvent = (event: number, instance: unknown, hook: unknown, cycleId: number | null) => { + if (!active) return; + switch (event) { + case PROFILER_EVENT.OutputStart: + if (depth === 0 && pending?.source === NOTIFY.Listener && pending.owner === undefined) { + pending.owner = instance; + pending.listener = hook; + } + return; + case PROFILER_EVENT.ChangeDetectionStart: { + // DOM updates from before the tick belong to no check. + if (depth === 0 && observer) read(() => observer!.takeRecords(), []); + const info: CycleInfo = { cause: causeOf(), refreshed: 0, unchanged: 0 }; + pending = null; + if (current) cycleStack.push({ info: current, frames, inSync }); + depth++; + current = info; + frames = []; + inSync = false; + causes[info.cause.kind] = (causes[info.cause.kind] ?? 0) + 1; + if (cycleId !== null) { + cycles.set(cycleId, info); + // The recorder keeps `maxCycles`; ids past that are no longer asked for. + while (cycles.size > options.maxCycles) cycles.delete(cycles.keys().next().value!); + } + return; + } + case PROFILER_EVENT.ChangeDetectionSyncStart: + inSync = true; + return; + case PROFILER_EVENT.ChangeDetectionSyncEnd: + inSync = false; + return; + case PROFILER_EVENT.ComponentStart: + if (!depth) return; + credit(); + frames.push({ first: NONE, changed: false }); + return; + case PROFILER_EVENT.TemplateUpdateStart: { + const top = frames.at(-1); + if (depth && top && top.first === NONE) top.first = instance; + return; + } + case PROFILER_EVENT.ComponentEnd: + if (depth) onComponentEnd(instance); + return; + case PROFILER_EVENT.ChangeDetectionEnd: { + if (!depth) return; + if (observer) read(() => observer!.takeRecords(), []); + depth--; + const outer = cycleStack.pop(); + current = outer?.info ?? null; + frames = outer?.frames ?? []; + inSync = outer?.inSync ?? false; + return; + } + } + }; + + const hookScheduler = () => { + const document = doc(); + const roots = document ? read(() => [...document.querySelectorAll('[ng-version]')], []) : []; + scheduler = findCdScheduler(options.getNg(), roots); + const target = scheduler; + if (!target) return; + const own = Object.prototype.hasOwnProperty.call(target, 'notify'); + const original = target.notify; + const wrapper = function (this: unknown, source: number) { + try { + onNotify(source); + } catch { + // Attribution never breaks Angular's scheduling. + } + return original.call(this, source); + }; + target.notify = wrapper; + unwrap = () => { + if (target.notify !== wrapper) return; + if (own) target.notify = original; + else delete (target as Partial).notify; + }; + }; + + const watchDom = () => { + const document = doc(); + const Observer = read( + () => global()['MutationObserver'] as typeof MutationObserver | undefined, + undefined, + ); + if (!document?.documentElement || typeof Observer !== 'function') return; + observer = read(() => { + const created = new Observer(() => {}); + created.observe(document.documentElement, { + subtree: true, + childList: true, + attributes: true, + characterData: true, + }); + return created; + }, null); + }; + + const reset = () => { + pending = null; + depth = 0; + inSync = false; + frames = []; + cycleStack = []; + current = null; + cycles = new Map(); + causes = {}; + classes = new Map(); + untracked = 0; + inputRows = new Map(); + seen = new WeakMap(); + }; + + const unhook = () => { + unwrap?.(); + unwrap = null; + scheduler = null; + observer?.disconnect(); + observer = null; + removeWriteHook?.(); + removeWriteHook = null; + }; + + return { + onEvent, + /** Starts a fresh diagnosis and hooks into the page. */ + start() { + unhook(); + reset(); + active = true; + started = true; + const run = ++generation; + hookScheduler(); + watchDom(); + hooked = { triggers: scheduler !== null, waste: observer !== null }; + void writeHook(onWrite) + .then((remove) => { + // Stopped, or started again, while the hook loaded. + if (run !== generation || !active) remove?.(); + else removeWriteHook = remove; + }) + .catch(() => {}); + }, + /** Stops and unhooks, keeping what was found. */ + stop() { + active = false; + generation++; + unhook(); + pending = null; + depth = 0; + inSync = false; + frames = []; + cycleStack = []; + current = null; + }, + clear() { + reset(); + }, + /** The cause and check counts of a cycle, by the recorder's id. */ + cycle(id: number): { cause?: CdCause; refreshed?: number; unchanged?: number } { + const info = cycles.get(id); + if (!info) return {}; + return { + cause: info.cause, + ...(info.refreshed ? { refreshed: info.refreshed } : {}), + ...(info.unchanged ? { unchanged: info.unchanged } : {}), + }; + }, + /** Totals over the recording, or undefined before the first start. */ + snapshot(major?: number): CdDiagnosis | undefined { + if (!started) return undefined; + const components: CdWasteStat[] = [...classes] + .filter(([, stat]) => stat.refreshed > 0) + .map(([ctor, stat]) => { + const strategy = metas.get(ctor)?.strategy; + return { + name: className(ctor as { name?: string }), + refreshed: stat.refreshed, + unchanged: stat.unchanged, + ...(strategy ? { strategy } : {}), + }; + }) + .sort((a, b) => b.unchanged - a.unchanged || b.refreshed - a.refreshed) + .slice(0, LISTED_CLASSES); + const inputs = [...inputRows.values()] + .filter((row) => row.inPlace || row.sameContents) + .sort((a, b) => b.inPlace - a.inPlace || b.sameContents - a.sameContents) + .slice(0, LISTED_ROWS) + .map((row) => ({ ...row })); + const zone: CdZoneStat[] = [...classes] + .filter(([, stat]) => stat.zone > 0) + .map(([ctor, stat]) => ({ + name: className(ctor as { name?: string }), + ticks: stat.zone, + ...(stat.tasks.length ? { tasks: [...stat.tasks] } : {}), + })) + .sort((a, b) => b.ticks - a.ticks) + .slice(0, LISTED_ROWS); + return { + triggers: hooked.triggers, + waste: hooked.waste, + ...(major ? { major } : {}), + causes: { ...causes }, + components, + ...(inputs.length ? { inputs } : {}), + ...(zone.length ? { zone } : {}), + }; + }, + /** Classes refreshed past the 1000 the diagnosis keeps totals for. */ + get untracked() { + return untracked; + }, + }; +} + +export type CdDiagnosisRecorder = ReturnType; diff --git a/packages/devtools/src/cd-overlay.ts b/packages/devtools/src/cd-overlay.ts index 9fb1cfd7..43194f0e 100644 --- a/packages/devtools/src/cd-overlay.ts +++ b/packages/devtools/src/cd-overlay.ts @@ -1,4 +1,5 @@ -import { addProfilerListener } from './change-detection.ts'; +import { addProfilerListener, angularMajor, type Profiler } from './change-detection.ts'; +import { createCdDiagnosis } from './cd-diagnosis.ts'; import { createDeltaChannel } from './delta-channel.ts'; import { CHANGE_DETECTION_SHAPE } from './push-delta.ts'; import { toCdOptionsRequest } from './cd-data.ts'; @@ -35,6 +36,12 @@ export function attachChangeDetection( active: () => boolean = () => true, ) { const recorder = createCdRecorder({ maxCycles }); + const diagnosis = createCdDiagnosis({ getNg, maxCycles }); + // The diagnosis reads each event after the recorder, with the id it gave the cycle. + const onEvent: Profiler = (event, instance, hook) => { + recorder.onEvent(event, instance, hook); + diagnosis.onEvent(event, instance, hook, recorder.cycleId); + }; const live = createCdLive({ getNg }); const hostIds = new WeakMap(); let removeListener: (() => void) | null = null; @@ -68,24 +75,32 @@ export function attachChangeDetection( const setRecording = (on: boolean) => { if (on) { - removeListener ??= addProfilerListener(getNg(), recorder.onEvent); + removeListener ??= addProfilerListener(getNg(), onEvent); supported = removeListener !== null; // A second start, such as an agent start sent to every tab, keeps the // recording that is running. Only `clear` empties it. - if (supported && !recorder.recording) recorder.start(); + if (supported && !recorder.recording) { + recorder.start(); + diagnosis.start(); + } return; } recorder.stop(); + diagnosis.stop(); removeListener?.(); removeListener = null; }; const collect = (): Record => { const options = live.report(); + const recording = recorder.snapshot(hostId); + const found = diagnosis.snapshot(angularMajor()); const report: CdReport = { pageId, supported, - ...recorder.snapshot(hostId), + ...recording, + cycles: recording.cycles.map((cycle) => ({ ...cycle, ...diagnosis.cycle(cycle.id) })), + ...(found ? { diagnosis: found } : {}), ...(options ? { options } : {}), }; return { ...report }; @@ -110,7 +125,10 @@ export function attachChangeDetection( handler: (message: { pageId?: unknown; on?: unknown; clear?: unknown } | null) => { if (typeof message?.pageId === 'string' && message.pageId !== pageId) return; if (typeof message?.on === 'boolean') setRecording(message.on); - if (message?.clear === true) recorder.clear(); + if (message?.clear === true) { + recorder.clear(); + diagnosis.clear(); + } void push(true).catch(() => {}); }, }); diff --git a/packages/devtools/src/cd-recorder.ts b/packages/devtools/src/cd-recorder.ts index 33235aee..865e07a9 100644 --- a/packages/devtools/src/cd-recorder.ts +++ b/packages/devtools/src/cd-recorder.ts @@ -23,6 +23,7 @@ import { className } from './injector-tree.ts'; * the enum in `@angular/core/fesm2022/_debug_node-chunk.mjs` (Angular 22). */ export const PROFILER_EVENT = { + TemplateUpdateStart: 2, LifecycleHookStart: 4, LifecycleHookEnd: 5, OutputStart: 6, @@ -30,6 +31,7 @@ export const PROFILER_EVENT = { ChangeDetectionStart: 12, ChangeDetectionEnd: 13, ChangeDetectionSyncStart: 14, + ChangeDetectionSyncEnd: 15, AfterRenderHooksStart: 16, AfterRenderHooksEnd: 17, ComponentStart: 18, @@ -411,6 +413,10 @@ export function createCdRecorder(options: { get recording() { return recording; }, + /** The id of the cycle that is running, or null between cycles. */ + get cycleId(): number | null { + return current?.id ?? null; + }, /** True while the recorder holds cycles, recording or stopped. */ get hasCycles() { return cycles.length > 0; diff --git a/packages/devtools/src/config.ts b/packages/devtools/src/config.ts index 79642420..796e8c12 100644 --- a/packages/devtools/src/config.ts +++ b/packages/devtools/src/config.ts @@ -337,6 +337,16 @@ export const PANEL_TABS = [ export type PanelTab = (typeof PANEL_TABS)[number]['id']; +/** + * Navigations a destroyed component has to outlive, along with + * {@link RETAINED_AFTER_MS}, before the leak views call it still retained. The + * garbage collector runs when it likes, so an instance still there right + * after one navigation says little. The panel and `find-leaks` share these. + */ +export const RETAINED_AFTER_NAVIGATIONS = 2; +/** Time a destroyed component has to outlive before it counts as still retained. */ +export const RETAINED_AFTER_MS = 10_000; + /** The panel tabs whose inspector is on under `config`. */ export function enabledPanelTabs(config: ResolvedPangularConfig): (typeof PANEL_TABS)[number][] { return PANEL_TABS.filter((tab) => !('inspector' in tab) || config.inspectors[tab.inspector]); @@ -785,6 +795,7 @@ export const AGENT_SAFETY: Record> = { 'set-http-rule': 'action', 'remove-http-rule': 'action', 'record-pipes': 'action', + 'track-subscriptions': 'action', 'watch-signal': 'action', 'change-detection': 'action', hydration: 'action', @@ -869,6 +880,9 @@ export const RPC_INSPECTOR: Record = { 'request-hydration-overlay': 'components', 'request-component-value': 'components', 'component-value-result': 'components', + 'push-leaks': 'components', + 'forget-leaks-page': 'components', + 'request-leak-tracking': 'components', 'get-signals': 'signals', 'push-signal-graph': 'signals', 'ping-signal-graph': 'signals', @@ -880,6 +894,7 @@ export const RPC_INSPECTOR: Record = { 'push-injector-tree': 'injectors', 'ping-injector-tree': 'injectors', 'forget-injector-page': 'injectors', + 'explain-injection': 'injectors', 'get-ngrx-store': 'ngrx', 'push-ngrx-state': 'ngrx', 'forget-ngrx-page': 'ngrx', @@ -944,13 +959,17 @@ export const AGENT_INSPECTOR: Record = { 'for-blocks': 'components', hydration: 'components', 'change-detection': 'components', + 'diagnose-change-detection': 'components', 'set-component-property': 'components', 'set-signal': 'components', + 'find-leaks': 'components', + 'track-subscriptions': 'components', 'signal-graph': 'signals', 'inspect-signals': 'signals', 'watch-signal': 'signals', 'injector-tree': 'injectors', 'inspect-providers': 'injectors', + 'explain-injection': 'injectors', 'ngrx-store': 'ngrx', 'dispatch-ngrx-action': 'ngrx', 'inspect-signal-store': 'ngrx', @@ -1004,6 +1023,7 @@ export const AGENT_INSPECTOR: Record = { export const SHARED_STATE_INSPECTOR: Record = { 'component-tree': 'components', 'change-detection': 'components', + leaks: 'components', 'signal-graph': 'signals', 'injector-tree': 'injectors', 'ngrx-store': 'ngrx', @@ -1051,13 +1071,17 @@ export const PAGE_AGENT_ENTRIES: readonly string[] = [ 'for-blocks', 'hydration', 'change-detection', + 'diagnose-change-detection', 'set-component-property', 'set-signal', + 'find-leaks', + 'track-subscriptions', 'signal-graph', 'inspect-signals', 'watch-signal', 'injector-tree', 'inspect-providers', + 'explain-injection', 'ngrx-store', 'dispatch-ngrx-action', 'inspect-signal-store', @@ -1251,6 +1275,115 @@ export interface CdCycle { spans?: CdSpan[]; /** Spans left out of `spans` past the cap. */ droppedSpans?: number; + /** What started the cycle, from the recording's trigger attribution (`cd-diagnosis.ts`). */ + cause?: CdCause; + /** Component checks where Angular ran the template, the dev-mode checkNoChanges pass left out. */ + refreshed?: number; + /** Refreshed checks where nothing the component renders changed. */ + unchanged?: number; +} + +/** + * What started a change detection cycle: + * - `event`: a template listener (DOM event or output), or a DOM event handler that notified Angular. + * - `http`: code that ran on an HTTP response. + * - `timer`: code that ran in a timer, as zone.js reports it. + * - `signal`: a signal write that marked a template for check. + * - `effect`: a signal write that scheduled an effect. + * - `markForCheck`: `ChangeDetectorRef.markForCheck()`, such as the async pipe. + * - `input`: `ComponentRef.setInput()`. + * - `view`: a view attached or detached, a defer block, an afterRender registration or animations. + * - `tick`: app code called `ApplicationRef.tick()`. + * - `zone`: zone.js ran the tick and nothing notified Angular before it, so only zone.js picked the change up. + * - `unknown`: Angular's scheduler ran a tick the recording saw no notification for. + */ +export type CdCauseKind = + | 'event' + | 'http' + | 'timer' + | 'signal' + | 'effect' + | 'markForCheck' + | 'input' + | 'view' + | 'tick' + | 'zone' + | 'unknown'; + +/** What started one cycle. The text form is `cdCauseText` in `cd-data.ts`. */ +export interface CdCause { + kind: CdCauseKind; + /** For `http`, `timer` and an `event` outside a template listener: how the code told Angular. */ + via?: CdCauseKind; + /** The component class: the listener's owner for an event, else the class of the first app frame. */ + component?: string; + /** The template listener's function name. */ + listener?: string; + /** The DOM event type, such as `click`. */ + event?: string; + /** The event target's tag, such as `button`. */ + target?: string; + /** The `debugName` of the signal written, `?` for an unnamed one. */ + signal?: string; + /** The zone.js task the code ran in, such as `setTimeout` or `XMLHttpRequest.send`. */ + task?: string; + /** True when zone.js (`NgZone`) ran the tick rather than Angular's zoneless scheduler. */ + zone?: boolean; + /** The first app frames of the code that notified Angular or called `tick()`. */ + stack?: string[]; + /** More notifications that came before the same tick. */ + more?: number; +} + +/** Refreshed and unchanged checks of one component class over a recording. */ +export interface CdWasteStat { + name: string; + /** Checks where Angular ran the component's template. */ + refreshed: number; + /** Refreshed checks where nothing it renders changed: no DOM update and no new input reference for a child. */ + unchanged: number; + /** The class's change detection strategy, from `ng.getDirectiveMetadata`. */ + strategy?: 'OnPush' | 'Eager'; +} + +/** One input of one component class that broke OnPush during a recording. */ +export interface CdInputStat { + /** The component class that declares the input. */ + name: string; + input: string; + /** The component class whose template set it, when the recording saw it. */ + parent?: string; + /** Checks where the input kept its reference but its contents changed (mutated in place). */ + inPlace: number; + /** Checks where the input got a new reference with the same contents. */ + sameContents: number; +} + +/** A component class that changed only in ticks zone.js started with no Angular notification. */ +export interface CdZoneStat { + name: string; + /** Zone-only ticks in which it changed. */ + ticks: number; + /** The zone.js tasks behind those ticks, at most 3, such as `setTimeout`. */ + tasks?: string[]; +} + +/** Trigger attribution and wasted checks over a recording. */ +export interface CdDiagnosis { + /** Whether the page found Angular's change detection scheduler, so cycles carry a cause. */ + triggers: boolean; + /** Whether the page could watch DOM updates, so unchanged checks are counted. */ + waste: boolean; + /** The page's Angular major version, for the OnPush hint. */ + major?: number; + /** Cycles per cause kind. */ + causes: Partial>; + /** Component classes by unchanged checks, at most 100. */ + components: CdWasteStat[]; + /** Inputs mutated in place or given equal new references, at most 50. */ + inputs?: CdInputStat[]; + /** Components that changed only in zone.js ticks, at most 50. */ + zone?: CdZoneStat[]; } /** What a {@link CdSpan} measures. */ @@ -1328,6 +1461,8 @@ export interface CdRecording { afterRender?: CdAfterRenderStat; /** Names the cycles' `spans` point to. */ spanNames?: string[]; + /** Trigger attribution, wasted checks and OnPush hints, on pages that record them. */ + diagnosis?: CdDiagnosis; } /** The change detection views a page shows while it runs, turned on from the panel or an agent. */ diff --git a/packages/devtools/src/devframe.ts b/packages/devtools/src/devframe.ts index 5ccdd802..f01a76d3 100644 --- a/packages/devtools/src/devframe.ts +++ b/packages/devtools/src/devframe.ts @@ -25,7 +25,9 @@ import { } from './rpc/hydration-tools.ts'; import { registerConsoleGlobals } from './rpc/console-globals.ts'; import { registerErrors } from './rpc/errors-register.ts'; +import { registerLeaks } from './rpc/leaks-register.ts'; import { inspectProvidersText } from './rpc/injector-tools.ts'; +import { registerInjectionExplain } from './rpc/injection-explain.ts'; import { sanitizeInjectorTree } from './rpc/injector-report.ts'; import { createFrameworkNames, markFramework } from './rpc/framework-tokens.ts'; import { lintPipes, lintPipesText } from './rpc/pipe-lint.ts'; @@ -200,6 +202,7 @@ import { type CdState, } from './rpc/cd-tools.ts'; import { cdExportText } from './rpc/cd-export-tools.ts'; +import { cdDiagnosisText } from './rpc/cd-diagnosis-tools.ts'; import { toCdOptionsRequest } from './cd-data.ts'; import type { HttpPage, HttpPayloadState, HttpReport, HttpState } from './types.ts'; @@ -743,6 +746,17 @@ const pangular = defineDevframe({ ttl: liveTtl, }) : null; + const leaksInspector = on.components + ? await registerLeaks({ + my, + rpcHost: ctx.rpc, + register, + agent, + owns, + mayForget, + ttl: liveTtl, + }) + : null; const routerPages = new Map(); const routerState = await my.rpc.sharedState('router', { @@ -1174,6 +1188,7 @@ const pangular = defineDevframe({ if (expireNgrxPages(ngrxPages, Date.now(), liveTtl)) applyNgrx(); if (expireCapacitorPages(capacitorPages, Date.now(), liveTtl)) applyCapacitor(); errorsInspector?.expire(); + leaksInspector?.expire(); componentDeltas.prune((id) => componentPages.has(id)); injectorDeltas.prune((id) => injectorPages.has(id)); cdDeltas.prune((id) => cdPages.has(id)); @@ -2869,6 +2884,37 @@ const pangular = defineDevframe({ }, }); + agent.registerTool({ + id: 'pangular:diagnose-change-detection', + description: + 'Why change detection ran and what it wasted, from the recording `pangular:change-detection` or the panel started (Angular 20+, development build). Lists what started each cycle (a DOM event with its type, target and listener component, a signal write with the signal name, an HTTP response, a timer, markForCheck, setInput, an effect, `ApplicationRef.tick()` from app code with its app frames, or a zone.js tick nothing in Angular asked for), the components that changed only in such zone.js ticks and so depend on zone.js, refreshed checks that changed nothing per component, inputs mutated in place or given an equal new reference (both break OnPush), and OnPush hints for components refreshed often that rarely change. While recording, the page wraps Angular\'s scheduler `notify`, adds a signal write hook and watches DOM updates; all three stop with the recording. Only reads. Empty until a recording ran: start one with `pangular:change-detection` and `record: "start"`.', + inputSchema: { + type: 'object', + properties: { + page: { type: 'string', description: 'Page id; defaults to the page that is recording.' }, + limit: { type: 'number', description: 'Rows per list (default 10, max 50).' }, + }, + }, + handler: async (args: { page?: string; limit?: number }) => { + const unknown = + args?.page && + cdUnknownPageText( + args.page, + cdState.value() as CdState, + [...componentPages.values(), ...injectorPages.values()].filter( + (page) => !goneCdPages.has(page.pageId), + ), + ); + if (unknown) return { markdown: unknown }; + const cd = cdState.value() as CdState; + const zonePage = args?.page ?? pickCdPage(cd)?.pageId; + const injectors = zonePage ? injectorPages.get(zonePage) : latestInjectorPage(); + const mode = injectors ? zoneModeText(injectors.zone, injectors.pageId) : ''; + const text = cdDiagnosisText(cd, args ?? {}, angularPages.get); + return { markdown: [mode, text].filter(Boolean).join('\n\n') }; + }, + }); + agent.registerTool({ id: 'pangular:inspect-signals', description: @@ -3030,6 +3076,21 @@ const pangular = defineDevframe({ }, }); + registerInjectionExplain({ + register, + agent, + page: (requested) => { + if (requested && !injectorPages.has(requested)) { + return { + error: unknownPageText(requested, [...injectorPages.values()], 'an injector tree'), + }; + } + const page = requested ? injectorPages.get(requested) : latestInjectorPage(); + const angular = angularPages.pick(page?.pageId ?? requested); + return { page, reduced: angular?.capabilities.injectorProviders === false }; + }, + }); + const noRouter = `No router state has been reported. Live data needs a page: connect through the MCP endpoint of the server that runs the app, with the app open in a browser. The stdio server has no page attached and only ever reports this.`; const pageProperty = PAGE_ARGUMENT; diff --git a/packages/devtools/src/dom-diff.ts b/packages/devtools/src/dom-diff.ts new file mode 100644 index 00000000..a531150c --- /dev/null +++ b/packages/devtools/src/dom-diff.ts @@ -0,0 +1,75 @@ +// A line diff of two DOM descriptions, such as the server HTML Angular expected +// and the client DOM it found when hydration failed (NG0500 to NG0502). + +/** One line of a diff: in both, only in what was expected (server), or only in what was found (client). */ +export interface DiffLine { + op: 'same' | 'expected' | 'actual'; + text: string; +} + +/** Lines compared at most per side; the rest is dropped, so the table stays small. */ +export const MAX_DIFF_LINES = 80; + +/** Angular marks the node it means with this text (`AT_THIS_LOCATION` in `@angular/core`). */ +const AT_THIS_LOCATION = /\s*<-- AT THIS LOCATION\s*$/; + +function lines(text: string): string[] { + return text + .replace(/\r\n?/g, '\n') + .split('\n') + .map((line) => line.replace(/\s+$/, '')) + .filter((line) => line.trim() !== '') + .slice(0, MAX_DIFF_LINES); +} + +/** The line without Angular's location marker, so a marked line matches its unmarked twin. */ +const comparable = (line: string) => line.replace(AT_THIS_LOCATION, '').trim(); + +/** + * Compares two DOM descriptions line by line (longest common subsequence), + * ignoring indentation and Angular's `<-- AT THIS LOCATION` marker when + * matching. Lines in both are `same`, lines only Angular expected are + * `expected`, lines only the client DOM has are `actual`. Either side may be + * empty, as when Angular found no node at all. + */ +export function diffDom(expected: string | undefined, actual: string | undefined): DiffLine[] { + const a = lines(expected ?? ''); + const b = lines(actual ?? ''); + const ka = a.map(comparable); + const kb = b.map(comparable); + // lcs[i][j]: the longest common run of a[i..] and b[j..]. + const lcs: number[][] = Array.from({ length: a.length + 1 }, () => + new Array(b.length + 1).fill(0), + ); + for (let i = a.length - 1; i >= 0; i--) { + for (let j = b.length - 1; j >= 0; j--) { + lcs[i]![j] = + ka[i] === kb[j] ? lcs[i + 1]![j + 1]! + 1 : Math.max(lcs[i + 1]![j]!, lcs[i]![j + 1]!); + } + } + const out: DiffLine[] = []; + let i = 0; + let j = 0; + while (i < a.length && j < b.length) { + if (ka[i] === kb[j]) { + // Keep the client's line: it carries the marker when only the client side has one. + out.push({ op: 'same', text: AT_THIS_LOCATION.test(a[i]!) ? a[i]! : b[j]! }); + i++; + j++; + } else if (lcs[i + 1]![j]! >= lcs[i]![j + 1]!) { + out.push({ op: 'expected', text: a[i++]! }); + } else { + out.push({ op: 'actual', text: b[j++]! }); + } + } + while (i < a.length) out.push({ op: 'expected', text: a[i++]! }); + while (j < b.length) out.push({ op: 'actual', text: b[j++]! }); + return out; +} + +/** The diff as unified text: two spaces, `-` for the server side and `+` for the client side. */ +export function diffText(diff: readonly DiffLine[]): string { + return diff + .map((line) => `${line.op === 'same' ? ' ' : line.op === 'expected' ? '-' : '+'} ${line.text}`) + .join('\n'); +} diff --git a/packages/devtools/src/error-explain.ts b/packages/devtools/src/error-explain.ts new file mode 100644 index 00000000..9fc38878 --- /dev/null +++ b/packages/devtools/src/error-explain.ts @@ -0,0 +1,344 @@ +// Page side of the Errors explainers: reads what Angular puts in an NG0100, a +// hydration mismatch (NG0500 to NG0503) or a missing provider (NG0201, +// NullInjectorError) error, and adds what the page knows when the group is +// pushed: the component fields that hold the new value, the named signals +// written with it just before the check, and the hydration info Angular left +// on the component host. Nothing here writes to the app or runs its code. + +import { readHydration, type HydrationDebugNg } from './hydration.ts'; +import { isSecretName, REDACTED, redactText } from './serialize.ts'; +import { clip } from './text.ts'; +import type { ErrorExplain, ExplainWrite } from './rpc/error-explain-tools.ts'; +import { MAX_DOM_TEXT, MAX_VALUE_TEXT } from './rpc/error-explain-tools.ts'; +import type { SignalChange } from './types.ts'; + +type AnyRecord = Record; + +/** How far back a signal write counts as the one behind an NG0100. */ +export const WRITE_WINDOW_MS = 2000; +/** Signal writes the page remembers for the explainer. */ +export const MAX_RECENT_WRITES = 50; +/** Own fields of a component compared with the new value. */ +const MAX_FIELDS = 200; +/** Longest error message read; Angular's hydration messages carry the DOM. */ +const MAX_RAW_MESSAGE = 20_000; + +function read(fn: () => T, fallback: T): T { + try { + return fn(); + } catch { + return fallback; + } +} + +/** The whole message of an error, before it is cut for the list. */ +export function rawMessage(value: unknown): string { + if (typeof value === 'string') return value.slice(0, MAX_RAW_MESSAGE); + const message = read(() => (value as AnyRecord | null)?.['message'], undefined); + return typeof message === 'string' ? message.slice(0, MAX_RAW_MESSAGE) : ''; +} + +const HYDRATION_CODES = new Set(['NG0500', 'NG0501', 'NG0502', 'NG0503']); + +/** + * The compiled template function on a stack, such as `App_Template` or + * `App_Conditional_2_Template`: the template the binding sits in. + */ +export function templateOf(stack: string | undefined): string | undefined { + for (const line of (stack ?? '').split('\n').slice(0, 40)) { + const match = /(?:^|[\s.@(])_?([A-Za-z$][\w$]*?_(?:[\w$]+_)*Template)(?![\w$])/.exec(line); + if (match && !/_listener$/.test(match[1]!)) return clip(match[1]!, 120); + } + return undefined; +} + +/** The parts of Angular's NG0100 message (`throwErrorIfNoChangesMode` in `@angular/core`). */ +export function parseExpressionChanged(message: string): { + binding?: string; + previous: string; + current: string; + creation: boolean; +} | null { + const match = + /Previous value(?: for '([^']*)')?: '([\s\S]*?)'\. Current value: '([\s\S]*?)'\.(?=\s|$)/.exec( + message, + ); + if (!match) return null; + return { + ...(match[1] ? { binding: match[1] } : {}), + previous: match[2]!, + current: match[3]!, + creation: /view has been created after its parent/.test(message), + }; +} + +/** The paragraph after `label` in Angular's hydration message, up to the next blank line. */ +function section(message: string, label: string): string | undefined { + const start = message.indexOf(label); + if (start < 0) return undefined; + const rest = message.slice(start + label.length).replace(/^\s*\n/, ''); + const end = rest.search(/\n\s*\n/); + const text = (end < 0 ? rest : rest.slice(0, end)).replace(/\s+$/, ''); + return text.trim() ? text : undefined; +} + +/** + * What Angular's hydration message says (`validateMatchingNode`, + * `validateSiblingNodeExists`, `validateNodeExists` in `@angular/core`): its + * first sentence, the DOM it expected and the DOM it found. + */ +export function parseHydrationMismatch(message: string): { + summary?: string; + expected?: string; + actual?: string; + external: boolean; +} { + const body = message.replace(/^NG0\d+:\s*/, ''); + const summary = body.split(/\n\s*\n/)[0]?.trim(); + let expected = section(body, 'Angular expected this DOM:'); + const actual = section(body, 'Actual DOM is:'); + // NG0502 puts the expected DOM right after its first sentence, with no label. + if (!expected && /expected an element to be present/.test(body)) { + const next = body.split(/\n\s*\n/)[1]?.replace(/\s+$/, ''); + if (next && /^\s*[<#…]/.test(next)) expected = next; + } + return { + ...(summary ? { summary: clip(summary, 500) } : {}), + ...(expected ? { expected: clip(expected, MAX_DOM_TEXT) } : {}), + ...(actual ? { actual: clip(actual, MAX_DOM_TEXT) } : {}), + external: /third-party script or browser extension/.test(body), + }; +} + +/** `InjectionToken API_URL` reads `API_URL`, like the Injectors tab names it. */ +const bareToken = (name: string) => name.trim().replace(/^InjectionToken\s+/, ''); + +/** + * The token, dependency path and source Angular puts in a missing provider + * error: `NG0201: No provider found for \`Api\`. Source: Standalone[App]. Path: + * App -> Api.` from 20.0 on, `R3InjectorError(AppModule)[Api -> Http]: + * NullInjectorError: No provider for Http!` before, and `No provider for Api + * found in NodeInjector` from an element injector. + */ +export function parseMissingProvider( + message: string, +): { token: string; path?: string[]; source?: string } | null { + let token = + /No provider found for `([^`]+)`/.exec(message)?.[1] ?? + /No provider for (.+?)(?: found in [\w$]+|!)/.exec(message)?.[1]; + let path: string[] | undefined; + let source: string | undefined; + const newPath = / Path: (.+?)\.(?:\s|$)/.exec(message)?.[1]; + const oldError = /R3InjectorError\(([^)]*)\)\[([^\]]+)\]/.exec(message); + if (newPath) path = newPath.split(' -> '); + else if (oldError) path = oldError[2]!.split(' -> '); + source = + / Source: (.+?)\.(?: |$)/.exec(message)?.[1] ?? + oldError?.[1] ?? + / found in ([\w$]+)/.exec(message)?.[1]; + path = path?.map(bareToken).filter(Boolean); + if (!token && path?.length) token = path.at(-1); + if (!token) return null; + return { + token: clip(bareToken(token), 120), + ...(path?.length ? { path: path.slice(0, 20).map((name) => clip(name, 120)) } : {}), + ...(source ? { source: clip(source, 120) } : {}), + }; +} + +/** The explainer of an error from its code, message and stack; `undefined` when it has none. */ +export function explainError( + ngCode: string | undefined, + message: string, + stack: string | undefined, +): ErrorExplain | undefined { + if (ngCode === 'NG0100' || /ExpressionChangedAfterItHasBeenChecked/.test(message)) { + const parts = parseExpressionChanged(message); + if (!parts) return undefined; + const masked = isSecretName(parts.binding); + const template = templateOf(stack); + return { + kind: 'expression-changed', + previous: masked ? REDACTED : clip(redactText(parts.previous), MAX_VALUE_TEXT), + current: masked ? REDACTED : clip(redactText(parts.current), MAX_VALUE_TEXT), + ...(parts.binding ? { binding: clip(parts.binding, 120) } : {}), + ...(template ? { template } : {}), + ...(masked ? { masked } : {}), + ...(parts.creation ? { creation: true } : {}), + }; + } + if ( + (ngCode && HYDRATION_CODES.has(ngCode)) || + /^\s*(NG050\d:\s*)?During hydration/.test(message) + ) { + const parts = parseHydrationMismatch(message); + return { + kind: 'hydration-mismatch', + ...(parts.summary ? { summary: redactText(parts.summary) } : {}), + ...(parts.expected ? { expected: redactText(parts.expected) } : {}), + ...(parts.actual ? { actual: redactText(parts.actual) } : {}), + ...(parts.external ? { external: true } : {}), + }; + } + if (ngCode === 'NG0201' || /NullInjectorError|No provider (?:found )?for/.test(message)) { + const parts = parseMissingProvider(message); + if (!parts) return undefined; + return { + kind: 'missing-provider', + token: redactText(parts.token), + ...(parts.path ? { path: parts.path.map(redactText) } : {}), + ...(parts.source ? { source: redactText(parts.source) } : {}), + }; + } + return undefined; +} + +/** A value the way Angular prints it in NG0100 (`formatValue` in `@angular/core`). */ +export function formatLikeAngular(value: unknown): string { + let text = read(() => String(value), ''); + try { + if (Array.isArray(value) || text === '[object Object]') text = JSON.stringify(value); + } catch { + // Angular keeps String(value) too. + } + return text.length > MAX_VALUE_TEXT ? `${text.slice(0, MAX_VALUE_TEXT)}…` : text; +} + +/** The value of a signal without calling it, so no computed runs; `undefined` for anything else. */ +function signalValue(value: unknown): { value: unknown } | undefined { + if (typeof value !== 'function') return undefined; + const key = read( + () => Object.getOwnPropertySymbols(value).find((s) => s.description === 'SIGNAL'), + undefined, + ); + const node = key ? read(() => (value as unknown as AnyRecord)[key as never], undefined) : null; + if (!node || typeof node !== 'object' || !('value' in node)) return undefined; + return { value: read(() => (node as AnyRecord)['value'], undefined) }; +} + +/** + * Own fields of a component that hold `current` now, as Angular prints it: + * plain fields read through their descriptors (getters never run) and signals + * read from their node. + */ +export function membersHolding(component: unknown, current: string): string[] { + if (!component || typeof component !== 'object') return []; + const out: string[] = []; + const keys = read(() => Object.keys(component).slice(0, MAX_FIELDS), [] as string[]); + for (const key of keys) { + const descriptor = read(() => Object.getOwnPropertyDescriptor(component, key), undefined); + if (!descriptor || !('value' in descriptor)) continue; + const raw = descriptor.value; + const sig = signalValue(raw); + if (typeof raw === 'function' && !sig) continue; + const value = sig ? sig.value : raw; + if (formatLikeAngular(value) === current) out.push(key); + if (out.length >= 10) break; + } + return out; +} + +interface RecentWrite { + signal: string; + at: number; + value: unknown; + stack?: string[]; +} + +/** + * The named signal writes of the last moments, from the signal history's + * `onChange`, for NG0100. Keeps {@link MAX_RECENT_WRITES}. + */ +export function createRecentWrites(max = MAX_RECENT_WRITES) { + const writes: RecentWrite[] = []; + let heard = false; + return { + /** Pass to the signal history as (part of) `onChange`. */ + add(_id: string | undefined, label: string, change: SignalChange) { + if (change.source !== 'write') return; + writes.push({ + signal: label, + at: change.at, + value: change.value, + ...(change.stack?.length ? { stack: change.stack } : {}), + }); + if (writes.length > max) writes.splice(0, writes.length - max); + }, + /** Marks that the page hears signal writes, once the write hook is installed. */ + listening() { + heard = true; + }, + get known() { + return heard; + }, + /** Writes whose value prints like `current`, in the window before `at`, newest first. */ + matching(at: number, current: string): ExplainWrite[] { + return writes + .filter( + (write) => + write.at <= at + 50 && + at - write.at <= WRITE_WINDOW_MS && + formatLikeAngular(write.value) === current, + ) + .reverse() + .slice(0, 5) + .map(({ signal, at: when, stack }) => ({ signal, at: when, ...(stack ? { stack } : {}) })); + }, + }; +} + +export type RecentWrites = ReturnType; + +/** + * Adds what the page knows once the group's component is found: for NG0100 + * the fields that hold the new value (values hidden when one has a secret + * name) and the signal writes behind it; for a hydration mismatch the + * expected and actual DOM Angular left on the host when the message had none. + */ +export function enrichExplain( + explain: ErrorExplain, + context: { + at: number; + component?: unknown; + host?: Element | null; + ng?: HydrationDebugNg; + writes?: RecentWrites; + }, +): ErrorExplain { + if (explain.kind === 'expression-changed') { + const out = { ...explain }; + if (!out.masked && context.component) { + const members = membersHolding(context.component, out.current); + if (members.some(isSecretName)) { + out.previous = REDACTED; + out.current = REDACTED; + out.masked = true; + } + if (members.length) out.members = members; + } + if (context.writes) { + out.writesKnown = context.writes.known; + if (!out.masked) { + const writes = context.writes.matching(context.at, explain.current); + if (writes.length) out.writes = writes; + } + } + return out; + } + if ( + explain.kind === 'hydration-mismatch' && + !explain.expected && + !explain.actual && + context.host + ) { + const info = readHydration(context.ng, context.host); + if (info?.status === 'mismatched') { + return { + ...explain, + ...(info.expected ? { expected: info.expected } : {}), + ...(info.actual ? { actual: info.actual } : {}), + }; + } + } + return explain; +} diff --git a/packages/devtools/src/errors-collector.ts b/packages/devtools/src/errors-collector.ts index a8d4b963..4feaeced 100644 --- a/packages/devtools/src/errors-collector.ts +++ b/packages/devtools/src/errors-collector.ts @@ -1,6 +1,8 @@ import { keepaliveDue } from './change-detection.ts'; import { CONSOLE_LEVELS, tapConsole, type ConsoleLevel } from './console-tap.ts'; -import { elementId } from './element-id.ts'; +import { elementById, elementId } from './element-id.ts'; +import { enrichExplain, explainError, rawMessage, type RecentWrites } from './error-explain.ts'; +import type { HydrationDebugNg } from './hydration.ts'; import { className } from './injector-tree.ts'; import { ngCodeOf, ngCodeUrl } from './ng-error-codes.ts'; import { providerOf, redactMessage, redactUrl, type RouterDebugApi } from './router.ts'; @@ -32,7 +34,7 @@ const VALUE_LIMITS = { depth: 3, keys: 10, items: 10, text: 200, budget: 100 }; type AnyRecord = Record; /** The parts of `window.ng` this collector reads. */ -export interface ErrorsDebugNg extends RouterDebugApi { +export interface ErrorsDebugNg extends RouterDebugApi, HydrationDebugNg { getComponent?: (el: Element) => unknown; getOwningComponent?: (el: Element) => unknown; getHostElement?: (component: unknown) => Element | null; @@ -61,12 +63,16 @@ export interface ErrorsOptions { /** Where errors and rejections come from; the page's window by default. */ target?: Pick; now?: () => number; + /** Recent named signal writes, for the NG0100 explainer (`error-explain.ts`). */ + writes?: RecentWrites; } interface Group extends ErrorGroup { key: string; /** Class names from the message and stack, for finding the owner later. */ candidates: string[]; + /** When the explainer still waits for the owner and the signal writes, from the next push. */ + explainAt?: number; } function read(fn: () => T, fallback: T): T { @@ -168,10 +174,13 @@ export function ownerCandidates(message: string, stack: string | undefined): str } }; for (const match of message.matchAll( - /(?:used in the '|in the template of |Expression location: )_?([A-Za-z$][\w$]*)'?(?: component)?/g, + /(?:used in the '|in the template of |Expression location: |check the ")_?([A-Za-z$][\w$]*)['"]?(?: component)?/g, )) { add(match[1]); } + // A missing provider names its requester first: `Path: App -> Api.` or `R3InjectorError(...)[App -> Api]`. + const path = / Path: (.+?)\.(?:\s|$)/.exec(message)?.[1] ?? /\)\[([^\]]+)\]/.exec(message)?.[1]; + for (const name of path?.split(' -> ').slice(0, -1) ?? []) add(name.trim()); for (const line of (stack ?? '').split('\n').slice(0, MAX_STACK_LINES)) { const fn = /^\s*at\s+(?:new\s+|async\s+)?([\w$.]+)/.exec(line)?.[1] ?? @@ -305,6 +314,7 @@ export function attachErrors( if (!group.sources.includes(source)) group.sources.push(source); } else { const stack = stackOf(value); + const explain = explainError(code, rawMessage(value), stack); group = { key, id: `e${++nextGroup}`, @@ -318,6 +328,7 @@ export function attachErrors( ...(code ? { code } : {}), ...(code && ngCodeUrl(code) ? { docUrl: ngCodeUrl(code) } : {}), ...(stack ? { stack } : {}), + ...(explain ? { explain, explainAt: at } : {}), }; groups.set(key, group); evictGroups(); @@ -447,9 +458,28 @@ export function attachErrors( group.candidates = []; if (owner) group.owner = owner; } + for (const group of changedGroups) { + if (group.explainAt === undefined || !group.explain) continue; + const ng = getNg(); + const host = group.owner ? elementById(group.owner.id) : null; + const component = + host && ng?.getComponent ? read(() => ng.getComponent!(host), null) : undefined; + group.explain = read( + () => + enrichExplain(group.explain!, { + at: group.explainAt!, + component, + host, + ng, + writes: options.writes, + }), + group.explain, + ); + delete group.explainAt; + } const all = full; const errors = [...(all ? groups.values() : changedGroups)].map( - ({ key: _key, candidates: _candidates, ...group }) => ({ + ({ key: _key, candidates: _candidates, explainAt: _explainAt, ...group }) => ({ ...group, sources: [...group.sources], }), diff --git a/packages/devtools/src/injector-tree.ts b/packages/devtools/src/injector-tree.ts index dedcc9fe..9196e371 100644 --- a/packages/devtools/src/injector-tree.ts +++ b/packages/devtools/src/injector-tree.ts @@ -211,6 +211,33 @@ export function injectorRef( return { id: idFor(injector), name: environmentName(injector, meta?.source) }; } +/** + * The injector id of the host element of the component whose template + * declares `el`: where a `host` lookup from `el` stops (`@Host()`, + * `{ host: true }`). Read through `ng.getOwningComponent`; undefined for a + * root component, or when the page's Angular can't tell. + */ +function hostBoundary( + debugNg: DebugNg, + el: H, + tree: HostNames, +): string | undefined { + // Not on `DebugNg`, so the collectors that extend it keep their own signatures. + const ng = debugNg as DebugNg & { + getOwningComponent?(el: H): unknown; + getHostElement?(component: object): unknown; + }; + if (!ng.getOwningComponent || !ng.getHostElement) return undefined; + try { + const owner = ng.getOwningComponent(el); + if (!owner || typeof owner !== 'object' || owner === ng.getComponent?.(el)) return undefined; + const host = ng.getHostElement(owner); + return host && host !== el && tree.isHost(host) ? idFor(host as object) : undefined; + } catch { + return undefined; + } +} + type DependencyFlags = { optional?: boolean; host?: boolean; self?: boolean; skipSelf?: boolean }; /** @@ -429,6 +456,8 @@ function readElement( // The component tree's id for the same host, so the panel can link the two views. info.componentId = elementId(el); } + const boundary = hostBoundary(ng, el, tree); + if (boundary) info.host = boundary; const entry: ElementEntry = { info, providers, diff --git a/packages/devtools/src/leaks-collector.ts b/packages/devtools/src/leaks-collector.ts new file mode 100644 index 00000000..99d81cd2 --- /dev/null +++ b/packages/devtools/src/leaks-collector.ts @@ -0,0 +1,843 @@ +import { + addProfilerListener, + angularMajor, + keepaliveDue, + type Profiler, +} from './change-detection.ts'; +import { componentHosts, type ComponentDebugNg } from './component-tree.ts'; +import { createDomDirty, type DomDirty } from './dom-dirty.ts'; +import { elementId } from './element-id.ts'; +import { domTree, type HostTree } from './host-tree.ts'; +import { className } from './injector-tree.ts'; +import { redactMessage, redactUrl } from './router.ts'; +import { redactText } from './serialize.ts'; +import { clip } from './text.ts'; +import { + MAX_LEAK_COMPONENTS, + MAX_LEAK_DESTROYED, + MAX_LEAK_SUBSCRIPTIONS, + type LeakComponent, + type LeakDestroyed, + type LeakSubscription, + type LeaksReport, + type SubscriptionTracking, +} from './rpc/leaks-tools.ts'; + +/** Components a scan walks. */ +const MAX_WALK = 2000; +/** Components whose signal graph a scan reads to count effects. */ +const MAX_EFFECT_HOSTS = 500; +/** Destroyed instances the page keeps tracking; the oldest goes first. */ +export const MAX_TRACKED_DESTROYED = 500; +/** Subscriptions the page keeps while tracking; closed ones go first, then the oldest. */ +export const MAX_TRACKED_SUBSCRIPTIONS = 2000; +/** A subscription whose stack names no component class is dropped after this long. */ +const UNRESOLVED_MS = 30_000; +/** + * A scan walks the page when elements came or went, and otherwise this + * rarely, so effects made without a DOM change still show. The component + * tree walks on its own pace; this walk stays out of its way. + */ +const SCAN_HEARTBEAT_MS = 30_000; +const MAX_FRAMES = 12; +const MAX_SOURCE = 200; +/** `sessionStorage` key that keeps subscription tracking on across a reload. */ +export const TRACKING_KEY = 'pangular-leak-subscriptions'; + +/** The parts of `window.ng` this collector reads. */ +export interface LeaksDebugNg extends ComponentDebugNg { + getInjector?(el: Element): unknown; + ɵgetSignalGraph?(injector: unknown): { nodes?: { id?: unknown; kind?: unknown }[] } | null; +} + +interface Rpc { + rpc: { + call(name: string, ...args: unknown[]): Promise; + register?(definition: { + name: string; + type: 'event' | 'action' | 'query'; + jsonSerializable: boolean; + handler: (...args: any[]) => unknown; + }): void; + }; +} + +interface WeakApi { + WeakRef?: new (target: T) => { deref(): T | undefined }; + FinalizationRegistry?: new (callback: (held: T) => void) => { + register(target: object, held: T, token?: object): void; + unregister(token: object): unknown; + }; +} + +type Ref = { deref(): T | undefined }; + +interface ObservableModule { + Observable?: { prototype?: Record }; +} + +export interface LeaksOptions { + /** The refresh interval, so keepalives come before the server expires the page. */ + tickMs?: () => number; + now?: () => number; + tree?: () => HostTree; + /** The page's current location, to count navigations and name routes. */ + route?: () => string; + /** Loads the app's RxJS when tracking starts. */ + loadRxjs?: () => Promise; + /** Adds an Angular profiler listener; `null` where Angular has no safe hook (before 20.0). */ + addProfiler?: (listener: Profiler) => (() => void) | null; + /** The Angular major the page runs, 0 when unknown. */ + angularMajor?: () => number; + /** Where the tracking choice is kept across a reload; `null` to keep it in memory. */ + storage?: Pick | null; + /** `WeakRef` and `FinalizationRegistry`, from the page by default. */ + weak?: WeakApi; + /** Whether a scan is due; the default watches the DOM for added and removed elements. */ + dirty?: DomDirty | null; + /** Navigation events, the page's window by default. */ + target?: Pick | null; +} + +export interface LeaksCollector { + /** Scans when the page changed, then pushes when the report changed or a keepalive is due. */ + push(force?: boolean): Promise; + /** Turns subscription tracking on or off. */ + setTracking(on: boolean): Promise<{ ok: boolean; message: string }>; + /** Walks the page now, for tests and forced pushes. */ + scan(): void; + report(): LeaksReport; + /** Stops pushing and tells the server the page left (`pagehide`). */ + leave(): void; + /** Starts again after `leave` (a page restored from the back/forward cache). */ + resume(): void; + stop(): void; +} + +interface Live { + id: string; + name: string; + ref: Ref; + host: Ref; + /** Where and when (in navigations) the page last showed it. */ + route: string; + navigation: number; + effects: number; + sharedEffects: number; +} + +interface Destroyed { + id: string; + name: string; + ref: Ref; + host: Ref; + route: string; + destroyedAt: number; + navigation: number; + detached: boolean; +} + +interface Tracked { + ref: Ref; + /** Class names from the stack, innermost first. */ + candidates: string[]; + frames: string[]; + name?: string; + instance?: Ref; + instanceId?: string; + openedAt: number; + route: string; +} + +function read(fn: () => T, fallback: T): T { + try { + return fn(); + } catch { + return fallback; + } +} + +const IDENT = /^[A-Za-z$][\w$]*$/; +const strip = (name: string) => name.replace(/^_+(?=[A-Za-z$])/, ''); + +/** + * Class names a stack points at, innermost first: `new Card` (a constructor), + * `Card.ngOnInit` (a method) and compiled template functions such as + * `Card_Template` or `Card_Conditional_2_Template_button_click_0_listener`. + */ +export function stackClasses(stack: string | undefined): { + names: string[]; + frames: string[]; + /** Names seen as a constructor (`new Card`): the object being built owns what it starts. */ + constructed: string[]; +} { + const names: string[] = []; + const frames: string[] = []; + const constructed: string[] = []; + const add = (raw: string | undefined) => { + const name = raw && strip(raw); + if (name && IDENT.test(name) && !names.includes(name)) names.push(name); + }; + for (const line of (stack ?? '').split('\n').slice(1, 40)) { + const fn = + /^\s*at\s+(?:async\s+)?(new\s+)?([\w$.]+)/.exec(line) ?? + /^(new\s+)?([\w$.]+)@/.exec(line.trim()); + if (!fn) continue; + const [first, ...rest] = fn[2]!.split('.'); + const before = names.length; + if (fn[1] || rest.length) add(first); + if (fn[1] && first) constructed.push(strip(first)); + // `Card_Conditional_2_Template_button_click_0_listener`: every prefix, longest first. + const bare = strip(first!); + if (/_(?:\w+_)*Template/.test(bare)) { + const pieces = bare.split('_'); + for (let n = pieces.length - 1; n >= 1; n--) add(pieces.slice(0, n).join('_')); + } + if (names.length > before && frames.length < MAX_FRAMES) frames.push(line.trim()); + } + return { names, frames, constructed }; +} + +/** A stack line without the URL's origin and query, masked and cut. */ +function sourceText(frame: string): string { + const short = frame + .replace(/^at\s+/, '') + .replace( + /\(?(?:https?|file|webpack|chrome-extension):\/\/[^\s)]*?([^/\s)?#]+)(?:[?#][^\s):]*)?(:\d+(?::\d+)?)?\)?$/, + '($1$2)', + ); + return clip(redactText(short), MAX_SOURCE); +} + +function nameOf(instance: object): string { + return read(() => className((instance as { constructor: Function }).constructor), '?'); +} + +/** + * Leak hints for one page: the live effects and (while tracking is on) the + * open RxJS subscriptions of each component, and the component instances that + * left the page but are still in memory. Instances are held through `WeakRef` + * only and noticed when collected through a `FinalizationRegistry`, so the + * collector itself keeps nothing alive. Destroyed means the host left the page + * and Angular dropped its view (`ng.getInjector` gives the null injector from + * Angular 14); a host that left while Angular still holds the view is + * reported as detached instead. Subscription tracking wraps + * `Observable.prototype.subscribe` only while it is on, and restores it when + * turned off. + */ +export function attachLeaks( + my: Rpc, + pageId: string, + getNg: () => LeaksDebugNg | undefined, + options: LeaksOptions = {}, +): LeaksCollector { + const now = options.now ?? Date.now; + const tickMs = options.tickMs ?? (() => 0); + const hasDocument = typeof document !== 'undefined'; + const tree = options.tree ?? (() => domTree()); + const route = + options.route ?? (() => read(() => location.pathname + location.search + location.hash, '')); + const major = + options.angularMajor ?? (() => (hasDocument ? read(() => angularMajor(document), 0) : 0)); + const weak: WeakApi = + options.weak ?? + ({ + WeakRef: (globalThis as WeakApi).WeakRef, + FinalizationRegistry: (globalThis as WeakApi).FinalizationRegistry, + } as WeakApi); + const storage = + options.storage === undefined + ? read(() => (typeof sessionStorage === 'undefined' ? null : sessionStorage), null) + : options.storage; + const target = + options.target === undefined ? (typeof window === 'undefined' ? null : window) : options.target; + const dirty = + options.dirty === undefined + ? hasDocument + ? createDomDirty(document, { heartbeatMs: SCAN_HEARTBEAT_MS, now }) + : null + : options.dirty; + const addProfiler = + options.addProfiler ?? + ((listener: Profiler) => + hasDocument ? addProfilerListener(getNg(), listener, document) : null); + const loadRxjs = + options.loadRxjs ?? (() => import('rxjs') as unknown as Promise); + + const live = new Map(); + const destroyed = new Map(); + const instanceIds = new WeakMap(); + const knownClasses = new Set(); + /** When an instance of each class was last destroyed. */ + const lastDestroyed = new Map(); + let tracked: Tracked[] = []; + let collected = 0; + let dropped = 0; + let navigations = 0; + let lastRoute = route(); + let tracking: SubscriptionTracking = 'off'; + let instancesKnown = false; + let restoreSubscribe: (() => void) | null = null; + let removeProfiler: (() => void) | null = null; + const contexts: unknown[] = []; + let lastKey = ''; + let sentAt = 0; + let left = false; + let stopped = false; + let nullInjector: { for: unknown; value: unknown } | null = null; + let effectsSupported = false; + let uniqueEffects = 0; + + const registry = weak.FinalizationRegistry + ? new weak.FinalizationRegistry((id) => { + if (stopped) return; + const entry = destroyed.get(id); + if (entry && entry.ref.deref() === undefined) { + destroyed.delete(id); + collected++; + } + }) + : null; + const retention = () => + !!weak.WeakRef && !!registry && typeof getNg()?.getComponent === 'function'; + + const checkNavigation = () => { + const next = route(); + if (next === lastRoute) return; + lastRoute = next; + navigations++; + }; + + /** The injector Angular gives for an element it does not know, to tell a dropped view apart. */ + const emptyInjector = (ng: LeaksDebugNg) => { + if (nullInjector?.for === ng) return nullInjector.value; + // A detached element is never put on the page, so the app's DOM is untouched. + const probe = hasDocument ? document.createElement('div') : null; + const value = probe ? read(() => ng.getInjector?.(probe) ?? null, null) : null; + nullInjector = { for: ng, value }; + return value; + }; + const detachSupported = (ng: LeaksDebugNg | undefined) => + !!ng && typeof ng.getInjector === 'function' && major() >= 14; + /** Angular still holds the view the host was rendered in. */ + const viewAlive = (ng: LeaksDebugNg, host: Element | undefined) => { + if (!host || !detachSupported(ng)) return false; + const injector = read(() => ng.getInjector!(host), null); + if (!injector) return false; + const empty = emptyInjector(ng); + return empty !== null && injector !== empty; + }; + + const forget = (entry: Destroyed) => { + destroyed.delete(entry.id); + registry?.unregister(entry); + }; + + const markGone = (entry: Live, ng: LeaksDebugNg) => { + live.delete(entry.id); + const instance = entry.ref.deref(); + if (!instance) { + collected++; + return; + } + const host = entry.host.deref(); + const detached = viewAlive(ng, host); + const gone: Destroyed = { + id: entry.id, + name: entry.name, + ref: entry.ref, + host: entry.host, + // The route it lived on: a navigation usually destroys it and changes the URL at once. + route: entry.route, + destroyedAt: now(), + navigation: entry.navigation, + detached, + }; + const previous = destroyed.get(entry.id); + if (previous) forget(previous); + destroyed.set(entry.id, gone); + registry?.register(instance, entry.id, gone); + if (!detached) lastDestroyed.set(entry.name, gone.destroyedAt); + while (destroyed.size > MAX_TRACKED_DESTROYED) { + const oldest = destroyed.values().next().value as Destroyed; + forget(oldest); + dropped++; + } + }; + + /** Effect node ids per component, from Angular's signal graph (ids from 20.1). */ + const effectIds = (ng: LeaksDebugNg, host: Element): string[] | null => { + const injector = read(() => ng.getInjector?.(host) ?? null, null); + if (!injector) return []; + const graph = read(() => ng.ɵgetSignalGraph!(injector), null); + const nodes = graph && Array.isArray(graph.nodes) ? graph.nodes : []; + const out: string[] = []; + for (const node of nodes) { + if (node?.kind !== 'effect') continue; + if (typeof node.id !== 'string' && typeof node.id !== 'number') return null; + out.push(String(node.id)); + } + return out; + }; + + const scan = () => { + const ng = getNg(); + checkNavigation(); + if (!ng || typeof ng.getComponent !== 'function' || !weak.WeakRef) return; + const WeakRefImpl = weak.WeakRef; + const walk = read(() => tree(), null); + if (!walk) return; + const hosts = read(() => componentHosts(ng, walk, MAX_WALK), [] as Element[]); + const seen = new Set(); + for (const host of hosts) { + const instance = read(() => ng.getComponent!(host), null); + if (!instance || typeof instance !== 'object') continue; + const id = elementId(host); + seen.add(id); + let entry = live.get(id); + if (entry && entry.ref.deref() !== instance) { + markGone(entry, ng); + entry = undefined; + } + if (!entry) { + const back = destroyed.get(id); + // A detached view put back on the page (route reuse) is live again. + if (back && back.ref.deref() === instance) forget(back); + const name = nameOf(instance); + knownClasses.add(name); + entry = { + id, + name, + ref: new WeakRefImpl(instance), + host: new WeakRefImpl(host), + route: lastRoute, + navigation: navigations, + effects: 0, + sharedEffects: 0, + }; + live.set(id, entry); + instanceIds.set(instance, id); + } + entry.route = lastRoute; + entry.navigation = navigations; + } + for (const entry of [...live.values()]) { + if (seen.has(entry.id)) continue; + const host = entry.host.deref(); + // Still on the page, past the walk's cap. + if (host && read(() => walk.connected(host), false) && hosts.length >= MAX_WALK) continue; + markGone(entry, ng); + } + // A detached view that Angular has since dropped is destroyed now. + for (const entry of destroyed.values()) { + if (!entry.detached || viewAlive(ng, entry.host.deref())) continue; + entry.detached = false; + entry.destroyedAt = now(); + entry.navigation = navigations; + lastDestroyed.set(entry.name, entry.destroyedAt); + } + countEffects(ng); + pruneTracked(); + }; + + const countEffects = (ng: LeaksDebugNg) => { + effectsSupported = typeof ng.ɵgetSignalGraph === 'function'; + if (!effectsSupported) return; + const owners = new Map(); + const perHost = new Map(); + let n = 0; + for (const entry of live.values()) { + entry.effects = 0; + entry.sharedEffects = 0; + if (n++ >= MAX_EFFECT_HOSTS) continue; + const host = entry.host.deref(); + if (!host) continue; + const ids = effectIds(ng, host); + if (ids === null) { + // Before 20.1 graph nodes carry no ids, so effects can't be told apart. + effectsSupported = false; + return; + } + perHost.set(entry.id, ids); + for (const effect of ids) { + const list = owners.get(effect) ?? []; + list.push(entry.id); + owners.set(effect, list); + } + } + // Angular files a component's effects under the view its host sits in, so + // components side by side in one template list each other's effects. + for (const [id, ids] of perHost) { + const entry = live.get(id)!; + for (const effect of ids) { + if (owners.get(effect)!.length === 1) entry.effects++; + else entry.sharedEffects++; + } + } + uniqueEffects = owners.size; + }; + // --- subscriptions --- + + /** Names the class (and instance id) once the walk knows them; `false` while it doesn't. */ + const resolve = (record: Tracked) => { + if (!record.instanceId && record.instance) { + const instance = record.instance.deref(); + const id = instance ? instanceIds.get(instance) : undefined; + if (id) record.instanceId = id; + } + if (record.name) return knownClasses.has(record.name); + const name = record.candidates.find((candidate) => knownClasses.has(candidate)); + if (!name) return false; + record.name = name; + return true; + }; + + const pruneTracked = () => { + const at = now(); + tracked = tracked.filter((record) => { + const sub = record.ref.deref(); + if (!sub || read(() => (sub as { closed?: unknown }).closed === true, true)) return false; + return resolve(record) || at - record.openedAt < UNRESOLVED_MS; + }); + }; + + const onSubscribe = (sub: unknown, stack: string | undefined) => { + if (!sub || typeof sub !== 'object' || !weak.WeakRef) return; + const { names, frames, constructed } = stackClasses(stack); + if (!names.length) return; + const record: Tracked = { + ref: new weak.WeakRef(sub), + candidates: names.slice(0, 8), + frames, + openedAt: now(), + route: route(), + }; + // The innermost class on the stack with an open Angular context (hook, + // template, listener) names the instance. A constructor before it stops + // the search: a component built inside its parent's template owns what + // its constructor starts, though the parent's context is the open one. + // Otherwise the class is resolved on the next scan, once it is known. + for (const name of record.candidates) { + const context = contextOf(name); + if (context) { + record.name = name; + record.instance = new weak.WeakRef(context); + resolve(record); + break; + } + if (constructed.includes(name)) break; + } + tracked.push(record); + if (tracked.length > MAX_TRACKED_SUBSCRIPTIONS) { + pruneTracked(); + if (tracked.length > MAX_TRACKED_SUBSCRIPTIONS) { + tracked.splice(0, tracked.length - MAX_TRACKED_SUBSCRIPTIONS); + } + } + }; + + const contextOf = (name: string) => { + for (let i = contexts.length - 1; i >= 0; i--) { + const instance = contexts[i]; + if (!instance || typeof instance !== 'object') continue; + // An instance built in this same pass is not walked yet: its id comes on the next scan. + if (nameOf(instance) === name) return instance; + } + return null; + }; + + /** Angular's profiler events with a context: template create and update, lifecycle hooks, outputs. */ + const onProfile: Profiler = (event, instance) => { + if (event === 0 || event === 2 || event === 4 || event === 6) contexts.push(instance); + else if (event === 1 || event === 3 || event === 5 || event === 7) contexts.pop(); + // The end of a change detection run, or a listener added mid-run, leaves nothing open. + else if (event === 13 || contexts.length > 64) contexts.length = 0; + }; + + const wrapSubscribe = (proto: Record) => { + const original = proto['subscribe']; + if (typeof original !== 'function') return null; + const own = Object.prototype.hasOwnProperty.call(proto, 'subscribe'); + let depth = 0; + let active = true; + const wrapped = function (this: unknown, ...args: unknown[]) { + // Operators subscribe to their source inside the outer call; only the outer one counts. + if (!active || depth > 0) return original.apply(this, args); + depth++; + let sub: unknown; + try { + sub = original.apply(this, args); + } finally { + depth--; + } + try { + onSubscribe(sub, new Error().stack); + } catch { + // Tracking never gets in the way of the app's subscription. + } + return sub; + }; + proto['subscribe'] = wrapped; + return () => { + active = false; + if (proto['subscribe'] !== wrapped) return; + if (own) proto['subscribe'] = original; + else delete proto['subscribe']; + }; + }; + + const remember = (on: boolean) => { + try { + if (on) storage?.setItem(TRACKING_KEY, '1'); + else storage?.removeItem(TRACKING_KEY); + } catch { + // the choice lasts for this page load only + } + }; + + const stopTracking = () => { + restoreSubscribe?.(); + restoreSubscribe = null; + removeProfiler?.(); + removeProfiler = null; + contexts.length = 0; + tracked = []; + instancesKnown = false; + }; + + let starting: Promise<{ ok: boolean; message: string }> | null = null; + const setTracking = async (on: boolean): Promise<{ ok: boolean; message: string }> => { + if (!on) { + starting = null; + const was = tracking === 'on'; + stopTracking(); + tracking = 'off'; + remember(false); + lastKey = ''; + return { ok: true, message: was ? 'Stopped tracking subscriptions.' : 'Not tracking.' }; + } + if (tracking === 'on') return { ok: true, message: 'Already tracking subscriptions.' }; + if (starting) return starting; + const attempt = (async () => { + const rxjs = await loadRxjs().catch(() => null); + if (!starting || stopped) return { ok: false, message: 'Tracking was turned off.' }; + const proto = read(() => rxjs?.Observable?.prototype ?? null, null); + const restore = proto ? wrapSubscribe(proto) : null; + if (!restore) { + tracking = 'unavailable'; + lastKey = ''; + return { ok: false, message: 'The page has no RxJS Observable the overlay can load.' }; + } + restoreSubscribe = restore; + removeProfiler = read(() => addProfiler(onProfile), null); + instancesKnown = !!removeProfiler; + tracking = 'on'; + remember(true); + lastKey = ''; + return { ok: true, message: 'Tracking subscriptions.' }; + })(); + starting = attempt; + try { + return await attempt; + } finally { + if (starting === attempt) starting = null; + } + }; + + // --- report --- + + const report = (): LeaksReport => { + const at = now(); + const ng = getNg(); + const openBy = new Map(); + const liveClasses = new Set(); + for (const entry of live.values()) liveClasses.add(entry.name); + const leaks = new Map(); + let totalSubs = 0; + for (const record of tracked) { + const sub = record.ref.deref(); + if (!sub || read(() => (sub as { closed?: unknown }).closed === true, true)) continue; + if (!resolve(record) || !record.name) continue; + const name = record.name; + let reason: LeakSubscription['reason'] | null = null; + if (record.instanceId) { + const instance = record.instance?.deref(); + if (instance && live.get(record.instanceId)?.ref.deref() === instance) { + openBy.set(record.instanceId, (openBy.get(record.instanceId) ?? 0) + 1); + totalSubs++; + } else { + const gone = destroyed.get(record.instanceId); + if (!gone?.detached) reason = 'instance-destroyed'; + if (instance && gone?.ref.deref() === instance) { + openBy.set(record.instanceId, (openBy.get(record.instanceId) ?? 0) + 1); + } + } + } else if (!liveClasses.has(name)) { + const lastGone = lastDestroyed.get(name); + if (lastGone !== undefined && lastGone >= record.openedAt) reason = 'no-live-instance'; + } else { + totalSubs++; + } + if (!reason) continue; + const frame = record.frames.find((line) => line.includes(name)) ?? record.frames[0]; + const source = frame ? sourceText(frame) : undefined; + const key = `${name}|${record.instanceId ?? ''}|${source ?? ''}`; + const held = leaks.get(key); + if (held) { + held.count++; + held.openedAt = Math.min(held.openedAt, record.openedAt); + continue; + } + leaks.set(key, { + name, + count: 1, + route: redactUrl(record.route), + openedAt: record.openedAt, + reason, + ...(record.instanceId ? { instanceId: record.instanceId } : {}), + ...(source ? { source } : {}), + }); + } + + const components: LeakComponent[] = [...live.values()] + .map((entry) => ({ + id: entry.id, + name: entry.name, + effects: entry.effects, + subscriptions: openBy.get(entry.id) ?? 0, + ...(entry.sharedEffects ? { sharedEffects: entry.sharedEffects } : {}), + })) + .filter((entry) => entry.effects || entry.subscriptions || entry.sharedEffects) + .sort( + (a, b) => + b.effects + + b.subscriptions + + (b.sharedEffects ?? 0) - + (a.effects + a.subscriptions + (a.sharedEffects ?? 0)), + ) + .slice(0, MAX_LEAK_COMPONENTS); + + const gone: LeakDestroyed[] = [...destroyed.values()] + .filter((entry) => entry.ref.deref() !== undefined) + .slice(0, MAX_LEAK_DESTROYED) + .map((entry) => { + const subs = openBy.get(entry.id) ?? 0; + return { + id: entry.id, + name: entry.name, + route: redactUrl(entry.route), + destroyedAt: entry.destroyedAt, + navigations: navigations - entry.navigation, + ...(entry.detached ? { detached: true } : {}), + ...(subs ? { subscriptions: subs } : {}), + }; + }); + + return { + pageId, + url: redactUrl(route()), + title: redactMessage(read(() => (hasDocument ? document.title : ''), '')), + at, + support: { + retention: retention(), + effects: effectsSupported, + subscriptions: tracking, + ...(tracking === 'on' && instancesKnown ? { instances: true } : {}), + ...(detachSupported(ng) ? { detached: true } : {}), + }, + navigations, + totals: { + components: live.size, + effects: uniqueEffects, + subscriptions: totalSubs, + destroyed: destroyed.size, + collected, + dropped, + }, + components, + destroyed: gone, + subscriptions: [...leaks.values()].slice(0, MAX_LEAK_SUBSCRIPTIONS), + }; + }; + + let scanDue = dirty ? dirty.cached(() => scan()) : null; + let queue = Promise.resolve(); + const pushOnce = async (force: boolean) => { + if (left || stopped) return; + checkNavigation(); + if (force || !scanDue) scan(); + else scanDue(); + const payload = report(); + const key = JSON.stringify({ ...payload, at: 0 }); + if (!force && key === lastKey && !keepaliveDue(sentAt, tickMs(), now())) return; + lastKey = key; + sentAt = now(); + try { + const answer = (await my.rpc.call('push-leaks', payload)) as { known?: boolean } | undefined; + if (answer?.known === false) lastKey = ''; + } catch { + lastKey = ''; + } + }; + const push = (force = false) => (queue = queue.then(() => pushOnce(force))); + + const onNavigate = () => { + checkNavigation(); + }; + target?.addEventListener('popstate', onNavigate); + target?.addEventListener('hashchange', onNavigate); + const navigation = read( + () => + (globalThis as { navigation?: Pick }) + .navigation ?? null, + null, + ); + if (options.target === undefined) navigation?.addEventListener('navigatesuccess', onNavigate); + + my.rpc.register?.({ + name: 'leak-tracking', + type: 'event', + jsonSerializable: true, + handler: (request: { pageId?: unknown; on?: unknown } | null) => { + if (!request || typeof request !== 'object' || request.pageId !== pageId) return; + void setTracking(request.on !== false).then(() => push(true)); + }, + }); + + // Tracking that was on before a reload starts again at once, so the first screen is seen. + if (read(() => storage?.getItem(TRACKING_KEY) === '1', false)) { + void setTracking(true).then(() => push(true)); + } + + return { + push, + setTracking, + scan, + report, + leave() { + if (left) return; + left = true; + lastKey = ''; + void my.rpc.call('forget-leaks-page', pageId).catch(() => {}); + }, + resume() { + left = false; + lastKey = ''; + void push(true); + }, + stop() { + stopped = true; + starting = null; + stopTracking(); + dirty?.stop(); + scanDue = null; + target?.removeEventListener('popstate', onNavigate); + target?.removeEventListener('hashchange', onNavigate); + if (options.target === undefined) { + navigation?.removeEventListener('navigatesuccess', onNavigate); + } + live.clear(); + destroyed.clear(); + }, + }; +} diff --git a/packages/devtools/src/overlay.ts b/packages/devtools/src/overlay.ts index 3101268c..7954816b 100644 --- a/packages/devtools/src/overlay.ts +++ b/packages/devtools/src/overlay.ts @@ -8,6 +8,8 @@ import { attachPipes } from './pipes-collector.ts'; import { attachHttp } from './http-overlay.ts'; import { attachCapacitor } from './capacitor-overlay.ts'; import { attachErrors } from './errors-collector.ts'; +import { attachLeaks } from './leaks-collector.ts'; +import { createRecentWrites } from './error-explain.ts'; import { allowClientRules, httpRegistry } from './http-rules.ts'; import { attachNgrx } from './ngrx-overlay.ts'; import { collectInjectorTree } from './injector-tree.ts'; @@ -346,13 +348,22 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) } const signalWatch = createSignalWatch(); + // Named signal writes of the last moments, for the NG0100 explainer of the Errors inspector. + const recentWrites = createRecentWrites(); const signalHistory = createSignalHistory( (value, name) => serializeNamed(name, value, { budget: 1000 }), Date.now, (value, name) => graphValue(name, value), - { stacks: signalWatch.stacks, onChange: signalWatch.onChange }, + { + stacks: signalWatch.stacks, + onChange: (id, label, change) => { + signalWatch.onChange(id, label, change); + if (on.errors) recentWrites.add(id, label, change); + }, + }, ); const restoreSignalHook = on.signals ? await installSignalWriteHook(signalHistory.onWrite) : null; + if (restoreSignalHook) recentWrites.listening(); if (!own(restoreSignalHook ?? (() => {}))) return; const writeHookMissing = on.signals && !restoreSignalHook; @@ -479,7 +490,10 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) ? attachChangeDetection(my, pageId, getNg, limits.cdCycles, tickMs, () => lease.active) : null; const ngrx = on.ngrx ? attachNgrx(my, pageId, getNg, limits.changeLog) : null; - const errors = on.errors ? attachErrors(my, pageId, getNg, { tickMs }) : null; + const errors = on.errors + ? attachErrors(my, pageId, getNg, { tickMs, writes: recentWrites }) + : null; + const leaks = on.components ? attachLeaks(my, pageId, getNg, { tickMs }) : null; const angularInfo = attachAngularInfo(my, pageId, getNg, { tickMs }); const consoleGlobals = attachConsoleGlobals(my, pageId, { getNg, @@ -678,6 +692,7 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) http && (() => void http.push().catch(() => {})), cd && paced(() => void cd.push().catch(() => {})), errors && (() => void errors.push().catch(() => {})), + leaks && (() => void leaks.push().catch(() => {})), ].filter((collect) => typeof collect === 'function'); const pushAll = () => collectors.forEach((run) => run()); pushAll(); @@ -892,6 +907,7 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) forget('analog', 'forget-analog-page'); ngrx?.leave(); errors?.leave(); + leaks?.leave(); angularInfo.leave(); }; addEventListener('pagehide', leave); @@ -900,6 +916,7 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) pipes?.resume(); capacitor?.resume(); errors?.resume(); + leaks?.resume(); void lease.refresh(); left = false; onVisibility(); @@ -919,6 +936,7 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) capacitor?.stop(); ngrx?.stop(); errors?.stop(); + leaks?.stop(); cd?.stop(); hydrationOverlay?.stop(); stopAnalog(); diff --git a/packages/devtools/src/rpc/__tests__/injection-explain.test.ts b/packages/devtools/src/rpc/__tests__/injection-explain.test.ts new file mode 100644 index 00000000..cf2d6529 --- /dev/null +++ b/packages/devtools/src/rpc/__tests__/injection-explain.test.ts @@ -0,0 +1,282 @@ +import { describe, expect, it } from 'vitest'; +import { NULL_INJECTOR_ID } from '../../injector-tree.ts'; +import type { InjectorPage, InjectorTreeNode, ProviderInfo } from '../../types.ts'; +import { + explainInjection, + explainInjectionText, + injectionArgs, + registerInjectionExplain, + type InjectionExplanation, +} from '../injection-explain.ts'; + +const provider = (token: string, isViewProvider = false): ProviderInfo => ({ + token, + type: 'class', + isViewProvider, +}); + +const ENV_PATH = ['env-r', 'env-p', NULL_INJECTOR_ID]; + +function element( + id: string, + component: string, + options: { + providers?: ProviderInfo[]; + host?: string; + up?: string[]; + children?: InjectorTreeNode[]; + }, +): InjectorTreeNode { + return { + injector: { + id, + type: 'element', + name: `<${component.toLowerCase()}>`, + providerCount: options.providers?.length ?? 0, + component, + componentId: `c-${id}`, + directives: [component], + path: [id, ...(options.up ?? []), ...ENV_PATH], + ...(options.host ? { host: options.host } : {}), + }, + providers: options.providers ?? [], + children: options.children ?? [], + }; +} + +/** + * App renders TripList, whose template renders TripCard. App's template also + * projects a Badge into TripList, so Badge is declared in App. + */ +function page(): InjectorPage { + const card = element('el-card', 'TripCard', { host: 'el-list', up: ['el-list', 'el-app'] }); + const badge = element('el-badge', 'Badge', { host: 'el-app', up: ['el-list', 'el-app'] }); + const list = element('el-list', 'TripList', { + host: 'el-app', + up: ['el-app'], + providers: [provider('TripStore'), provider('Tooltip', true)], + children: [card, badge], + }); + const app = element('el-app', 'App', { providers: [provider('Logger')], children: [list] }); + app.dependencies = [{ from: 'App', token: 'HttpClient', flags: [], providedBy: 'env-r' }]; + const root: InjectorTreeNode = { + injector: { id: 'env-r', type: 'environment', name: 'Root', providerCount: 1 }, + providers: [provider('ApiConfig')], + children: [], + }; + const platform: InjectorTreeNode = { + injector: { id: 'env-p', type: 'environment', name: 'Platform', providerCount: 0 }, + providers: [], + children: [root], + }; + return { pageId: 'p1', reportedAt: 1, roots: [app], environment: [platform] }; +} + +const explained = (args: Parameters[1], reduced = false, of = page()) => + explainInjection(of, args, reduced) as InjectionExplanation; + +const statuses = (result: InjectionExplanation) => + result.steps.map((step) => `${step.id}:${step.status}`); + +describe('explainInjection', () => { + it('walks up the element injectors and stops at the first one that provides the token', () => { + const result = explained({ selector: 'TripCard', token: 'TripStore' }); + expect(result.outcome).toBe('resolved'); + expect(result.resolvedBy).toBe('el-list'); + expect(statuses(result)).toEqual([ + 'el-card:missing', + 'el-list:provides', + 'el-app:not-asked', + 'env-r:not-asked', + 'env-p:not-asked', + `${NULL_INJECTOR_ID}:not-asked`, + ]); + expect(result.summary).toContain('`TripList`'); + }); + + it('lets an element inside a component view see its viewProviders, and hides them from projected content', () => { + expect(explained({ selector: 'TripCard', token: 'Tooltip' }).resolvedBy).toBe('el-list'); + const projected = explained({ selector: 'Badge', token: 'Tooltip' }); + expect(projected.outcome).toBe('error'); + expect(projected.steps[1]).toMatchObject({ id: 'el-list', status: 'hidden' }); + expect(projected.steps[1]!.reason).toContain('viewProviders'); + }); + + it('ends at the null injector with NG0201, or null when optional', () => { + const missing = explained({ selector: 'TripCard', token: 'Missing' }); + expect(missing.outcome).toBe('error'); + expect(missing.steps.at(-1)).toMatchObject({ type: 'null', status: 'missing' }); + expect(missing.summary).toContain('NG0201'); + expect(explained({ selector: 'TripCard', token: 'Missing', optional: true }).outcome).toBe( + 'null', + ); + }); + + it('asks only the first injector with `self`', () => { + const result = explained({ selector: 'TripCard', token: 'TripStore', self: true }); + expect(result.outcome).toBe('error'); + expect(statuses(result).slice(0, 2)).toEqual(['el-card:missing', 'el-list:not-asked']); + expect(result.steps[1]!.reason).toContain('`self`'); + expect(result.flags).toEqual(['self']); + }); + + it('starts at the parent with `skipSelf`', () => { + const own = explained({ selector: 'TripList', token: 'TripStore', skipSelf: true }); + expect(own.steps[0]).toMatchObject({ id: 'el-list', status: 'skipped' }); + expect(own.outcome).toBe('error'); + expect(explained({ selector: 'TripCard', token: 'TripStore', skipSelf: true }).resolvedBy).toBe( + 'el-list', + ); + }); + + it('stops at the host of the declaring component with `host`, where only viewProviders count', () => { + const logger = explained({ selector: 'TripCard', token: 'Logger', host: true }); + expect(logger.outcome).toBe('error'); + expect(statuses(logger).slice(0, 3)).toEqual([ + 'el-card:missing', + 'el-list:missing', + 'el-app:not-asked', + ]); + expect(logger.steps[2]!.reason).toContain('`host`'); + // Without `host` the lookup goes on to App. + expect(explained({ selector: 'TripCard', token: 'Logger' }).resolvedBy).toBe('el-app'); + const store = explained({ selector: 'TripCard', token: 'TripStore', host: true }); + expect(store.steps[1]).toMatchObject({ status: 'hidden' }); + expect(explained({ selector: 'TripCard', token: 'Tooltip', host: true }).resolvedBy).toBe( + 'el-list', + ); + }); + + it('never asks environment injectors from an element with `self` or `host`', () => { + const result = explained({ selector: 'App', token: 'ApiConfig', host: true, optional: true }); + expect(result.outcome).toBe('null'); + expect(result.steps.find((s) => s.id === 'env-r')).toMatchObject({ status: 'not-asked' }); + }); + + it('counts a service the page already got from an environment injector as provided there', () => { + const result = explained({ selector: 'c-el-card', token: 'HttpClient' }); + expect(result.resolvedBy).toBe('env-r'); + expect(result.steps.find((s) => s.id === 'env-r')!.reason).toContain('providedIn'); + }); + + it("says the root injector may create an unlisted providedIn: 'root' class", () => { + const result = explained({ selector: 'TripCard', token: 'NotYetUsed' }); + expect(result.steps.find((s) => s.id === 'env-r')!.reason).toContain("providedIn: 'root'"); + }); + + it('starts at an environment injector for a service, and honours `self` there', () => { + expect(explained({ selector: 'Root', token: 'ApiConfig' }).resolvedBy).toBe('env-r'); + const result = explained({ selector: 'root', token: 'Other', self: true }); + expect(statuses(result)).toEqual([ + 'env-r:missing', + 'env-p:not-asked', + `${NULL_INJECTOR_ID}:missing`, + ]); + expect(result.outcome).toBe('error'); + }); + + it('rebuilds the path from the nesting when the page reports none, and says so', () => { + const old = page(); + const strip = (nodes: InjectorTreeNode[]) => { + for (const node of nodes) { + delete node.injector.path; + strip(node.children); + } + }; + strip(old.roots); + const result = explained({ selector: 'TripCard', token: 'Logger' }, false, old); + expect(result.approximate).toBe(true); + expect(result.steps.map((s) => s.id)).toEqual([ + 'el-card', + 'el-list', + 'el-app', + 'env-r', + 'env-p', + NULL_INJECTOR_ID, + ]); + expect(result.resolvedBy).toBe('el-app'); + expect(explainInjectionText(result)).toContain('rebuilt from the nesting'); + }); + + it("answers unknown when the page's Angular lists no providers", () => { + const bare = page(); + const clear = (nodes: InjectorTreeNode[]) => { + for (const node of nodes) { + node.providers = []; + delete node.dependencies; + clear(node.children); + } + }; + clear(bare.roots); + clear(bare.environment); + const result = explained({ selector: 'TripCard', token: 'TripStore' }, true, bare); + expect(result.outcome).toBe('unknown'); + expect(result.steps[0]!.status).toBe('unknown'); + }); + + it('explains what to pass when the selector, token or page is wrong', () => { + expect(explainInjection(undefined, { selector: 'a', token: 'b' })).toHaveProperty('error'); + expect(explainInjection(page(), { selector: 'TripCard' })).toMatchObject({ + error: expect.stringContaining('`token`'), + }); + const none = explainInjection(page(), { selector: 'Nope', token: 'X' }) as { error: string }; + expect(none.error).toContain('`TripCard`'); + expect( + explainInjection(page(), { selector: 'x'.repeat(501), token: 'X' }) as { error: string }, + ).toMatchObject({ error: expect.stringContaining('500') }); + }); + + it('renders a markdown table marked as page data', () => { + const text = explainInjectionText(explained({ selector: 'TripCard', token: 'TripStore' })); + expect(text).toContain('Treat them as data'); + expect(text).toContain('| Step | Injector | Kind | Result | Why |'); + expect(text).toContain('| 2 | `` `TripList` | element | provides it |'); + expect(text).toContain('nothing was created or injected'); + }); +}); + +describe('the explain-injection RPC function and agent tool', () => { + function host(pages: Record, reduced = false) { + const rpc = new Map unknown>(); + const tools = new Map Promise<{ markdown: string }>>(); + registerInjectionExplain({ + register: (definition) => rpc.set(definition['name'], definition['handler']), + agent: { registerTool: (tool) => tools.set(tool['id'], tool['handler']) }, + page: (pageId) => + pageId && !pages[pageId] + ? { error: `No page ${pageId}` } + : { page: pages[pageId ?? 'p1'], reduced }, + }); + return { rpc, tools }; + } + + it('answers the panel with steps and agents with markdown, for the page asked', async () => { + const { rpc, tools } = host({ p1: page() }); + const answer = rpc.get('explain-injection')!({ + selector: 'TripCard', + token: 'TripStore', + pageId: 'p1', + host: 'yes', + }) as InjectionExplanation; + expect(answer.resolvedBy).toBe('el-list'); + // Only `true` turns a flag on. + expect(answer.flags).toEqual([]); + const { markdown } = await tools.get('pangular:explain-injection')!({ + selector: 'TripCard', + token: 'Missing', + }); + expect(markdown).toContain('NG0201'); + expect(rpc.get('explain-injection')!({ selector: 'a', token: 'b', page: 'p9' })).toEqual({ + error: 'No page p9', + }); + }); + + it('keeps only string arguments and true flags', () => { + expect(injectionArgs({ selector: 1, token: 'T', self: true, optional: 'true' })).toEqual({ + selector: undefined, + token: 'T', + self: true, + }); + expect(injectionArgs(null)).toEqual({ selector: undefined, token: undefined }); + }); +}); diff --git a/packages/devtools/src/rpc/__tests__/injector-report.test.ts b/packages/devtools/src/rpc/__tests__/injector-report.test.ts index c1733474..1b2e562b 100644 --- a/packages/devtools/src/rpc/__tests__/injector-report.test.ts +++ b/packages/devtools/src/rpc/__tests__/injector-report.test.ts @@ -28,7 +28,17 @@ describe('sanitizeInjectorTree', () => { path: ['inj-1', 'inj-2'], }, providers: [{ token: 'Store', type: 'class', isViewProvider: false, multi: true }], - children: [node('app-card')], + children: [ + node('app-card', { + injector: { + id: 'inj-3', + type: 'element', + name: 'app-card', + providerCount: 0, + host: 'inj-1', + }, + }), + ], dependencies: [ { from: 'App', token: 'Store', flags: ['optional'], providedBy: null }, { from: 'App', token: 'Http', flags: [], providedBy: 'inj-2', providedByName: 'Root' }, diff --git a/packages/devtools/src/rpc/cd-diagnosis-tools.ts b/packages/devtools/src/rpc/cd-diagnosis-tools.ts new file mode 100644 index 00000000..996ee0fa --- /dev/null +++ b/packages/devtools/src/rpc/cd-diagnosis-tools.ts @@ -0,0 +1,134 @@ +import { CD_CAUSE_KINDS, CD_CAUSE_LABEL, cdCauseText, cdHints } from '../cd-data.ts'; +import type { AngularPageInfo, CdCycle } from '../config.ts'; +import { unsupportedToolText } from './angular-pages.ts'; +import { pickCdPage, type CdState } from './cd-tools.ts'; +import { code, UNTRUSTED } from './forms-tools.ts'; + +const percent = (part: number, whole: number) => + whole ? `${Math.round((part / whole) * 100)}%` : '0%'; + +/** + * Markdown for the `diagnose-change-detection` agent tool: what started the + * recorded cycles, which components only zone.js keeps up to date, which + * checks changed nothing, inputs that broke OnPush, and the hints from them. + */ +export function cdDiagnosisText( + state: CdState, + args: { page?: string; limit?: number } = {}, + angularOf: (pageId: string) => AngularPageInfo | undefined = () => undefined, +): string { + const page = pickCdPage(state, args.page); + if (!page) { + return args.page + ? `Page ${code(args.page)} has no change detection recording yet. Start one with \`pangular:change-detection\` and \`record: "start"\` (or **Record** in the panel), use the app, then call this tool again.` + : 'No change detection recording yet. Start one with `pangular:change-detection` and `record: "start"` (or **Record** in the panel), use the app, then call this tool again.'; + } + if (!page.supported) { + const unsupported = unsupportedToolText(angularOf(page.pageId), 'profiler'); + if (unsupported) return `Page ${code(page.pageId)}: ${unsupported}`; + return `Page ${code(page.pageId)} can't record change detection: it needs Angular 20 or later in a development build.`; + } + const diagnosis = page.diagnosis; + if (!diagnosis) { + return `Page ${code(page.pageId)} reported no diagnosis. Its overlay is older than this server, or the recording started before the page loaded it; clear the recording and record again.`; + } + const asked = Number(args.limit ?? 10); + const limit = Math.max(1, Math.min(Math.floor(Number.isFinite(asked) ? asked : 10), 50)); + const status = page.recording ? 'Recording is on.' : 'Recording is off.'; + const cycles = page.cycles.length; + if (!cycles && !diagnosis.components.length) { + return `${status} No change detection cycle was recorded on page ${code(page.pageId)} yet. Use the app, then call this tool again.`; + } + const parts: string[] = [ + `${UNTRUSTED}\n\n${status} Page ${code(page.pageId)}: ${cycles} cycle(s) kept.`, + ]; + + if (diagnosis.triggers) { + const rows = CD_CAUSE_KINDS.filter((kind) => diagnosis.causes[kind]).map( + (kind) => `- ${CD_CAUSE_LABEL[kind]} (\`${kind}\`): ${diagnosis.causes[kind]} cycle(s)`, + ); + const recent = page.cycles + .filter((c): c is CdCycle & Required> => !!c.cause) + .slice(-limit) + .reverse() + .map( + (c) => + `- #${c.id}: ${code(cdCauseText(c.cause))}${c.cause.stack?.length ? ` at ${c.cause.stack.map(code).join(' < ')}` : ''}`, + ); + parts.push( + `**What started the cycles**\n${rows.length ? rows.join('\n') : '- No cycle had a cause yet.'}${recent.length ? `\n\n**Latest causes**, newest first\n${recent.join('\n')}` : ''}`, + ); + } else { + parts.push( + '_The page has no Angular change detection scheduler the overlay could find (it needs Angular 18 or later), so cycles carry no cause. Wasted checks below still count._', + ); + } + + const zone = diagnosis.zone ?? []; + const zoneOnly = diagnosis.causes.zone ?? 0; + if (zone.length) { + parts.push( + `**Components that depend on zone.js**: they changed in ticks zone.js started with no signal write, markForCheck, event listener or input before them (${zoneOnly} such tick(s))\n${zone + .slice(0, limit) + .map( + (z) => + `- ${code(z.name)}: ${z.ticks} tick(s)${z.tasks?.length ? `, after ${z.tasks.map(code).join(', ')}` : ''}`, + ) + .join('\n')}`, + ); + } else if (zoneOnly) { + parts.push( + `**zone.js**: ${zoneOnly} tick(s) came from zone.js alone, and no component changed in them, so they only cost time.`, + ); + } else if (diagnosis.triggers) { + parts.push( + '**zone.js**: no component changed in a tick that only zone.js started, so the recorded interactions would work zoneless.', + ); + } + + if (diagnosis.waste) { + const wasted = diagnosis.components.filter((c) => c.unchanged > 0).slice(0, limit); + parts.push( + `**Wasted checks**: refreshed checks where nothing the component renders changed (no DOM update, no new input reference for a child), the development checkNoChanges pass left out\n${ + wasted.length + ? wasted + .map( + (c) => + `- ${code(c.name)}: ${c.unchanged} of ${c.refreshed} refreshed check(s) changed nothing (${percent(c.unchanged, c.refreshed)})${c.strategy ? `, ${c.strategy}` : ''}`, + ) + .join('\n') + : '- None: every refreshed check changed something.' + }`, + ); + } else { + parts.push( + '_The page could not watch DOM updates (no `MutationObserver`), so wasted checks are not counted._', + ); + } + + const inputs = diagnosis.inputs ?? []; + if (inputs.length) { + parts.push( + `**Inputs that break OnPush**\n${inputs + .slice(0, limit) + .map( + (i) => + `- ${code(`${i.name}.${i.input}`)}${i.parent ? ` (set by ${code(i.parent)})` : ''}: ${i.inPlace} change(s) in place, ${i.sameContents} new reference(s) with the same contents`, + ) + .join('\n')}`, + ); + } + + const hints = cdHints(diagnosis); + parts.push( + `**Hints**\n${ + hints.length + ? hints + .slice(0, limit) + .map((h) => `- ${h.text}`) + .join('\n') + : `- No hint: no component was refreshed at least 10 times while changing in under 20% of them, and no input or zone.js problem was seen.` + }`, + ); + return parts.join('\n\n'); +} diff --git a/packages/devtools/src/rpc/cd-export-tools.ts b/packages/devtools/src/rpc/cd-export-tools.ts index cde7443e..81bf95d2 100644 --- a/packages/devtools/src/rpc/cd-export-tools.ts +++ b/packages/devtools/src/rpc/cd-export-tools.ts @@ -1,6 +1,5 @@ import { cdExportFile, cdTraceFile } from '../cd-data.ts'; -import type { CdRecording } from '../config.ts'; -import { redactText } from '../text-redact.ts'; +import { redactCdRecording } from './cd-redact.ts'; import { pickCdPage, type CdState } from './cd-tools.ts'; import { code, UNTRUSTED } from './forms-tools.ts'; @@ -9,33 +8,6 @@ export const CD_EXPORT_MAX_CHARS = 100_000; export type CdExportKind = 'json' | 'trace'; -/** Every page-controlled string of a recording, masked with the redaction helpers. */ -export function redactCdRecording(recording: CdRecording): CdRecording { - const mask = (text: string) => redactText(text); - return { - ...recording, - cycles: recording.cycles.map((cycle) => ({ - ...cycle, - ...(cycle.trigger ? { trigger: mask(cycle.trigger) } : {}), - components: cycle.components.map((c) => ({ ...c, name: mask(c.name) })), - })), - components: recording.components.map((c) => ({ ...c, name: mask(c.name) })), - ...(recording.hooks - ? { hooks: recording.hooks.map((h) => ({ ...h, name: mask(h.name), hook: mask(h.hook) })) } - : {}), - ...(recording.outputs - ? { - outputs: recording.outputs.map((o) => ({ - ...o, - name: mask(o.name), - ...(o.listener ? { listener: mask(o.listener) } : {}), - })), - } - : {}), - ...(recording.spanNames ? { spanNames: recording.spanNames.map(mask) } : {}), - }; -} - /** A code fence longer than any run of backticks in `text`. */ function fence(text: string): string { const longest = Math.max(0, ...(text.match(/`+/g) ?? []).map((run) => run.length)); diff --git a/packages/devtools/src/rpc/cd-redact.ts b/packages/devtools/src/rpc/cd-redact.ts new file mode 100644 index 00000000..7ff6d38b --- /dev/null +++ b/packages/devtools/src/rpc/cd-redact.ts @@ -0,0 +1,70 @@ +import type { CdCause, CdDiagnosis, CdRecording } from '../config.ts'; +import { redactText } from '../text-redact.ts'; + +/** Every page-controlled string of a recording, masked with the redaction helpers. */ +export function redactCdRecording(recording: CdRecording): CdRecording { + const mask = (text: string) => redactText(text); + return { + ...recording, + cycles: recording.cycles.map((cycle) => ({ + ...cycle, + ...(cycle.trigger ? { trigger: mask(cycle.trigger) } : {}), + components: cycle.components.map((c) => ({ ...c, name: mask(c.name) })), + ...(cycle.cause ? { cause: redactCdCause(cycle.cause) } : {}), + })), + ...(recording.diagnosis ? { diagnosis: redactCdDiagnosis(recording.diagnosis) } : {}), + components: recording.components.map((c) => ({ ...c, name: mask(c.name) })), + ...(recording.hooks + ? { hooks: recording.hooks.map((h) => ({ ...h, name: mask(h.name), hook: mask(h.hook) })) } + : {}), + ...(recording.outputs + ? { + outputs: recording.outputs.map((o) => ({ + ...o, + name: mask(o.name), + ...(o.listener ? { listener: mask(o.listener) } : {}), + })), + } + : {}), + ...(recording.spanNames ? { spanNames: recording.spanNames.map(mask) } : {}), + }; +} + +/** A cycle's cause with every page-controlled string masked. */ +export function redactCdCause(cause: CdCause): CdCause { + const out: CdCause = { ...cause }; + for (const field of ['component', 'listener', 'event', 'target', 'signal', 'task'] as const) { + const value = out[field]; + if (value) out[field] = redactText(value); + } + if (out.stack) out.stack = out.stack.map((frame) => redactText(frame)); + return out; +} + +/** A diagnosis with every class, input and task name masked. */ +export function redactCdDiagnosis(diagnosis: CdDiagnosis): CdDiagnosis { + const mask = (text: string) => redactText(text); + return { + ...diagnosis, + components: diagnosis.components.map((c) => ({ ...c, name: mask(c.name) })), + ...(diagnosis.inputs + ? { + inputs: diagnosis.inputs.map((i) => ({ + ...i, + name: mask(i.name), + input: mask(i.input), + ...(i.parent ? { parent: mask(i.parent) } : {}), + })), + } + : {}), + ...(diagnosis.zone + ? { + zone: diagnosis.zone.map((z) => ({ + ...z, + name: mask(z.name), + ...(z.tasks ? { tasks: z.tasks.map(mask) } : {}), + })), + } + : {}), + }; +} diff --git a/packages/devtools/src/rpc/cd-tools.ts b/packages/devtools/src/rpc/cd-tools.ts index 152f5aa6..f245ee17 100644 --- a/packages/devtools/src/rpc/cd-tools.ts +++ b/packages/devtools/src/rpc/cd-tools.ts @@ -2,7 +2,8 @@ import type { AngularPageInfo } from '../config.ts'; import { unsupportedToolText } from './angular-pages.ts'; import type { CdReport } from '../cd-overlay.ts'; import type { CdOptions } from '../config.ts'; -import { sanitizeCdRecording, toCdOptions } from '../cd-data.ts'; +import { cdCauseText, sanitizeCdRecording, toCdOptions } from '../cd-data.ts'; +import { redactCdCause, redactCdDiagnosis } from './cd-redact.ts'; import type { CdComponentStat, CdCycle } from '../cd-recorder.ts'; import { droppedNote } from '../timeline-limits.ts'; import { code, UNTRUSTED } from './forms-tools.ts'; @@ -27,8 +28,16 @@ export function toCdPage(value: unknown, maxCycles: number, now = Date.now()): C const report = value as Record; const pageId = report['pageId']; if (typeof pageId !== 'string' || !pageId || pageId.length >= 50) return null; - const recording = sanitizeCdRecording(report, maxCycles); - if (!recording) return null; + const sanitized = sanitizeCdRecording(report, maxCycles); + if (!sanitized) return null; + // Causes carry stack frames and signal names from the page: mask them before anyone reads them. + const recording = { + ...sanitized, + cycles: sanitized.cycles.map((cycle) => + cycle.cause ? { ...cycle, cause: redactCdCause(cycle.cause) } : cycle, + ), + ...(sanitized.diagnosis ? { diagnosis: redactCdDiagnosis(sanitized.diagnosis) } : {}), + }; const options = toCdOptions(report['options']); return { pageId, @@ -252,7 +261,7 @@ export function changeDetectionText( const line = (c: CdComponentStat) => `- ${code(c.name)}: ${c.checks} check(s) in ${c.cycles} cycle(s), ${ms(c.ms)} in its own template and hooks (slowest ${ms(c.maxMs)})`; const cycleLine = (c: CdCycle) => - `- #${c.id}: ${ms(c.ms)}, ${c.checks} component check(s), ${c.passes} pass(es)${c.trigger ? `, after output in ${code(c.trigger)}${c.outputMs ? ` (${ms(c.outputMs)})` : ''}` : ''}${c.hookMs ? `, hooks ${ms(c.hookMs)}` : ''}${c.afterRenderMs ? `, afterRender ${ms(c.afterRenderMs)}` : ''}${ + `- #${c.id}: ${ms(c.ms)}, ${c.checks} component check(s), ${c.passes} pass(es)${c.cause ? `, started by ${code(cdCauseText(c.cause))}` : ''}${c.unchanged ? `, ${c.unchanged} of ${c.refreshed ?? c.unchanged} refreshed check(s) changed nothing` : ''}${c.trigger ? `, after output in ${code(c.trigger)}${c.outputMs ? ` (${ms(c.outputMs)})` : ''}` : ''}${c.hookMs ? `, hooks ${ms(c.hookMs)}` : ''}${c.afterRenderMs ? `, afterRender ${ms(c.afterRenderMs)}` : ''}${ c.components.length ? `; slowest ${c.components .slice(0, 3) diff --git a/packages/devtools/src/rpc/error-explain-tools.ts b/packages/devtools/src/rpc/error-explain-tools.ts new file mode 100644 index 00000000..0596acd3 --- /dev/null +++ b/packages/devtools/src/rpc/error-explain-tools.ts @@ -0,0 +1,252 @@ +// The explainers of the Errors inspector on the server: the shapes a page +// sends with an NG0100, a hydration mismatch or a missing provider, checked +// and masked again here, and the markdown `explain-error` adds for them. + +import { diffDom, diffText, type DiffLine } from '../dom-diff.ts'; +import { REDACTED, redactText } from '../serialize.ts'; +import { clip } from '../text.ts'; +import { code } from './forms-tools.ts'; + +/** A signal written just before Angular's check, with the value the binding now reads. */ +export interface ExplainWrite { + /** The signal's `debugName`. */ + signal: string; + at: number; + /** The first app frames of the code that wrote it, when write stacks were on. */ + stack?: string[]; +} + +/** NG0100: a binding read a different value when Angular checked it again. */ +export interface ExpressionChangedExplain { + kind: 'expression-changed'; + /** The property Angular names (`for 'title'`), missing for a text interpolation. */ + binding?: string; + /** The compiled template function on the stack, such as `App_Template` or `App_Conditional_2_Template`. */ + template?: string; + /** The value of the first check, as Angular prints it (masked, at most 200 characters). */ + previous: string; + /** The value of the second check. */ + current: string; + /** The values are hidden: the binding or a component field holding them has a secret-looking name. */ + masked?: boolean; + /** Angular says the view was created after its parent was checked (created in a hook). */ + creation?: boolean; + /** Fields of the component that hold the current value now, the likely sources of the binding. */ + members?: string[]; + /** Named signals written with the current value shortly before the error. */ + writes?: ExplainWrite[]; + /** Whether the page hears signal writes at all (Signals inspector on, Angular 17+). */ + writesKnown?: boolean; +} + +/** NG0500 to NG0503: the DOM the client found did not match the server HTML. */ +export interface HydrationMismatchExplain { + kind: 'hydration-mismatch'; + /** Angular's first sentence, such as `During hydration Angular expected
    but found .` */ + summary?: string; + /** The server DOM Angular expected around the node, as Angular describes it. */ + expected?: string; + /** The client DOM Angular found there. */ + actual?: string; + /** Angular suspects a browser extension or third-party script changed the DOM. */ + external?: boolean; + /** Line diff of `expected` and `actual`, built by the server. */ + diff?: DiffLine[]; +} + +/** NG0201 and NullInjectorError: no injector on the lookup path provides a token. */ +export interface MissingProviderExplain { + kind: 'missing-provider'; + /** The token no injector provided, named like the Injectors tab names it. */ + token: string; + /** Angular's dependency path, requester first (`App -> Api -> HttpClient`). */ + path?: string[]; + /** The injector Angular names as the source (`Standalone[App]`, `NodeInjector`). */ + source?: string; +} + +export type ErrorExplain = + ExpressionChangedExplain | HydrationMismatchExplain | MissingProviderExplain; + +export const MAX_VALUE_TEXT = 200; +export const MAX_DOM_TEXT = 3000; +const MAX_NAME = 120; +const MAX_WRITES = 5; +const MAX_MEMBERS = 10; +const MAX_PATH = 20; +const MAX_FRAMES = 5; + +function isRecord(value: unknown): value is Record { + return !!value && typeof value === 'object' && !Array.isArray(value); +} + +const str = (value: unknown, max: number): string | undefined => + typeof value === 'string' && value ? clip(redactText(value), max) : undefined; + +const names = (value: unknown, max: number): string[] => + Array.isArray(value) + ? value + .filter((item): item is string => typeof item === 'string' && !!item) + .slice(0, max) + .map((item) => clip(redactText(item), MAX_NAME)) + : []; + +function toWrite(value: unknown): ExplainWrite | null { + if (!isRecord(value) || typeof value['at'] !== 'number') return null; + const signal = str(value['signal'], MAX_NAME); + if (!signal) return null; + const stack = names(value['stack'], MAX_FRAMES).map((frame) => clip(frame, 200)); + return { signal, at: value['at'], ...(stack.length ? { stack } : {}) }; +} + +/** Checks and masks the explainer a page sent with an error group; `undefined` when there is none. */ +export function toErrorExplain(value: unknown): ErrorExplain | undefined { + if (!isRecord(value)) return undefined; + switch (value['kind']) { + case 'expression-changed': { + const masked = value['masked'] === true; + const previous = masked ? REDACTED : (str(value['previous'], MAX_VALUE_TEXT) ?? ''); + const current = masked ? REDACTED : (str(value['current'], MAX_VALUE_TEXT) ?? ''); + const binding = str(value['binding'], MAX_NAME); + const template = str(value['template'], MAX_NAME); + const members = names(value['members'], MAX_MEMBERS); + const writes = Array.isArray(value['writes']) + ? value['writes'] + .slice(0, MAX_WRITES) + .map(toWrite) + .filter((w): w is ExplainWrite => !!w) + : []; + return { + kind: 'expression-changed', + previous, + current, + ...(binding ? { binding } : {}), + ...(template ? { template } : {}), + ...(masked ? { masked } : {}), + ...(value['creation'] === true ? { creation: true } : {}), + ...(members.length ? { members } : {}), + ...(writes.length ? { writes } : {}), + ...(typeof value['writesKnown'] === 'boolean' ? { writesKnown: value['writesKnown'] } : {}), + }; + } + case 'hydration-mismatch': { + const summary = str(value['summary'], 500); + const expected = str(value['expected'], MAX_DOM_TEXT); + const actual = str(value['actual'], MAX_DOM_TEXT); + // The diff is built here from the masked sides, never taken from the page. + const diff = expected || actual ? diffDom(expected, actual) : []; + return { + kind: 'hydration-mismatch', + ...(summary ? { summary } : {}), + ...(expected ? { expected } : {}), + ...(actual ? { actual } : {}), + ...(value['external'] === true ? { external: true } : {}), + ...(diff.length ? { diff } : {}), + }; + } + case 'missing-provider': { + const token = str(value['token'], MAX_NAME); + if (!token) return undefined; + const path = names(value['path'], MAX_PATH); + const source = str(value['source'], MAX_NAME); + return { + kind: 'missing-provider', + token, + ...(path.length ? { path } : {}), + ...(source ? { source } : {}), + }; + } + default: + return undefined; + } +} + +function fence(text: string): string { + return ['```text', text.replace(/```/g, "'''"), '```'].join('\n'); +} + +/** The markdown section `explain-error` adds for a group with an explainer. */ +export function explainSection( + explain: ErrorExplain, + owner: { id: string; name: string } | undefined, +): string { + const component = owner + ? `${code(owner.name)} (instance ${code(owner.id)})` + : 'the component Angular names'; + switch (explain.kind) { + case 'expression-changed': { + const lines = [ + '**What changed** (NG0100 explainer):', + '', + `- Component: ${component}.`, + `- Binding: ${explain.binding ? `the ${code(explain.binding)} property` : 'a text interpolation or a binding Angular does not name'}${explain.template ? `, in the template function ${code(explain.template)}` : ''}.`, + `- Previous value: ${code(explain.previous)}. Current value: ${code(explain.current)}.${explain.masked ? ' Both are hidden because the binding or the field that holds them has a secret-looking name.' : ''}`, + ]; + if (explain.members?.length) { + lines.push( + `- Fields of the component that hold the current value now: ${explain.members.map(code).join(', ')}.`, + ); + } + if (explain.creation) { + lines.push( + '- Angular says the view was created after its parent and children were checked, so a change detection hook (such as ngAfterViewInit) created it.', + ); + } + if (explain.writes?.length) { + for (const write of explain.writes) { + lines.push( + `- Signal ${code(write.signal)} was written with this value just before the check${ + write.stack?.length + ? `, from ${write.stack.map(code).join(' < ')}.` + : '. Turn on write stacks (the Signals tab, or pangular:watch-signal with `stacks: true`) and reproduce to see the code that wrote it.' + }`, + ); + } + } else if (explain.writesKnown) { + lines.push( + '- No named signal was written with this value just before the check. Look for code that sets a field the template reads during change detection: a lifecycle hook such as ngAfterViewInit or ngAfterViewChecked, a getter that returns a new value on each call, or a child that changes its parent state.', + ); + } else { + lines.push( + '- Where it was written is unknown: the page does not report signal writes (the Signals inspector is off, or Angular is older than 17.0).', + ); + } + return lines.join('\n'); + } + case 'hydration-mismatch': { + const lines = ['**Server vs client DOM** (hydration mismatch explainer):', '']; + if (explain.summary) lines.push(explain.summary, ''); + lines.push(`Component: ${component}.`); + if (explain.diff?.length) { + lines.push( + '', + 'Diff of the server HTML Angular expected (`-`) and the client DOM it found (`+`); `<-- AT THIS LOCATION` marks the node Angular means:', + '', + fence(diffText(explain.diff)), + ); + } else { + lines.push('', 'Angular described neither side of the mismatch.'); + } + if (explain.external) { + lines.push( + '', + 'Angular thinks a browser extension or third-party script may have changed the DOM before hydration. Try a clean browser profile, or add `ngSkipHydration` to the host.', + ); + } + return lines.join('\n'); + } + case 'missing-provider': + return [ + '**Missing provider** explainer:', + '', + `- Token: ${code(explain.token)}.`, + explain.path?.length + ? `- Dependency path, requester first: ${explain.path.map(code).join(' -> ')}.` + : '', + explain.source ? `- Source injector: ${code(explain.source)}.` : '', + `- Walk the lookup: pangular:explain-injection with \`selector\` ${owner ? code(owner.id) : '(the component)'} and \`token\` ${code(explain.token)} lists each injector Angular asks and why the lookup stops.`, + ] + .filter(Boolean) + .join('\n'); + } +} diff --git a/packages/devtools/src/rpc/errors-register.ts b/packages/devtools/src/rpc/errors-register.ts index 96c0844c..7bf9e2c7 100644 --- a/packages/devtools/src/rpc/errors-register.ts +++ b/packages/devtools/src/rpc/errors-register.ts @@ -117,7 +117,7 @@ export async function registerErrors(host: ErrorsHost): Promise`)} ${code(mismatch.id)}${mismatch.expected ? `: expected ${code(mismatch.expected)}` : ''}${mismatch.actual ? `, found ${code(mismatch.actual)}` : ''}`, - ); + lines.push(`- ${code(mismatch.name)} ${code(`<${mismatch.tag}>`)} ${code(mismatch.id)}`); + if (mismatch.expected || mismatch.actual) { + // Server HTML Angular expected (-) against the client DOM it found (+). + const diff = diffText(diffDom(mismatch.expected, mismatch.actual)).replace(/```/g, "'''"); + lines.push('', ' ```diff', ...diff.split('\n').map((line) => ` ${line}`), ' ```'); + } } + lines.push( + '', + 'In each diff, `-` lines are the server HTML Angular expected, `+` lines the client DOM it found, and `<-- AT THIS LOCATION` marks the node. pangular:explain-error shows the same diff for the NG05xx error.', + ); } const client = hostsWith(page.roots, 'client'); if (client.length) { diff --git a/packages/devtools/src/rpc/injection-explain.ts b/packages/devtools/src/rpc/injection-explain.ts new file mode 100644 index 00000000..e637f9b9 --- /dev/null +++ b/packages/devtools/src/rpc/injection-explain.ts @@ -0,0 +1,500 @@ +// `explain-injection`: walks the lookup path of a token from an element or +// environment injector the way Angular resolves it (`lookupTokenUsingNodeInjector` +// and `R3Injector.get` in `@angular/core`), honouring `self`, `skipSelf`, +// `host` and `optional`, and says at each injector whether it provides the +// token and why the lookup stops. It reads only the injector tree the page +// reported, so it never creates a service or runs app code. + +import { NULL_INJECTOR_ID } from '../injector-tree.ts'; +import type { InjectorPage, InjectorTreeNode, ProviderInfo } from '../types.ts'; +import { code, untrusted } from './forms-tools.ts'; +import { MAX_ARG_CHARS, NO_INJECTORS } from './injector-tools.ts'; + +export interface InjectionFlags { + self?: boolean; + skipSelf?: boolean; + host?: boolean; + optional?: boolean; +} + +export interface ExplainInjectionArgs extends InjectionFlags { + /** An element injector (tag, class name, component id, injector id) or an environment injector name. */ + selector?: string; + token?: string; +} + +/** What one injector on the path did with the token. */ +export type InjectionStepStatus = + /** It provides the token: the lookup ends here. */ + | 'provides' + /** It was asked and does not provide the token. */ + | 'missing' + /** It provides the token only in `viewProviders`, which this lookup can't see. */ + | 'hidden' + /** `skipSelf`: Angular starts at the parent. */ + | 'skipped' + /** The lookup stopped before it got here. */ + | 'not-asked' + /** The page's Angular does not list providers, so it can't be told. */ + | 'unknown'; + +export interface InjectionStep { + id: string; + name: string; + type: 'element' | 'environment' | 'null'; + /** The component on an element injector. */ + component?: string; + status: InjectionStepStatus; + reason: string; + provider?: ProviderInfo; +} + +export interface InjectionExplanation { + pageId: string; + token: string; + flags: (keyof InjectionFlags)[]; + start: { + id: string; + name: string; + type: InjectorTreeNode['injector']['type']; + component?: string; + }; + steps: InjectionStep[]; + /** `resolved`: an injector provides it; `null`: optional and not found; `error`: NG0201; `unknown`: no provider data. */ + outcome: 'resolved' | 'null' | 'error' | 'unknown'; + /** The id of the injector that provides the token. */ + resolvedBy?: string; + summary: string; + /** Before Angular 16.2 the path is rebuilt from the tree's nesting and may differ from Angular's. */ + approximate?: boolean; + /** Other injectors the selector matched; the first one was used. */ + alsoMatched?: string[]; +} + +const FLAG_NAMES: (keyof InjectionFlags)[] = ['self', 'skipSelf', 'host', 'optional']; + +function flatten(nodes: InjectorTreeNode[], out: InjectorTreeNode[] = []): InjectorTreeNode[] { + for (const node of nodes) { + out.push(node); + flatten(node.children, out); + } + return out; +} + +/** Each node's ancestors in the report, nearest first. */ +function ancestors( + nodes: InjectorTreeNode[], + above: string[] = [], + out = new Map(), +): Map { + for (const node of nodes) { + out.set(node.injector.id, above); + ancestors(node.children, [node.injector.id, ...above], out); + } + return out; +} + +const loose = (text: string) => text.trim().replace(/\s+/g, ' ').toLowerCase(); + +function matches(node: InjectorTreeNode, selector: string): boolean { + const { injector } = node; + if (injector.id === selector || injector.componentId === selector) return true; + if (injector.type === 'environment') return loose(injector.name) === loose(selector); + if (injector.type !== 'element') return false; + if (injector.selector === selector) return true; + const want = selector.replace(/^<|>$/g, '').toLowerCase(); + return ( + injector.name.replace(/^<|>$/g, '').toLowerCase() === want || + injector.component?.toLowerCase() === want || + !!injector.directives?.some((name) => name.toLowerCase() === want) + ); +} + +/** Token names compare as written, then without case. */ +function sameToken(a: string, b: string): boolean { + return a === b || a.toLowerCase() === b.toLowerCase(); +} + +/** + * Walks the lookup and returns each step, or a sentence saying why it can't + * (`{ error }`). `reduced` is true when the page's Angular has no + * `ɵgetInjectorProviders` (before 16.2), so providers are unknown. + */ +export function explainInjection( + page: InjectorPage | undefined, + args: ExplainInjectionArgs, + reduced = false, +): InjectionExplanation | { error: string } { + if (!page || (!page.roots.length && !page.environment.length)) return { error: NO_INJECTORS }; + const selector = args.selector?.trim() ?? ''; + const token = args.token?.trim() ?? ''; + if (!selector || !token) { + return { + error: + 'Pass `selector` (the component or element that injects, or an environment injector name such as Root) and `token` (the service class or InjectionToken name).', + }; + } + if (selector.length > MAX_ARG_CHARS || token.length > MAX_ARG_CHARS) { + return { error: `\`selector\` and \`token\` take at most ${MAX_ARG_CHARS} characters each.` }; + } + const elements = flatten(page.roots); + const environments = flatten(page.environment); + const all = [...elements, ...environments]; + const byId = new Map(all.map((node) => [node.injector.id, node])); + const found = [ + ...elements.filter((node) => matches(node, selector)), + ...environments.filter((node) => matches(node, selector)), + ]; + const start = found[0]; + if (!start) { + const tags = [ + ...new Set(elements.map((node) => node.injector.component ?? node.injector.name)), + ]; + return { + error: `No injector on page ${code(page.pageId)} matches ${code(selector)}. Pass a component class name, a tag, a component or injector id, or an environment injector name. On the page: ${tags + .slice(0, 20) + .map(code) + .join(', ')}.`, + }; + } + const flags = FLAG_NAMES.filter((flag) => args[flag] === true); + const fromElement = start.injector.type === 'element'; + + // The path Angular asks. From 16.2 the page reports it; before, the nesting + // of the report stands in: element ancestors, then the root's environment chain. + let path = start.injector.path?.length ? [...start.injector.path] : []; + let approximate = false; + if (!path.length) { + approximate = fromElement; + const elementUp = fromElement ? (ancestors(page.roots).get(start.injector.id) ?? []) : []; + const envParents = ancestors(page.environment); + const firstEnv = fromElement + ? (environments.find((node) => loose(node.injector.name) === 'root') ?? environments.at(-1)) + : start; + const envChain = firstEnv + ? [firstEnv.injector.id, ...(envParents.get(firstEnv.injector.id) ?? [])] + : []; + path = fromElement + ? [start.injector.id, ...elementUp, ...envChain] + : [start.injector.id, ...(envParents.get(start.injector.id) ?? [])]; + if (path.at(-1) !== NULL_INJECTOR_ID) path.push(NULL_INJECTOR_ID); + } + + // `host`: Angular stops at the host of the component whose template declares the start. + const boundary = fromElement ? start.injector.host : undefined; + // Tokens some injection on the page resolved here: services created on demand, + // such as `providedIn: 'root'`, are not in a provider list. + const resolvedHere = (id: string) => + all.some((node) => + (node.dependencies ?? []).some((dep) => dep.providedBy === id && sameToken(dep.token, token)), + ); + + const steps: InjectionStep[] = []; + let outcome: InjectionExplanation['outcome'] | undefined; + let resolvedBy: string | undefined; + let stopReason = ''; + let previousElement: InjectorTreeNode | undefined; + let asked = 0; + + for (let i = 0; i < path.length; i++) { + const id = path[i]!; + const node = byId.get(id); + const type: InjectionStep['type'] = + id === NULL_INJECTOR_ID ? 'null' : (node?.injector.type ?? 'environment'); + const name = + id === NULL_INJECTOR_ID ? 'Null injector' : (node?.injector.name ?? '(not in the report)'); + const base = { + id, + name, + type, + ...(node?.injector.component ? { component: node.injector.component } : {}), + }; + if (outcome || stopReason) { + steps.push({ + ...base, + status: 'not-asked', + reason: stopReason || 'The lookup already ended.', + }); + continue; + } + if (i === 0 && args.skipSelf) { + steps.push({ + ...base, + status: 'skipped', + reason: '`skipSelf`: Angular starts at the parent injector.', + }); + if (args.self) + stopReason = '`self` with `skipSelf`: nothing past the skipped injector is asked.'; + continue; + } + if (type === 'null') { + outcome = args.optional ? 'null' : 'error'; + steps.push({ + ...base, + status: 'missing', + reason: args.optional + ? 'Every injector was asked; `optional` makes the null injector return null.' + : 'Every injector was asked; the null injector throws NG0201 (NullInjectorError).', + }); + continue; + } + if (type === 'environment' && fromElement && (args.self || args.host)) { + stopReason = `\`${args.self ? 'self' : 'host'}\`: a lookup from an element never asks environment injectors.`; + outcome = args.optional ? 'null' : 'error'; + steps.push({ ...base, status: 'not-asked', reason: stopReason }); + continue; + } + asked++; + const providers = node?.providers ?? []; + const atBoundary = !!args.host && boundary === id; + let status: InjectionStepStatus = 'missing'; + let reason = ''; + let provider: ProviderInfo | undefined; + if (type === 'element') { + // viewProviders are seen from the component's own view: by the component + // itself (the first step) and when the lookup comes up from inside its view. + const fromInside = i === 0 || previousElement?.injector.host === id; + const canSeeView = fromInside && (i > 0 || !!node?.injector.component); + const matching = providers.filter((p) => sameToken(p.token, token)); + const visible = matching.filter((p) => + atBoundary ? p.isViewProvider : canSeeView || !p.isViewProvider, + ); + const isOwnClass = + !!node && + (sameToken(node.injector.component ?? '', token) || + (!atBoundary && !!node.injector.directives?.some((d) => sameToken(d, token)))); + if (visible.length) { + status = 'provides'; + provider = visible[0]; + reason = `Its ${provider!.isViewProvider ? 'viewProviders' : 'providers'} list the token (${provider!.type}).`; + } else if (isOwnClass && i > 0) { + status = 'provides'; + reason = + 'The token is the component or a directive on this element, so the instance itself is injected.'; + } else if (matching.length) { + status = 'hidden'; + reason = atBoundary + ? 'It provides the token in `providers`, but at the `host` boundary only `viewProviders` and the component itself count.' + : 'It provides the token only in `viewProviders`, which projected content and elements outside its view can not see.'; + } else if (reduced && !providers.length) { + status = 'unknown'; + reason = "This Angular version doesn't list element providers."; + } else { + reason = 'Not in its providers.'; + } + previousElement = node; + } else { + const listed = providers.find((p) => sameToken(p.token, token)); + if (listed) { + status = 'provides'; + provider = listed; + reason = `Its providers list the token (${listed.type}).`; + } else if (resolvedHere(id)) { + status = 'provides'; + reason = + "Not in its provider list, but another injection on the page got the token from here (a service created on demand, such as `providedIn: 'root'`)."; + } else if (reduced && !providers.length) { + status = 'unknown'; + reason = "This Angular version doesn't list environment providers."; + } else { + reason = + loose(name) === 'root' + ? "Not in its providers, and nothing on the page got it from here yet. An `@Injectable({ providedIn: 'root' })` class would still be created here on first use; the page can't tell from the token name alone." + : 'Not in its providers.'; + } + } + steps.push({ ...base, status, reason, ...(provider ? { provider } : {}) }); + if (status === 'provides') { + outcome = 'resolved'; + resolvedBy = id; + continue; + } + if (args.self && asked === 1) { + stopReason = '`self`: only the first injector is asked.'; + if (!fromElement) { + // R3Injector with `self` goes straight to the null injector. + const nullIndex = path.indexOf(NULL_INJECTOR_ID); + if (nullIndex > i) { + for (let k = i + 1; k < nullIndex; k++) { + const skipped = byId.get(path[k]!); + steps.push({ + id: path[k]!, + name: skipped?.injector.name ?? '(not in the report)', + type: skipped?.injector.type ?? 'environment', + status: 'not-asked', + reason: stopReason, + }); + } + stopReason = ''; + i = nullIndex - 1; + continue; + } + } + outcome = args.optional ? 'null' : 'error'; + continue; + } + if (atBoundary) { + stopReason = `\`host\`: the lookup stops at the host element of the component that declares ${code(start.injector.component ?? start.injector.name)}.`; + outcome = args.optional ? 'null' : 'error'; + } + } + if (!outcome) + outcome = steps.some((s) => s.status === 'unknown') + ? 'unknown' + : args.optional + ? 'null' + : 'error'; + if (outcome !== 'resolved' && steps.some((s) => s.status === 'unknown')) outcome = 'unknown'; + + const startName = start.injector.component ?? start.injector.name; + const by = resolvedBy ? byId.get(resolvedBy)?.injector : undefined; + const flagText = flags.length ? ` with ${flags.map((flag) => `\`${flag}\``).join(', ')}` : ''; + const summary = + outcome === 'resolved' + ? `${code(token)} resolves${flagText} from ${code(startName)} at ${code(by?.component ?? by?.name ?? resolvedBy ?? '')}.` + : outcome === 'null' + ? `No injector Angular asks${flagText} provides ${code(token)}; \`optional\` makes the injection return null.` + : outcome === 'unknown' + ? `Whether ${code(token)} resolves from ${code(startName)} can't be told: the page's Angular doesn't list providers (16.2 and later do).` + : `No injector Angular asks${flagText} provides ${code(token)}, so injecting it from ${code(startName)} throws NG0201 (NullInjectorError).`; + return { + pageId: page.pageId, + token, + flags, + start: { + id: start.injector.id, + name: start.injector.name, + type: start.injector.type, + ...(start.injector.component ? { component: start.injector.component } : {}), + }, + steps, + outcome, + ...(resolvedBy ? { resolvedBy } : {}), + summary, + ...(approximate ? { approximate } : {}), + ...(found.length > 1 + ? { alsoMatched: found.slice(1, 11).map((node) => node.injector.id) } + : {}), + }; +} + +const STATUS_TEXT: Record = { + provides: 'provides it', + missing: 'not provided', + hidden: 'hidden', + skipped: 'skipped', + 'not-asked': 'not asked', + unknown: 'unknown', +}; + +const cell = (text: string) => text.replace(/\|/g, '\\|').replace(/\s+/g, ' '); + +/** The markdown answer of `pangular:explain-injection`. */ +export function explainInjectionText(result: InjectionExplanation | { error: string }): string { + if ('error' in result) return result.error; + const rows = result.steps.map( + (step, index) => + `| ${index + 1} | ${cell(code(step.name))}${step.component ? ` ${cell(code(step.component))}` : ''} | ${step.type} | ${STATUS_TEXT[step.status]} | ${cell(step.reason)} |`, + ); + const notes = [ + result.approximate + ? "The page's Angular has no `ɵgetInjectorResolutionPath` (16.2 and later), so this path is rebuilt from the nesting of the injector tree: element ancestors as rendered, then the root's environment injectors. Projected content resolves from where it is declared, so its real path can differ." + : '', + result.alsoMatched?.length + ? `The selector matched ${result.alsoMatched.length + 1} injectors; this is the first. Others: ${result.alsoMatched.map(code).join(', ')}.` + : '', + ].filter(Boolean); + return untrusted( + [ + `**${result.summary}**`, + '', + `Lookup of ${code(result.token)} from ${code(result.start.component ?? result.start.name)} (${code(result.start.id)}) on page ${code(result.pageId)}, flags: ${result.flags.length ? result.flags.join(', ') : 'none'}. Read from the injector tree the page reported; nothing was created or injected.`, + '', + '| Step | Injector | Kind | Result | Why |', + '| --- | --- | --- | --- | --- |', + ...rows, + ...(notes.length ? ['', ...notes] : []), + ].join('\n'), + ); +} + +export const EXPLAIN_INJECTION_DESCRIPTION = + "Explain how Angular resolves one token for one component, element or environment injector, the way it does at run time: each injector on the lookup path in order (the element injectors up the declaration tree, then the environment injectors from the route or root injector to the platform, then the null injector), whether it provides the token and why the lookup stops there. Honours `self` (only the first injector), `skipSelf` (start at the parent), `host` (stop at the host element of the component that declares the start; only its `viewProviders` and the component itself count there; never the environment injectors) and `optional` (null instead of NG0201). Notes tokens provided only in `viewProviders` that the lookup can't see. Use it for NG0201 / NullInjectorError: pass the component from pangular:explain-error and the missing token. Read from the injector tree the page reported (pangular:inspect-providers), so nothing is created or injected. A service created on demand (`providedIn: 'root'`) counts as provided once something on the page got it; before that the answer says it can't tell from the name. Before Angular 16.2 the path is rebuilt from the tree's nesting and providers are unknown; the answer says so. Each open tab reports its own tree; `page` picks one and defaults to the most recent."; + +const FLAG_SCHEMA = (text: string) => ({ type: 'boolean', description: text }) as const; + +export const EXPLAIN_INJECTION_SCHEMA = { + type: 'object', + properties: { + selector: { + type: 'string', + description: + 'Where the injection happens: a component or directive class name (CardComponent), a tag (app-card), a component id from the component tree or an error owner (c12), an injector id, or an environment injector name (Root, Route: admin) for a service. At most 500 characters.', + }, + token: { + type: 'string', + description: + 'The token, as the Injectors tab names it: a class name (HttpClient) or an InjectionToken description (API_URL). At most 500 characters.', + }, + self: FLAG_SCHEMA('`inject(T, { self: true })` / `@Self()`: ask only the first injector.'), + skipSelf: FLAG_SCHEMA('`{ skipSelf: true }` / `@SkipSelf()`: start at the parent injector.'), + host: FLAG_SCHEMA( + '`{ host: true }` / `@Host()`: stop at the host element of the declaring component.', + ), + optional: FLAG_SCHEMA('`{ optional: true }` / `@Optional()`: null instead of NG0201.'), + page: { + type: 'string', + description: + 'Page id, when more than one tab reports (see pangular:list-pages). Defaults to the most recent.', + }, + }, + required: ['selector', 'token'], +} as const; + +/** The arguments of the RPC function and the agent tool, checked. */ +export function injectionArgs(raw: unknown): ExplainInjectionArgs & { page?: string } { + const args = raw && typeof raw === 'object' ? (raw as Record) : {}; + const str = (key: string) => (typeof args[key] === 'string' ? (args[key] as string) : undefined); + const page = str('page') ?? str('pageId'); + return { + selector: str('selector'), + token: str('token'), + ...(page ? { page } : {}), + ...Object.fromEntries(FLAG_NAMES.filter((flag) => args[flag] === true).map((f) => [f, true])), + }; +} + +// Typed loosely like `errors-register.ts`, so devframe's own definitions fit. +type AnyRecord = Record; + +export interface InjectionExplainHost { + register(definition: AnyRecord): void; + agent: { registerTool(tool: AnyRecord): void }; + /** The injector tree of a page, or of the most recent page without one; `{ error }` for an unknown page. */ + page(pageId: string | undefined): { page?: InjectorPage; reduced: boolean } | { error: string }; +} + +/** + * The `explain-injection` RPC function (the panel's Explain lookup) and the + * `pangular:explain-injection` agent tool. Both read only. + */ +export function registerInjectionExplain(host: InjectionExplainHost): void { + const run = (raw: unknown) => { + const args = injectionArgs(raw); + const picked = host.page(args.page); + if ('error' in picked) return picked; + return explainInjection(picked.page, args, picked.reduced); + }; + host.register({ + name: 'explain-injection', + type: 'query', + jsonSerializable: true, + handler: (raw: unknown) => run(raw), + }); + host.agent.registerTool({ + id: 'pangular:explain-injection', + description: EXPLAIN_INJECTION_DESCRIPTION, + inputSchema: EXPLAIN_INJECTION_SCHEMA, + handler: async (raw: unknown) => ({ markdown: explainInjectionText(run(raw)) }), + }); +} diff --git a/packages/devtools/src/rpc/injector-report.ts b/packages/devtools/src/rpc/injector-report.ts index db0415e9..aebdfe04 100644 --- a/packages/devtools/src/rpc/injector-report.ts +++ b/packages/devtools/src/rpc/injector-report.ts @@ -32,6 +32,7 @@ const InjectorSchema = v.object({ directives: v.optional(texts(100)), selector: v.optional(clipped(MAX_SELECTOR)), path: v.optional(texts(200)), + host: v.optional(text), }); const ProviderSchema = v.object({ diff --git a/packages/devtools/src/rpc/leaks-register.ts b/packages/devtools/src/rpc/leaks-register.ts new file mode 100644 index 00000000..bd7e94c5 --- /dev/null +++ b/packages/devtools/src/rpc/leaks-register.ts @@ -0,0 +1,186 @@ +import { createSharedState } from 'devframe/utils/shared-state'; +import { + findLeaksText, + leakTrackingRequest, + staleLeakPages, + toLeaksReport, + trackSubscriptionsText, + type LeaksState, +} from './leaks-tools.ts'; +import { PAGE_ARGUMENT, pageArgument } from './pages.ts'; +import { trackPageSessions } from './page-sessions.ts'; +import type { PageTtl } from './page-ttl.ts'; + +type AnyRecord = Record; + +interface Scoped { + rpc: { + sharedState(name: string, options: AnyRecord): Promise; + broadcast(message: { method: string; args: unknown[]; optional?: boolean }): unknown; + }; +} + +export interface LeaksHost { + my: Scoped; + /** devframe's RPC host, to drop a page the moment its connection closes. */ + rpcHost: unknown; + /** Registers an RPC function, skipped when the Components inspector is off. */ + register(definition: AnyRecord): void; + agent: { registerTool(tool: AnyRecord): void }; + /** Whether the connection of the current call owns the page (`rpc/page-owners.ts`). */ + owns(pageId: unknown): pageId is string; + mayForget(pageId: unknown): pageId is string; + ttl: PageTtl; +} + +export interface LeaksRegistration { + /** The pages that report leak data, for `list-pages`. */ + pages(): { pageId: string; reportedAt: number; url?: string; title?: string }[]; + /** Drops pages that stopped reporting; call it from the shared expiry interval. */ + expire(now?: number): void; +} + +/** + * Leak hints on the server, part of the Components inspector: the `leaks` + * shared state, the `push-leaks`, `forget-leaks-page` and + * `request-leak-tracking` RPC functions, and the `find-leaks` and + * `track-subscriptions` agent tools. + */ +export async function registerLeaks(host: LeaksHost): Promise { + const shared = await host.my.rpc.sharedState('leaks', { + sharedState: createSharedState({ + initialValue: { pages: {} }, + enablePatches: true, + }), + }); + const state = () => shared['value']() as LeaksState; + const drop = (pageIds: readonly string[]) => { + const present = pageIds.filter((id) => state().pages[id]); + if (!present.length) return; + shared['mutate']((draft: LeaksState) => { + for (const id of present) delete draft.pages[id]; + }); + }; + const sessions = trackPageSessions(host.rpcHost, drop); + + host.register({ + name: 'push-leaks', + type: 'action', + jsonSerializable: true, + handler: (message: unknown) => { + const report = toLeaksReport(message); + if (!report || !host.owns(report.pageId)) return { known: true }; + sessions.bind(report.pageId); + shared['mutate']((draft: LeaksState) => { + draft.pages[report.pageId] = { ...report, reportedAt: Date.now() }; + }); + return { known: true }; + }, + }); + + host.register({ + name: 'forget-leaks-page', + type: 'action', + jsonSerializable: true, + handler: (pageId: unknown) => { + if (!host.mayForget(pageId)) return; + sessions.unbind(pageId); + drop([pageId]); + }, + }); + + // Shared by the panel's Track subscriptions button and the track-subscriptions agent tool. + const requestTracking = (message: unknown) => { + const request = leakTrackingRequest(message, Object.values(state().pages)); + // No page reports yet: starting now would patch every connected tab. + if (request.on && !request.pageId) return { request, pages: 0 }; + const pages = request.pageId + ? state().pages[request.pageId] + ? 1 + : 0 + : Object.keys(state().pages).length; + if (request.pageId) { + void host.my.rpc.broadcast({ method: 'leak-tracking', args: [request], optional: true }); + } else { + // Off for every page: each page answers only to its own id. + for (const pageId of Object.keys(state().pages)) { + void host.my.rpc.broadcast({ + method: 'leak-tracking', + args: [{ pageId, on: false }], + optional: true, + }); + } + } + return { request, pages }; + }; + + host.register({ + name: 'request-leak-tracking', + type: 'action', + jsonSerializable: true, + handler: (message: unknown) => ({ pages: requestTracking(message).pages }), + }); + + host.agent.registerTool({ + id: 'pangular:find-leaks', + description: + 'Leak hints for the running page, in three parts. **Still retained**: component instances that left the page (destroyed) but are still in memory after at least 2 navigations and 10 seconds, with class, instance id, the route when destroyed, age and navigations since; the overlay holds them only through WeakRef and drops them once a FinalizationRegistry sees them collected. Garbage collection timing is up to the browser, so this is a hint to check retainers in the Chrome Memory panel, not proof of a leak. Detached views (kept on purpose, such as by a RouteReuseStrategy) are listed apart. **Open subscriptions after destroy**: RxJS subscriptions a component made that are still open after it went away, grouped by class, instance and call site, only while subscription tracking is on (pangular:track-subscriptions). **Live effects and subscriptions** per component, from the signal graph Angular keeps (20.1+). Names and routes are masked like other live values. Empty when no page is connected.', + inputSchema: { + type: 'object', + properties: { + page: PAGE_ARGUMENT, + component: { + type: 'string', + description: 'Only components whose class name contains this, any case.', + }, + limit: { type: 'integer', description: 'Rows per table (1-200, default 20).' }, + }, + }, + handler: async (args: AnyRecord) => ({ + markdown: findLeaksText(state(), { + page: pageArgument(args), + component: typeof args?.['component'] === 'string' ? args['component'] : undefined, + limit: args?.['limit'], + }), + }), + }); + + host.agent.registerTool({ + id: 'pangular:track-subscriptions', + description: + 'Start or stop tracking RxJS subscriptions on the running page, the same switch as Track subscriptions in the Components panel. While on, the overlay wraps `Observable.prototype.subscribe` to record which component made each subscription (from the call stack, and the instance through the Angular profiler on 20.0+), so pangular:find-leaks can count open subscriptions per component and flag those still open after their component is destroyed. Turning it off restores `subscribe`. Subscriptions made before tracking started are not seen; the choice survives a reload of the tab. `start` tracks the page `page` names, or the most recent page; `stop` stops that page, or every page without `page`.', + inputSchema: { + type: 'object', + properties: { + action: { type: 'string', enum: ['start', 'stop'] }, + page: PAGE_ARGUMENT, + }, + required: ['action'], + }, + handler: async (args: AnyRecord) => { + const action = args?.['action']; + if (action !== 'start' && action !== 'stop') { + return { markdown: 'Pass `action`: `start` or `stop`.' }; + } + const page = pageArgument(args); + if (page && !state().pages[page]) { + return { + markdown: findLeaksText(state(), { page }), + }; + } + const sent = requestTracking({ on: action === 'start', ...(page ? { pageId: page } : {}) }); + return { markdown: trackSubscriptionsText(sent.request, sent.pages) }; + }, + }); + + return { + pages: () => + Object.values(state().pages).map((page) => ({ + pageId: page.pageId, + reportedAt: page.reportedAt, + url: page.url, + title: page.title, + })), + expire: (now = Date.now()) => drop(staleLeakPages(state(), now, host.ttl)), + }; +} diff --git a/packages/devtools/src/rpc/leaks-tools.ts b/packages/devtools/src/rpc/leaks-tools.ts new file mode 100644 index 00000000..d0ff2c21 --- /dev/null +++ b/packages/devtools/src/rpc/leaks-tools.ts @@ -0,0 +1,406 @@ +import { RETAINED_AFTER_MS, RETAINED_AFTER_NAVIGATIONS } from '../config.ts'; +import { redactMessage, redactUrl } from '../router.ts'; +import { redactText } from '../serialize.ts'; +import { clip } from '../text.ts'; +import { code, untrusted } from './forms-tools.ts'; +import { byRecency, unknownPageText } from './pages.ts'; + +export { RETAINED_AFTER_MS, RETAINED_AFTER_NAVIGATIONS }; + +/** Live components a report lists, those with the most effects and subscriptions first. */ +export const MAX_LEAK_COMPONENTS = 200; +/** Destroyed instances a report lists, oldest first. */ +export const MAX_LEAK_DESTROYED = 100; +/** Open subscriptions after destroy a report lists. */ +export const MAX_LEAK_SUBSCRIPTIONS = 100; +const MAX_NAME = 120; +const MAX_ROUTE = 300; +const MAX_SOURCE = 300; +const MAX_ID = 40; + +/** Whether subscription tracking runs on the page. */ +export type SubscriptionTracking = 'off' | 'on' | 'unavailable'; + +/** One component on the page with its live effects and tracked open subscriptions. */ +export interface LeakComponent { + /** The host element id, the same one the Components tab and `inspect-component` use. */ + id: string; + name: string; + /** Effects Angular's signal graph lists for this component only. */ + effects: number; + /** + * Effects Angular files under the view the host sits in, which components + * side by side in one template share, so they can't be told apart. + */ + sharedEffects?: number; + /** Open subscriptions made by this instance while tracking was on. */ + subscriptions: number; +} + +/** A component instance that left the page and was not garbage collected yet. */ +export interface LeakDestroyed { + id: string; + name: string; + /** The page's path and query when the instance was destroyed, masked. */ + route: string; + /** The page clock when it was destroyed. */ + destroyedAt: number; + /** Navigations on the page since then. */ + navigations: number; + /** + * Angular still holds the view, so it was detached rather than destroyed, + * as a `RouteReuseStrategy` or a portal does on purpose. + */ + detached?: boolean; + /** Subscriptions it made that are still open. */ + subscriptions?: number; +} + +/** A subscription a component made that is still open after the component went away. */ +export interface LeakSubscription { + /** The component class whose code made it, from the call stack. */ + name: string; + /** The instance, when the subscription was made inside its hooks, template or listeners. */ + instanceId?: string; + /** How many open subscriptions share this class, instance and call site. */ + count: number; + /** The first call site in the component, masked. */ + source?: string; + route: string; + openedAt: number; + /** + * `instance-destroyed`: its instance is gone; `no-live-instance`: the class + * has no instance on the page any more, and one was destroyed since it opened. + */ + reason: 'instance-destroyed' | 'no-live-instance'; +} + +/** What a page pushes, in full each time. */ +export interface LeaksReport { + pageId: string; + url: string; + title: string; + /** The page clock when the report was made, to turn its times into ages. */ + at: number; + support: { + /** `WeakRef`, `FinalizationRegistry` and `ng.getComponent` are there. */ + retention: boolean; + /** `ng.ɵgetSignalGraph` is there, so effects can be counted. */ + effects: boolean; + subscriptions: SubscriptionTracking; + /** Subscriptions are tied to instances through Angular's profiler (20.0+), not only to classes. */ + instances?: boolean; + /** Destroyed and detached views can be told apart (Angular 14+). */ + detached?: boolean; + }; + /** Navigations the page saw since the overlay started. */ + navigations: number; + totals: { + components: number; + effects: number; + /** Open subscriptions tied to a component, tracked while tracking was on. */ + subscriptions: number; + /** Destroyed instances the page still tracks (not collected yet). */ + destroyed: number; + /** Destroyed instances the garbage collector freed since the overlay started. */ + collected: number; + /** Destroyed instances the page stopped tracking to stay under its cap. */ + dropped: number; + }; + components: LeakComponent[]; + destroyed: LeakDestroyed[]; + subscriptions: LeakSubscription[]; +} + +export interface LeaksPageView extends LeaksReport { + reportedAt: number; +} + +export interface LeaksState { + pages: Record; +} + +function isRecord(value: unknown): value is Record { + return !!value && typeof value === 'object' && !Array.isArray(value); +} + +const num = (value: unknown, fallback = 0) => + typeof value === 'number' && Number.isFinite(value) ? value : fallback; +const count = (value: unknown) => Math.max(0, Math.floor(num(value))); +const text = (value: unknown, max: number) => + typeof value === 'string' ? clip(redactText(value), max) : ''; +const id = (value: unknown) => (typeof value === 'string' ? clip(value, MAX_ID) : ''); + +function list(value: unknown, map: (item: unknown) => T | null, max: number): T[] { + if (!Array.isArray(value)) return []; + return value + .slice(0, max) + .map(map) + .filter((item): item is T => item !== null); +} + +function toComponent(value: unknown): LeakComponent | null { + if (!isRecord(value) || typeof value['id'] !== 'string') return null; + return { + id: id(value['id']), + name: text(value['name'], MAX_NAME) || '?', + effects: count(value['effects']), + subscriptions: count(value['subscriptions']), + ...(count(value['sharedEffects']) ? { sharedEffects: count(value['sharedEffects']) } : {}), + }; +} + +function toDestroyed(value: unknown): LeakDestroyed | null { + if (!isRecord(value) || typeof value['id'] !== 'string') return null; + const subscriptions = count(value['subscriptions']); + return { + id: id(value['id']), + name: text(value['name'], MAX_NAME) || '?', + route: typeof value['route'] === 'string' ? clip(redactUrl(value['route']), MAX_ROUTE) : '', + destroyedAt: num(value['destroyedAt']), + navigations: count(value['navigations']), + ...(value['detached'] === true ? { detached: true } : {}), + ...(subscriptions ? { subscriptions } : {}), + }; +} + +function toSubscription(value: unknown): LeakSubscription | null { + if (!isRecord(value) || typeof value['name'] !== 'string') return null; + const reason = + value['reason'] === 'instance-destroyed' ? 'instance-destroyed' : 'no-live-instance'; + const instanceId = id(value['instanceId']); + const source = text(value['source'], MAX_SOURCE); + return { + name: text(value['name'], MAX_NAME) || '?', + count: Math.max(1, count(value['count'])), + route: typeof value['route'] === 'string' ? clip(redactUrl(value['route']), MAX_ROUTE) : '', + openedAt: num(value['openedAt']), + reason, + ...(instanceId ? { instanceId } : {}), + ...(source ? { source } : {}), + }; +} + +/** Checks and masks a pushed report again on the server; `null` when it is not one. */ +export function toLeaksReport(message: unknown): LeaksReport | null { + if (!isRecord(message) || typeof message['pageId'] !== 'string' || !message['pageId']) { + return null; + } + if (message['pageId'].length > 64) return null; + const support = isRecord(message['support']) ? message['support'] : {}; + const totals = isRecord(message['totals']) ? message['totals'] : {}; + const tracking = support['subscriptions']; + return { + pageId: message['pageId'], + url: typeof message['url'] === 'string' ? redactUrl(message['url']) : '', + title: typeof message['title'] === 'string' ? redactMessage(message['title']) : '', + at: num(message['at'], Date.now()), + support: { + retention: support['retention'] === true, + effects: support['effects'] === true, + subscriptions: tracking === 'on' || tracking === 'unavailable' ? tracking : 'off', + ...(support['instances'] === true ? { instances: true } : {}), + ...(support['detached'] === true ? { detached: true } : {}), + }, + navigations: count(message['navigations']), + totals: { + components: count(totals['components']), + effects: count(totals['effects']), + subscriptions: count(totals['subscriptions']), + destroyed: count(totals['destroyed']), + collected: count(totals['collected']), + dropped: count(totals['dropped']), + }, + components: list(message['components'], toComponent, MAX_LEAK_COMPONENTS), + destroyed: list(message['destroyed'], toDestroyed, MAX_LEAK_DESTROYED), + subscriptions: list(message['subscriptions'], toSubscription, MAX_LEAK_SUBSCRIPTIONS), + }; +} + +/** The pages that stopped reporting, to drop. */ +export function staleLeakPages( + state: LeaksState, + now: number, + ttl: (pageId: string) => number, +): string[] { + return Object.values(state.pages) + .filter((page) => now - page.reportedAt > ttl(page.pageId)) + .map((page) => page.pageId); +} + +/** How long ago a destroyed instance went, on the server's clock. */ +export function destroyedAge(page: LeaksPageView, item: LeakDestroyed, now = Date.now()): number { + return Math.max(0, now - page.reportedAt + (page.at - item.destroyedAt)); +} + +/** Destroyed, not collected, and outlived enough navigations and time to be worth a look. */ +export function isRetained(page: LeaksPageView, item: LeakDestroyed, now = Date.now()): boolean { + return ( + !item.detached && + item.navigations >= RETAINED_AFTER_NAVIGATIONS && + destroyedAge(page, item, now) >= RETAINED_AFTER_MS + ); +} + +/** Which page a `page` argument names, or `pageId` as it is when the request names one. */ +export function leakTrackingRequest( + message: unknown, + pages: Iterable<{ pageId: string; reportedAt: number }>, +): { pageId?: string; on: boolean } { + const record = isRecord(message) ? message : undefined; + const on = record ? record['on'] !== false : message !== false; + const asked = record?.['pageId']; + if (typeof asked === 'string' && asked.length > 0 && asked.length < 64) { + return { pageId: asked, on }; + } + if (!on) return { on }; + const latest = byRecency(pages)[0]; + return latest ? { pageId: latest.pageId, on } : { on }; +} + +const NO_PAGE = + 'No page reports leak data. Live data needs a page: connect through the MCP endpoint of the server that runs the app, with the app open in a browser and the overlay loaded.'; + +const cell = (value: string) => value.replace(/\|/g, '\\|').replace(/\s+/g, ' '); + +function duration(ms: number): string { + const seconds = Math.max(0, Math.round(ms / 1000)); + if (seconds < 120) return `${seconds}s`; + const minutes = Math.round(seconds / 60); + return minutes < 120 ? `${minutes} min` : `${Math.round(minutes / 60)} h`; +} + +const plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? one : many}`; + +function trackingNote(page: LeaksPageView): string { + if (page.support.subscriptions === 'on') { + return page.support.instances + ? 'Subscription tracking is on.' + : 'Subscription tracking is on; without Angular 20 profiler hooks subscriptions are tied to component classes only.'; + } + if (page.support.subscriptions === 'unavailable') { + return 'Subscription tracking could not start: the page has no RxJS the overlay can load.'; + } + return 'Subscription tracking is off, so subscriptions are not counted. Turn it on with pangular:track-subscriptions or the Track subscriptions button in the Components panel; it wraps `Observable.prototype.subscribe` until it is turned off.'; +} + +/** `find-leaks`: retained instances, open subscriptions after destroy, and live effects and subscriptions per component. */ +export function findLeaksText( + state: LeaksState, + args: { page?: string; component?: string; limit?: unknown } = {}, + now = Date.now(), +): string { + const pages = byRecency(Object.values(state.pages)); + if (args.page && !state.pages[args.page]) { + return unknownPageText(args.page, pages, 'leak data'); + } + const page = args.page ? state.pages[args.page]! : pages[0]; + if (!page) return NO_PAGE; + const limit = Math.min(Math.max(Math.floor(num(args.limit, 20)), 1), MAX_LEAK_COMPONENTS); + const wanted = args.component?.trim().toLowerCase(); + const match = (name: string) => !wanted || name.toLowerCase().includes(wanted); + const out: string[] = []; + if (pages.length > 1 && !args.page) { + out.push( + `Page ${code(page.pageId)}; ${pages.length} pages report leak data, pass \`page\` to pick another.`, + ); + } + if (!page.support.retention) { + out.push( + 'This page cannot track destroyed components: it needs `WeakRef`, `FinalizationRegistry` and the Angular debug API (a development build).', + ); + } + + const destroyed = page.destroyed.filter((item) => match(item.name)); + const retained = destroyed.filter((item) => isRetained(page, item, now)); + const recent = destroyed.filter((item) => !item.detached && !isRetained(page, item, now)); + const detached = destroyed.filter((item) => item.detached); + out.push( + `## Still retained\n\n${page.navigations} navigations on this page so far. ${page.totals.collected} destroyed instances were garbage collected since the overlay started. Garbage collection runs when the browser decides, so an instance listed here is not proof of a leak: it is still in memory after at least ${RETAINED_AFTER_NAVIGATIONS} navigations and ${RETAINED_AFTER_MS / 1000} seconds. Take a heap snapshot in the Chrome DevTools Memory panel, search for the class, and read its retainers to see what holds it.`, + ); + if (retained.length) { + const rows = retained.slice(0, limit).map((item) => { + const subs = item.subscriptions ? String(item.subscriptions) : ''; + return `| ${code(item.name)} | ${code(item.id)} | ${code(item.route || '/')} | ${duration(destroyedAge(page, item, now))} | ${item.navigations} | ${subs} |`; + }); + out.push( + `| Class | Instance | Route when destroyed | Age | Navigations since | Open subscriptions |\n| --- | --- | --- | --- | --- | --- |\n${rows.join('\n')}${retained.length > limit ? `\n\n${retained.length - limit} more; raise \`limit\`.` : ''}`, + ); + } else { + out.push('No destroyed component is still retained after enough navigations.'); + } + if (recent.length) { + out.push( + `${plural(recent.length, 'instance was', 'instances were')} destroyed recently and not collected yet: ${recent + .slice(0, 10) + .map((item) => code(item.name)) + .join(', ')}. Navigate a few times and ask again.`, + ); + } + if (detached.length) { + out.push( + `${plural(detached.length, 'instance is', 'instances are')} off the page but not destroyed (detached views, such as a \`RouteReuseStrategy\` cache): ${detached + .slice(0, 10) + .map((item) => code(item.name)) + .join(', ')}.`, + ); + } + if (page.totals.dropped) { + out.push( + `${page.totals.dropped} older destroyed instances are no longer tracked, to stay under the page's cap.`, + ); + } + + out.push(`## Open subscriptions after destroy\n\n${trackingNote(page)}`); + const subs = page.subscriptions.filter((item) => match(item.name)); + if (subs.length) { + const rows = subs.slice(0, limit).map((item) => { + const reason = + item.reason === 'instance-destroyed' ? 'its instance is destroyed' : 'no instance left'; + return `| ${code(item.name)} | ${item.instanceId ? code(item.instanceId) : ''} | ${item.count} | ${reason} | ${item.source ? cell(code(item.source)) : ''} |`; + }); + out.push( + `These subscriptions are still open although the component that made them is gone. Each one keeps its callback, and what the callback uses, alive until the source completes. Tear them down with \`takeUntilDestroyed()\`, \`DestroyRef.onDestroy\` or the \`async\` pipe.\n\n| Class | Instance | Open | Why flagged | Made at |\n| --- | --- | --- | --- | --- |\n${rows.join('\n')}`, + ); + } else if (page.support.subscriptions === 'on') { + out.push('No subscription is still open after its component went away.'); + } + + const live = page.components + .filter( + (item) => match(item.name) && (item.effects || item.sharedEffects || item.subscriptions), + ) + .slice(0, limit); + const effectsNote = page.support.effects + ? '' + : ' Effects are not counted: the page has no `ng.ɵgetSignalGraph` (Angular 19.1+ development builds).'; + out.push( + `## Live effects and subscriptions\n\n${page.totals.components} components on the page with ${plural(page.totals.effects, 'live effect')} and ${plural(page.totals.subscriptions, 'tracked open subscription')}.${effectsNote}`, + ); + if (live.length) { + const rows = live.map( + (item) => + `| ${code(item.name)} | ${code(item.id)} | ${item.effects}${item.sharedEffects ? ` (+${item.sharedEffects} shared)` : ''} | ${page.support.subscriptions === 'on' ? item.subscriptions : ''} |`, + ); + out.push( + `Pass an instance id to pangular:inspect-component for its details. Angular files a component's effects under the template its host sits in, so effects of components side by side in one template are counted as shared.\n\n| Component | Instance | Effects | Subscriptions |\n| --- | --- | --- | --- |\n${rows.join('\n')}`, + ); + } + return untrusted(out.join('\n\n')); +} + +/** The answer of `track-subscriptions`. */ +export function trackSubscriptionsText( + request: { pageId?: string; on: boolean }, + pages: number, +): string { + if (request.on && !pages) { + return 'No page reports leak data, so there is nothing to track. Open the app with the overlay loaded and try again.'; + } + if (request.on) { + return `Tracking subscriptions on page ${code(request.pageId ?? '?')}. The overlay wraps \`Observable.prototype.subscribe\` and records which component makes each subscription, until tracking is turned off. Subscriptions made before now are not seen, so reload the page or navigate to the screen again, then call pangular:find-leaks.`; + } + return request.pageId + ? `Stopped tracking subscriptions on page ${code(request.pageId)}; \`Observable.prototype.subscribe\` is restored.` + : 'Stopped tracking subscriptions on every page; `Observable.prototype.subscribe` is restored.'; +} diff --git a/packages/devtools/src/types.ts b/packages/devtools/src/types.ts index 58c1a08f..87b78290 100644 --- a/packages/devtools/src/types.ts +++ b/packages/devtools/src/types.ts @@ -312,6 +312,12 @@ export interface InjectorInfo { directives?: string[]; selector?: string; path?: string[]; + /** + * On an element injector: the id of the element injector where a `host` + * lookup from here stops, the host of the component whose template declares + * this element. Missing on a root component. + */ + host?: string; /** Set by the server: one of Angular's own injectors (see `framework-tokens.ts`). */ framework?: boolean; } diff --git a/packages/devtools/vitest.compat.config.ts b/packages/devtools/vitest.compat.config.ts index d46b1b97..9dcdc852 100644 --- a/packages/devtools/vitest.compat.config.ts +++ b/packages/devtools/vitest.compat.config.ts @@ -27,6 +27,8 @@ const pageSide = [ 'http-server', 'injector-tree', 'injector-tree-real', + 'leaks-collector', + 'leaks-real', 'ngrx-collector', 'pipes-collector', 'pipes-runtime', From 888894e13aa4fda2c0edf3bcdb9de1f974ea7d42 Mon Sep 17 00:00:00 2001 From: erKam Date: Tue, 13 Oct 2026 03:46:57 +0000 Subject: [PATCH 2/9] build(extension): rebuild the panel bundle The panel gained the diagnosis, leaks and error explainer views. --- ...=> browser-agent-rpc-BXhoSh1z-DD97nExW.js} | 2 +- .../{index-Drhsb2ad.js => index-BNWPqdBD.js} | 550 ++++++++++++++++-- extension/ui/index.html | 2 +- 3 files changed, 495 insertions(+), 59 deletions(-) rename extension/ui/assets/{browser-agent-rpc-BXhoSh1z-C7rzNywl.js => browser-agent-rpc-BXhoSh1z-DD97nExW.js} (93%) rename extension/ui/assets/{index-Drhsb2ad.js => index-BNWPqdBD.js} (56%) diff --git a/extension/ui/assets/browser-agent-rpc-BXhoSh1z-C7rzNywl.js b/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DD97nExW.js similarity index 93% rename from extension/ui/assets/browser-agent-rpc-BXhoSh1z-C7rzNywl.js rename to extension/ui/assets/browser-agent-rpc-BXhoSh1z-DD97nExW.js index ab1c106d..42015e37 100644 --- a/extension/ui/assets/browser-agent-rpc-BXhoSh1z-C7rzNywl.js +++ b/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DD97nExW.js @@ -1 +1 @@ -import{t as e}from"./index-Drhsb2ad.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge}; \ No newline at end of file +import{t as e}from"./index-BNWPqdBD.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge}; \ No newline at end of file diff --git a/extension/ui/assets/index-Drhsb2ad.js b/extension/ui/assets/index-BNWPqdBD.js similarity index 56% rename from extension/ui/assets/index-Drhsb2ad.js rename to extension/ui/assets/index-BNWPqdBD.js index 178709e4..09e14240 100644 --- a/extension/ui/assets/index-Drhsb2ad.js +++ b/extension/ui/assets/index-BNWPqdBD.js @@ -1,14 +1,14 @@ (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=Object.defineProperty,t=Object.getOwnPropertySymbols,n=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,i=(t,n,r)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[n]=r,a=(e,a)=>{for(var o in a||={})n.call(a,o)&&i(e,o,a[o]);if(t)for(var o of t(a))r.call(a,o)&&i(e,o,a[o]);return e},o=(e,t,n)=>(i(e,typeof t==`symbol`?t:t+``,n),n),s=globalThis;function c(e){let t=s.__Zone_symbol_prefix;return(typeof t==`string`?t:`__zone_symbol__`)+e}function l(){let e=s.performance;function t(t){e&&e.mark&&e.mark(t)}function n(t,n){e&&e.measure&&e.measure(t,n)}t(`Zone`);let r=class e{constructor(e,t){o(this,`_parent`),o(this,`_name`),o(this,`_properties`),o(this,`_zoneDelegate`),this._parent=e,this._name=t?t.name||`unnamed`:``,this._properties=t&&t.properties||{},this._zoneDelegate=new l(this,this._parent&&this._parent._zoneDelegate,t)}static assertZonePatched(){if(s.Promise!==pe.ZoneAwarePromise)throw Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let t=e.current;for(;t.parent;)t=t.parent;return t}static get current(){return he.zone}static get currentTask(){return ge}static __load_patch(r,i,a=!1){if(Object.hasOwn(pe,r)){let e=s[c(`forceDuplicateZoneCheck`)]===!0;if(!a&&e)throw Error(`Already loaded patch: `+r)}else if(!s[`__Zone_disable_`+r]){let a=`Zone:`+r;t(a),pe[r]=i(s,e,me),n(a,a)}}get parent(){return this._parent}get name(){return this._name}get(e){let t=this.getZoneWith(e);if(t)return t._properties[e]}getZoneWith(e){let t=this;for(;t;){if(Object.hasOwn(t._properties,e))return t;t=t._parent}return null}fork(e){if(!e)throw Error(`ZoneSpec required!`);return this._zoneDelegate.fork(this,e)}wrap(e,t){if(typeof e!=`function`)throw Error(`Expecting function got: `+e);let n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}}run(e,t,n,r){he={parent:he,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{he=he.parent}}runGuarded(e,t=null,n,r){he={parent:he,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{he=he.parent}}runTask(e,t,n){if(e.zone!=this)throw Error(`A task can only be run in the zone of creation! (Creation: `+(e.zone||re).name+`; Execution: `+this.name+`)`);let r=e,{type:i,data:{isPeriodic:a=!1,isRefreshable:o=!1}={}}=e;if(e.state===ie&&(i===fe||i===de))return;let s=e.state!=se;s&&r._transitionTo(se,oe);let c=ge;ge=r,he={parent:he,zone:this};try{i==de&&e.data&&!a&&!o&&(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,r,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{let t=e.state;if(t!==ie&&t!==le){if(i==fe||a||o&&t===ae)s&&r._transitionTo(oe,se,ae);else{let e=r._zoneDelegates;this._updateTaskCount(r,-1),s&&r._transitionTo(ie,se,ie),o&&(r._zoneDelegates=e)}}he=he.parent,ge=c}}scheduleTask(e){if(e.zone&&e.zone!==this){let t=this;for(;t;){if(t===e.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${e.zone.name}`);t=t.parent}}e._transitionTo(ae,ie);let t=[];e._zoneDelegates=t,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(le,ae,ie),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===t&&this._updateTaskCount(e,1),e.state==ae&&e._transitionTo(oe,ae),e}scheduleMicroTask(e,t,n,r){return this.scheduleTask(new u(ue,e,t,n,r,void 0))}scheduleMacroTask(e,t,n,r,i){return this.scheduleTask(new u(de,e,t,n,r,i))}scheduleEventTask(e,t,n,r,i){return this.scheduleTask(new u(fe,e,t,n,r,i))}cancelTask(e){if(e.zone!=this)throw Error(`A task can only be cancelled in the zone of creation! (Creation: `+(e.zone||re).name+`; Execution: `+this.name+`)`);if(e.state===oe||e.state===se){e._transitionTo(ce,oe,se);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(le,ce),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(ie,ce),e.runCount=-1,e}}_updateTaskCount(e,t){let n=e._zoneDelegates;t==-1&&(e._zoneDelegates=null);for(let r=0;re.hasTask(n,r),onScheduleTask:(e,t,n,r)=>e.scheduleTask(n,r),onInvokeTask:(e,t,n,r,i,a)=>e.invokeTask(n,r,i,a),onCancelTask:(e,t,n,r)=>e.cancelTask(n,r)};class l{constructor(e,t,n){o(this,`_zone`),o(this,`_taskCounts`,{microTask:0,macroTask:0,eventTask:0}),o(this,`_forkDlgt`),o(this,`_forkZS`),o(this,`_forkCurrZone`),o(this,`_interceptDlgt`),o(this,`_interceptZS`),o(this,`_interceptCurrZone`),o(this,`_invokeDlgt`),o(this,`_invokeZS`),o(this,`_invokeCurrZone`),o(this,`_handleErrorDlgt`),o(this,`_handleErrorZS`),o(this,`_handleErrorCurrZone`),o(this,`_scheduleTaskDlgt`),o(this,`_scheduleTaskZS`),o(this,`_scheduleTaskCurrZone`),o(this,`_invokeTaskDlgt`),o(this,`_invokeTaskZS`),o(this,`_invokeTaskCurrZone`),o(this,`_cancelTaskDlgt`),o(this,`_cancelTaskZS`),o(this,`_cancelTaskCurrZone`),o(this,`_hasTaskDlgt`),o(this,`_hasTaskDlgtOwner`),o(this,`_hasTaskZS`),o(this,`_hasTaskCurrZone`),this._zone=e,this._forkZS=n&&(n&&n.onFork?n:t._forkZS),this._forkDlgt=n&&(n.onFork?t:t._forkDlgt),this._forkCurrZone=n&&(n.onFork?this._zone:t._forkCurrZone),this._interceptZS=n&&(n.onIntercept?n:t._interceptZS),this._interceptDlgt=n&&(n.onIntercept?t:t._interceptDlgt),this._interceptCurrZone=n&&(n.onIntercept?this._zone:t._interceptCurrZone),this._invokeZS=n&&(n.onInvoke?n:t._invokeZS),this._invokeDlgt=n&&(n.onInvoke?t:t._invokeDlgt),this._invokeCurrZone=n&&(n.onInvoke?this._zone:t._invokeCurrZone),this._handleErrorZS=n&&(n.onHandleError?n:t._handleErrorZS),this._handleErrorDlgt=n&&(n.onHandleError?t:t._handleErrorDlgt),this._handleErrorCurrZone=n&&(n.onHandleError?this._zone:t._handleErrorCurrZone),this._scheduleTaskZS=n&&(n.onScheduleTask?n:t._scheduleTaskZS),this._scheduleTaskDlgt=n&&(n.onScheduleTask?t:t._scheduleTaskDlgt),this._scheduleTaskCurrZone=n&&(n.onScheduleTask?this._zone:t._scheduleTaskCurrZone),this._invokeTaskZS=n&&(n.onInvokeTask?n:t._invokeTaskZS),this._invokeTaskDlgt=n&&(n.onInvokeTask?t:t._invokeTaskDlgt),this._invokeTaskCurrZone=n&&(n.onInvokeTask?this._zone:t._invokeTaskCurrZone),this._cancelTaskZS=n&&(n.onCancelTask?n:t._cancelTaskZS),this._cancelTaskDlgt=n&&(n.onCancelTask?t:t._cancelTaskDlgt),this._cancelTaskCurrZone=n&&(n.onCancelTask?this._zone:t._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;let r=n&&n.onHasTask,i=t&&t._hasTaskZS;(r||i)&&(this._hasTaskZS=r?n:a,this._hasTaskDlgt=t,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,n.onScheduleTask||(this._scheduleTaskZS=a,this._scheduleTaskDlgt=t,this._scheduleTaskCurrZone=this._zone),n.onInvokeTask||(this._invokeTaskZS=a,this._invokeTaskDlgt=t,this._invokeTaskCurrZone=this._zone),n.onCancelTask||(this._cancelTaskZS=a,this._cancelTaskDlgt=t,this._cancelTaskCurrZone=this._zone))}get zone(){return this._zone}fork(e,t){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,e,t):new i(e,t)}intercept(e,t,n){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,e,t,n):t}invoke(e,t,n,r,i){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,e,t,n,r,i):t.apply(n,r)}handleError(e,t){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,e,t)}scheduleTask(e,t){let n=t;if(this._scheduleTaskZS)this._hasTaskZS&&n._zoneDelegates.push(this._hasTaskDlgtOwner),n=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,e,t),n||=t;else if(t.scheduleFn)t.scheduleFn(t);else if(t.type==ue)te(t);else throw Error(`Task is missing scheduleFn.`);return n}invokeTask(e,t,n,r){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,e,t,n,r):t.callback.apply(n,r)}cancelTask(e,t){let n;if(this._cancelTaskZS)n=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,e,t);else{if(!t.cancelFn)throw Error(`Task is not cancelable`);n=t.cancelFn(t)}return n}hasTask(e,t){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,e,t)}catch(t){this.handleError(e,t)}}_updateTaskCount(e,t){let n=this._taskCounts,r=n[e],i=n[e]=r+t;if(i<0)throw Error(`More tasks executed then were scheduled.`);if(r==0||i==0){let t={microTask:n.microTask>0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e};this.hasTask(this._zone,t)}}}class u{constructor(e,t,n,r,i,a){if(o(this,`type`),o(this,`source`),o(this,`invoke`),o(this,`callback`),o(this,`data`),o(this,`scheduleFn`),o(this,`cancelFn`),o(this,`_zone`,null),o(this,`runCount`,0),o(this,`_zoneDelegates`,null),o(this,`_state`,`notScheduled`),this.type=e,this.source=t,this.data=r,this.scheduleFn=i,this.cancelFn=a,!n)throw Error(`callback is not defined`);this.callback=n;let c=this;this.invoke=e===fe&&r&&r.useG?u.invokeTask:function(){return u.invokeTask.call(s,c,this,arguments)}}static invokeTask(e,t,n){e||=this,_e++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{try{_e===1&&!s[m]&&ne()}finally{_e--}}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(ie,ae)}_transitionTo(e,t,n){if(this._state===t||this._state===n)this._state=e,e==ie&&(this._zoneDelegates=null);else throw Error(`${this.type} '${this.source}': can not transition to '${e}', expecting state '${t}'${n?` or '`+n+`'`:``}, was '${this._state}'.`)}toString(){return this.data&&this.data.handleId!==void 0?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}let d=c(`setTimeout`),f=c(`Promise`),p=c(`then`),m=c(`enable_native_microtask_draining`),h=[],g=!1,_;function ee(e){!_&&s[f]&&(_=s[f].resolve(0)),_?(_[p]??_.then).call(_,e):s[d](e,0)}function te(e){let t=s[m],n=t&&h.length===0&&!g,r=!t&&_e===0&&h.length===0;(n||r)&&ee(ne),e&&h.push(e)}function ne(){if(!g){g=!0;try{for(;h.length;){let e=h;h=[];for(let t of e)try{t.zone.runTask(t,null,null)}catch(e){me.onUnhandledError(e)}}}finally{if(s[m])g=!1,me.microtaskDrainDone();else try{me.microtaskDrainDone()}finally{g=!1}}}}let re={name:`NO ZONE`},ie=`notScheduled`,ae=`scheduling`,oe=`scheduled`,se=`running`,ce=`canceling`,le=`unknown`,ue=`microTask`,de=`macroTask`,fe=`eventTask`,pe=Object.create(null),me={symbol:c,currentZoneFrame:()=>he,onUnhandledError:ve,microtaskDrainDone:ve,scheduleMicroTask:te,showUncaughtError:()=>!i[c(`ignoreConsoleErrorUncaughtError`)],patchEventTarget:()=>[],patchOnProperties:ve,patchMethod:()=>ve,bindArguments:()=>[],patchThen:()=>ve,patchMacroTask:()=>ve,patchEventPrototype:()=>ve,getGlobalObjects:()=>void 0,ObjectDefineProperty:()=>ve,ObjectGetOwnPropertyDescriptor:()=>void 0,ObjectCreate:()=>void 0,ArraySlice:()=>[],patchClass:()=>ve,wrapWithCurrentZone:()=>ve,filterProperties:()=>[],attachOriginToPatched:()=>ve,_redefineProperty:()=>ve,patchCallbacks:()=>ve,nativeScheduleMicroTask:ee},he={parent:null,zone:new i(null,null)},ge=null,_e=0;function ve(){}return n(`Zone`,`Zone`),i}function u(){let e=globalThis,t=e[c(`forceDuplicateZoneCheck`)]===!0;if(e.Zone&&(t||typeof e.Zone.__symbol__!=`function`))throw Error(`Zone already loaded.`);return e.Zone??=l(),e.Zone}var d=Object.getOwnPropertyDescriptor,f=Object.defineProperty,p=Object.getPrototypeOf,m=Object.create,h=Array.prototype.slice,g=`addEventListener`,_=`removeEventListener`,ee=c(g),te=c(_),ne=`true`,re=`false`,ie=c(``);function ae(e,t){return Zone.current.wrap(e,t)}function oe(e,t,n,r,i){return Zone.current.scheduleMacroTask(e,t,n,r,i)}var se=c,ce=typeof window<`u`,le=ce?window:void 0,ue=ce&&le||globalThis,de=`removeAttribute`;function fe(e,t){for(let n=e.length-1;n>=0;n--)typeof e[n]==`function`&&(e[n]=ae(e[n],t+`_`+n));return e}function pe(e,t){let n=e.constructor.name;for(let r=0;r{let t=function(){return e.apply(this,fe(arguments,n+`.`+i))};return Oe(t,e),t})(a)}}}function me(e){return e?e.writable===!1?!1:typeof e.get!=`function`||e.set!==void 0:!0}var he=typeof WorkerGlobalScope<`u`&&self instanceof WorkerGlobalScope,ge=!(`nw`in ue)&&ue.process!==void 0&&ue.process.toString()===`[object process]`,_e=!ge&&!he&&!!(ce&&le.HTMLElement),ve=ue.process!==void 0&&ue.process.toString()===`[object process]`&&!he&&!!(ce&&le.HTMLElement),ye=Object.create(null),be=se(`enable_beforeunload`),xe=function(e){if(e||=ue.event,!e)return;let t=ye[e.type];t||=ye[e.type]=se(`ON_PROPERTY`+e.type);let n=this||e.target||ue,r=n[t],i;if(_e&&n===le&&e.type===`error`){let t=e;i=r&&r.call(this,t.message,t.filename,t.lineno,t.colno,t.error),i===!0&&e.preventDefault()}else i=r&&r.apply(this,arguments),e.type===`beforeunload`&&ue[be]&&typeof i==`string`?e.returnValue=i:i!=null&&!i&&e.preventDefault();return i};function Se(e,t,n){let r=d(e,t);if(!r&&n&&d(n,t)&&(r={enumerable:!0,configurable:!0}),!r||!r.configurable)return;let i=se(`on`+t+`patched`);if(Object.hasOwn(e,i)&&e[i])return;delete r.writable,delete r.value;let a=r.get,o=r.set,s=t.slice(2),c=ye[s];c||=ye[s]=se(`ON_PROPERTY`+s),r.set=function(t){let n=this;!n&&e===ue&&(n=ue),n&&(typeof n[c]==`function`&&n.removeEventListener(s,xe),o?.call(n,null),n[c]=t,typeof t==`function`&&n.addEventListener(s,xe,!1))},r.get=function(){let n=this;if(!n&&e===ue&&(n=ue),!n)return null;let i=n[c];if(i)return i;if(a){let e=a.call(this);if(e)return r.set.call(this,e),typeof n[de]==`function`&&n.removeAttribute(t),e}return null},f(e,t,r),e[i]=!0}function Ce(e,t,n){if(t)for(let r=0;rfunction(t,r){let a=n(t,r);return a.cbIdx>=0&&typeof r[a.cbIdx]==`function`?oe(a.name,r[a.cbIdx],a,i):e.apply(t,r)})}function Oe(e,t){e[se(`OriginalDelegate`)]=t}function ke(e){return typeof e==`function`}function Ae(e){return typeof e==`number`}var je={useG:!0},Me=Object.create(null),Ne={},Pe=RegExp(`^`+ie+`(\\w+)(true|false)$`),Fe=se(`propagationStopped`),Ie=[`capture`,`once`,`passive`,`signal`];function Le(e,t){let n=(t?t(e):e)+re,r=(t?t(e):e)+ne,i=ie+n,a=ie+r;Me[e]={[re]:i,[ne]:a}}function Re(e,t,n,r){let i=r&&r.add||g,o=r&&r.rm||_,s=r&&r.listeners||`eventListeners`,c=r&&r.rmAll||`removeAllListeners`,l=se(i),u=`.`+i+`:`,d=function(e,t,n){if(e.isRemoved)return;let r=e.callback;typeof r==`object`&&r.handleEvent&&(e.callback=e=>r.handleEvent(e),e.originalDelegate=r);let i;try{e.invoke(e,t,[n])}catch(e){i=e}let a=e.options;if(a&&typeof a==`object`&&a.once){let r=e.originalDelegate?e.originalDelegate:e.callback;t[o].call(t,n.type,r,a)}return i};function f(n,r,i){if(r||=e.event,!r)return;let a=n||r.target||e,o=a[Me[r.type][i?ne:re]];if(o){let e=[];if(o.length===1){let t=d(o[0],a,r);t&&e.push(t)}else{let t=o.slice();for(let n=0;n{throw r})}}}let m=function(e){return f(this,e,!1)},h=function(e){return f(this,e,!0)};function ee(t,n){if(!t)return!1;let r=!0;n&&n.useG!==void 0&&(r=n.useG);let d=n&&n.vh,f=!0;n&&n.chkDup!==void 0&&(f=n.chkDup);let g=!1;n&&n.rt!==void 0&&(g=n.rt);let _=t;for(;_&&!Object.hasOwn(_,i);)_=p(_);if(!_&&t[i]&&(_=t),!_||_[l])return!1;let ee=n&&n.eventNameToString,te={},ae=_[l]=_[i],oe=_[se(o)]=_[o],ce=_[se(s)]=_[s],le=_[se(c)]=_[c],ue;n&&n.prepend&&(ue=_[se(n.prepend)]=_[n.prepend]);function de(e,t){return t?typeof e==`boolean`?{capture:e,passive:!0}:e?(typeof e==`object`&&e.passive!==!1&&(e.passive=!0),e):{passive:!0}:e}let fe=function(e){if(!te.isExisting)return ae.call(te.target,te.eventName,te.capture?h:m,te.options)},pe=function(e){if(!e.isRemoved){let t=Me[e.eventName],n;t&&(n=t[e.capture?ne:re]);let r=n&&e.target[n];if(r){for(let t=0;t_e.zone.cancelTask(_e);t.call(_,`abort`,e,{once:!0}),_e.removeAbortListener=()=>_.removeEventListener(`abort`,e)}if(te.target=null,he&&(he.taskData=null),ae&&(te.options.once=!0),typeof _e.options!=`boolean`&&(_e.options=g),_e.target=l,_e.capture=ie,_e.eventName=u,m&&(_e.originalDelegate=p),c?le.unshift(_e):le.push(_e),s)return l}};return _[i]=we(ae,u,ve,ye,g),ue&&(_.prependListener=we(ue,`.prependListener:`,he,ye,g,!0)),_[o]=function(){let t=this||e,r=arguments[0];n&&n.transferEventName&&(r=n.transferEventName(r));let i=arguments[2],a=i?typeof i==`boolean`||i.capture:!1,o=arguments[1];if(!o)return oe.apply(this,arguments);if(d&&!d(oe,o,t,arguments))return;let s=Me[r],c;s&&(c=s[a?ne:re]);let l=c&&t[c];if(l)for(let e=0;efunction(t,n){t[Fe]=!0,e&&e.apply(t,n)})}function Ve(e,t){t.patchMethod(e,`queueMicrotask`,e=>function(e,t){Zone.current.scheduleMicroTask(`queueMicrotask`,t[0])})}var He=se(`zoneTask`);function Ue(e,t,n,r){let i=null,a=null;t+=r,n+=r;let o={};function s(t){let n=t.data;n.args[0]=function(){return t.invoke.apply(this,arguments)};let r=i.apply(e,n.args);return Ae(r)?n.handleId=r:(n.handle=r,n.isRefreshable=ke(r?.refresh)),t}function c(t){let{handle:n,handleId:r}=t.data;return a.call(e,n??r)}i=Ee(e,t,n=>function(i,a){if(ke(a[0])){let e={isRefreshable:!1,isPeriodic:r===`Interval`,delay:r===`Timeout`||r===`Interval`?a[1]||0:void 0,args:a},n=a[0];a[0]=function(){try{return n.apply(this,arguments)}finally{let{handle:t,handleId:n,isPeriodic:r,isRefreshable:i}=e;!r&&!i&&(n?delete o[n]:t&&(t[He]=null))}};let i=oe(t,a[0],e,s,c);if(!i)return i;let{handleId:l,handle:u,isRefreshable:d,isPeriodic:f}=i.data;if(l)o[l]=i;else if(u&&(u[He]=i,d&&!f)){let e=u.refresh;u.refresh=function(){let{zone:t,state:n}=i;return n===`notScheduled`?(i._state=`scheduled`,t._updateTaskCount(i,1)):n===`running`&&(i._state=`scheduling`),e.call(this)}}return u??l??i}return n.apply(e,a)}),a=Ee(e,n,t=>function(n,r){let i=r[0],a;Ae(i)?(a=o[i],delete o[i]):(a=i?.[He],a?i[He]=null:a=i),a?.type?a.cancelFn&&a.zone.cancelTask(a):t.apply(e,r)})}function We(e,t){let{isBrowser:n,isMix:r}=t.getGlobalObjects();(n||r)&&e.customElements&&`customElements`in e&&t.patchCallbacks(t,e.customElements,`customElements`,`define`,[`connectedCallback`,`disconnectedCallback`,`adoptedCallback`,`attributeChangedCallback`,`formAssociatedCallback`,`formDisabledCallback`,`formResetCallback`,`formStateRestoreCallback`])}function Ge(e,t){if(Zone[t.symbol(`patchEventTarget`)])return;let{eventNames:n,zoneSymbolEventNames:r,TRUE_STR:i,FALSE_STR:a,ZONE_SYMBOL_PREFIX:o}=t.getGlobalObjects();for(let e=0;et.target===e);if(r.length===0)return t;let i=r[0].ignoreProperties;return t.filter(e=>i.indexOf(e)===-1)}function Je(e,t,n,r){e&&Ce(e,qe(e,t,n),r)}function Ye(e){return Object.getOwnPropertyNames(e).filter(e=>e.startsWith(`on`)&&e.length>2).map(e=>e.substring(2))}function Xe(e,t){if(ge&&!ve||Zone[e.symbol(`patchEvents`)])return;let n=t.__Zone_ignore_on_properties,r=[];if(_e){let e=window;r=r.concat([`Document`,`SVGElement`,`Element`,`HTMLElement`,`HTMLBodyElement`,`HTMLMediaElement`,`HTMLFrameSetElement`,`HTMLFrameElement`,`HTMLIFrameElement`,`HTMLMarqueeElement`,`Worker`]),Je(e,Ye(e),n,p(e))}r=r.concat([`XMLHttpRequest`,`XMLHttpRequestEventTarget`,`IDBIndex`,`IDBRequest`,`IDBOpenDBRequest`,`IDBDatabase`,`IDBTransaction`,`IDBCursor`,`WebSocket`]);for(let e=0;e{let t=`clear`;Ue(e,`set`,t,`Timeout`),Ue(e,`set`,t,`Interval`),Ue(e,`set`,t,`Immediate`)}),e.__load_patch(`requestAnimationFrame`,e=>{Ue(e,`request`,`cancel`,`AnimationFrame`),Ue(e,`mozRequest`,`mozCancel`,`AnimationFrame`),Ue(e,`webkitRequest`,`webkitCancel`,`AnimationFrame`)}),e.__load_patch(`blocking`,(e,t)=>{let n=[`alert`,`prompt`,`confirm`];for(let r=0;rfunction(r,a){return t.current.run(n,e,a,i)})}}),e.__load_patch(`EventTarget`,(e,t,n)=>{Ke(e,n),Ge(e,n);let r=e.XMLHttpRequestEventTarget;r&&r.prototype&&n.patchEventTarget(e,n,[r.prototype])}),e.__load_patch(`MutationObserver`,(e,t,n)=>{Te(`MutationObserver`),Te(`WebKitMutationObserver`)}),e.__load_patch(`IntersectionObserver`,(e,t,n)=>{Te(`IntersectionObserver`)}),e.__load_patch(`FileReader`,(e,t,n)=>{Te(`FileReader`)}),e.__load_patch(`on_property`,(e,t,n)=>{Xe(n,e)}),e.__load_patch(`customElements`,(e,t,n)=>{We(e,n)}),e.__load_patch(`XHR`,(e,t)=>{c(e);let n=se(`xhrTask`),r=se(`xhrSync`),i=se(`xhrListener`),a=se(`xhrScheduled`),o=se(`xhrURL`),s=se(`xhrErrorBeforeScheduled`);function c(e){let c=e.XMLHttpRequest;if(!c)return;let l=c.prototype;function u(e){return e[n]}let d=l[ee],f=l[te];if(!d){let t=e.XMLHttpRequestEventTarget;if(t){let e=t.prototype;d=e[ee],f=e[te]}}let p=`readystatechange`,m=`scheduled`;function h(e){let r=e.data,o=r.target;o[a]=!1,o[s]=!1;let c=o[i];d||(d=o[ee],f=o[te]),c&&f.call(o,p,c);let l=o[i]=()=>{if(o.readyState===o.DONE){if(!r.aborted&&o[a]&&e.state===m){let n=o[t.__symbol__(`loadfalse`)];if(o.status!==0&&n&&n.length>0){let i=e.invoke;e.invoke=function(){let n=o[t.__symbol__(`loadfalse`)];for(let t=0;tfunction(e,t){return e[r]=t[2]==0,e[o]=t[1],ne.apply(e,t)}),re=se(`fetchTaskAborting`),ie=se(`fetchTaskScheduling`),ae=Ee(l,`send`,()=>function(e,n){if(t.current[ie]===!0||e[r])return ae.apply(e,n);{let t={target:e,url:e[o],isPeriodic:!1,args:n,aborted:!1},r=oe(`XMLHttpRequest.send`,g,t,h,_);e&&e[s]===!0&&!t.aborted&&r.state===m&&r.invoke()}}),ce=Ee(l,`abort`,()=>function(e,n){let r=u(e);if(r&&typeof r.type==`string`){if(r.cancelFn==null||r.data&&r.data.aborted)return;r.zone.cancelTask(r)}else if(t.current[re]===!0)return ce.apply(e,n)})}}),e.__load_patch(`geolocation`,e=>{e.navigator&&e.navigator.geolocation&&pe(e.navigator.geolocation,[`getCurrentPosition`,`watchPosition`])}),e.__load_patch(`PromiseRejectionEvent`,(e,t)=>{function n(t){return function(n){ze(e,t).forEach(r=>{let i=e.PromiseRejectionEvent;if(i){let e=new i(t,{promise:n.promise,reason:n.rejection});r.invoke(e)}})}}e.PromiseRejectionEvent&&(t[se(`unhandledPromiseRejectionHandler`)]=n(`unhandledrejection`),t[se(`rejectionHandledHandler`)]=n(`rejectionhandled`))}),e.__load_patch(`queueMicrotask`,(e,t,n)=>{Ve(e,n)})}function Qe(e){e.__load_patch(`ZoneAwarePromise`,(e,t,n)=>{let r=Object.getOwnPropertyDescriptor,i=Object.defineProperty;function a(e){return e&&e.toString===Object.prototype.toString?(e.constructor&&e.constructor.name||``)+`: `+JSON.stringify(e):e?e.toString():Object.prototype.toString.call(e)}let o=n.symbol,s=[],c=e[o(`DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION`)]!==!1,l=o(`Promise`),u=o(`then`);n.onUnhandledError=e=>{if(n.showUncaughtError()){let t=e&&e.rejection;t&&e.zone&&e.task?console.error(`Unhandled Promise rejection:`,t instanceof Error?t.message:t,`; Zone:`,e.zone.name,`; Task:`,e.task&&e.task.source,`; Value:`,t,t instanceof Error?t.stack:void 0):console.error(e)}},n.microtaskDrainDone=()=>{for(;s.length;){let e=s.shift();try{e.zone.runGuarded(()=>{throw e.throwOriginal?e.rejection:e})}catch(e){f(e)}}};let d=o(`unhandledPromiseRejectionHandler`);function f(e){n.onUnhandledError(e);try{let n=t[d];typeof n==`function`&&n.call(this,e)}catch{}}function p(e){return e&&typeof e.then==`function`}function m(e){return e}function h(e){return fe.reject(e)}let g=o(`state`),_=o(`value`),ee=o(`finally`),te=o(`parentPromiseValue`),ne=o(`parentPromiseState`);function re(e,t){return n=>{try{oe(e,t,n)}catch(t){oe(e,!1,t)}}}let ie=function(){let e=!1;return function(t){return function(){e||(e=!0,t.apply(null,arguments))}}},ae=o(`currentTaskTrace`);function oe(e,r,o){let l=ie();if(e===o)throw TypeError(`Promise resolved with itself`);if(e[g]===null){let u=null;try{(typeof o==`object`||typeof o==`function`)&&(u=o&&o.then)}catch(t){return l(()=>{oe(e,!1,t)})(),e}if(r!==!1&&o instanceof fe&&Object.hasOwn(o,g)&&Object.hasOwn(o,_)&&o[g]!==null)ce(o),oe(e,o[g],o[_]);else if(r!==!1&&typeof u==`function`)try{u.call(o,l(re(e,r)),l(re(e,!1)))}catch(t){l(()=>{oe(e,!1,t)})()}else{e[g]=r;let l=e[_];if(e[_]=o,e[ee]===ee&&r===!0&&(e[g]=e[ne],e[_]=e[te]),r===!1&&o instanceof Error){let e=t.currentTask&&t.currentTask.data&&t.currentTask.data.__creationTrace__;e&&i(o,ae,{configurable:!0,enumerable:!1,writable:!0,value:e})}for(let t=0;t{try{let r=e[_],i=!!n&&ee===n[ee];i&&(n[te]=r,n[ne]=a),oe(n,!0,t.run(o,void 0,i&&o!==h&&o!==m?[]:[r]))}catch(e){oe(n,!1,e)}},n)}let ue=function(){},de=e.AggregateError;class fe{static toString(){return`function ZoneAwarePromise() { [native code] }`}static resolve(e){return e instanceof fe?e:oe(new this(null),!0,e)}static reject(e){return oe(new this(null),!1,e)}static withResolvers(){let e={};return e.promise=new fe((t,n)=>{e.resolve=t,e.reject=n}),e}static any(e){if(!e||typeof e[Symbol.iterator]!=`function`)return Promise.reject(new de([],`All promises were rejected`));let t=[],n=0;try{for(let r of e)n++,t.push(fe.resolve(r))}catch{return Promise.reject(new de([],`All promises were rejected`))}if(n===0)return Promise.reject(new de([],`All promises were rejected`));let r=!1,i=[];return new fe((e,a)=>{for(let o=0;o{r||(r=!0,e(t))},e=>{i.push(e),n--,n===0&&(r=!0,a(new de(i,`All promises were rejected`)))})})}static race(e){let t,n,r=new this((e,r)=>{t=e,n=r});function i(e){t(e)}function a(e){n(e)}for(let t of e)p(t)||(t=this.resolve(t)),t.then(i,a);return r}static all(e){return fe.allWithCallback(e)}static allSettled(e){return(this&&this.prototype instanceof fe?this:fe).allWithCallback(e,{thenCallback:e=>({status:`fulfilled`,value:e}),errorCallback:e=>({status:`rejected`,reason:e})})}static allWithCallback(e,t){let n,r,i=new this((e,t)=>{n=e,r=t}),a=2,o=0,s=[];for(let i of e){p(i)||(i=this.resolve(i));let e=o;try{i.then(r=>{s[e]=t?t.thenCallback(r):r,a--,a===0&&n(s)},i=>{t?(s[e]=t.errorCallback(i),a--,a===0&&n(s)):r(i)})}catch(e){r(e)}a++,o++}return a-=2,a===0&&n(s),i}constructor(e){let t=this;if(!(t instanceof fe))throw Error(`Must be an instanceof Promise.`);t[g]=null,t[_]=[];try{let n=ie();e&&e(n(re(t,!0)),n(re(t,!1)))}catch(e){oe(t,!1,e)}}get[Symbol.toStringTag](){return`Promise`}get[Symbol.species](){return fe}then(e,n){let r=this.constructor?.[Symbol.species];(!r||typeof r!=`function`)&&(r=this.constructor||fe);let i=new r(ue),a=t.current;return this[g]==null?this[_].push(a,i,e,n):le(this,a,i,e,n),i}catch(e){return this.then(null,e)}finally(e){let n=this.constructor?.[Symbol.species];(!n||typeof n!=`function`)&&(n=fe);let r=new n(ue);r[ee]=ee;let i=t.current;return this[g]==null?this[_].push(i,r,e,e):le(this,i,r,e,e),r}}fe.resolve=fe.resolve,fe.reject=fe.reject,fe.race=fe.race,fe.all=fe.all;let pe=e[l]=e.Promise;e.Promise=fe;let me=o(`thenPatched`);function he(e){let t=e.prototype,n=r(t,`then`);if(n&&(n.writable===!1||!n.configurable))return;let i=t.then;t[u]=i,e.prototype.then=function(e,t){return new fe((e,t)=>{i.call(this,e,t)}).then(e,t)},e[me]=!0}n.patchThen=he;function ge(e){return function(t,n){let r=e.apply(t,n);if(r instanceof fe)return r;let i=r.constructor;return i[me]||he(i),r}}if(pe){he(pe);let t=pe.try;t&&typeof t==`function`&&(fe.try=t),Ee(e,`fetch`,e=>ge(e))}return Promise[t.__symbol__(`uncaughtPromiseErrors`)]=s,fe})}function $e(e){e.__load_patch(`toString`,e=>{let t=Function.prototype.toString,n=se(`OriginalDelegate`),r=se(`Promise`),i=se(`Error`),a=function(){if(typeof this==`function`){let a=this[n];if(a)return typeof a==`function`?t.call(a):Object.prototype.toString.call(a);if(this===Promise){let n=e[r];if(n)return t.call(n)}if(this===Error){let n=e[i];if(n)return t.call(n)}}return t.call(this)};a[n]=t,Function.prototype.toString=a;let o=Object.prototype.toString;Object.prototype.toString=function(){return typeof Promise==`function`&&this instanceof Promise?`[object Promise]`:o.call(this)}})}function et(e,t,n,r,i){let a=Zone.__symbol__(r);if(t[a])return;let o=t[a]=t[r];t[r]=function(a,s,c){return s&&s.prototype&&i.forEach(function(t){let i=`${n}.${r}::`+t,a=s.prototype;try{if(Object.hasOwn(a,t)){let n=e.ObjectGetOwnPropertyDescriptor(a,t);n&&n.value?(n.value=e.wrapWithCurrentZone(n.value,i),e._redefineProperty(s.prototype,t,n)):a[t]&&(a[t]=e.wrapWithCurrentZone(a[t],i))}else a[t]&&(a[t]=e.wrapWithCurrentZone(a[t],i))}catch{}}),o.call(t,a,s,c)},e.attachOriginToPatched(t[r],o)}function tt(e){e.__load_patch(`util`,(e,t,n)=>{let r=Ye(e);n.patchOnProperties=Ce,n.patchMethod=Ee,n.bindArguments=fe,n.patchMacroTask=De;let i=t.__symbol__(`BLACK_LISTED_EVENTS`),a=t.__symbol__(`UNPATCHED_EVENTS`);e[a]&&(e[i]=e[a]),e[i]&&(t[i]=t[a]=e[i]),n.patchEventPrototype=Be,n.patchEventTarget=Re,n.ObjectDefineProperty=f,n.ObjectGetOwnPropertyDescriptor=d,n.ObjectCreate=m,n.ArraySlice=h,n.patchClass=Te,n.wrapWithCurrentZone=ae,n.filterProperties=qe,n.attachOriginToPatched=Oe,n._redefineProperty=Object.defineProperty,n.patchCallbacks=et,n.getGlobalObjects=()=>({globalSources:Ne,zoneSymbolEventNames:Me,eventNames:r,isBrowser:_e,isMix:ve,isNode:ge,TRUE_STR:ne,FALSE_STR:re,ZONE_SYMBOL_PREFIX:ie,ADD_EVENT_LISTENER_STR:g,REMOVE_EVENT_LISTENER_STR:_})})}function nt(e){Qe(e),$e(e),tt(e)}var rt=u();nt(rt),Ze(rt);var it=(function(e){return e[e.NONE=0]=`NONE`,e[e.HTML=1]=`HTML`,e[e.STYLE=2]=`STYLE`,e[e.SCRIPT=3]=`SCRIPT`,e[e.URL=4]=`URL`,e[e.RESOURCE_URL=5]=`RESOURCE_URL`,e[e.ATTRIBUTE_NO_BINDING=6]=`ATTRIBUTE_NO_BINDING`,e})(it||{}),at=(function(e){return e[e.None=0]=`None`,e[e.Const=1]=`Const`,e})(at||{}),ot=class{modifiers;constructor(e=at.None){this.modifiers=e}hasModifier(e){return(this.modifiers&e)!==0}},st=(function(e){return e[e.Dynamic=0]=`Dynamic`,e[e.Bool=1]=`Bool`,e[e.String=2]=`String`,e[e.Int=3]=`Int`,e[e.Number=4]=`Number`,e[e.Function=5]=`Function`,e[e.Inferred=6]=`Inferred`,e[e.None=7]=`None`,e})(st||{}),ct=class extends ot{name;constructor(e,t){super(t),this.name=e}visitType(e,t){return e.visitBuiltinType(this,t)}};st.Dynamic;var lt=new ct(st.Inferred);st.Bool,st.Int,st.Number,st.String,st.Function,st.None;var v=(function(e){return e[e.Equals=0]=`Equals`,e[e.NotEquals=1]=`NotEquals`,e[e.Assign=2]=`Assign`,e[e.Identical=3]=`Identical`,e[e.NotIdentical=4]=`NotIdentical`,e[e.Minus=5]=`Minus`,e[e.Plus=6]=`Plus`,e[e.Divide=7]=`Divide`,e[e.Multiply=8]=`Multiply`,e[e.Modulo=9]=`Modulo`,e[e.And=10]=`And`,e[e.Or=11]=`Or`,e[e.BitwiseOr=12]=`BitwiseOr`,e[e.BitwiseAnd=13]=`BitwiseAnd`,e[e.Lower=14]=`Lower`,e[e.LowerEquals=15]=`LowerEquals`,e[e.Bigger=16]=`Bigger`,e[e.BiggerEquals=17]=`BiggerEquals`,e[e.NullishCoalesce=18]=`NullishCoalesce`,e[e.Exponentiation=19]=`Exponentiation`,e[e.In=20]=`In`,e[e.InstanceOf=21]=`InstanceOf`,e[e.AdditionAssignment=22]=`AdditionAssignment`,e[e.SubtractionAssignment=23]=`SubtractionAssignment`,e[e.MultiplicationAssignment=24]=`MultiplicationAssignment`,e[e.DivisionAssignment=25]=`DivisionAssignment`,e[e.RemainderAssignment=26]=`RemainderAssignment`,e[e.ExponentiationAssignment=27]=`ExponentiationAssignment`,e[e.AndAssignment=28]=`AndAssignment`,e[e.OrAssignment=29]=`OrAssignment`,e[e.NullishCoalesceAssignment=30]=`NullishCoalesceAssignment`,e})(v||{});function ut(e,t){return e==null||t==null?e==t:e.isEquivalent(t)}function dt(e,t,n){let r=e.length;if(r!==t.length)return!1;for(let i=0;ie.isEquivalent(t))}var pt=class{leadingComments;type;sourceSpan;constructor(e,t,n){this.leadingComments=n,this.type=e||null,this.sourceSpan=t||null}prop(e,t){return new Ct(this,e,null,t)}key(e,t,n){return new wt(this,e,t,n)}callFn(e,t,n,r){return new gt(this,e,null,t,n,r)}instantiate(e,t,n,r){return new _t(this,e,t,n)}conditional(e,t=null,n,r){return new xt(this,e,t,null,n)}equals(e,t){return new St(v.Equals,this,e,null,t)}notEquals(e,t){return new St(v.NotEquals,this,e,null,t)}identical(e,t){return new St(v.Identical,this,e,null,t)}notIdentical(e,t){return new St(v.NotIdentical,this,e,null,t)}minus(e,t){return new St(v.Minus,this,e,null,t)}plus(e,t){return new St(v.Plus,this,e,null,t)}divide(e,t){return new St(v.Divide,this,e,null,t)}multiply(e,t){return new St(v.Multiply,this,e,null,t)}modulo(e,t){return new St(v.Modulo,this,e,null,t)}power(e,t){return new St(v.Exponentiation,this,e,null,t)}and(e,t){return new St(v.And,this,e,null,t)}bitwiseOr(e,t){return new St(v.BitwiseOr,this,e,null,t)}bitwiseAnd(e,t){return new St(v.BitwiseAnd,this,e,null,t)}or(e,t){return new St(v.Or,this,e,null,t)}lower(e,t){return new St(v.Lower,this,e,null,t)}lowerEquals(e,t){return new St(v.LowerEquals,this,e,null,t)}bigger(e,t){return new St(v.Bigger,this,e,null,t)}biggerEquals(e,t){return new St(v.BiggerEquals,this,e,null,t)}isBlank(e){return this.equals(kt,e)}nullishCoalesce(e,t){return new St(v.NullishCoalesce,this,e,null,t)}toStmt(e){return new Mt(this,null,e)}},mt=class e extends pt{name;constructor(e,t,n,r){super(t,n,r),this.name=e}isEquivalent(t){return t instanceof e&&this.name===t.name}isConstant(){return!1}visitExpression(e,t){return e.visitReadVarExpr(this,t)}clone(){return new e(this.name,this.type,this.sourceSpan)}set(e){return new St(v.Assign,this,e,null,this.sourceSpan)}},ht=class e extends pt{expr;constructor(e,t,n,r){super(t,n,r),this.expr=e}visitExpression(e,t){return e.visitTypeofExpr(this,t)}isEquivalent(t){return t instanceof e&&t.expr.isEquivalent(this.expr)}isConstant(){return this.expr.isConstant()}clone(){return new e(this.expr.clone())}},gt=class e extends pt{fn;args;pure;isOptional;constructor(e,t,n,r,i=!1,a,o=!1){super(n,r,a),this.fn=e,this.args=t,this.pure=i,this.isOptional=o}get receiver(){return this.fn}isEquivalent(t){return t instanceof e&&this.fn.isEquivalent(t.fn)&&ft(this.args,t.args)&&this.pure===t.pure}isConstant(){return!1}visitExpression(e,t){return e.visitInvokeFunctionExpr(this,t)}clone(){return new e(this.fn.clone(),this.args.map(e=>e.clone()),this.type,this.sourceSpan,this.pure,[],this.isOptional)}},_t=class e extends pt{classExpr;args;constructor(e,t,n,r,i){super(n,r,i),this.classExpr=e,this.args=t}isEquivalent(t){return t instanceof e&&this.classExpr.isEquivalent(t.classExpr)&&ft(this.args,t.args)}isConstant(){return!1}visitExpression(e,t){return e.visitInstantiateExpr(this,t)}clone(){return new e(this.classExpr.clone(),this.args.map(e=>e.clone()),this.type,this.sourceSpan)}},vt=class e extends pt{body;flags;constructor(e,t,n,r){super(null,n,r),this.body=e,this.flags=t}isEquivalent(t){return t instanceof e&&this.body===t.body&&this.flags===t.flags}isConstant(){return!0}visitExpression(e,t){return e.visitRegularExpressionLiteral(this,t)}clone(){return new e(this.body,this.flags,this.sourceSpan)}},yt=class e extends pt{value;constructor(e,t,n,r){super(t,n,r),this.value=e}isEquivalent(t){return t instanceof e&&this.value===t.value}isConstant(){return!0}visitExpression(e,t){return e.visitLiteralExpr(this,t)}clone(){return new e(this.value,this.type,this.sourceSpan)}},bt=class e extends pt{value;typeParams;constructor(e,t,n=null,r,i){super(t,r,i),this.value=e,this.typeParams=n}isEquivalent(t){return t instanceof e&&this.value.name===t.value.name&&this.value.moduleName===t.value.moduleName}isConstant(){return!1}visitExpression(e,t){return e.visitExternalExpr(this,t)}clone(){return new e(this.value,this.type,this.typeParams,this.sourceSpan)}},xt=class e extends pt{condition;falseCase;trueCase;constructor(e,t,n=null,r,i,a){super(r||t.type,i,a),this.condition=e,this.falseCase=n,this.trueCase=t}isEquivalent(t){return t instanceof e&&this.condition.isEquivalent(t.condition)&&this.trueCase.isEquivalent(t.trueCase)&&ut(this.falseCase,t.falseCase)}isConstant(){return!1}visitExpression(e,t){return e.visitConditionalExpr(this,t)}clone(){return new e(this.condition.clone(),this.trueCase.clone(),this.falseCase?.clone(),this.type,this.sourceSpan)}},St=class e extends pt{operator;rhs;lhs;constructor(e,t,n,r,i,a){super(r||t.type,i,a),this.operator=e,this.rhs=n,this.lhs=t}isEquivalent(t){return t instanceof e&&this.operator===t.operator&&this.lhs.isEquivalent(t.lhs)&&this.rhs.isEquivalent(t.rhs)}isConstant(){return!1}visitExpression(e,t){return e.visitBinaryOperatorExpr(this,t)}clone(){return new e(this.operator,this.lhs.clone(),this.rhs.clone(),this.type,this.sourceSpan)}isAssignment(){let e=this.operator;return e===v.Assign||e===v.AdditionAssignment||e===v.SubtractionAssignment||e===v.MultiplicationAssignment||e===v.DivisionAssignment||e===v.RemainderAssignment||e===v.ExponentiationAssignment||e===v.AndAssignment||e===v.OrAssignment||e===v.NullishCoalesceAssignment}},Ct=class e extends pt{receiver;name;isOptional;constructor(e,t,n,r,i,a=!1){super(n,r,i),this.receiver=e,this.name=t,this.isOptional=a}get index(){return this.name}isEquivalent(t){return t instanceof e&&this.receiver.isEquivalent(t.receiver)&&this.name===t.name&&this.isOptional===t.isOptional}isConstant(){return!1}visitExpression(e,t){return e.visitReadPropExpr(this,t)}set(e){return new St(v.Assign,this.receiver.prop(this.name),e,null,this.sourceSpan)}clone(){return new e(this.receiver.clone(),this.name,this.type,this.sourceSpan,[],this.isOptional)}},wt=class e extends pt{receiver;index;isOptional;constructor(e,t,n,r,i,a=!1){super(n,r,i),this.receiver=e,this.index=t,this.isOptional=a}isEquivalent(t){return t instanceof e&&this.receiver.isEquivalent(t.receiver)&&this.index.isEquivalent(t.index)&&this.isOptional===t.isOptional}isConstant(){return!1}visitExpression(e,t){return e.visitReadKeyExpr(this,t)}set(e){return new St(v.Assign,this.receiver.key(this.index),e,null,this.sourceSpan)}clone(){return new e(this.receiver.clone(),this.index.clone(),this.type,this.sourceSpan,[],this.isOptional)}},Tt=class e extends pt{entries;constructor(e,t,n,r){super(t,n,r),this.entries=e}isConstant(){return this.entries.every(e=>e.isConstant())}isEquivalent(t){return t instanceof e&&ft(this.entries,t.entries)}visitExpression(e,t){return e.visitLiteralArrayExpr(this,t)}clone(){return new e(this.entries.map(e=>e.clone()),this.type,this.sourceSpan)}},Et=class e{expression;constructor(e){this.expression=e}isEquivalent(t){return t instanceof e&&this.expression.isEquivalent(t.expression)}clone(){return new e(this.expression.clone())}isConstant(){return this.expression.isConstant()}},Dt=class e extends pt{entries;valueType=null;constructor(e,t,n,r){super(t,n,r),this.entries=e,t&&(this.valueType=t.valueType)}isEquivalent(t){return t instanceof e&&ft(this.entries,t.entries)}isConstant(){return this.entries.every(e=>e.isConstant())}visitExpression(e,t){return e.visitLiteralMapExpr(this,t)}clone(){let t=this.entries.map(e=>e.clone());return new e(t,this.type,this.sourceSpan)}},Ot=class e extends pt{expression;constructor(e,t,n){super(null,t,n),this.expression=e}isEquivalent(t){return t instanceof e&&this.expression.isEquivalent(t.expression)}isConstant(){return this.expression.isConstant()}visitExpression(e,t){return e.visitSpreadElementExpr(this,t)}clone(){return new e(this.expression.clone(),this.sourceSpan)}},kt=new yt(null,lt,null),At=(function(e){return e[e.None=0]=`None`,e[e.Final=1]=`Final`,e[e.Private=2]=`Private`,e[e.Exported=4]=`Exported`,e[e.Static=8]=`Static`,e})(At||{}),jt=class{modifiers;sourceSpan;leadingComments;constructor(e=At.None,t=null,n){this.modifiers=e,this.sourceSpan=t,this.leadingComments=n}hasModifier(e){return(this.modifiers&e)!==0}addLeadingComment(e){this.leadingComments=this.leadingComments??[],this.leadingComments.push(e)}},Mt=class e extends jt{expr;constructor(e,t,n){super(At.None,t,n),this.expr=e}isEquivalent(t){return t instanceof e&&this.expr.isEquivalent(t.expr)}visitStatement(e,t){return e.visitExpressionStmt(this,t)}};(class e{static INSTANCE=new e;keyOf(e){if(e instanceof yt&&typeof e.value==`string`)return`"${e.value}"`;if(e instanceof yt)return String(e.value);if(e instanceof vt)return`/${e.body}/${e.flags??``}`;if(e instanceof Tt){let t=[];for(let n of e.entries)t.push(this.keyOf(n));return`[${t.join(`,`)}]`}if(e instanceof Dt){let t=[];for(let n of e.entries)if(n instanceof Et)t.push(`...`+this.keyOf(n.expression));else{let e=n.key;n.quoted&&(e=`"${e}"`),t.push(e+`:`+this.keyOf(n.value))}return`{${t.join(`,`)}}`}if(e instanceof bt)return`import("${e.value.moduleName}", ${e.value.name})`;if(e instanceof mt)return`read(${e.name})`;if(e instanceof ht)return`typeof(${this.keyOf(e.expr)})`;if(e instanceof Ot)return`...${this.keyOf(e.expression)}`;throw Error(`${this.constructor.name} does not handle expressions of type ${e.constructor.name}`)}});var y=`@angular/core`,b=(()=>{class e{static core={name:null,moduleName:y};static namespaceHTML={name:`ɵɵnamespaceHTML`,moduleName:y};static namespaceMathML={name:`ɵɵnamespaceMathML`,moduleName:y};static namespaceSVG={name:`ɵɵnamespaceSVG`,moduleName:y};static element={name:`ɵɵelement`,moduleName:y};static elementStart={name:`ɵɵelementStart`,moduleName:y};static elementEnd={name:`ɵɵelementEnd`,moduleName:y};static foreignComponent={name:`ɵɵforeignComponent`,moduleName:y};static foreignContent={name:`ɵɵforeignContent`,moduleName:y};static foreignContentFn={name:`ɵɵforeignContentFn`,moduleName:y};static domElement={name:`ɵɵdomElement`,moduleName:y};static domElementStart={name:`ɵɵdomElementStart`,moduleName:y};static domElementEnd={name:`ɵɵdomElementEnd`,moduleName:y};static domElementContainer={name:`ɵɵdomElementContainer`,moduleName:y};static domElementContainerStart={name:`ɵɵdomElementContainerStart`,moduleName:y};static domElementContainerEnd={name:`ɵɵdomElementContainerEnd`,moduleName:y};static domTemplate={name:`ɵɵdomTemplate`,moduleName:y};static domListener={name:`ɵɵdomListener`,moduleName:y};static advance={name:`ɵɵadvance`,moduleName:y};static syntheticHostProperty={name:`ɵɵsyntheticHostProperty`,moduleName:y};static syntheticHostListener={name:`ɵɵsyntheticHostListener`,moduleName:y};static attribute={name:`ɵɵattribute`,moduleName:y};static classProp={name:`ɵɵclassProp`,moduleName:y};static elementContainerStart={name:`ɵɵelementContainerStart`,moduleName:y};static elementContainerEnd={name:`ɵɵelementContainerEnd`,moduleName:y};static elementContainer={name:`ɵɵelementContainer`,moduleName:y};static styleMap={name:`ɵɵstyleMap`,moduleName:y};static classMap={name:`ɵɵclassMap`,moduleName:y};static styleProp={name:`ɵɵstyleProp`,moduleName:y};static interpolate={name:`ɵɵinterpolate`,moduleName:y};static interpolate1={name:`ɵɵinterpolate1`,moduleName:y};static interpolate2={name:`ɵɵinterpolate2`,moduleName:y};static interpolate3={name:`ɵɵinterpolate3`,moduleName:y};static interpolate4={name:`ɵɵinterpolate4`,moduleName:y};static interpolate5={name:`ɵɵinterpolate5`,moduleName:y};static interpolate6={name:`ɵɵinterpolate6`,moduleName:y};static interpolate7={name:`ɵɵinterpolate7`,moduleName:y};static interpolate8={name:`ɵɵinterpolate8`,moduleName:y};static interpolateV={name:`ɵɵinterpolateV`,moduleName:y};static nextContext={name:`ɵɵnextContext`,moduleName:y};static resetView={name:`ɵɵresetView`,moduleName:y};static templateCreate={name:`ɵɵtemplate`,moduleName:y};static defer={name:`ɵɵdefer`,moduleName:y};static deferWhen={name:`ɵɵdeferWhen`,moduleName:y};static deferOnIdle={name:`ɵɵdeferOnIdle`,moduleName:y};static deferOnImmediate={name:`ɵɵdeferOnImmediate`,moduleName:y};static deferOnTimer={name:`ɵɵdeferOnTimer`,moduleName:y};static deferOnHover={name:`ɵɵdeferOnHover`,moduleName:y};static deferOnInteraction={name:`ɵɵdeferOnInteraction`,moduleName:y};static deferOnViewport={name:`ɵɵdeferOnViewport`,moduleName:y};static deferPrefetchWhen={name:`ɵɵdeferPrefetchWhen`,moduleName:y};static deferPrefetchOnIdle={name:`ɵɵdeferPrefetchOnIdle`,moduleName:y};static deferPrefetchOnImmediate={name:`ɵɵdeferPrefetchOnImmediate`,moduleName:y};static deferPrefetchOnTimer={name:`ɵɵdeferPrefetchOnTimer`,moduleName:y};static deferPrefetchOnHover={name:`ɵɵdeferPrefetchOnHover`,moduleName:y};static deferPrefetchOnInteraction={name:`ɵɵdeferPrefetchOnInteraction`,moduleName:y};static deferPrefetchOnViewport={name:`ɵɵdeferPrefetchOnViewport`,moduleName:y};static deferHydrateWhen={name:`ɵɵdeferHydrateWhen`,moduleName:y};static deferHydrateNever={name:`ɵɵdeferHydrateNever`,moduleName:y};static deferHydrateOnIdle={name:`ɵɵdeferHydrateOnIdle`,moduleName:y};static deferHydrateOnImmediate={name:`ɵɵdeferHydrateOnImmediate`,moduleName:y};static deferHydrateOnTimer={name:`ɵɵdeferHydrateOnTimer`,moduleName:y};static deferHydrateOnHover={name:`ɵɵdeferHydrateOnHover`,moduleName:y};static deferHydrateOnInteraction={name:`ɵɵdeferHydrateOnInteraction`,moduleName:y};static deferHydrateOnViewport={name:`ɵɵdeferHydrateOnViewport`,moduleName:y};static deferEnableTimerScheduling={name:`ɵɵdeferEnableTimerScheduling`,moduleName:y};static enableIncrementalHydrationRuntime={name:`ɵɵenableIncrementalHydrationRuntime`,moduleName:y};static conditionalCreate={name:`ɵɵconditionalCreate`,moduleName:y};static conditionalBranchCreate={name:`ɵɵconditionalBranchCreate`,moduleName:y};static conditional={name:`ɵɵconditional`,moduleName:y};static repeater={name:`ɵɵrepeater`,moduleName:y};static repeaterCreate={name:`ɵɵrepeaterCreate`,moduleName:y};static repeaterTrackByIndex={name:`ɵɵrepeaterTrackByIndex`,moduleName:y};static repeaterTrackByIdentity={name:`ɵɵrepeaterTrackByIdentity`,moduleName:y};static componentInstance={name:`ɵɵcomponentInstance`,moduleName:y};static text={name:`ɵɵtext`,moduleName:y};static enableBindings={name:`ɵɵenableBindings`,moduleName:y};static disableBindings={name:`ɵɵdisableBindings`,moduleName:y};static getCurrentView={name:`ɵɵgetCurrentView`,moduleName:y};static textInterpolate={name:`ɵɵtextInterpolate`,moduleName:y};static textInterpolate1={name:`ɵɵtextInterpolate1`,moduleName:y};static textInterpolate2={name:`ɵɵtextInterpolate2`,moduleName:y};static textInterpolate3={name:`ɵɵtextInterpolate3`,moduleName:y};static textInterpolate4={name:`ɵɵtextInterpolate4`,moduleName:y};static textInterpolate5={name:`ɵɵtextInterpolate5`,moduleName:y};static textInterpolate6={name:`ɵɵtextInterpolate6`,moduleName:y};static textInterpolate7={name:`ɵɵtextInterpolate7`,moduleName:y};static textInterpolate8={name:`ɵɵtextInterpolate8`,moduleName:y};static textInterpolateV={name:`ɵɵtextInterpolateV`,moduleName:y};static restoreView={name:`ɵɵrestoreView`,moduleName:y};static pureFunction0={name:`ɵɵpureFunction0`,moduleName:y};static pureFunction1={name:`ɵɵpureFunction1`,moduleName:y};static pureFunction2={name:`ɵɵpureFunction2`,moduleName:y};static pureFunction3={name:`ɵɵpureFunction3`,moduleName:y};static pureFunction4={name:`ɵɵpureFunction4`,moduleName:y};static pureFunction5={name:`ɵɵpureFunction5`,moduleName:y};static pureFunction6={name:`ɵɵpureFunction6`,moduleName:y};static pureFunction7={name:`ɵɵpureFunction7`,moduleName:y};static pureFunction8={name:`ɵɵpureFunction8`,moduleName:y};static pureFunctionV={name:`ɵɵpureFunctionV`,moduleName:y};static pipeBind1={name:`ɵɵpipeBind1`,moduleName:y};static pipeBind2={name:`ɵɵpipeBind2`,moduleName:y};static pipeBind3={name:`ɵɵpipeBind3`,moduleName:y};static pipeBind4={name:`ɵɵpipeBind4`,moduleName:y};static pipeBindV={name:`ɵɵpipeBindV`,moduleName:y};static domProperty={name:`ɵɵdomProperty`,moduleName:y};static ariaProperty={name:`ɵɵariaProperty`,moduleName:y};static property={name:`ɵɵproperty`,moduleName:y};static control={name:`ɵɵcontrol`,moduleName:y};static controlCreate={name:`ɵɵcontrolCreate`,moduleName:y};static animationEnterListener={name:`ɵɵanimateEnterListener`,moduleName:y};static animationLeaveListener={name:`ɵɵanimateLeaveListener`,moduleName:y};static animationEnter={name:`ɵɵanimateEnter`,moduleName:y};static animationLeave={name:`ɵɵanimateLeave`,moduleName:y};static i18n={name:`ɵɵi18n`,moduleName:y};static i18nAttributes={name:`ɵɵi18nAttributes`,moduleName:y};static i18nExp={name:`ɵɵi18nExp`,moduleName:y};static i18nStart={name:`ɵɵi18nStart`,moduleName:y};static i18nEnd={name:`ɵɵi18nEnd`,moduleName:y};static i18nApply={name:`ɵɵi18nApply`,moduleName:y};static i18nPostprocess={name:`ɵɵi18nPostprocess`,moduleName:y};static pipe={name:`ɵɵpipe`,moduleName:y};static projection={name:`ɵɵprojection`,moduleName:y};static projectionDef={name:`ɵɵprojectionDef`,moduleName:y};static reference={name:`ɵɵreference`,moduleName:y};static inject={name:`ɵɵinject`,moduleName:y};static injectAttribute={name:`ɵɵinjectAttribute`,moduleName:y};static directiveInject={name:`ɵɵdirectiveInject`,moduleName:y};static invalidFactory={name:`ɵɵinvalidFactory`,moduleName:y};static invalidFactoryDep={name:`ɵɵinvalidFactoryDep`,moduleName:y};static templateRefExtractor={name:`ɵɵtemplateRefExtractor`,moduleName:y};static forwardRef={name:`forwardRef`,moduleName:y};static resolveForwardRef={name:`resolveForwardRef`,moduleName:y};static replaceMetadata={name:`ɵɵreplaceMetadata`,moduleName:y};static getReplaceMetadataURL={name:`ɵɵgetReplaceMetadataURL`,moduleName:y};static ɵɵdefineInjectable={name:`ɵɵdefineInjectable`,moduleName:y};static declareInjectable={name:`ɵɵngDeclareInjectable`,moduleName:y};static InjectableDeclaration={name:`ɵɵInjectableDeclaration`,moduleName:y};static defineService={name:`ɵɵdefineService`,moduleName:y};static declareService={name:`ɵɵngDeclareService`,moduleName:y};static resolveWindow={name:`ɵɵresolveWindow`,moduleName:y};static resolveDocument={name:`ɵɵresolveDocument`,moduleName:y};static resolveBody={name:`ɵɵresolveBody`,moduleName:y};static getComponentDepsFactory={name:`ɵɵgetComponentDepsFactory`,moduleName:y};static defineComponent={name:`ɵɵdefineComponent`,moduleName:y};static declareComponent={name:`ɵɵngDeclareComponent`,moduleName:y};static setComponentScope={name:`ɵɵsetComponentScope`,moduleName:y};static ChangeDetectionStrategy={name:`ChangeDetectionStrategy`,moduleName:y};static ViewEncapsulation={name:`ViewEncapsulation`,moduleName:y};static ComponentDeclaration={name:`ɵɵComponentDeclaration`,moduleName:y};static FactoryDeclaration={name:`ɵɵFactoryDeclaration`,moduleName:y};static declareFactory={name:`ɵɵngDeclareFactory`,moduleName:y};static FactoryTarget={name:`ɵɵFactoryTarget`,moduleName:y};static defineDirective={name:`ɵɵdefineDirective`,moduleName:y};static declareDirective={name:`ɵɵngDeclareDirective`,moduleName:y};static DirectiveDeclaration={name:`ɵɵDirectiveDeclaration`,moduleName:y};static InjectorDef={name:`ɵɵInjectorDef`,moduleName:y};static InjectorDeclaration={name:`ɵɵInjectorDeclaration`,moduleName:y};static defineInjector={name:`ɵɵdefineInjector`,moduleName:y};static declareInjector={name:`ɵɵngDeclareInjector`,moduleName:y};static NgModuleDeclaration={name:`ɵɵNgModuleDeclaration`,moduleName:y};static ModuleWithProviders={name:`ModuleWithProviders`,moduleName:y};static defineNgModule={name:`ɵɵdefineNgModule`,moduleName:y};static declareNgModule={name:`ɵɵngDeclareNgModule`,moduleName:y};static setNgModuleScope={name:`ɵɵsetNgModuleScope`,moduleName:y};static registerNgModuleType={name:`ɵɵregisterNgModuleType`,moduleName:y};static PipeDeclaration={name:`ɵɵPipeDeclaration`,moduleName:y};static definePipe={name:`ɵɵdefinePipe`,moduleName:y};static declarePipe={name:`ɵɵngDeclarePipe`,moduleName:y};static declareClassMetadata={name:`ɵɵngDeclareClassMetadata`,moduleName:y};static declareClassMetadataAsync={name:`ɵɵngDeclareClassMetadataAsync`,moduleName:y};static setClassMetadata={name:`ɵsetClassMetadata`,moduleName:y};static setClassMetadataAsync={name:`ɵsetClassMetadataAsync`,moduleName:y};static setClassDebugInfo={name:`ɵsetClassDebugInfo`,moduleName:y};static queryRefresh={name:`ɵɵqueryRefresh`,moduleName:y};static viewQuery={name:`ɵɵviewQuery`,moduleName:y};static loadQuery={name:`ɵɵloadQuery`,moduleName:y};static contentQuery={name:`ɵɵcontentQuery`,moduleName:y};static viewQuerySignal={name:`ɵɵviewQuerySignal`,moduleName:y};static contentQuerySignal={name:`ɵɵcontentQuerySignal`,moduleName:y};static queryAdvance={name:`ɵɵqueryAdvance`,moduleName:y};static twoWayProperty={name:`ɵɵtwoWayProperty`,moduleName:y};static twoWayBindingSet={name:`ɵɵtwoWayBindingSet`,moduleName:y};static twoWayListener={name:`ɵɵtwoWayListener`,moduleName:y};static declareLet={name:`ɵɵdeclareLet`,moduleName:y};static storeLet={name:`ɵɵstoreLet`,moduleName:y};static readContextLet={name:`ɵɵreadContextLet`,moduleName:y};static arrowFunction={name:`ɵɵarrowFunction`,moduleName:y};static attachSourceLocations={name:`ɵɵattachSourceLocations`,moduleName:y};static NgOnChangesFeature={name:`ɵɵNgOnChangesFeature`,moduleName:y};static ControlFeature={name:`ɵɵControlFeature`,moduleName:y};static InheritDefinitionFeature={name:`ɵɵInheritDefinitionFeature`,moduleName:y};static ProvidersFeature={name:`ɵɵProvidersFeature`,moduleName:y};static HostDirectivesFeature={name:`ɵɵHostDirectivesFeature`,moduleName:y};static ExternalStylesFeature={name:`ɵɵExternalStylesFeature`,moduleName:y};static listener={name:`ɵɵlistener`,moduleName:y};static getInheritedFactory={name:`ɵɵgetInheritedFactory`,moduleName:y};static sanitizeHtml={name:`ɵɵsanitizeHtml`,moduleName:y};static sanitizeStyle={name:`ɵɵsanitizeStyle`,moduleName:y};static validateAttribute={name:`ɵɵvalidateAttribute`,moduleName:y};static sanitizeResourceUrl={name:`ɵɵsanitizeResourceUrl`,moduleName:y};static sanitizeScript={name:`ɵɵsanitizeScript`,moduleName:y};static sanitizeUrl={name:`ɵɵsanitizeUrl`,moduleName:y};static sanitizeUrlOrResourceUrl={name:`ɵɵsanitizeUrlOrResourceUrl`,moduleName:y};static trustConstantHtml={name:`ɵɵtrustConstantHtml`,moduleName:y};static trustConstantResourceUrl={name:`ɵɵtrustConstantResourceUrl`,moduleName:y};static inputDecorator={name:`Input`,moduleName:y};static outputDecorator={name:`Output`,moduleName:y};static viewChildDecorator={name:`ViewChild`,moduleName:y};static viewChildrenDecorator={name:`ViewChildren`,moduleName:y};static contentChildDecorator={name:`ContentChild`,moduleName:y};static contentChildrenDecorator={name:`ContentChildren`,moduleName:y};static InputSignalBrandWriteType={name:`ɵINPUT_SIGNAL_BRAND_WRITE_TYPE`,moduleName:y};static UnwrapDirectiveSignalInputs={name:`ɵUnwrapDirectiveSignalInputs`,moduleName:y};static unwrapWritableSignal={name:`ɵunwrapWritableSignal`,moduleName:y};static assertType={name:`ɵassertType`,moduleName:y}}return e})();v.And,v.Bigger,v.BiggerEquals,v.BitwiseOr,v.BitwiseAnd,v.Divide,v.Assign,v.Equals,v.Identical,v.Lower,v.LowerEquals,v.Minus,v.Modulo,v.Exponentiation,v.Multiply,v.NotEquals,v.NotIdentical,v.NullishCoalesce,v.Or,v.Plus,v.In,v.InstanceOf,v.AdditionAssignment,v.SubtractionAssignment,v.MultiplicationAssignment,v.DivisionAssignment,v.RemainderAssignment,v.ExponentiationAssignment,v.AndAssignment,v.OrAssignment,v.NullishCoalesceAssignment;var Nt=class{span;sourceSpan;constructor(e,t){this.span=e,this.sourceSpan=t}toString(){return`AST`}},Pt=class extends Nt{receiver;args;argumentSpan;constructor(e,t,n,r,i){super(e,t),this.receiver=n,this.args=r,this.argumentSpan=i}visit(e,t=null){return e.visitCall(this,t)}},Ft=(function(e){return e[e.Property=0]=`Property`,e[e.Attribute=1]=`Attribute`,e[e.Class=2]=`Class`,e[e.Style=3]=`Style`,e[e.LegacyAnimation=4]=`LegacyAnimation`,e[e.TwoWay=5]=`TwoWay`,e[e.Animation=6]=`Animation`,e})(Ft||{}),It=`(:(where|is)\\()?`,Lt=`-shadowcsshost`,Rt=`-shadowcsscontext`,zt=`[^)(]*`,Bt=String.raw`(?:\(${zt}\)|${zt})+?`,Vt=String.raw`(?:\(${Bt}\)|${zt})+?`,Ht=String.raw`(?:\((${Vt})\))`;String.raw`(:nth-[-\w]+)`+Ht,Lt+Ht+``,`${It}`,Rt+Ht+``;var x=(function(e){return e[e.ListEnd=0]=`ListEnd`,e[e.Statement=1]=`Statement`,e[e.Variable=2]=`Variable`,e[e.ElementStart=3]=`ElementStart`,e[e.Element=4]=`Element`,e[e.ForeignComponent=5]=`ForeignComponent`,e[e.Template=6]=`Template`,e[e.ElementEnd=7]=`ElementEnd`,e[e.ContainerStart=8]=`ContainerStart`,e[e.Container=9]=`Container`,e[e.ContainerEnd=10]=`ContainerEnd`,e[e.DisableBindings=11]=`DisableBindings`,e[e.ConditionalCreate=12]=`ConditionalCreate`,e[e.ConditionalBranchCreate=13]=`ConditionalBranchCreate`,e[e.Conditional=14]=`Conditional`,e[e.EnableBindings=15]=`EnableBindings`,e[e.Text=16]=`Text`,e[e.Listener=17]=`Listener`,e[e.InterpolateText=18]=`InterpolateText`,e[e.Binding=19]=`Binding`,e[e.Property=20]=`Property`,e[e.StyleProp=21]=`StyleProp`,e[e.ClassProp=22]=`ClassProp`,e[e.StyleMap=23]=`StyleMap`,e[e.ClassMap=24]=`ClassMap`,e[e.Advance=25]=`Advance`,e[e.Pipe=26]=`Pipe`,e[e.Attribute=27]=`Attribute`,e[e.ExtractedAttribute=28]=`ExtractedAttribute`,e[e.Defer=29]=`Defer`,e[e.DeferOn=30]=`DeferOn`,e[e.DeferWhen=31]=`DeferWhen`,e[e.I18nMessage=32]=`I18nMessage`,e[e.DomProperty=33]=`DomProperty`,e[e.Namespace=34]=`Namespace`,e[e.ProjectionDef=35]=`ProjectionDef`,e[e.EnableIncrementalHydrationRuntime=36]=`EnableIncrementalHydrationRuntime`,e[e.Projection=37]=`Projection`,e[e.Content=38]=`Content`,e[e.RepeaterCreate=39]=`RepeaterCreate`,e[e.Repeater=40]=`Repeater`,e[e.TwoWayProperty=41]=`TwoWayProperty`,e[e.TwoWayListener=42]=`TwoWayListener`,e[e.DeclareLet=43]=`DeclareLet`,e[e.StoreLet=44]=`StoreLet`,e[e.I18nStart=45]=`I18nStart`,e[e.I18n=46]=`I18n`,e[e.I18nEnd=47]=`I18nEnd`,e[e.I18nExpression=48]=`I18nExpression`,e[e.I18nApply=49]=`I18nApply`,e[e.IcuStart=50]=`IcuStart`,e[e.IcuEnd=51]=`IcuEnd`,e[e.IcuPlaceholder=52]=`IcuPlaceholder`,e[e.I18nContext=53]=`I18nContext`,e[e.I18nAttributes=54]=`I18nAttributes`,e[e.SourceLocation=55]=`SourceLocation`,e[e.Animation=56]=`Animation`,e[e.AnimationString=57]=`AnimationString`,e[e.AnimationBinding=58]=`AnimationBinding`,e[e.AnimationListener=59]=`AnimationListener`,e[e.Control=60]=`Control`,e[e.ControlCreate=61]=`ControlCreate`,e})(x||{}),Ut=(function(e){return e[e.LexicalRead=0]=`LexicalRead`,e[e.Context=1]=`Context`,e[e.TrackContext=2]=`TrackContext`,e[e.ReadVariable=3]=`ReadVariable`,e[e.NextContext=4]=`NextContext`,e[e.Reference=5]=`Reference`,e[e.StoreLet=6]=`StoreLet`,e[e.ContextLetReference=7]=`ContextLetReference`,e[e.GetCurrentView=8]=`GetCurrentView`,e[e.RestoreView=9]=`RestoreView`,e[e.ResetView=10]=`ResetView`,e[e.PureFunctionExpr=11]=`PureFunctionExpr`,e[e.PureFunctionParameterExpr=12]=`PureFunctionParameterExpr`,e[e.PipeBinding=13]=`PipeBinding`,e[e.PipeBindingVariadic=14]=`PipeBindingVariadic`,e[e.SafePropertyRead=15]=`SafePropertyRead`,e[e.SafeKeyedRead=16]=`SafeKeyedRead`,e[e.SafeNavigationMigration=17]=`SafeNavigationMigration`,e[e.SafeTernaryExpr=18]=`SafeTernaryExpr`,e[e.EmptyExpr=19]=`EmptyExpr`,e[e.AssignTemporaryExpr=20]=`AssignTemporaryExpr`,e[e.ReadTemporaryExpr=21]=`ReadTemporaryExpr`,e[e.SlotLiteralExpr=22]=`SlotLiteralExpr`,e[e.ConditionalCase=23]=`ConditionalCase`,e[e.ConstCollected=24]=`ConstCollected`,e[e.TwoWayBindingSet=25]=`TwoWayBindingSet`,e[e.ForeignContent=26]=`ForeignContent`,e[e.ArrowFunction=27]=`ArrowFunction`,e})(Ut||{}),Wt=(function(e){return e[e.None=0]=`None`,e[e.AlwaysInline=1]=`AlwaysInline`,e})(Wt||{}),Gt=(function(e){return e[e.Context=0]=`Context`,e[e.Identifier=1]=`Identifier`,e[e.SavedView=2]=`SavedView`,e[e.Alias=3]=`Alias`,e})(Gt||{}),Kt=(function(e){return e[e.Attribute=0]=`Attribute`,e[e.ClassName=1]=`ClassName`,e[e.StyleProperty=2]=`StyleProperty`,e[e.Property=3]=`Property`,e[e.Template=4]=`Template`,e[e.I18n=5]=`I18n`,e[e.LegacyAnimation=6]=`LegacyAnimation`,e[e.TwoWayProperty=7]=`TwoWayProperty`,e[e.Animation=8]=`Animation`,e})(Kt||{}),qt=(function(e){return e[e.Creation=0]=`Creation`,e[e.Postproccessing=1]=`Postproccessing`,e})(qt||{}),Jt=(function(e){return e[e.I18nText=0]=`I18nText`,e[e.I18nAttribute=1]=`I18nAttribute`,e})(Jt||{}),Yt=(function(e){return e[e.None=0]=`None`,e[e.ElementTag=1]=`ElementTag`,e[e.TemplateTag=2]=`TemplateTag`,e[e.OpenTag=4]=`OpenTag`,e[e.CloseTag=8]=`CloseTag`,e[e.ExpressionIndex=16]=`ExpressionIndex`,e})(Yt||{}),Xt=(function(e){return e[e.HTML=0]=`HTML`,e[e.SVG=1]=`SVG`,e[e.Math=2]=`Math`,e})(Xt||{}),Zt=(function(e){return e[e.Idle=0]=`Idle`,e[e.Immediate=1]=`Immediate`,e[e.Timer=2]=`Timer`,e[e.Hover=3]=`Hover`,e[e.Interaction=4]=`Interaction`,e[e.Viewport=5]=`Viewport`,e[e.Never=6]=`Never`,e})(Zt||{}),Qt=(function(e){return e[e.RootI18n=0]=`RootI18n`,e[e.Icu=1]=`Icu`,e[e.Attr=2]=`Attr`,e})(Qt||{}),$t=(function(e){return e[e.NgTemplate=0]=`NgTemplate`,e[e.Structural=1]=`Structural`,e[e.Block=2]=`Block`,e})($t||{}),en=(function(e){return e[e.None=0]=`None`,e[e.InChildOperation=1]=`InChildOperation`,e[e.InArrowFunctionOperation=2]=`InArrowFunctionOperation`,e[e.InSafeNavigationMigration=4]=`InSafeNavigationMigration`,e})(en||{});x.Element,x.ElementStart,x.Container,x.ContainerStart,x.Template,x.RepeaterCreate,x.ConditionalCreate,x.ConditionalBranchCreate;var S=(function(e){return e[e.Tmpl=0]=`Tmpl`,e[e.Host=1]=`Host`,e[e.Both=2]=`Both`,e})(S||{}),tn=(function(e){return e[e.Full=0]=`Full`,e[e.DomOnly=1]=`DomOnly`,e})(tn||{});b.ariaProperty,b.ariaProperty,b.attribute,b.attribute,b.classProp,b.classProp,b.element,b.element,b.elementContainer,b.elementContainer,b.elementContainerEnd,b.elementContainerEnd,b.elementContainerStart,b.elementContainerStart,b.elementEnd,b.elementEnd,b.elementStart,b.elementStart,b.domProperty,b.domProperty,b.i18nExp,b.i18nExp,b.listener,b.listener,b.listener,b.listener,b.property,b.property,b.styleProp,b.styleProp,b.syntheticHostListener,b.syntheticHostListener,b.syntheticHostProperty,b.syntheticHostProperty,b.templateCreate,b.templateCreate,b.twoWayProperty,b.twoWayProperty,b.twoWayListener,b.twoWayListener,b.declareLet,b.declareLet,b.conditionalCreate,b.conditionalBranchCreate,b.conditionalBranchCreate,b.conditionalBranchCreate,b.domElement,b.domElement,b.domElementStart,b.domElementStart,b.domElementEnd,b.domElementEnd,b.domElementContainer,b.domElementContainer,b.domElementContainerStart,b.domElementContainerStart,b.domElementContainerEnd,b.domElementContainerEnd,b.domListener,b.domListener,b.domTemplate,b.domTemplate,b.animationEnter,b.animationEnter,b.animationLeave,b.animationLeave,b.animationEnterListener,b.animationEnterListener,b.animationLeaveListener,b.animationLeaveListener,v.And,v.Bigger,v.BiggerEquals,v.BitwiseOr,v.BitwiseAnd,v.Divide,v.Assign,v.Equals,v.Identical,v.Lower,v.LowerEquals,v.Minus,v.Modulo,v.Exponentiation,v.Multiply,v.NotEquals,v.NotIdentical,v.NullishCoalesce,v.Or,v.Plus,v.In,v.InstanceOf,v.AdditionAssignment,v.SubtractionAssignment,v.MultiplicationAssignment,v.DivisionAssignment,v.RemainderAssignment,v.ExponentiationAssignment,v.AndAssignment,v.OrAssignment,v.NullishCoalesceAssignment,x.Property,x.Property,x.Property,x.Attribute,x.Attribute,x.Property,x.TwoWayProperty,x.Container,x.ContainerStart,x.ContainerEnd,x.Element,x.ElementStart,x.ElementEnd,x.Template,x.ElementEnd,x.ElementStart,x.Element,x.ContainerEnd,x.ContainerStart,x.Container,x.I18nEnd,x.I18nStart,x.I18n,x.Pipe;var nn=` \f -\r \v ᠎ - \u2028\u2029   `;`${nn}`,`${nn}`;var rn=(function(e){return e[e.Character=0]=`Character`,e[e.Identifier=1]=`Identifier`,e[e.PrivateIdentifier=2]=`PrivateIdentifier`,e[e.Keyword=3]=`Keyword`,e[e.String=4]=`String`,e[e.Operator=5]=`Operator`,e[e.Number=6]=`Number`,e[e.RegExpBody=7]=`RegExpBody`,e[e.RegExpFlags=8]=`RegExpFlags`,e[e.Error=9]=`Error`,e})(rn||{}),an=(function(e){return e[e.Plain=0]=`Plain`,e[e.TemplateLiteralPart=1]=`TemplateLiteralPart`,e[e.TemplateLiteralEnd=2]=`TemplateLiteralEnd`,e})(an||{});rn.Character,x.StyleMap,x.ClassMap,x.StyleProp,x.ClassProp,x.Attribute,x.Property,x.Attribute,x.Control,x.DomProperty,x.DomProperty,x.Attribute,x.StyleMap,x.ClassMap,x.StyleProp,x.ClassProp,x.Listener,x.TwoWayListener,x.AnimationListener,x.StyleMap,x.ClassMap,x.StyleProp,x.ClassProp,x.Property,x.TwoWayProperty,x.DomProperty,x.Attribute,x.Animation,x.Control,Zt.Idle,b.deferOnIdle,b.deferPrefetchOnIdle,b.deferHydrateOnIdle,Zt.Immediate,b.deferOnImmediate,b.deferPrefetchOnImmediate,b.deferHydrateOnImmediate,Zt.Timer,b.deferOnTimer,b.deferPrefetchOnTimer,b.deferHydrateOnTimer,Zt.Hover,b.deferOnHover,b.deferPrefetchOnHover,b.deferHydrateOnHover,Zt.Interaction,b.deferOnInteraction,b.deferPrefetchOnInteraction,b.deferHydrateOnInteraction,Zt.Viewport,b.deferOnViewport,b.deferPrefetchOnViewport,b.deferHydrateOnViewport,Zt.Never,b.deferHydrateNever,b.deferHydrateNever,b.deferHydrateNever,b.pipeBind1,b.pipeBind2,b.pipeBind3,b.pipeBind4,b.textInterpolate,b.textInterpolate1,b.textInterpolate2,b.textInterpolate3,b.textInterpolate4,b.textInterpolate5,b.textInterpolate6,b.textInterpolate7,b.textInterpolate8,b.textInterpolateV,b.interpolate,b.interpolate1,b.interpolate2,b.interpolate3,b.interpolate4,b.interpolate5,b.interpolate6,b.interpolate7,b.interpolate8,b.interpolateV,b.pureFunction0,b.pureFunction1,b.pureFunction2,b.pureFunction3,b.pureFunction4,b.pureFunction5,b.pureFunction6,b.pureFunction7,b.pureFunction8,b.pureFunctionV,b.resolveWindow,b.resolveDocument,b.resolveBody,it.HTML,b.sanitizeHtml,it.RESOURCE_URL,b.sanitizeResourceUrl,it.SCRIPT,b.sanitizeScript,it.STYLE,b.sanitizeStyle,it.URL,b.sanitizeUrl,it.ATTRIBUTE_NO_BINDING,b.validateAttribute,it.HTML,b.trustConstantHtml,it.RESOURCE_URL,b.trustConstantResourceUrl;var on=(function(e){return e[e.None=0]=`None`,e[e.ViewContextRead=1]=`ViewContextRead`,e[e.ViewContextWrite=2]=`ViewContextWrite`,e[e.SideEffectful=4]=`SideEffectful`,e})(on||{});S.Tmpl,S.Tmpl,S.Both,S.Host,S.Tmpl,S.Tmpl,S.Tmpl,S.Both,S.Both,S.Both,S.Tmpl,S.Both,S.Both,S.Tmpl,S.Both,S.Tmpl,S.Both,S.Both,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Both,S.Both,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Both,S.Both,S.Both,S.Tmpl,S.Tmpl,S.Both,S.Tmpl,S.Tmpl,S.Tmpl,S.Both,S.Both,S.Tmpl,S.Both,S.Both,S.Both,S.Both,S.Both,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Both,S.Tmpl,S.Both,S.Tmpl,S.Both,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Tmpl,S.Both,S.Both,S.Both,Ft.Property,Kt.Property,Ft.TwoWay,Kt.TwoWayProperty,Ft.Attribute,Kt.Attribute,Ft.Class,Kt.ClassName,Ft.Style,Kt.StyleProperty,Ft.LegacyAnimation,Kt.LegacyAnimation,Ft.Animation,Kt.Animation;var sn=`%COMP%`;`${sn}`,`${sn}`,class e{static SINGLETON=new e;static veWillInferAnyFor(t){let n=e.SINGLETON;return t instanceof Pt?t.visit(n):t.receiver.visit(n)}visitUnary(e){return e.expr.visit(this)}visitBinary(e){return e.left.visit(this)||e.right.visit(this)}visitChain(){return!1}visitConditional(e){return e.condition.visit(this)||e.trueExp.visit(this)||e.falseExp.visit(this)}visitCall(){return!0}visitSafeCall(){return!1}visitImplicitReceiver(){return!1}visitThisReceiver(){return!1}visitInterpolation(e){return e.expressions.some(e=>e.visit(this))}visitKeyedRead(){return!1}visitLiteralArray(){return!0}visitLiteralMap(){return!0}visitLiteralPrimitive(){return!1}visitPipe(){return!0}visitPrefixNot(e){return e.expression.visit(this)}visitTypeofExpression(e){return e.expression.visit(this)}visitVoidExpression(e){return e.expression.visit(this)}visitNonNullAssert(e){return e.expression.visit(this)}visitPropertyRead(){return!1}visitSafePropertyRead(){return!1}visitSafeKeyedRead(){return!1}visitTemplateLiteral(){return!1}visitTemplateLiteralElement(){return!1}visitTaggedTemplateLiteral(){return!1}visitParenthesizedExpression(e){return e.expression.visit(this)}visitRegularExpressionLiteral(){return!1}visitSpreadElement(e){return e.expression.visit(this)}visitArrowFunction(e,t){return!1}};var cn=null,ln=!1,un=1,dn=null,fn=Symbol(`SIGNAL`);function C(e){let t=cn;return cn=e,t}function pn(){return cn}var mn={version:0,lastCleanEpoch:0,dirty:!1,producers:void 0,producersTail:void 0,consumers:void 0,consumersTail:void 0,recomputing:!1,consumerAllowSignalWrites:!1,consumerIsAlwaysLive:!1,kind:`unknown`,producerMustRecompute:()=>!1,producerRecomputeValue:()=>{},consumerMarkedDirty:()=>{},consumerOnSignalRead:()=>{}};function hn(e){if(ln)throw Error(``);if(cn===null)return;cn.consumerOnSignalRead(e);let t=cn.producersTail;if(t!==void 0&&t.producer===e)return;let n,r=cn.recomputing;if(r&&(n=t===void 0?cn.producers:t.nextProducer,n!==void 0&&n.producer===e)){cn.producersTail=n,n.lastReadVersion=e.version,n.knownValidAtEpoch=un;return}let i=e.consumersTail;if(i!==void 0&&i.consumer===cn&&(!r||i.knownValidAtEpoch===un))return;let a=An(cn),o={producer:e,consumer:cn,nextProducer:n,prevConsumer:void 0,knownValidAtEpoch:un,lastReadVersion:e.version,nextConsumer:void 0};cn.producersTail=o,t===void 0?cn.producers=o:t.nextProducer=o,a&&On(e,o)}function gn(){un++}function _n(e){if((!An(e)||e.dirty)&&(e.dirty||e.lastCleanEpoch!==un)){if(!e.producerMustRecompute(e)&&!En(e)){xn(e);return}e.producerRecomputeValue(e),xn(e)}}function vn(e){if(e.consumers===void 0)return;let t=ln;ln=!0;try{for(let t=e.consumers;t!==void 0;t=t.nextConsumer){let e=t.consumer;e.dirty||bn(e)}}finally{ln=t}}function yn(){return cn?.consumerAllowSignalWrites!==!1}function bn(e){e.dirty=!0,vn(e),e.consumerMarkedDirty?.(e)}function xn(e){e.dirty=!1,e.lastCleanEpoch=un}function Sn(e){return e&&Cn(e),C(e)}function Cn(e){if(e.producersTail?.knownValidAtEpoch===un){let t=e.producers;for(;t!==void 0;)t.knownValidAtEpoch=null,t=t.nextProducer}e.producersTail=void 0,e.recomputing=!0}function wn(e,t){C(t),e&&Tn(e)}function Tn(e){e.recomputing=!1;let t=e.producersTail,n=t===void 0?e.producers:t.nextProducer;if(n!==void 0){if(An(e))do n=kn(n);while(n!==void 0);t===void 0?e.producers=void 0:t.nextProducer=void 0}}function En(e){for(let t=e.producers;t!==void 0;t=t.nextProducer){let e=t.producer,n=t.lastReadVersion;if(n!==e.version||(_n(e),n!==e.version))return!0}return!1}function Dn(e){if(An(e)){let t=e.producers;for(;t!==void 0;)t=kn(t)}e.producers=void 0,e.producersTail=void 0,e.consumers=void 0,e.consumersTail=void 0}function On(e,t){let n=e.consumersTail,r=An(e);if(n===void 0?(t.nextConsumer=void 0,e.consumers=t):(t.nextConsumer=n.nextConsumer,n.nextConsumer=t),t.prevConsumer=n,e.consumersTail=t,!r)for(let t=e.producers;t!==void 0;t=t.nextProducer)On(t.producer,t)}function kn(e){let t=e.producer,n=e.nextProducer,r=e.nextConsumer,i=e.prevConsumer;if(e.nextConsumer=void 0,e.prevConsumer=void 0,r===void 0?t.consumersTail=i:r.prevConsumer=i,i!==void 0)i.nextConsumer=r;else if(t.consumers=r,!An(t)){let e=t.producers;for(;e!==void 0;)e=kn(e)}return n}function An(e){return e.consumerIsAlwaysLive||e.consumers!==void 0}function jn(e){dn?.(e)}function Mn(e,t){return Object.is(e,t)}function Nn(e,t){let n=Object.create(Ln);n.computation=e,t!==void 0&&(n.equal=t);let r=()=>{if(_n(n),hn(n),n.value===In)throw n.error;return n.value};return r[fn]=n,jn(n),r}var Pn=Symbol(`UNSET`),Fn=Symbol(`COMPUTING`),In=Symbol(`ERRORED`),Ln={...mn,value:Pn,dirty:!0,error:null,equal:Mn,kind:`computed`,producerMustRecompute(e){return e.value===Pn||e.value===Fn},producerRecomputeValue(e){if(e.value===Fn)throw Error(``);let t=e.value;e.value=Fn;let n=Sn(e),r,i=!1;try{r=e.computation(),C(null),i=t!==Pn&&t!==In&&r!==In&&e.equal(t,r)}catch(t){r=In,e.error=t}finally{wn(e,n)}if(i){e.value=t;return}e.value=r,e.version++}};function Rn(){throw Error()}var zn=Rn;function Bn(e){zn(e)}function Vn(e){zn=e}var Hn=null;function Un(e,t){let n=Object.create(qn);n.value=e,t!==void 0&&(n.equal=t);let r=()=>Wn(n);return r[fn]=n,jn(n),[r,e=>Gn(n,e),e=>Kn(n,e)]}function Wn(e){return hn(e),e.value}function Gn(e,t){yn()||Bn(e),e.equal(e.value,t)||(e.value=t,Jn(e))}function Kn(e,t){yn()||Bn(e),Gn(e,t(e.value))}var qn={...mn,equal:Mn,value:void 0,kind:`signal`};function Jn(e){e.version++,gn(),vn(e),Hn?.(e)}var Yn={...mn,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,dirty:!0,kind:`effect`};function Xn(e){if(e.dirty=!1,e.version>0&&!En(e))return;e.version++;let t=Sn(e);try{e.cleanup(),e.fn()}finally{wn(e,t)}}var Zn=void 0;function Qn(){return Zn}function $n(e){let t=Zn;return Zn=e,t}var er=Symbol(`NotFound`);function tr(e){return e===er||e?.name===`ɵNotFound`}function nr(e,t,n){let r=Object.create(ar);r.source=e,r.computation=t,n!=null&&(r.equal=n);let i=()=>{if(_n(r),hn(r),r.value===In)throw r.error;return r.value};return i[fn]=r,jn(r),i}function rr(e,t){_n(e),Gn(e,t),xn(e)}function ir(e,t){if(_n(e),e.value===In)throw e.error;Kn(e,t),xn(e)}var ar={...mn,value:Pn,dirty:!0,error:null,equal:Mn,kind:`linkedSignal`,producerMustRecompute(e){return e.value===Pn||e.value===Fn},producerRecomputeValue(e){if(e.value===Fn)throw Error(``);let t=e.value;e.value=Fn;let n=Sn(e),r,i=!1;try{let n=e.source(),a=t!==Pn&&t!==In,o=a?{source:e.sourceValue,value:t}:void 0;r=e.computation(n,o),e.sourceValue=n,C(null),i=a&&r!==In&&e.equal(t,r)}catch(t){r=In,e.error=t}finally{wn(e,n)}if(i){e.value=t;return}e.value=r,e.version++}};function or(e){let t=C(null);try{return e()}finally{C(t)}}var sr=function(e,t){return sr=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},sr(e,t)};function cr(e,t){if(typeof t!=`function`&&t!==null)throw TypeError(`Class extends value `+String(t)+` is not a constructor or null`);sr(e,t);function n(){this.constructor=e}e.prototype=t===null?Object.create(t):(n.prototype=t.prototype,new n)}function lr(e){var t=typeof Symbol==`function`&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&typeof e.length==`number`)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw TypeError(t?`Object is not iterable.`:`Symbol.iterator is not defined.`)}function ur(e,t){var n=typeof Symbol==`function`&&e[Symbol.iterator];if(!n)return e;var r=n.call(e),i,a=[],o;try{for(;(t===void 0||t-->0)&&!(i=r.next()).done;)a.push(i.value)}catch(e){o={error:e}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(o)throw o.error}}return a}function dr(e,t,n){if(n||arguments.length===2)for(var r=0,i=t.length,a;re.visit(this))}visitKeyedRead(){return!1}visitLiteralArray(){return!0}visitLiteralMap(){return!0}visitLiteralPrimitive(){return!1}visitPipe(){return!0}visitPrefixNot(e){return e.expression.visit(this)}visitTypeofExpression(e){return e.expression.visit(this)}visitVoidExpression(e){return e.expression.visit(this)}visitNonNullAssert(e){return e.expression.visit(this)}visitPropertyRead(){return!1}visitSafePropertyRead(){return!1}visitSafeKeyedRead(){return!1}visitTemplateLiteral(){return!1}visitTemplateLiteralElement(){return!1}visitTaggedTemplateLiteral(){return!1}visitParenthesizedExpression(e){return e.expression.visit(this)}visitRegularExpressionLiteral(){return!1}visitSpreadElement(e){return e.expression.visit(this)}visitArrowFunction(e,t){return!1}};var cn=null,ln=!1,un=1,dn=null,fn=Symbol(`SIGNAL`);function pn(e){let t=cn;return cn=e,t}function mn(){return cn}var hn={version:0,lastCleanEpoch:0,dirty:!1,producers:void 0,producersTail:void 0,consumers:void 0,consumersTail:void 0,recomputing:!1,consumerAllowSignalWrites:!1,consumerIsAlwaysLive:!1,kind:`unknown`,producerMustRecompute:()=>!1,producerRecomputeValue:()=>{},consumerMarkedDirty:()=>{},consumerOnSignalRead:()=>{}};function gn(e){if(ln)throw Error(``);if(cn===null)return;cn.consumerOnSignalRead(e);let t=cn.producersTail;if(t!==void 0&&t.producer===e)return;let n,r=cn.recomputing;if(r&&(n=t===void 0?cn.producers:t.nextProducer,n!==void 0&&n.producer===e)){cn.producersTail=n,n.lastReadVersion=e.version,n.knownValidAtEpoch=un;return}let i=e.consumersTail;if(i!==void 0&&i.consumer===cn&&(!r||i.knownValidAtEpoch===un))return;let a=jn(cn),o={producer:e,consumer:cn,nextProducer:n,prevConsumer:void 0,knownValidAtEpoch:un,lastReadVersion:e.version,nextConsumer:void 0};cn.producersTail=o,t===void 0?cn.producers=o:t.nextProducer=o,a&&kn(e,o)}function _n(){un++}function vn(e){if((!jn(e)||e.dirty)&&(e.dirty||e.lastCleanEpoch!==un)){if(!e.producerMustRecompute(e)&&!Dn(e)){Sn(e);return}e.producerRecomputeValue(e),Sn(e)}}function yn(e){if(e.consumers===void 0)return;let t=ln;ln=!0;try{for(let t=e.consumers;t!==void 0;t=t.nextConsumer){let e=t.consumer;e.dirty||xn(e)}}finally{ln=t}}function bn(){return cn?.consumerAllowSignalWrites!==!1}function xn(e){e.dirty=!0,yn(e),e.consumerMarkedDirty?.(e)}function Sn(e){e.dirty=!1,e.lastCleanEpoch=un}function Cn(e){return e&&wn(e),pn(e)}function wn(e){if(e.producersTail?.knownValidAtEpoch===un){let t=e.producers;for(;t!==void 0;)t.knownValidAtEpoch=null,t=t.nextProducer}e.producersTail=void 0,e.recomputing=!0}function Tn(e,t){pn(t),e&&En(e)}function En(e){e.recomputing=!1;let t=e.producersTail,n=t===void 0?e.producers:t.nextProducer;if(n!==void 0){if(jn(e))do n=An(n);while(n!==void 0);t===void 0?e.producers=void 0:t.nextProducer=void 0}}function Dn(e){for(let t=e.producers;t!==void 0;t=t.nextProducer){let e=t.producer,n=t.lastReadVersion;if(n!==e.version||(vn(e),n!==e.version))return!0}return!1}function On(e){if(jn(e)){let t=e.producers;for(;t!==void 0;)t=An(t)}e.producers=void 0,e.producersTail=void 0,e.consumers=void 0,e.consumersTail=void 0}function kn(e,t){let n=e.consumersTail,r=jn(e);if(n===void 0?(t.nextConsumer=void 0,e.consumers=t):(t.nextConsumer=n.nextConsumer,n.nextConsumer=t),t.prevConsumer=n,e.consumersTail=t,!r)for(let t=e.producers;t!==void 0;t=t.nextProducer)kn(t.producer,t)}function An(e){let t=e.producer,n=e.nextProducer,r=e.nextConsumer,i=e.prevConsumer;if(e.nextConsumer=void 0,e.prevConsumer=void 0,r===void 0?t.consumersTail=i:r.prevConsumer=i,i!==void 0)i.nextConsumer=r;else if(t.consumers=r,!jn(t)){let e=t.producers;for(;e!==void 0;)e=An(e)}return n}function jn(e){return e.consumerIsAlwaysLive||e.consumers!==void 0}function Mn(e){dn?.(e)}function Nn(e,t){return Object.is(e,t)}function Pn(e,t){let n=Object.create(Rn);n.computation=e,t!==void 0&&(n.equal=t);let r=()=>{if(vn(n),gn(n),n.value===Ln)throw n.error;return n.value};return r[fn]=n,Mn(n),r}var Fn=Symbol(`UNSET`),In=Symbol(`COMPUTING`),Ln=Symbol(`ERRORED`),Rn={...hn,value:Fn,dirty:!0,error:null,equal:Nn,kind:`computed`,producerMustRecompute(e){return e.value===Fn||e.value===In},producerRecomputeValue(e){if(e.value===In)throw Error(``);let t=e.value;e.value=In;let n=Cn(e),r,i=!1;try{r=e.computation(),pn(null),i=t!==Fn&&t!==Ln&&r!==Ln&&e.equal(t,r)}catch(t){r=Ln,e.error=t}finally{Tn(e,n)}if(i){e.value=t;return}e.value=r,e.version++}};function zn(){throw Error()}var Bn=zn;function Vn(e){Bn(e)}function Hn(e){Bn=e}var Un=null;function Wn(e,t){let n=Object.create(Jn);n.value=e,t!==void 0&&(n.equal=t);let r=()=>Gn(n);return r[fn]=n,Mn(n),[r,e=>Kn(n,e),e=>qn(n,e)]}function Gn(e){return gn(e),e.value}function Kn(e,t){bn()||Vn(e),e.equal(e.value,t)||(e.value=t,Yn(e))}function qn(e,t){bn()||Vn(e),Kn(e,t(e.value))}var Jn={...hn,equal:Nn,value:void 0,kind:`signal`};function Yn(e){e.version++,_n(),yn(e),Un?.(e)}var Xn={...hn,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,dirty:!0,kind:`effect`};function Zn(e){if(e.dirty=!1,e.version>0&&!Dn(e))return;e.version++;let t=Cn(e);try{e.cleanup(),e.fn()}finally{Tn(e,t)}}var Qn=void 0;function $n(){return Qn}function er(e){let t=Qn;return Qn=e,t}var tr=Symbol(`NotFound`);function nr(e){return e===tr||e?.name===`ɵNotFound`}function rr(e,t,n){let r=Object.create(or);r.source=e,r.computation=t,n!=null&&(r.equal=n);let i=()=>{if(vn(r),gn(r),r.value===Ln)throw r.error;return r.value};return i[fn]=r,Mn(r),i}function ir(e,t){vn(e),Kn(e,t),Sn(e)}function ar(e,t){if(vn(e),e.value===Ln)throw e.error;qn(e,t),Sn(e)}var or={...hn,value:Fn,dirty:!0,error:null,equal:Nn,kind:`linkedSignal`,producerMustRecompute(e){return e.value===Fn||e.value===In},producerRecomputeValue(e){if(e.value===In)throw Error(``);let t=e.value;e.value=In;let n=Cn(e),r,i=!1;try{let n=e.source(),a=t!==Fn&&t!==Ln,o=a?{source:e.sourceValue,value:t}:void 0;r=e.computation(n,o),e.sourceValue=n,pn(null),i=a&&r!==Ln&&e.equal(t,r)}catch(t){r=Ln,e.error=t}finally{Tn(e,n)}if(i){e.value=t;return}e.value=r,e.version++}};function sr(e){let t=pn(null);try{return e()}finally{pn(t)}}var cr=function(e,t){return cr=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},cr(e,t)};function lr(e,t){if(typeof t!=`function`&&t!==null)throw TypeError(`Class extends value `+String(t)+` is not a constructor or null`);cr(e,t);function n(){this.constructor=e}e.prototype=t===null?Object.create(t):(n.prototype=t.prototype,new n)}function ur(e){var t=typeof Symbol==`function`&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&typeof e.length==`number`)return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw TypeError(t?`Object is not iterable.`:`Symbol.iterator is not defined.`)}function dr(e,t){var n=typeof Symbol==`function`&&e[Symbol.iterator];if(!n)return e;var r=n.call(e),i,a=[],o;try{for(;(t===void 0||t-->0)&&!(i=r.next()).done;)a.push(i.value)}catch(e){o={error:e}}finally{try{i&&!i.done&&(n=r.return)&&n.call(r)}finally{if(o)throw o.error}}return a}function fr(e,t,n){if(n||arguments.length===2)for(var r=0,i=t.length,a;r0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(t){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,t)},t.prototype._subscribe=function(e){return this._throwIfClosed(),this._checkFinalizedStatuses(e),this._innerSubscribe(e)},t.prototype._innerSubscribe=function(e){var t=this,n=this,r=n.hasError,i=n.isStopped,a=n.observers;return r||i?_r:(this.currentObservers=null,a.push(e),new gr(function(){t.currentObservers=null,hr(a,e)}))},t.prototype._checkFinalizedStatuses=function(e){var t=this,n=t.hasError,r=t.thrownError,i=t.isStopped;n?e.error(r):i&&e.complete()},t.prototype.asObservable=function(){var e=new Ur;return e.source=this,e},t.create=function(e,t){return new $r(e,t)},t}(Ur),$r=function(e){cr(t,e);function t(t,n){var r=e.call(this)||this;return r.destination=t,r.source=n,r}return t.prototype.next=function(e){var t,n;(n=(t=this.destination)?.next)==null||n.call(t,e)},t.prototype.error=function(e){var t,n;(n=(t=this.destination)?.error)==null||n.call(t,e)},t.prototype.complete=function(){var e,t;(t=(e=this.destination)?.complete)==null||t.call(e)},t.prototype._subscribe=function(e){return this.source?.subscribe(e)??_r},t}(Qr),ei=function(e){cr(t,e);function t(t){var n=e.call(this)||this;return n._value=t,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(t){var n=e.prototype._subscribe.call(this,t);return!n.closed&&t.next(this._value),n},t.prototype.getValue=function(){var e=this,t=e.hasError,n=e.thrownError,r=e._value;if(t)throw n;return this._throwIfClosed(),r},t.prototype.next=function(t){e.prototype.next.call(this,this._value=t)},t}(Qr);function ti(e,t){return Jr(function(n,r){var i=0;n.subscribe(Yr(r,function(n){r.next(e.call(t,n,i++))}))})}var ni=`https://angular.dev/best-practices/security#preventing-cross-site-scripting-xss`,ri=class extends Error{code;constructor(e,t){super(ai(e,t)),this.code=e}};function ii(e){return`NG0${Math.abs(e)}`}function ai(e,t){return`${ii(e)}${t?`: `+t:``}`}function oi(e){for(let t in e)if(e[t]===oi)return t;throw Error(``)}function si(e){if(typeof e==`string`)return e;if(Array.isArray(e))return`[${e.map(si).join(`, `)}]`;if(e==null)return``+e;let t=e.overriddenName||e.name;if(t)return`${t}`;let n=e.toString();if(n==null)return``+n;let r=n.indexOf(` -`);return r>=0?n.slice(0,r):n}function ci(e,t){return e?t?`${e} ${t}`:e:t||``}var li=oi({__forward_ref__:oi});function ui(e){return e.__forward_ref__=ui,e}function di(e){return fi(e)?e():e}function fi(e){return typeof e==`function`&&Object.hasOwn(e,li)&&e.__forward_ref__===ui}function pi(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function mi(e){return hi(e,vi)}function hi(e,t){return Object.hasOwn(e,t)&&e[t]||null}function gi(e){return(e?.[vi]??null)||null}function _i(e){return e&&Object.hasOwn(e,yi)?e[yi]:null}var vi=oi({ɵprov:oi}),yi=oi({ɵinj:oi}),bi=class{_desc;ngMetadataName=`InjectionToken`;ɵprov;constructor(e,t){this._desc=e,this.ɵprov=void 0,typeof t==`number`?this.__NG_ELEMENT_ID__=t:t!==void 0&&(this.ɵprov=pi({token:this,providedIn:t.providedIn||`root`,factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}};function xi(e){return e&&!!e.ɵproviders}var Si=oi({ɵcmp:oi}),Ci=oi({ɵdir:oi}),wi=oi({ɵpipe:oi}),Ti=oi({ɵfac:oi}),Ei=oi({__NG_ELEMENT_ID__:oi}),Di=oi({__NG_ENV_ID__:oi});function Oi(e){return ji(e,`@Component`),e[Si]||null}function ki(e){return ji(e,`@Directive`),e[Ci]||null}function Ai(e){return ji(e,`@Pipe`),e[wi]||null}function ji(e,t){if(e==null)throw new ri(-919,!1)}function Mi(e){return typeof e==`string`?e:e==null?``:String(e)}var Ni=oi({ngErrorCode:oi}),Pi=oi({ngErrorMessage:oi}),Fi=oi({ngTokenPath:oi});function Ii(e,t){return Ri(``,-200,t)}function Li(e,t){throw new ri(-201,!1)}function Ri(e,t,n){let r=new ri(t,e);return r[Ni]=t,r[Pi]=e,n&&(r[Fi]=n),r}function zi(e){return e[Ni]}var Bi;function Vi(){return Bi}function Hi(e){let t=Bi;return Bi=e,t}function Ui(e,t,n){let r=mi(e);if(r&&r.providedIn==`root`)return r.value===void 0?r.value=r.factory():r.value;if(n&8)return null;if(t!==void 0)return t;Li(e,``)}var Wi=globalThis,Gi={},Ki=`__NG_DI_FLAG__`,qi=class{injector;constructor(e){this.injector=e}retrieve(e,t){let n=Xi(t)||0;try{return this.injector.get(e,n&8?null:Gi,n)}catch(e){if(tr(e))return e;throw e}}};function Ji(e,t=0){let n=Qn();if(n===void 0)throw new ri(-203,!1);if(n===null)return Ui(e,void 0,t);{let r=Zi(t),i=n.retrieve(e,r);if(tr(i)){if(r.optional)return null;throw i}return i}}function Yi(e,t=0){return(Vi()||Ji)(di(e),t)}function w(e,t){return Yi(e,Xi(t))}function Xi(e){return e===void 0||typeof e==`number`?e:0|(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function Zi(e){return{optional:!!(e&8),host:!!(e&1),self:!!(e&2),skipSelf:!!(e&4)}}function Qi(e){let t=[];for(let n=0;nArray.isArray(e)?ra(e,t):t(e))}function ia(e,t,n){t>=e.length?e.push(n):e.splice(t,0,n)}function aa(e,t){return t>=e.length-1?e.pop():e.splice(t,1)[0]}function oa(e,t){let n=[];for(let r=0;rt;){let t=i-2;e[i]=e[t],i--}e[t]=n,e[t+1]=r}}function ca(e,t,n){let r=ua(e,t);return r>=0?e[r|1]=n:(r=~r,sa(e,r,t,n)),r}function la(e,t){let n=ua(e,t);if(n>=0)return e[n|1]}function ua(e,t){return da(e,t,1)}function da(e,t,n){let r=0,i=e.length>>n;for(;i!==r;){let a=r+(i-r>>1),o=e[a<t?i=a:r=a+1}return~(i<{n.push(e)};return ra(t,e=>{let t=e;xa(t,a,[],r)&&(i||=[],i.push(t))}),i!==void 0&&ba(i,a),n}function ba(e,t){for(let n=0;n{t(e,r)})}}function xa(e,t,n,r){if(e=di(e),!e)return!1;let i=null,a=_i(e),o=!a&&Oi(e);if(!a&&!o){let t=e.ngModule;if(a=_i(t),a)i=t;else return!1}else if(o&&!o.standalone)return!1;else i=e;let s=r.has(i);if(o){if(s)return!1;if(r.add(i),o.dependencies){let e=typeof o.dependencies==`function`?o.dependencies():o.dependencies;for(let i of e)xa(i,t,n,r)}}else if(a){if(a.imports!=null&&!s){r.add(i);let e;try{ra(a.imports,i=>{xa(i,t,n,r)&&(e||=[],e.push(i))})}finally{}e!==void 0&&ba(e,t)}if(!s){let e=ea(i)||(()=>new i);t({provide:i,useFactory:e,deps:pa},i),t({provide:ga,useValue:i,multi:!0},i),t({provide:ma,useValue:()=>Yi(i),multi:!0},i)}let o=a.providers;if(o!=null&&!s){let n=e;Sa(o,e=>{t(e,n)})}}else return!1;return i!==e&&e.providers!==void 0}function Sa(e,t){for(let n of e)xi(n)&&(n=n.ɵproviders),Array.isArray(n)?Sa(n,t):t(n)}var Ca=oi({provide:String,useValue:oi});function wa(e){return typeof e==`object`&&!!e&&Ca in e}function Ta(e){return!!(e&&e.useExisting)}function Ea(e){return!!(e&&e.useFactory)}function Da(e){return typeof e==`function`}var Oa=new bi(``),ka={},Aa={},ja=void 0;function Ma(){return ja===void 0&&(ja=new _a),ja}var Na=class{},Pa=class extends Na{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(e,t,n,r){super(),this.parent=t,this.source=n,this.scopes=r,Wa(e,e=>this.processProvider(e)),this.records.set(ha,Ba(void 0,this)),r.has(`environment`)&&this.records.set(Na,Ba(void 0,this));let i=this.records.get(Oa);i!=null&&typeof i.value==`string`&&this.scopes.add(i.value),this.injectorDefTypes=new Set(this.get(ga,pa,{self:!0}))}retrieve(e,t){let n=Xi(t)||0;try{return this.get(e,Gi,n)}catch(e){if(tr(e))return e;throw e}}destroy(){za(this),this._destroyed=!0;let e=C(null);try{for(let e of this._ngOnDestroyHooks)e.ngOnDestroy();let e=this._onDestroyHooks;this._onDestroyHooks=[];for(let t of e)t()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),C(e)}}onDestroy(e){return za(this),this._onDestroyHooks.push(e),()=>this.removeOnDestroy(e)}runInContext(e){za(this);let t=$n(this),n=Hi(void 0);try{return e()}finally{$n(t),Hi(n)}}get(e,t=Gi,n){if(za(this),Object.hasOwn(e,Di))return e[Di](this);let r=Xi(n),i=$n(this),a=Hi(void 0);try{if(!(r&4)){let t=this.records.get(e);if(t===void 0){let n=Ua(e)&&mi(e);t=n&&this.injectableDefInScope(n)?Ba(Fa(e),ka):null,this.records.set(e,t)}if(t!=null)return this.hydrate(e,t,r)}let n=r&2?Ma():this.parent;return t=r&8&&t===Gi?null:t,n.get(e,t)}catch(e){let t=zi(e);throw t===-200||t===-201?new ri(t,null):e}finally{Hi(a),$n(i)}}resolveInjectorInitializers(){let e=C(null),t=$n(this),n=Hi(void 0);try{let e=this.get(ma,pa,{self:!0});for(let t of e)t()}finally{$n(t),Hi(n),C(e)}}toString(){return`R3Injector[...]`}processProvider(e){e=di(e);let t=Da(e)?e:di(e&&e.provide),n=La(e);if(!Da(e)&&e.multi===!0){let n=this.records.get(t);n||(n=Ba(void 0,ka,!0),n.factory=()=>Qi(n.multi),this.records.set(t,n)),t=e,n.multi.push(e)}this.records.set(t,n)}hydrate(e,t,n){let r=C(null);try{if(t.value===Aa)throw Ii(``);return t.value===ka&&(t.value=Aa,t.value=t.factory(void 0,n)),typeof t.value==`object`&&t.value&&Ha(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}finally{C(r)}}injectableDefInScope(e){if(!e.providedIn)return!1;let t=di(e.providedIn);return typeof t==`string`?t===`any`||this.scopes.has(t):this.injectorDefTypes.has(t)}removeOnDestroy(e){let t=this._onDestroyHooks.indexOf(e);t!==-1&&this._onDestroyHooks.splice(t,1)}};function Fa(e){let t=mi(e),n=t===null?ea(e):t.factory;if(n!==null)return n;if(e instanceof bi)throw new ri(-204,!1);if(e instanceof Function)return Ia(e);throw new ri(-204,!1)}function Ia(e){if(e.length>0)throw new ri(-204,!1);let t=gi(e);return t===null?()=>new e:()=>t.factory(e)}function La(e){return wa(e)?Ba(void 0,e.useValue):Ba(Ra(e),ka)}function Ra(e,t,n){let r;if(Da(e)){let t=di(e);return ea(t)||Fa(t)}if(wa(e))r=()=>di(e.useValue);else if(Ea(e))r=()=>e.useFactory(...Qi(e.deps||[]));else if(Ta(e))r=(t,n)=>Yi(di(e.useExisting),n!==void 0&&n&8?8:void 0);else{let t=di(e&&(e.useClass||e.provide));if(Va(e))r=()=>new t(...Qi(e.deps));else return ea(t)||Fa(t)}return r}function za(e){if(e.destroyed)throw new ri(-205,!1)}function Ba(e,t,n=!1){return{factory:e,value:t,multi:n?[]:void 0}}function Va(e){return!!e.deps}function Ha(e){return typeof e==`object`&&!!e&&typeof e.ngOnDestroy==`function`}function Ua(e){return typeof e==`function`||typeof e==`object`&&e.ngMetadataName===`InjectionToken`}function Wa(e,t){for(let n of e)Array.isArray(n)?Wa(n,t):n&&xi(n)?Wa(n.ɵproviders,t):t(n)}function Ga(e,t){let n;e instanceof Pa?(za(e),n=e):n=new qi(e);let r=$n(n),i=Hi(void 0);try{return t()}finally{$n(r),Hi(i)}}function Ka(){return Vi()!==void 0||Qn()!=null}var qa=1;function Ja(e){return Array.isArray(e)&&typeof e[qa]==`object`}function Ya(e){return Array.isArray(e)&&e[qa]===!0}function Xa(e){return!!(e.flags&4)}function Za(e){return e.componentOffset>-1}function Qa(e){return(e.flags&1)==1}function $a(e){return!!e.template}function eo(e){return!!(e[2]&512)}function to(e){return(e[2]&256)==256}var no=(function(e){return e[e.NONE=0]=`NONE`,e[e.HTML=1]=`HTML`,e[e.STYLE=2]=`STYLE`,e[e.SCRIPT=3]=`SCRIPT`,e[e.URL=4]=`URL`,e[e.RESOURCE_URL=5]=`RESOURCE_URL`,e[e.ATTRIBUTE_NO_BINDING=6]=`ATTRIBUTE_NO_BINDING`,e})(no||{}),ro=`math`;function io(e){for(;Array.isArray(e);)e=e[0];return e}function ao(e,t){return io(t[e])}function oo(e,t){return io(t[e.index])}function so(e,t){return e.data[t]}function co(e,t){return e[t]}function lo(e,t,n,r){n>=e.data.length&&(e.data[n]=null,e.blueprint[n]=null),t[n]=r}function uo(e,t){let n=t[e];return Ja(n)?n:n[0]}function fo(e){return(e[2]&128)==128}function po(e){return Ya(e[3])}function mo(e,t){return t==null?null:e[t]}function ho(e){e[17]=0}function go(e){e[2]&1024||(e[2]|=1024,fo(e)&&bo(e))}function _o(e,t){for(;e>0;)t=t[14],e--;return t}function vo(e){return!!(e[2]&9216||e[24]?.dirty)}function yo(e){e[10].changeDetectionScheduler?.notify(8),e[2]&64&&(e[2]|=1024),vo(e)&&bo(e)}function bo(e){e[10].changeDetectionScheduler?.notify(0);let t=Co(e);for(;t!==null&&!(t[2]&8192||(t[2]|=8192,!fo(t)));)t=Co(t)}function xo(e,t){if(to(e))throw new ri(911,!1);e[21]===null&&(e[21]=[]),e[21].push(t)}function So(e,t){if(e[21]===null)return;let n=e[21].indexOf(t);n!==-1&&e[21].splice(n,1)}function Co(e){let t=e[3];return Ya(t)?t[3]:t}function wo(e){return e[7]??=[]}function To(e){return e.cleanup??=[]}function Eo(e,t,n,r){let i=wo(t);i.push(n),e.firstCreatePass&&To(e).push(r,i.length-1)}var Do={lFrame:cs(null),bindingsEnabled:!0,skipHydrationRootTNode:null},Oo=!1;function ko(){return Do.lFrame.elementDepthCount}function Ao(){Do.lFrame.elementDepthCount++}function jo(){Do.lFrame.elementDepthCount--}function Mo(){return Do.bindingsEnabled}function No(){return Do.skipHydrationRootTNode!==null}function Po(e){return Do.skipHydrationRootTNode===e}function Fo(){Do.skipHydrationRootTNode=null}function T(){return Do.lFrame.lView}function Io(){return Do.lFrame.tView}function E(e){return Do.lFrame.contextLView=e,e[8]}function D(e){return Do.lFrame.contextLView=null,e}function Lo(){let e=Ro();for(;e!==null&&e.type===64;)e=e.parent;return e}function Ro(){return Do.lFrame.currentTNode}function zo(){let e=Do.lFrame,t=e.currentTNode;return e.isParent?t:t.parent}function Bo(e,t){let n=Do.lFrame;n.currentTNode=e,n.isParent=t}function Vo(){return Do.lFrame.isParent}function Ho(){Do.lFrame.isParent=!1}function Uo(){return Do.lFrame.contextLView}function Wo(){return Oo}function Go(e){let t=Oo;return Oo=e,t}function Ko(){let e=Do.lFrame,t=e.bindingRootIndex;return t===-1&&(t=e.bindingRootIndex=e.tView.bindingStartIndex),t}function qo(){return Do.lFrame.bindingIndex}function Jo(e){return Do.lFrame.bindingIndex=e}function Yo(){return Do.lFrame.bindingIndex++}function Xo(e){let t=Do.lFrame,n=t.bindingIndex;return t.bindingIndex+=e,n}function Zo(){return Do.lFrame.inI18n}function Qo(e,t){let n=Do.lFrame;n.bindingIndex=n.bindingRootIndex=e,es(t)}function $o(){return Do.lFrame.currentDirectiveIndex}function es(e){Do.lFrame.currentDirectiveIndex=e}function ts(e){let t=Do.lFrame.currentDirectiveIndex;return t===-1?null:e[t]}function ns(){return Do.lFrame.currentQueryIndex}function rs(e){Do.lFrame.currentQueryIndex=e}function is(e){let t=e[1];return t.type===2?t.declTNode:t.type===1?e[5]:null}function as(e,t,n){if(n&4){let r=t,i=e;for(;r=r.parent,r===null&&!(n&1)&&(r=is(i),!(r===null||(i=i[14],r.type&10))););if(r===null)return!1;t=r,e=i}let r=Do.lFrame=ss();return r.currentTNode=t,r.lView=e,!0}function os(e){let t=ss(),n=e[1];Do.lFrame=t,t.currentTNode=n.firstChild,t.lView=e,t.tView=n,t.contextLView=e,t.bindingIndex=n.bindingStartIndex,t.inI18n=!1}function ss(){let e=Do.lFrame,t=e===null?null:e.child;return t===null?cs(e):t}function cs(e){let t={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return e!==null&&(e.child=t),t}function ls(){let e=Do.lFrame;return Do.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}var us=ls;function ds(){let e=ls();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function fs(e){return(Do.lFrame.contextLView=_o(e,Do.lFrame.contextLView))[8]}function ps(){return Do.lFrame.selectedIndex}function ms(e){Do.lFrame.selectedIndex=e}function hs(){let e=Do.lFrame;return so(e.tView,e.selectedIndex)}function O(){Do.lFrame.currentNamespace=`svg`}function gs(){_s()}function _s(){Do.lFrame.currentNamespace=null}function vs(){return Do.lFrame.currentNamespace}var ys=!0;function bs(){return ys}function xs(e){ys=e}function Ss(e,t=null,n=null,r){let i=Cs(e,t,n,r);return i.resolveInjectorInitializers(),i}function Cs(e,t=null,n=null,r,i=new Set){return new Pa([n||pa,va(e)],t||Ma(),null,i)}var ws=class e{static THROW_IF_NOT_FOUND=Gi;static NULL=new _a;static create(e,t){if(Array.isArray(e))return Ss({name:``},t,e,``);{let t=e.name??``;return Ss({name:t},e.parent,e.providers,t)}}static ɵprov=pi({token:e,providedIn:`any`,factory:()=>Yi(ha)});static __NG_ELEMENT_ID__=-1},Ts=new bi(``),Es=class{static __NG_ELEMENT_ID__=Os;static __NG_ENV_ID__=e=>e},Ds=class extends Es{_lView;constructor(e){super(),this._lView=e}get destroyed(){return to(this._lView)}onDestroy(e){let t=this._lView;return xo(t,e),()=>So(t,e)}};function Os(){return new Ds(T())}var ks=new bi(``),As=(()=>{class e{taskId=0;pendingTasks=new Set;destroyed=!1;pendingTask=new ei(!1);debugTaskTracker=w(ks,{optional:!0});get hasPendingTasks(){return!this.destroyed&&this.pendingTask.value}get hasPendingTasksObservable(){return this.destroyed?new Ur(e=>{e.next(!1),e.complete()}):this.pendingTask}add(){!this.hasPendingTasks&&!this.destroyed&&this.pendingTask.next(!0);let e=this.taskId++;return this.pendingTasks.add(e),this.debugTaskTracker?.add(e),e}has(e){return this.pendingTasks.has(e)}remove(e){this.pendingTasks.delete(e),this.debugTaskTracker?.remove(e),this.pendingTasks.size===0&&this.hasPendingTasks&&this.pendingTask.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this.hasPendingTasks&&this.pendingTask.next(!1),this.destroyed=!0,this.pendingTask.unsubscribe()}static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),js=class extends Qr{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(e=!1){super(),this.__isAsync=e,Ka()&&(this.destroyRef=w(Es,{optional:!0})??void 0,this.pendingTasks=w(As,{optional:!0})??void 0)}emit(e){let t=C(null);try{super.next(e)}finally{C(t)}}subscribe(e,t,n){let r=e,i=t||(()=>null),a=n;if(e&&typeof e==`object`){let t=e;r=t.next?.bind(t),i=t.error?.bind(t),a=t.complete?.bind(t)}this.__isAsync&&(i=this.wrapInTimeout(i),r&&=this.wrapInTimeout(r),a&&=this.wrapInTimeout(a));let o=super.subscribe({next:r,error:i,complete:a});return e instanceof gr&&e.add(o),o}wrapInTimeout(e){return t=>{let n=this.pendingTasks?.add();setTimeout(()=>{try{e(t)}finally{n!==void 0&&this.pendingTasks?.remove(n)}})}}};function Ms(...e){}function Ns(e){let t,n;function r(){e=Ms;try{n!==void 0&&typeof cancelAnimationFrame==`function`&&cancelAnimationFrame(n),t!==void 0&&clearTimeout(t)}catch{}}return t=setTimeout(()=>{e(),r()}),typeof requestAnimationFrame==`function`&&(n=requestAnimationFrame(()=>{e(),r()})),()=>r()}function Ps(e){return queueMicrotask(()=>e()),()=>{e=Ms}}var Fs=`isAngularZone`,Is=`isAngularZone_ID`,Ls=0,Rs=class e{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new js(!1);onMicrotaskEmpty=new js(!1);onStable=new js(!1);onError=new js(!1);constructor(e){let{enableLongStackTrace:t=!1,shouldCoalesceEventChangeDetection:n=!1,shouldCoalesceRunChangeDetection:r=!1,scheduleInRootZone:i=!1}=e;if(typeof Zone>`u`)throw new ri(908,!1);Zone.assertZonePatched();let a=this;a._nesting=0,a._outer=a._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(a._inner=a._inner.fork(new Zone.TaskTrackingZoneSpec)),t&&Zone.longStackTraceZoneSpec&&(a._inner=a._inner.fork(Zone.longStackTraceZoneSpec)),a.shouldCoalesceEventChangeDetection=!r&&n,a.shouldCoalesceRunChangeDetection=r,a.callbackScheduled=!1,a.scheduleInRootZone=i,Hs(a)}static isInAngularZone(){return typeof Zone<`u`&&Zone.current.get(Fs)===!0}static assertInAngularZone(){if(!e.isInAngularZone())throw new ri(909,!1)}static assertNotInAngularZone(){if(e.isInAngularZone())throw new ri(909,!1)}run(e,t,n){return this._inner.run(e,t,n)}runTask(e,t,n,r){let i=this._inner,a=i.scheduleEventTask(`NgZoneEvent: `+r,e,zs,Ms,Ms);try{return i.runTask(a,t,n)}finally{i.cancelTask(a)}}runGuarded(e,t,n){return this._inner.runGuarded(e,t,n)}runOutsideAngular(e){return this._outer.run(e)}},zs={};function Bs(e){if(e._nesting==0&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function Vs(e){if(e.isCheckStableRunning||e.callbackScheduled)return;e.callbackScheduled=!0;function t(){Ns(()=>{e.callbackScheduled=!1,Us(e),e.isCheckStableRunning=!0,Bs(e),e.isCheckStableRunning=!1})}e.scheduleInRootZone?Zone.root.run(()=>{t()}):e._outer.run(()=>{t()}),Us(e)}function Hs(e){let t=()=>{Vs(e)},n=Ls++;e._inner=e._inner.fork({name:`angular`,properties:{[Fs]:!0,[Is]:n,[Is+n]:!0},onInvokeTask:(n,r,i,a,o,s)=>{if(qs(s))return n.invokeTask(i,a,o,s);try{return Ws(e),n.invokeTask(i,a,o,s)}finally{(e.shouldCoalesceEventChangeDetection&&a.type===`eventTask`||e.shouldCoalesceRunChangeDetection)&&t(),Gs(e)}},onInvoke:(n,r,i,a,o,s,c)=>{try{return Ws(e),n.invoke(i,a,o,s,c)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!Js(s)&&t(),Gs(e)}},onHasTask:(t,n,r,i)=>{t.hasTask(r,i),n===r&&(i.change==`microTask`?(e._hasPendingMicrotasks=i.microTask,Us(e),Bs(e)):i.change==`macroTask`&&(e.hasPendingMacrotasks=i.macroTask))},onHandleError:(t,n,r,i)=>(t.handleError(r,i),e.runOutsideAngular(()=>e.onError.emit(i)),!1)})}function Us(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&e.callbackScheduled===!0)}function Ws(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function Gs(e){e._nesting--,Bs(e)}var Ks=class{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new js;onMicrotaskEmpty=new js;onStable=new js;onError=new js;run(e,t,n){return e.apply(t,n)}runGuarded(e,t,n){return e.apply(t,n)}runOutsideAngular(e){return e()}runTask(e,t,n,r){return e.apply(t,n)}};function qs(e){return Ys(e,`__ignore_ng_zone__`)}function Js(e){return Ys(e,`__scheduler_tick__`)}function Ys(e,t){return!Array.isArray(e)||e.length!==1?!1:e[0]?.data?.[t]===!0}var Xs=class{_console=console;handleError(e){this._console.error(`ERROR`,e)}},Zs=new bi(``,{factory:()=>{let e=w(Rs),t=w(Na),n;return r=>{e.runOutsideAngular(()=>{t.destroyed&&!n?setTimeout(()=>{throw r}):(n??=t.get(Xs),n.handleError(r))})}}}),Qs={provide:ma,useValue:()=>{w(Xs,{optional:!0})},multi:!0};function k(e,t){let[n,r,i]=Un(e,t?.equal),a=n;return a[fn],a.set=r,a.update=i,a.asReadonly=$s.bind(a),a}function $s(){let e=this[fn];if(e.readonlyFn===void 0){let t=()=>this();t[fn]=e,e.readonlyFn=t}return e.readonlyFn}var ec=new bi(``,{factory:()=>tc}),tc=`ng`,nc=new bi(``),rc=new bi(``,{providedIn:`platform`,factory:()=>`unknown`}),ic=new bi(``,{factory:()=>w(Ts).body?.querySelector(`[ngCspNonce]`)?.getAttribute(`ngCspNonce`)||null}),ac=(()=>{class e{view;node;constructor(e,t){this.view=e,this.node=t}static __NG_ELEMENT_ID__=oc}return e})();function oc(){return new ac(T(),Lo())}var sc=class{},cc=new bi(``,{factory:()=>!0}),lc=new bi(``),uc=(()=>{class e{static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new dc})}return e})(),dc=class{dirtyEffectCount=0;queues=new Map;add(e){this.enqueue(e),this.schedule(e)}schedule(e){e.dirty&&this.dirtyEffectCount++}remove(e){let t=e.zone,n=this.queues.get(t);n.has(e)&&(n.delete(e),e.dirty&&this.dirtyEffectCount--)}enqueue(e){let t=e.zone;this.queues.has(t)||this.queues.set(t,new Set);let n=this.queues.get(t);n.has(e)||n.add(e)}flush(){for(;this.dirtyEffectCount>0;){let e=!1;for(let[t,n]of this.queues)e||=t===null?this.flushQueue(n):t.run(()=>this.flushQueue(n));e||(this.dirtyEffectCount=0)}}flushQueue(e){let t=!1;for(let n of e)n.dirty&&(this.dirtyEffectCount--,t=!0,n.run());return t}},fc=class{[fn];constructor(e){this[fn]=e}destroy(){this[fn].destroy()}};function pc(e,t){let n=t?.injector??w(ws),r=t?.manualCleanup===!0?null:n.get(Es),i,a=n.get(ac,null,{optional:!0}),o=n.get(sc);return a===null?i=vc(e,n.get(uc),o):(i=_c(a.view,o,e),r instanceof Ds&&r._lView===a.view&&(r=null)),i.injector=n,r!==null&&(i.onDestroyFns=[r.onDestroy(()=>i.destroy())]),new fc(i)}var mc={...Yn,cleanupFns:void 0,zone:null,onDestroyFns:null,run(){let e=Go(!1);try{Xn(this)}finally{Go(e)}},cleanup(){if(!this.cleanupFns?.length)return;let e=C(null);try{for(;this.cleanupFns.length;)this.cleanupFns.pop()()}finally{this.cleanupFns=[],C(e)}}},hc={...mc,consumerMarkedDirty(){this.scheduler.schedule(this),this.notifier.notify(12)},destroy(){if(Dn(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.scheduler.remove(this)}},gc={...mc,consumerMarkedDirty(){this.view[2]|=8192,bo(this.view),this.notifier.notify(13)},destroy(){if(Dn(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.view[23]?.delete(this)}};function _c(e,t,n){let r=Object.create(gc);return r.view=e,r.zone=typeof Zone<`u`?Zone.current:null,r.notifier=t,r.fn=yc(r,n),e[23]??=new Set,e[23].add(r),r.consumerMarkedDirty(r),r}function vc(e,t,n){let r=Object.create(hc);return r.fn=yc(r,e),r.scheduler=t,r.notifier=n,r.zone=typeof Zone<`u`?Zone.current:null,r.scheduler.add(r),r.notifier.notify(12),r}function yc(e,t){return()=>{t(t=>(e.cleanupFns??=[]).push(t))}}function bc(e){return typeof e==`function`&&e[fn]!==void 0}function xc(e){return bc(e)&&typeof e.set==`function`}var Sc=Symbol(`InputSignalNode#UNSET`),Cc={...qn,transformFn:void 0,applyValueToInputSignal(e,t){Gn(e,t)}};function wc(e){return{toString:e}.toString()}var Tc=(function(e){return e[e.TemplateCreateStart=0]=`TemplateCreateStart`,e[e.TemplateCreateEnd=1]=`TemplateCreateEnd`,e[e.TemplateUpdateStart=2]=`TemplateUpdateStart`,e[e.TemplateUpdateEnd=3]=`TemplateUpdateEnd`,e[e.LifecycleHookStart=4]=`LifecycleHookStart`,e[e.LifecycleHookEnd=5]=`LifecycleHookEnd`,e[e.OutputStart=6]=`OutputStart`,e[e.OutputEnd=7]=`OutputEnd`,e[e.BootstrapApplicationStart=8]=`BootstrapApplicationStart`,e[e.BootstrapApplicationEnd=9]=`BootstrapApplicationEnd`,e[e.BootstrapComponentStart=10]=`BootstrapComponentStart`,e[e.BootstrapComponentEnd=11]=`BootstrapComponentEnd`,e[e.ChangeDetectionStart=12]=`ChangeDetectionStart`,e[e.ChangeDetectionEnd=13]=`ChangeDetectionEnd`,e[e.ChangeDetectionSyncStart=14]=`ChangeDetectionSyncStart`,e[e.ChangeDetectionSyncEnd=15]=`ChangeDetectionSyncEnd`,e[e.AfterRenderHooksStart=16]=`AfterRenderHooksStart`,e[e.AfterRenderHooksEnd=17]=`AfterRenderHooksEnd`,e[e.ComponentStart=18]=`ComponentStart`,e[e.ComponentEnd=19]=`ComponentEnd`,e[e.DeferBlockStateStart=20]=`DeferBlockStateStart`,e[e.DeferBlockStateEnd=21]=`DeferBlockStateEnd`,e[e.DynamicComponentStart=22]=`DynamicComponentStart`,e[e.DynamicComponentEnd=23]=`DynamicComponentEnd`,e[e.HostBindingsUpdateStart=24]=`HostBindingsUpdateStart`,e[e.HostBindingsUpdateEnd=25]=`HostBindingsUpdateEnd`,e})(Tc||{}),Ec=class{previousValue;currentValue;firstChange;constructor(e,t,n){this.previousValue=e,this.currentValue=t,this.firstChange=n}isFirstChange(){return this.firstChange}};function Dc(e,t,n,r){t===null?e[n]=r:t.applyValueToInputSignal(t,r)}var Oc=null,kc=(()=>{Oc=jc;let e=()=>jc;return e.ngInherit=!0,e})();function Ac(){return Oc}function jc(e){return e.type.prototype.ngOnChanges&&(e.setInput=Nc),Mc}function Mc(){let e=Fc(this),t=e?.current;if(t){let n=e.previous;if(n===fa)e.previous=t;else for(let e in t)n[e]=t[e];e.current=null,this.ngOnChanges(t)}}function Nc(e,t,n,r,i){let a=this.declaredInputs[r],o=Fc(e)||Ic(e,{previous:fa,current:null}),s=o.current||={},c=o.previous,l=c[a];s[a]=new Ec(l&&l.currentValue,n,c===fa),Dc(e,t,i,n)}var Pc=`__ngSimpleChanges__`;function Fc(e){return Object.hasOwn(e,Pc)&&e[Pc]||null}function Ic(e,t){return e[Pc]=t}var Lc=[],Rc=function(e,t=null,n){for(let r=0;r=r)break}else t[c]<0&&(e[17]+=65536),(s>14>16&&(e[2]&3)===t&&(e[2]+=16384,Gc(o,a)):Gc(o,a)}var qc=-1,Jc=class{factory;name;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(e,t,n,r){this.factory=e,this.name=r,this.canSeeViewProviders=t,this.injectImpl=n}};function Yc(e){return!!(e.flags&8)}function Xc(e){return!!(e.flags&16)}function Zc(e,t,n){let r=0;for(;rt){o=a-1;break}}}for(;a>16}function al(e,t){let n=il(e),r=t;for(;n>0;)r=r[14],n--;return r}var ol=!0;function sl(e){let t=ol;return ol=e,t}var cl=255,ll=5,ul=0,dl={};function fl(e,t,n){let r;typeof n==`string`?r=n.charCodeAt(0)||0:Object.hasOwn(n,Ei)&&(r=n[Ei]),r??=n[Ei]=ul++;let i=r&cl,a=1<>ll)]|=a}function pl(e,t){let n=hl(e,t);if(n!==-1)return n;let r=t[1];r.firstCreatePass&&(e.injectorIndex=t.length,ml(r.data,e),ml(t,null),ml(r.blueprint,null));let i=gl(e,t),a=e.injectorIndex;if(nl(i)){let e=rl(i),n=al(i,t),r=n[1].data;for(let i=0;i<8;i++)t[a+i]=n[e+i]|r[e+i]}return t[a+8]=i,a}function ml(e,t){e.push(0,0,0,0,0,0,0,0,t)}function hl(e,t){return e.injectorIndex===-1||e.parent&&e.parent.injectorIndex===e.injectorIndex||t[e.injectorIndex+8]===null?-1:e.injectorIndex}function gl(e,t){if(e.parent&&e.parent.injectorIndex!==-1)return e.parent.injectorIndex;let n=0,r=null,i=t;for(;i!==null;){if(r=jl(i),r===null)return qc;if(n++,i=i[14],r.injectorIndex!==-1)return r.injectorIndex|n<<16}return qc}function _l(e,t,n){fl(e,t,n)}function vl(e,t,n){if(n&8||e!==void 0)return e;Li(t,`NodeInjector`)}function yl(e,t,n,r){if(n&8&&r===void 0&&(r=null),!(n&3)){let i=e[9],a=Hi(void 0);try{return i?i.get(t,r,n&8):Ui(t,r,n&8)}finally{Hi(a)}}return vl(r,t,n)}function bl(e,t,n,r=0,i){if(e!==null){if(t[2]&2048&&!(r&2)){let i=Al(e,t,n,r,dl);if(i!==dl)return i}let i=xl(e,t,n,r,dl);if(i!==dl)return i}return yl(t,n,r,i)}function xl(e,t,n,r,i){let a=Tl(n);if(typeof a==`function`){if(!as(t,e,r))return r&1?vl(i,n,r):yl(t,n,r,i);try{let e;if(e=a(r),e==null&&!(r&8))Li(n);else return e}finally{us()}}else if(typeof a==`number`){let i=null,o=hl(e,t),s=qc,c=r&1?t[15][5]:null;for((o===-1||r&4)&&(s=o===-1?gl(e,t):t[o+8],s===qc||!Dl(r,!1)?o=-1:(i=t[1],o=rl(s),t=al(s,t)));o!==-1;){let e=t[1];if(El(a,o,e.data)){let e=Sl(o,t,n,i,r,c);if(e!==dl)return e}s=t[o+8],s!==qc&&Dl(r,t[1].data[o+8]===c)&&El(a,o,t)?(i=e,o=rl(s),t=al(s,t)):o=-1}}return i}function Sl(e,t,n,r,i,a){let o=t[1],s=o.data[e+8],c=Cl(s,o,n,r==null?Za(s)&&ol:r!=o&&!!(s.type&3),i&1&&a===s);return c===null?dl:wl(t,o,c,s,i)}function Cl(e,t,n,r,i){let a=e.providerIndexes,o=t.data,s=a&1048575,c=e.directiveStart,l=e.directiveEnd,u=a>>20,d=r?s:s+u,f=i?s+u:l;for(let e=d;e=c&&t.type===n)return e}if(i){let e=o[c];if(e&&$a(e)&&e.type===n)return c}return null}function wl(e,t,n,r,i){let a=e[n],o=t.data;if(a instanceof Jc){let s=a;if(s.resolving)throw Ii(``);let c=sl(s.canSeeViewProviders);s.resolving=!0,o[n].type||o[n];let l=s.injectImpl?Hi(s.injectImpl):null;as(e,r,0);try{a=e[n]=s.factory(void 0,i,o,e,r),t.firstCreatePass&&n>=r.directiveStart&&zc(n,o[n],t)}finally{l!==null&&Hi(l),sl(c),s.resolving=!1,us()}}return a}function Tl(e){if(typeof e==`string`)return e.charCodeAt(0)||0;let t=Object.hasOwn(e,Ei)?e[Ei]:void 0;return typeof t==`number`?t>=0?t&cl:kl:t}function El(e,t,n){let r=1<>ll)]&r)}function Dl(e,t){return!(e&2)&&!(e&1&&t)}var Ol=class{_tNode;_lView;constructor(e,t){this._tNode=e,this._lView=t}get(e,t,n){return bl(this._tNode,this._lView,e,Xi(n),t)}};function kl(){return new Ol(Lo(),T())}function Al(e,t,n,r,i){let a=e,o=t;for(;a!==null&&o!==null&&o[2]&2048&&!eo(o);){let e=xl(a,o,n,r|2,dl);if(e!==dl)return e;r&=-5;let t=a.parent;if(!t){let e=o[20];if(e){let t=e.get(n,dl,r);if(t!==dl)return t}t=jl(o),o=o[14]}a=t}return i}function jl(e){let t=e[1],n=t.type;return n===2?t.declTNode:n===1?e[5]:null}function Ml(e){return{token:e.token,providedIn:e.autoProvided===!1?null:`root`,factory:e.factory,value:void 0}}function Nl(){return Pl(Lo(),T())}function Pl(e,t){return new Fl(oo(e,t))}var Fl=(()=>{class e{nativeElement;constructor(e){this.nativeElement=e}static __NG_ELEMENT_ID__=Nl}return e})();function Il(e){return e instanceof Fl?e.nativeElement:e}function Ll(){return this._results[Symbol.iterator]()}var Rl=class{_emitDistinctChangesOnly;dirty=!0;_onDirty=void 0;_results=[];_changesDetected=!1;_changes=void 0;length=0;first=void 0;last=void 0;get changes(){return this._changes??=new Qr}constructor(e=!1){this._emitDistinctChangesOnly=e}get(e){return this._results[e]}map(e){return this._results.map(e)}filter(e){return this._results.filter(e)}find(e){return this._results.find(e)}reduce(e,t){return this._results.reduce(e,t)}forEach(e){this._results.forEach(e)}some(e){return this._results.some(e)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(e,t){this.dirty=!1;let n=na(e);(this._changesDetected=!ta(this._results,n,t))&&(this._results=n,this.length=n.length,this.last=n[this.length-1],this.first=n[0])}notifyOnChanges(){this._changes!==void 0&&(this._changesDetected||!this._emitDistinctChangesOnly)&&this._changes.next(this)}onDirty(e){this._onDirty=e}setDirty(){this.dirty=!0,this._onDirty?.()}destroy(){this._changes!==void 0&&(this._changes.complete(),this._changes.unsubscribe())}[Symbol.iterator]=Ll};function zl(e){return(e.flags&128)==128}var Bl=(function(e){return e[e.OnPush=0]=`OnPush`,e[e.Eager=1]=`Eager`,e[e.Default=1]=`Default`,e})(Bl||{}),Vl=new Map,Hl=0;function Ul(){return Hl++}function Wl(e){Vl.set(e[19],e)}function Gl(e){Vl.delete(e[19])}var Kl=`__ngContext__`;function ql(e,t){Ja(t)?(e[Kl]=t[19],Wl(t)):e[Kl]=t}function Jl(e){return Xl(e[12])}function Yl(e){return Xl(e[4])}function Xl(e){for(;e!==null&&!Ya(e);)e=e[4];return e}var Zl=void 0;function Ql(e){Zl=e}function $l(){if(Zl!==void 0)return Zl;if(typeof document<`u`)return document;throw new ri(210,!1)}var eu=!1,tu=new bi(``,{factory:()=>eu}),nu=new WeakMap;function ru(e,t){if(typeof e!=`object`||!e)return;let n=nu.get(e);n||(n=new WeakSet,nu.set(e,n)),n.add(t)}function iu(e){return(e.flags&32)==32}var au=()=>null;function ou(e,t,n=!1){return au(e,t,n)}function su(e,t){let n=e.contentQueries;if(n!==null){let r=C(null);try{for(let r=0;r|^->||--!>|)/g,yu=`​$1​`;function bu(e){return e.replace(_u,e=>e.replace(vu,yu))}function xu(e,t){return e.createText(t)}function Su(e,t,n){e.setValue(t,n)}function Cu(e,t){return e.createComment(bu(t))}function wu(e,t,n){return e.createElement(t,n)}function Tu(e,t,n,r,i){e.insertBefore(t,n,r,i)}function Eu(e,t,n){e.appendChild(t,n)}function Du(e,t,n,r,i){r===null?Eu(e,t,n):Tu(e,t,n,r,i)}function Ou(e,t,n,r){e.removeChild(null,t,n,r)}function ku(e,t,n){e.setAttribute(t,`style`,n)}function Au(e,t,n){n===``?e.removeAttribute(t,`class`):e.setAttribute(t,`class`,n)}function ju(e,t,n){let{mergedAttrs:r,classes:i,styles:a}=n;r!==null&&Zc(e,t,r),i!==null&&Au(e,t,i),a!==null&&ku(e,t,a)}function Mu(e){let t=Nu();return t?t.sanitize(no.URL,e)||``:pu(e,`URL`)?fu(e):gu(Mi(e))}function Nu(){let e=T();return e&&e[10].sanitizer}function Pu(e){return e.ownerDocument.defaultView}function Fu(e){return e.ownerDocument}function Iu(e,t,n){let r=e.length;for(;;){let i=e.indexOf(t,n);if(i===-1)return i;if(i===0||e.charCodeAt(i-1)<=32){let n=t.length;if(i+n===r||e.charCodeAt(i+n)<=32)return i}n=i+1}}var Lu=`ng-template`;function Ru(e,t,n,r){let i=0;if(r){for(;i-1){let e;for(;++ia?``:i[u+1].toLowerCase(),r&2&&l!==e){if(Hu(r))return!1;o=!0}}}}}return Hu(r)||o}function Hu(e){return!(e&1)}function Uu(e,t,n,r){if(t===null)return-1;let i=0;if(r||!n){let n=!1;for(;i-1)for(n++;n0?`="`+t+`"`:``)+`]`}else r&8?i+=`.`+o:r&4&&(i+=` `+o)}else i!==``&&!Hu(o)&&(t+=Yu(a,i),i=``),r=o,a||=!Hu(r);n++}return i!==``&&(t+=Yu(a,i)),t}function Zu(e){return e.map(Xu).join(`,`)}function Qu(e){let t=[],n=[],r=1,i=2;for(;r!1});function id(e){if(!e)return 0;let t=e.toLowerCase().indexOf(`ms`)>-1?1:1e3;return parseFloat(e)*t}function ad(e,t){return e.getPropertyValue(t).split(`,`).map(e=>e.trim())}function od(e){let t=ad(e,`transition-property`),n=ad(e,`transition-duration`),r=ad(e,`transition-delay`),i={propertyName:``,duration:0,animationName:void 0};for(let e=0;ei.duration&&(i.propertyName=t[e],i.duration=a)}return i}function sd(e){let t=ad(e,`animation-name`),n=ad(e,`animation-delay`),r=ad(e,`animation-duration`),i=ad(e,`animation-iteration-count`),a={animationName:``,propertyName:void 0,duration:0};for(let e=0;ea.duration&&s!==`infinite`&&(a.animationName=t[e],a.duration=o)}return a}function cd(e,t){return e!==void 0&&e.duration>t.duration}function ld(e){return(e.animationName!=null||e.propertyName!=null)&&e.duration>0}function ud(e){let t=e.effect?.getTiming();if(t===void 0)return;let n=typeof t.duration==`number`?t.duration:0,r=(t.delay??0)+n,i=e.playbackRate;return i!==void 0&&i!==0&&i!==1&&(r/=Math.abs(i)),r}function dd(e,t){let n=getComputedStyle(e),r=sd(n),i=od(n),a=r.duration>i.duration?r:i;cd(t.get(e),a)||ld(a)&&t.set(e,a)}function fd(e,t,n){if(!n)return;let r=e.getAnimations();return r.length===0?dd(e,t):pd(e,t,r)}function pd(e,t,n){let r={animationName:void 0,propertyName:void 0,duration:0};for(let e of n){if(e.effect?.getTiming()?.iterations===1/0)continue;let t=ud(e)??0,n,i;e.animationName?i=e.animationName:n=e.transitionProperty,t>=r.duration&&(r={animationName:i,propertyName:n,duration:t})}cd(t.get(e),r)||ld(r)&&t.set(e,r)}var md=new Set,hd=!1,gd=1,_d=typeof document<`u`&&typeof document?.documentElement?.getAnimations==`function`;function vd(e){return e[9].get(rd,hd)}function yd(e,t,n){let r=xd.get(e);if(r){for(let e of t)r.classList.push(e);for(let e of n)r.cleanupFns.push(e)}else xd.set(e,{classList:t,cleanupFns:n})}function bd(e){let t=xd.get(e);if(t){for(let e of t.cleanupFns)e();xd.delete(e)}Sd.delete(e)}var xd=new WeakMap,Sd=new WeakMap,Cd=new WeakMap;function wd(e){return e?e[14]??e:null}var Td=new WeakSet;function Ed(e,t,n){let r=Cd.get(e);if(!r||r.length===0)return;let i=t.parentNode,a=t.previousSibling,o=wd(n);for(let e=r.length-1;e>=0;e--){let{el:n,declarationView:s}=r[e],c=n.parentNode;n===t?(r.splice(e,1),Td.add(n),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}}))):(a&&n===a||c&&i&&c!==i&&(o===null||s===null||o===s))&&(r.splice(e,1),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}})),n.parentNode?.removeChild(n))}}function Dd(e,t,n){let r=wd(n),i=Cd.get(e);i?i.some(e=>e.el===t)||i.push({el:t,declarationView:r}):Cd.set(e,[{el:t,declarationView:r}])}function Od(e){let t=e[26]??={};return t.enter??=new Map}function kd(e){let t=typeof e==`function`?e():e,n=Array.isArray(t)?t:null;return typeof t==`string`&&(n=t.trim().split(/\s+/).filter(e=>e)),n}function Ad(e){return e.composedPath?e.composedPath()[0]:e.target}function jd(e,t){let n=Sd.get(t);if(n===void 0)return!0;if(t!==Ad(e))return!1;let r=e.animation;if(r){let e=ud(r);if(e!==void 0&&e+gd{class e{impl=null;execute(){this.impl?.execute()}static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Rd=[0,1,2,3],zd=(()=>{class e{ngZone=w(Rs);scheduler=w(sc);errorHandler=w(Xs,{optional:!0});sequences=new Set;deferredRegistrations=new Set;executing=!1;constructor(){w(Pd,{optional:!0})}execute(){let e=this.sequences.size>0;e&&Rc(Tc.AfterRenderHooksStart),this.executing=!0;for(let e of Rd)for(let t of this.sequences)if(!t.erroredOrDestroyed&&t.hooks[e])try{t.pipelinedValue=this.ngZone.runOutsideAngular(()=>this.maybeTrace(()=>{let n=t.hooks[e];return n(t.pipelinedValue)},t.snapshot))}catch(e){t.erroredOrDestroyed=!0,this.errorHandler?.handleError(e)}this.executing=!1;for(let e of this.sequences)e.afterRun(),e.once&&(this.sequences.delete(e),e.destroy());for(let e of this.deferredRegistrations)this.sequences.add(e);this.deferredRegistrations.size>0&&this.scheduler.notify(7),this.deferredRegistrations.clear(),e&&Rc(Tc.AfterRenderHooksEnd)}register(e){let{view:t}=e;t===void 0?this.executing?this.deferredRegistrations.add(e):this.addSequence(e):((t[25]??=[]).push(e),bo(t),t[2]|=8192)}addSequence(e){this.sequences.add(e),this.scheduler.notify(7)}unregister(e){this.executing&&this.sequences.has(e)?(e.erroredOrDestroyed=!0,e.pipelinedValue=void 0,e.once=!0):(this.sequences.delete(e),this.deferredRegistrations.delete(e))}maybeTrace(e,t){return t?t.run(Nd.AFTER_NEXT_RENDER,e):e()}static ɵprov=pi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Bd=class{impl;hooks;view;once;snapshot;erroredOrDestroyed=!1;pipelinedValue=void 0;unregisterOnDestroy;constructor(e,t,n,r,i,a=null){this.impl=e,this.hooks=t,this.view=n,this.once=r,this.snapshot=a,this.unregisterOnDestroy=i?.onDestroy(()=>this.destroy())}afterRun(){this.erroredOrDestroyed=!1,this.pipelinedValue=void 0,this.snapshot?.dispose(),this.snapshot=null}destroy(){this.impl.unregister(this),this.unregisterOnDestroy?.();let e=this.view?.[25];e&&(this.view[25]=e.filter(e=>e!==this))}};function Vd(e,t){let n=t?.injector??w(ws);return Id(`NgAfterNextRender`),Ud(e,n,t,!0)}function Hd(e){return e instanceof Function?[void 0,void 0,e,void 0]:[e.earlyRead,e.write,e.mixedReadWrite,e.read]}function Ud(e,t,n,r){let i=t.get(Ld);i.impl??=t.get(zd);let a=t.get(Pd,null,{optional:!0}),o=n?.manualCleanup===!0?null:t.get(Es),s=t.get(ac,null,{optional:!0}),c=new Bd(i.impl,Hd(e),s?.view,r,o,a?.snapshot(null));return i.impl.register(c),c}var Wd=new bi(``,{factory:()=>{let e=w(Na),t=new Set;return e.onDestroy(()=>t.clear()),{queue:t,isScheduled:!1,scheduler:null,injector:e}}});function Gd(e,t,n){let r=e.get(Wd);if(Array.isArray(t))for(let e of t)r.queue.add(e),n?.detachedLeaveAnimationFns?.push(e);else r.queue.add(t),n?.detachedLeaveAnimationFns?.push(t);r.scheduler&&r.scheduler(e)}function Kd(e,t){let n=e.get(Wd);if(Array.isArray(t))for(let e of t)n.queue.delete(e);else n.queue.delete(t)}function qd(e,t){let n=e.get(Wd);if(t.detachedLeaveAnimationFns){for(let e of t.detachedLeaveAnimationFns)n.queue.delete(e);t.detachedLeaveAnimationFns=void 0}}function Jd(e){let t=e.get(Wd);t.isScheduled||=(Vd(()=>{t.isScheduled=!1;for(let e of t.queue)e();t.queue.clear()},{injector:t.injector}),!0)}function Yd(e){let t=e.get(Wd);t.scheduler=Jd,t.scheduler(e)}function Xd(e,t){for(let[n,r]of t)Gd(e,r.animateFns)}function Zd(e,t,n,r){let i=e?.[26]?.enter;t!==null&&i&&i.has(n.index)&&Xd(r,i)}function Qd(e,t,n,r){try{n.get(ha)}catch{return r(!1)}let i=e?.[26];i?.enter?.has(t.index)&&Kd(n,i.enter.get(t.index).animateFns);let a=$d(e,t,i);if(a.size===0){let n=!1;if(e){let r=[];tf(e,t,r),n=r.length>0}if(!n)return r(!1)}e&&md.add(e[19]),Gd(n,()=>ef(e,t,i||void 0,a,r),i||void 0)}function $d(e,t,n){let r=new Map,i=n?.leave;if(i&&i.has(t.index)&&r.set(t.index,i.get(t.index)),e&&i)for(let[n,a]of i){if(r.has(n))continue;let i=e[1].data[n].parent;for(;i;){if(i===t){r.set(n,a);break}i=i.parent}}return r}function ef(e,t,n,r,i){let a=[];if(n&&n.leave)for(let[e]of r){if(!n.leave.has(e))continue;let t=n.leave.get(e);for(let e of t.animateFns){let{promise:t}=e();a.push(t)}n.detachedLeaveAnimationFns=void 0}if(e&&tf(e,t,a),a.length>0){let t=n||e?.[26];if(t){let n=t.running;n&&a.push(n),t.running=Promise.allSettled(a),rf(e,t.running,i)}else Promise.allSettled(a).then(()=>{e&&md.delete(e[19]),i(!0)})}else e&&md.delete(e[19]),i(!1)}function tf(e,t,n){if(t.type&12){let r=e[t.index];if(Ya(r))for(let e=10;e{e[26]?.running===t&&(e[26].running=void 0,md.delete(e[19])),n(!0)})}function af(e,t,n,r,i,a,o,s){if(i!=null){let c,l=!1;Ya(i)?c=i:Ja(i)&&(l=!0,i=i[0]);let u=io(i);e===0&&r!==null?(Zd(s,r,a,n),o==null?Eu(t,r,u):Tu(t,r,u,o||null,!0)):e===1&&r!==null?(Zd(s,r,a,n),Tu(t,r,u,o||null,!0),Ed(a,u,s)):e===2?(s?.[26]?.leave?.has(a.index)&&Dd(a,u,s),Td.delete(u),Qd(s,a,n,e=>{if(Td.has(u)){Td.delete(u);return}Ou(t,u,l,e)})):e===3&&(Td.delete(u),Qd(s,a,n,()=>{t.destroyNode(u)})),c!=null&&kf(t,e,n,c,a,r,o)}}function of(e,t){cf(e,t),t[0]=null,t[5]=null}function sf(e,t,n,r,i,a){r[0]=i,r[5]=t,Tf(e,r,n,1,i,a)}function cf(e,t){t[10].changeDetectionScheduler?.notify(9),Tf(e,t,t[11],2,null,null)}function lf(e){let t=e[12];if(!t)return ff(e[1],e);for(;t;){let n=null;if(Ja(t))n=t[12];else{let e=t[10];e&&(n=e)}if(!n){for(;t&&!t[4]&&t!==e;)Ja(t)&&ff(t[1],t),t=t[3];t===null&&(t=e),Ja(t)&&ff(t[1],t),n=t&&t[4]}t=n}}function uf(e,t){let n=e[9],r=n.indexOf(t);n.splice(r,1)}function df(e,t){if(to(t))return;let n=t[11];n.destroyNode&&Tf(e,t,n,3,null,null),lf(t)}function ff(e,t){if(to(t))return;let n=C(null);try{t[2]&=-129,t[2]|=256,t[24]&&Dn(t[24]),mf(e,t),pf(e,t),t[1].type===1&&t[11].destroy();let n=t[16];if(n!==null&&Ya(t[3])){n!==t[3]&&uf(n,t);let r=t[18];r!==null&&r.detachView(e)}Gl(t)}finally{C(n)}}function pf(e,t){let n=e.cleanup,r=t[7];if(n!==null)for(let e=0;e=0?r[t]():r[-t].unsubscribe(),e+=2}else{let t=r[n[e+1]];n[e].call(t)}r!==null&&(t[7]=null);let i=t[21];if(i!==null){t[21]=null;for(let e=0;e27&&zf(e,t,27,!1),Rc(o?Tc.TemplateUpdateStart:Tc.TemplateCreateStart,i,n),n(r,i)}finally{ms(a),Rc(o?Tc.TemplateUpdateEnd:Tc.TemplateCreateEnd,i,n)}}function Uf(e,t,n){Xf(e,t,n),(n.flags&64)==64&&Zf(e,t,n)}function Wf(e,t,n=oo){let r=t.localNames;if(r!==null){let i=t.index+1;for(let a=0;a{bo(e.lView)},consumerOnSignalRead(){this.lView[24]=this}};function xp(e){let t=e[24]??Object.create(Sp);return t.lView=e,t}var Sp={...mn,consumerIsAlwaysLive:!0,kind:`template`,consumerMarkedDirty:e=>{let t=Co(e.lView);for(;t&&!Cp(t[1]);)t=Co(t);t&&go(t)},consumerOnSignalRead(){this.lView[24]=this}};function Cp(e){return e.type!==2}function wp(e){if(e[23]===null)return;let t=!0;for(;t;){let n=!1;for(let t of e[23])if(t.dirty&&(n=!0,t.zone===null||Zone.current===t.zone?t.run():t.zone.run(()=>t.run()),e[23]===null))return;t=n&&!!(e[2]&8192)}}var Tp=100;function Ep(e,t=0){let n=e[10].rendererFactory;n.begin?.();try{Dp(e,t)}finally{n.end?.()}}function Dp(e,t){let n=Wo();try{Go(!0),Np(e,t);let n=0;for(;vo(e);){if(n===Tp)throw new ri(103,!1);n++,Np(e,1)}}finally{Go(n)}}function Op(e,t,n,r){if(to(t))return;let i=t[2];os(t);let a=!0,o=null,s=null;Cp(e)?(s=_p(t),o=Sn(s)):pn()===null?(a=!1,s=xp(t),o=Sn(s)):t[24]&&=(Dn(t[24]),null);try{ho(t),Jo(e.bindingStartIndex),n!==null&&Hf(e,t,n,2,r);let a=(i&3)==3;if(a){let n=e.preOrderCheckHooks;n!==null&&Vc(t,n,null)}else{let n=e.preOrderHooks;n!==null&&Hc(t,n,0,null),Uc(t,0)}if(Ap(t),wp(t),kp(t,0),e.contentQueries!==null&&su(e,t),a){let n=e.contentCheckHooks;n!==null&&Vc(t,n)}else{let n=e.contentHooks;n!==null&&Hc(t,n,1),Uc(t,1)}Fp(e,t);let o=e.components;o!==null&&Pp(t,o,0);let s=e.viewQuery;if(s!==null&&cu(2,s,r),a){let n=e.viewCheckHooks;n!==null&&Vc(t,n)}else{let n=e.viewHooks;n!==null&&Hc(t,n,2),Uc(t,2)}if(e.firstUpdatePass===!0&&(e.firstUpdatePass=!1),t[22]){for(let e of t[22])e();t[22]=null}hp(t),t[2]&=-73}catch(e){throw bo(t),e}finally{s!==null&&(wn(s,o),a&&yp(s)),ds()}}function kp(e,t){for(let n=Jl(e);n!==null;n=Yl(n))for(let e=10;e0&&(e[n-1][4]=r[4]);let a=aa(e,10+t);of(r[1],r);let o=a[18];o!==null&&o.detachView(a[1]),r[3]=null,r[4]=null,r[2]&=-129}return r}function Hp(e,t,n,r){let i=10+r,a=n.length;r>0&&(n[i-1][4]=t),r-1&&(Vp(e,n),aa(t,n))}this._attachedToViewContainer=!1}df(this._lView[1],this._lView)}onDestroy(e){xo(this._lView,e)}markForCheck(){Ip(this._cdRefInjectingView||this._lView,4)}detach(){this._lView[2]&=-129}reattach(){yo(this._lView),this._lView[2]|=128}detectChanges(){this._lView[2]|=1024,Ep(this._lView)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new ri(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;let e=eo(this._lView),t=this._lView[16];t!==null&&!e&&uf(t,this._lView),cf(this._lView[1],this._lView)}attachToAppRef(e){if(this._attachedToViewContainer)throw new ri(902,!1);this._appRef=e;let t=eo(this._lView),n=this._lView[16];n!==null&&!t&&Up(n,this._lView),yo(this._lView)}},Gp=(()=>{class e{_declarationLView;_declarationTContainer;elementRef;static __NG_ELEMENT_ID__=Kp;constructor(e,t,n){this._declarationLView=e,this._declarationTContainer=t,this.elementRef=n}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(e,t){return this.createEmbeddedViewImpl(e,t)}createEmbeddedViewImpl(e,t,n){return new Wp(dp(this._declarationLView,this._declarationTContainer,e,{embeddedViewInjector:t,dehydratedView:n}))}}return e})();function Kp(){return qp(Lo(),T())}function qp(e,t){return e.type&4?new Gp(t,e,Pl(e,t)):null}function Jp(e,t,n,r,i){let a=e.data[t];if(a===null)a=Yp(e,t,n,r,i),Zo()&&(a.flags|=32);else if(a.type&64){a.type=n,a.value=r,a.attrs=i;let e=zo();a.injectorIndex=e===null?-1:e.injectorIndex}return Bo(a,!0),a}function Yp(e,t,n,r,i){let a=Ro(),o=Vo(),s=o?a:a&&a.parent,c=e.data[t]=Zp(e,s,n,t,r,i);return Xp(e,c,a,o),c}function Xp(e,t,n,r){e.firstChild===null&&(e.firstChild=t),n!==null&&(r?n.child==null&&t.parent!==null&&(n.child=t):n.next===null&&(n.next=t,t.prev=n))}function Zp(e,t,n,r,i,a){let o=t?t.injectorIndex:-1,s=0;return No()&&(s|=128),{type:n,index:r,insertBeforeIndex:null,injectorIndex:o,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,controlDirectiveIndex:-1,customControlIndex:-1,propertyBindings:null,flags:s,providerIndexes:0,value:i,namespace:vs(),attrs:a,mergedAttrs:null,localNames:null,initialInputs:null,inputs:null,hostDirectiveInputs:null,outputs:null,hostDirectiveOutputs:null,directiveToIndex:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:t,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}function Qp(e){let t=e[6]??[],n=e[3][11],r=[];for(let e of t)e.data.di===void 0?$p(e,n):r.push(e);e[6]=r}function $p(e,t){let n=0,r=e.firstChild;if(r){let i=e.data.r;for(;nnull,tm=()=>null;function nm(e,t){return em(e,t)}function rm(e,t,n){return tm(e,t,n)}var im=class{},am=class{},om=(()=>{class e{static ɵprov=pi({token:e,providedIn:`root`,factory:()=>null})}return e})();function sm(e){return e.debugInfo?.className||e.type.name||null}var cm={},lm=class{injector;parentInjector;constructor(e,t){this.injector=e,this.parentInjector=t}get(e,t,n){let r=this.injector.get(e,cm,n);return r!==cm||t===cm?r:this.parentInjector.get(e,t,n)}};function um(e,t,n){return e[t]=n}function dm(e,t){return e[t]}function fm(e,t,n){if(n===$u)return!1;let r=e[t];return!Object.is(r,n)&&(e[t]=n,!0)}function pm(e,t,n,r){let i=fm(e,t,n);return fm(e,t+1,r)||i}function mm(e,t,n,r,i){let a=pm(e,t,n,r);return fm(e,t+2,i)||a}function hm(e,t,n,r,i,a){let o=pm(e,t,n,r);return pm(e,t+2,i,a)||o}function gm(e,t,n){return function r(i){let a=r.__ngNativeEl__;a!==void 0&&ru(i,a),Ip(Za(e)?uo(e.index,t):t,5);let o=t[8],s=_m(t,o,n,i),c=r.__ngNextListenerFn__;for(;c;)s=_m(t,o,c,i)&&s,c=c.__ngNextListenerFn__;return s}}function _m(e,t,n,r){let i=C(null);try{return Rc(Tc.OutputStart,t,n),n(r)!==!1}catch(t){return ap(e,t),!1}finally{Rc(Tc.OutputEnd,t,n),C(i)}}function vm(e,t,n,r,i,a,o,s){let c=Qa(e),l=!1,u=null;if(!r&&c&&(u=bm(t,n,a,e.index)),u!==null){let e=u.__ngLastListenerFn__||u;e.__ngNextListenerFn__=o,u.__ngLastListenerFn__=o,l=!0}else{let o=oo(e,n),c=r?r(o):o;r||(s.__ngNativeEl__=o);let l=i.listen(c,a,s);ym(a)||xm(r?t=>r(io(t[e.index])):e.index,t,n,a,s,l,!1)}return l}function ym(e){return e.startsWith(`animation`)||e.startsWith(`transition`)}function bm(e,t,n,r){let i=e.cleanup;if(i!=null)for(let e=0;er?n[r]:null}typeof a==`string`&&(e+=2)}return null}function xm(e,t,n,r,i,a,o){let s=t.firstCreatePass?To(t):null,c=wo(n),l=c.length;c.push(i,a),s&&s.push(r,e,l,(l+1)*(o?-1:1))}function Sm(e,t,n,r,i,a){let o=t[n],s=t[1],c=o[s.data[n].outputs[r]].subscribe(a);xm(e.index,s,t,i,a,c,!0)}var Cm=Symbol(`BINDING`),wm=new bi(``);function Tm(e,t,n){let r=n?e.styles:null,i=n?e.classes:null,a=0;if(t!==null)for(let e=0;e0&&(n.directiveToIndex=new Map);for(let c=0;c0;){let n=e[--t];if(typeof n==`number`&&n<0)return n}return 0}function zm(e,t,n){if(n){if(t.exportAs)for(let r=0;r{let[n,r,i]=e[t],a={propName:n,templateName:t,isSignal:(r&Bf.SignalBased)!==0};return i&&(a.transform=i),a})}function qm(e){return Object.keys(e).map(t=>({propName:e[t],templateName:t}))}function Jm(e,t,n){let r=t instanceof Na?t:t?.injector;return r&&e.getStandaloneInjector!==null&&(r=e.getStandaloneInjector(r)||r),r?new lm(n,r):n}function Ym(e){let t=e.get(am,null);if(t===null)throw new ri(407,!1);return{rendererFactory:t,sanitizer:e.get(om,null),changeDetectionScheduler:e.get(sc,null),ngReflect:!1,tracingService:e.get(Pd,null,{optional:!0})}}function Xm(e,t,n){let r=Qm(e);return wu(t,r,r===`svg`?`svg`:r===`math`?ro:n)}function Zm(e){if((e&&`localName`in e&&typeof e.localName==`string`?e.localName:e?.tagName)?.toLowerCase()===`script`)throw new ri(905,!1)}function Qm(e){return(e.selectors[0][0]||`div`).toLowerCase()}var $m=class{componentDef;ngModule;selector;componentType;ngContentSelectors;isBoundToModule;cachedInputs=null;cachedOutputs=null;get inputs(){return this.cachedInputs??=Km(this.componentDef.inputs),this.cachedInputs}get outputs(){return this.cachedOutputs??=qm(this.componentDef.outputs),this.cachedOutputs}constructor(e,t){this.componentDef=e,this.ngModule=t,this.componentType=e.type,this.selector=Zu(e.selectors),this.ngContentSelectors=e.ngContentSelectors??[],this.isBoundToModule=!!t}create(e,t,n,r,i,a,o){Rc(Tc.DynamicComponentStart);let s=C(null);try{let s=this.componentDef,c=Jm(s,r||this.ngModule,e),l=Ym(c),u=l.tracingService;return u&&u.componentCreate?u.componentCreate(sm(s),()=>this.createComponentRef(l,c,t,n,i,a,o)):this.createComponentRef(l,c,t,n,i,a,o)}finally{C(s)}}createComponentRef(e,t,n,r,i,a,o){let s=this.componentDef,c=eh(r,s,a,i),l=e.rendererFactory.createRenderer(null,s),u=r?Gf(l,r,s.encapsulation,t):Xm(s,l,o??null);Zm(u);let d=t.get(wm,null),f=th(u,()=>t.get(Ts,null)??$l());d&&d.addHost(f);let p=a?.some(rh)||i?.some(e=>typeof e!=`function`&&e.bindings.some(rh)),m=Pf(null,c,null,512|If(s),null,null,e,l,t,null,ou(u,t,!0));d&&Wm&&f instanceof ShadowRoot&&xo(m,()=>{d.removeHost(f)}),m[27]=u,os(m);let h=null;try{let e=Vm(27,m,2,`#host`,()=>c.directiveRegistry,!0,0);ju(l,u,e),ql(u,m),Uf(c,m,e),lu(c,e,m),Hm(c,e),n!==void 0&&ah(e,this.ngContentSelectors,n),h=uo(e.index,m),m[8]=h[8],lp(c,m,null)}catch(e){throw h!==null&&Gl(h),Gl(m),e}finally{Rc(Tc.DynamicComponentEnd),ds()}return new ih(this.componentType,m,!!p)}};function eh(e,t,n,r){let i=e?[`ng-version`,`22.1.7`]:Qu(t.selectors[0]),a=null,o=null,s=0;if(n)for(let e of n)s+=e[Cm].requiredVars,e.create&&(e.targetIdx=0,(a??=[]).push(e)),e.update&&(e.targetIdx=0,(o??=[]).push(e));if(r)for(let e=0;e{if(n&1&&e)for(let t of e)t.create();if(n&2&&t)for(let e of t)e.update()}}function rh(e){let t=e[Cm].kind;return t===`input`||t===`twoWay`}var ih=class extends im{_rootLView;_hasInputBindings;instance;hostView;changeDetectorRef;componentType;location;previousInputValues=null;_tNode;constructor(e,t,n){super(),this._rootLView=t,this._hasInputBindings=n,this._tNode=so(t[1],27),this.location=Pl(this._tNode,t),this.instance=uo(this._tNode.index,t)[8],this.hostView=this.changeDetectorRef=new Wp(t,void 0),this.componentType=e}setInput(e,t){this._hasInputBindings;let n=this._tNode;if(this.previousInputValues??=new Map,this.previousInputValues.has(e)&&Object.is(this.previousInputValues.get(e),t))return;let r=this._rootLView;op(n,r[1],r,e,t),this.previousInputValues.set(e,t),Ip(uo(n.index,r),1)}get injector(){return new Ol(this._tNode,this._rootLView)}destroy(){this.hostView.destroy()}onDestroy(e){this.hostView.onDestroy(e)}};function ah(e,t,n){let r=e.projection=[];for(let e=0;e{class e{static __NG_ELEMENT_ID__=sh}return e})();function sh(){return dh(Lo(),T())}var ch=class e extends oh{_lContainer;_hostTNode;_hostLView;constructor(e,t,n){super(),this._lContainer=e,this._hostTNode=t,this._hostLView=n}get element(){return Pl(this._hostTNode,this._hostLView)}get injector(){return new Ol(this._hostTNode,this._hostLView)}get parentInjector(){let e=gl(this._hostTNode,this._hostLView);if(nl(e)){let t=al(e,this._hostLView),n=rl(e),r=t[1].data[n+8];return new Ol(r,t)}return new Ol(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(e){let t=lh(this._lContainer);return t!==null&&t[e]||null}get length(){return this._lContainer.length-10}createEmbeddedView(e,t,n){let r,i;typeof n==`number`?r=n:n!=null&&(r=n.index,i=n.injector);let a=nm(this._lContainer,e.ssrId),o=e.createEmbeddedViewImpl(t||{},i,a);return this.insertImpl(o,r,fp(this._hostTNode,a)),o}createComponent(e,t,n,r,i,a,o){let s,c=t||{};s=c.index,n=c.injector,r=c.projectableNodes,i=c.environmentInjector||c.ngModuleRef,a=c.directives,o=c.bindings;let l=new $m(Oi(e)),u=n||this.parentInjector;if(!i&&l.ngModule==null){let e=this.parentInjector.get(Na,null);e&&(i=e)}let d=Oi(l.componentType??{}),f=nm(this._lContainer,d?.id??null),p=f?.firstChild??null,m=l.create(u,r,p,i,a,o,this._getHostElementNamespace());return this.insertImpl(m.hostView,s,fp(this._hostTNode,f)),m}_getHostElementNamespace(){if(this._hostTNode.type&2){let e=this._hostTNode.parent??this._hostLView[5];return e!==null&&e.type&2&&typeof e.value==`string`&&e.value.toLowerCase()===`foreignobject`?null:e?.namespace??null}return this._hostTNode.namespace}insert(e,t){return this.insertImpl(e,t,!0)}insertImpl(t,n,r){let i=t._lView;if(po(i)){let n=this.indexOf(t);if(n!==-1)this.detach(n);else{let n=i[3],r=new e(n,n[5],n[3]);r.detach(r.indexOf(t))}}let a=this._adjustIndex(n),o=this._lContainer;return zp(o,i,a,r),t.attachToViewContainerRef(),ia(uh(o),a,t),t}move(e,t){return this.insert(e,t)}indexOf(e){let t=lh(this._lContainer);return t===null?-1:t.indexOf(e)}remove(e){let t=this._adjustIndex(e,-1),n=Vp(this._lContainer,t);n&&(aa(uh(this._lContainer),t),df(n[1],n))}detach(e){let t=this._adjustIndex(e,-1),n=Vp(this._lContainer,t);return n&&aa(uh(this._lContainer),t)!=null?new Wp(n):null}_adjustIndex(e,t=0){return e??this.length+t}};function lh(e){return e[8]}function uh(e){return e[8]||=[]}function dh(e,t){let n,r=t[e.index];return Ya(r)?n=r:(n=Lp(r,t,null,e),t[e.index]=n,Rf(t,n)),ph(n,t,e,r),new ch(n,e,t)}function fh(e,t){let n=e[11],r=n.createComment(``),i=oo(t,e);return Tu(n,n.parentNode(i),r,n.nextSibling(i),!1),r}var ph=gh,mh=()=>!1;function hh(e,t,n){return mh(e,t,n)}function gh(e,t,n,r){if(e[7])return;let i;i=n.type&8?io(r):fh(t,n),e[7]=i}var _h=class e{queryList;matches=null;constructor(e){this.queryList=e}clone(){return new e(this.queryList)}setDirty(){this.queryList.setDirty()}},vh=class e{queries;constructor(e=[]){this.queries=e}createEmbeddedView(t){let n=t.queries;if(n!==null){let r=t.contentQueries===null?n.length:t.contentQueries[0],i=[];for(let e=0;e0)r.push(o[e/2]);else{let i=a[e+1],o=t[-n];for(let e=10;ee.trim())}function Mh(e,t,n){e.queries===null&&(e.queries=new bh),e.queries.track(new xh(t,n))}function Nh(e,t){return e.queries.getByIndex(t)}function Ph(e,t){let n=e[1],r=Nh(n,t);return r.crossesNgTemplate?Dh(n,e,t,[]):Eh(n,e,r,t)}function Fh(e,t,n){let r,i=Nn(()=>{r._dirtyCounter();let n=zh(r,e);if(t&&n===void 0)throw new ri(-951,!1);return n});return r=i[fn],r._dirtyCounter=k(0),r._flatValue=void 0,i}function Ih(e){return Fh(!0,!1,e)}function Lh(e){return Fh(!0,!0,e)}function Rh(e,t){let n=e[fn];n._lView=T(),n._queryIndex=t,n._queryList=Oh(n._lView,t),n._queryList.onDirty(()=>n._dirtyCounter.update(e=>e+1))}function zh(e,t){let n=e._lView,r=e._queryIndex;if(n===void 0||r===void 0||n[2]&4)return t?void 0:pa;let i=Oh(n,r),a=Ph(n,r);return i.reset(a,Il),t?i.first:i._changesDetected||e._flatValue===void 0?e._flatValue=i.toArray():e._flatValue}function Bh(e){return!!e&&typeof e.then==`function`}function Vh(e){return!!e&&typeof e.subscribe==`function`}var Hh=class{},Uh=class extends Hh{injector;instance=null;constructor(e){super();let t=new Pa([...e.providers,{provide:Hh,useValue:this}],e.parent||Ma(),e.debugName,new Set([`environment`]));this.injector=t,e.runEnvironmentInitializers&&t.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(e){this.injector.onDestroy(e)}};function Wh(e,t,n=null){return new Uh({providers:e,parent:t,debugName:n,runEnvironmentInitializers:!0}).injector}var Gh=(()=>{class e{_injector;cachedInjectors=new Map;constructor(e){this._injector=e}getOrCreateStandaloneInjector(e){if(!e.standalone)return null;if(!this.cachedInjectors.has(e)){let t=ya(!1,e.type),n=t.length>0?Wh([t],this._injector,``):null;this.cachedInjectors.set(e,n)}return this.cachedInjectors.get(e)}ngOnDestroy(){try{for(let e of this.cachedInjectors.values())e!==null&&e.destroy()}finally{this.cachedInjectors.clear()}}static ɵprov=pi({token:e,providedIn:`environment`,factory:()=>new e(Yi(Na))})}return e})();function Kh(e){return wc(()=>{let t=Qh(e),n={...t,decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection!==Bl.Eager,directiveDefs:null,pipeDefs:null,dependencies:t.standalone&&e.dependencies||null,getStandaloneInjector:t.standalone?e=>e.get(Gh).getOrCreateStandaloneInjector(n):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||uu.Emulated,styles:e.styles||pa,_:null,schemas:e.schemas||null,tView:null,id:``};t.standalone&&Id(`NgStandalone`),$h(n);let r=e.dependencies;return n.directiveDefs=eg(r,qh),n.pipeDefs=eg(r,Ai),n.id=tg(n),n})}function qh(e){return Oi(e)||ki(e)}function Jh(e,t){if(e==null)return fa;let n={};for(let r in e)if(Object.hasOwn(e,r)){let i=e[r],a,o,s,c;Array.isArray(i)?(s=i[0],a=i[1],o=i[2]??a,c=i[3]||null):(a=i,o=i,s=Bf.None,c=null),n[a]=[r,s,c],t[a]=o}return n}function Yh(e){if(e==null)return fa;let t={};for(let n in e)Object.hasOwn(e,n)&&(t[e[n]]=n);return t}function Xh(e){return wc(()=>{let t=Qh(e);return $h(t),t})}function Zh(e){return{type:e.type,name:e.name,factory:null,pure:e.pure!==!1,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function Qh(e){let t={};return{type:e.type,providersResolver:null,viewProvidersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:t,inputConfig:e.inputs||fa,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:e.signals===!0,selectors:e.selectors||pa,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,resolveHostDirectives:null,hostDirectives:null,controlDef:null,signalFormsInputPresence:null,inputs:Jh(e.inputs,t),outputs:Yh(e.outputs),debugInfo:null}}function $h(e){e.features?.forEach(t=>t(e))}function eg(e,t){return e?()=>{let n=typeof e==`function`?e():e,r=[];for(let e of n){let n=t(e);n!==null&&r.push(n)}return r}:null}function tg(e){let t=0,n=typeof e.consts==`function`?``:e.consts,r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,n,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(let e of r.join(`|`))t=Math.imul(31,t)+e.charCodeAt(0)<<0;return t+=2147483648,`c`+t}var ng=new bi(``),rg=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((e,t)=>{this.resolve=e,this.reject=t});appInits=w(ng,{optional:!0})??[];injector=w(ws);constructor(){}runInitializers(){if(this.initialized)return;let e=[];for(let t of this.appInits){let n=Ga(this.injector,t);if(Bh(n))e.push(n);else if(Vh(n)){let t=new Promise((e,t)=>{n.subscribe({complete:e,error:t})});e.push(t)}}let t=()=>{this.done=!0,this.resolve()};Promise.all(e).then(()=>{t()}).catch(e=>{this.reject(e)}),e.length===0&&t(),this.initialized=!0}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})}return e})();function ig(e,t,n,r,i,a,o,s){if(n.firstCreatePass){e.mergedAttrs=el(e.mergedAttrs,e.attrs);let t=e.tView=jf(2,e,i,a,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,n.consts,null);n.queries!==null&&(n.queries.template(n,e),t.queries=n.queries.embeddedTView(e))}s&&(e.flags|=s),Bo(e,!1);let c=cg(n,t,e,r);bs()&&bf(n,t,c,e),ql(c,t);let l=Lp(c,t,c,e);t[r+27]=l,Rf(t,l),hh(l,e,t)}function ag(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;return t.firstCreatePass?(f=Jp(t,d,4,o||null,s||null),Mo()&&Dm(t,e,f,mo(t.consts,l),$f),Bc(t,f)):f=t.data[d],ig(f,e,t,n,r,i,a,c),Qa(f)&&Uf(t,e,f),l!=null&&Wf(e,f,u),f}function og(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;if(t.firstCreatePass){if(f=Jp(t,d,4,o||null,s||null),l!=null){let e=mo(t.consts,l);f.localNames=[];for(let t=0;t{throw new ri(600,``)})}var pg=10,mg=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=w(Zs);afterRenderManager=w(Ld);zonelessEnabled=w(cc);rootEffectScheduler=w(uc);dirtyFlags=0;tracingSnapshot=null;allTestViews=new Set;autoDetectTestViews=new Set;includeAllTestViews=!1;afterTick=new Qr;get allViews(){return[...(this.includeAllTestViews?this.allTestViews:this.autoDetectTestViews).keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];internalPendingTask=w(As);get isStable(){return this.internalPendingTask.hasPendingTasksObservable.pipe(ti(e=>!e))}constructor(){w(Pd,{optional:!0})}whenStable(){let e;return new Promise(t=>{e=this.isStable.subscribe({next:e=>{e&&t()}})}).finally(()=>{e.unsubscribe()})}_injector=w(Na);_rendererFactory=null;get injector(){return this._injector}bootstrap(e,t){return this.bootstrapImpl(e,t)}bootstrapImpl(e,t,n=ws.NULL){return this._injector.get(Rs).run(()=>{if(Rc(Tc.BootstrapComponentStart),!this._injector.get(rg).done)throw new ri(405,``);let r=Oi(e),i=this._injector.get(Hh),a=new $m(r,i);this.componentTypes.push(e);let{hostElement:o,directives:s,bindings:c}=hg(t),l=o||a.selector,u=a.create(n,[],l,i.injector,s,c),d=u.location.nativeElement,f=u.injector.get(ug,null);return f?.registerApplication(d),u.onDestroy(()=>{this.detachView(u.hostView),gg(this.components,u),f?.unregisterApplication(d)}),this._loadComponent(u),Rc(Tc.BootstrapComponentEnd,u),u})}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick(){Rc(Tc.ChangeDetectionStart),this.tracingSnapshot===null?this.tickImpl():this.tracingSnapshot.run(Nd.CHANGE_DETECTION,this.tickImpl)}tickImpl=()=>{if(this._runningTick)throw Rc(Tc.ChangeDetectionEnd),new ri(101,!1);let e=C(null);try{this._runningTick=!0,this.synchronize()}finally{this._runningTick=!1,this.tracingSnapshot?.dispose(),this.tracingSnapshot=null,C(e),this.afterTick.next(),Rc(Tc.ChangeDetectionEnd)}};synchronize(){this._rendererFactory===null&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(am,null,{optional:!0}));let e=0;for(;this.dirtyFlags!==0&&e++vo(e))){this.dirtyFlags|=2;return}this.dirtyFlags&=-8}attachView(e){let t=e;this._views.push(t),t.attachToAppRef(this)}detachView(e){let t=e;gg(this._views,t),t.detachFromAppRef()}_loadComponent(e){this.attachView(e.hostView);try{this.tick()}catch(e){this.internalErrorHandler(e)}this.components.push(e),this._injector.get(dg,[]).forEach(t=>t(e))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(e=>e()),this._views.slice().forEach(e=>e.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(e){return this._destroyListeners.push(e),()=>gg(this._destroyListeners,e)}destroy(){if(this._destroyed)throw new ri(406,!1);let e=this._injector;e.destroy&&!e.destroyed&&e.destroy()}get viewCount(){return this._views.length}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})}return e})();function hg(e){return e===void 0||typeof e==`string`||e instanceof Element?{hostElement:e}:e}function gg(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}function j(e,t,n,r){let i=T();return fm(i,Yo(),t)&&(Io(),ep(hs(),i,e,t,n,r)),j}function _g(e){if(Id(`NgAnimateEnter`),!_d)return _g;let t=T();if(vd(t))return _g;let n=Lo(),r=t[9].get(Rs);return Md(Od(t),n,()=>vg(t,n,e,r)),Yd(t[9]),Xd(t[9],Od(t)),_g}function vg(e,t,n,r){let i=oo(t,e),a=e[11],o=kd(n),s=[],c=!1,l=e=>{if(Ad(e)!==i)return;let t=e instanceof AnimationEvent?`animationend`:`transitionend`;r.runOutsideAngular(()=>{a.listen(i,t,u)})},u=e=>{Ad(e)===i&&(jd(e,i)&&(c=!0),yg(e,i,a))};if(o&&o.length>0){r.runOutsideAngular(()=>{s.push(a.listen(i,`animationstart`,l)),s.push(a.listen(i,`transitionstart`,l))}),yd(i,o,s);for(let e of o)a.addClass(i,e);r.runOutsideAngular(()=>{requestAnimationFrame(()=>{if(!c&&(fd(i,Sd,_d),!Sd.has(i))){for(let e of o)a.removeClass(i,e);bd(i)}})})}}function yg(e,t,n){let r=xd.get(t);if(Ad(e)===t&&r&&jd(e,t)){e.stopPropagation();for(let e of r.classList)n.removeClass(t,e);bd(t)}}var bg=class{destroy(e){}updateValue(e,t){}swap(e,t){let n=Math.min(e,t),r=Math.max(e,t),i=this.detach(r);if(r-n>1){let e=this.detach(n);this.attach(n,i),this.attach(r,e)}else this.attach(n,i)}move(e,t){this.attach(t,this.detach(e))}};function xg(e,t,n,r,i){return e===n&&Object.is(t,r)?1:Object.is(i(e,t),i(n,r))?-1:0}function Sg(e,t,n,r){let i,a,o=0,s=e.length-1;if(Array.isArray(t)){C(r);let c=t.length-1;for(C(null);o<=s&&o<=c;){let r=e.at(o),l=t[o],u=xg(o,r,o,l,n);if(u!==0){u<0&&e.updateValue(o,l),o++;continue}let d=e.at(s),f=t[c],p=xg(s,d,c,f,n);if(p!==0){p<0&&e.updateValue(s,f),s--,c--;continue}let m=n(o,r),h=n(s,d),g=n(o,l);if(Object.is(g,h)){let t=n(c,f);Object.is(t,m)?(e.swap(o,s),e.updateValue(s,f),c--,s--):e.move(s,o),e.updateValue(o,l),o++;continue}if(i??=new Eg,a??=Tg(e,o,s,n),Cg(e,i,o,g))e.updateValue(o,l),o++,s++;else if(a.has(g))i.set(m,e.detach(o)),s--;else{let n=e.create(o,t[o]);e.attach(o,n),o++,s++}}for(;o<=c;)wg(e,i,n,o,t[o]),o++}else if(t!=null){C(r);let c=t[Symbol.iterator]();C(null);let l=c.next();for(;!l.done&&o<=s;){let t=e.at(o),r=l.value,u=xg(o,t,o,r,n);if(u!==0)u<0&&e.updateValue(o,r),o++,l=c.next();else{i??=new Eg,a??=Tg(e,o,s,n);let u=n(o,r);if(Cg(e,i,o,u))e.updateValue(o,r),o++,s++,l=c.next();else if(!a.has(u))e.attach(o,e.create(o,r)),o++,s++,l=c.next();else{let r=n(o,t);i.set(r,e.detach(o)),s--}}}for(;!l.done;)wg(e,i,n,e.length,l.value),l=c.next()}for(;o<=s;)e.destroy(e.detach(s--));i?.forEach(t=>{e.destroy(t)})}function Cg(e,t,n,r){return t!==void 0&&t.has(r)?(e.attach(n,t.get(r)),t.delete(r),!0):!1}function wg(e,t,n,r,i){if(Cg(e,t,r,n(r,i)))e.updateValue(r,i);else{let t=e.create(r,i);e.attach(r,t)}}function Tg(e,t,n,r){let i=new Set;for(let a=t;a<=n;a++)i.add(r(a,e.at(a)));return i}var Eg=class{kvMap=new Map;_vMap=void 0;has(e){return this.kvMap.has(e)}delete(e){if(!this.has(e))return!1;let t=this.kvMap.get(e);return this._vMap!==void 0&&this._vMap.has(t)?(this.kvMap.set(e,this._vMap.get(t)),this._vMap.delete(t)):this.kvMap.delete(e),!0}get(e){return this.kvMap.get(e)}set(e,t){if(this.kvMap.has(e)){let n=this.kvMap.get(e);this._vMap===void 0&&(this._vMap=new Map);let r=this._vMap;for(;r.has(n);)n=r.get(n);r.set(n,t)}else this.kvMap.set(e,t)}forEach(e){for(let[t,n]of this.kvMap)if(e(n,t),this._vMap!==void 0){let r=this._vMap;for(;r.has(n);)n=r.get(n),e(n,t)}}};function M(e,t,n,r,i,a,o,s){Id(`NgControlFlow`);let c=T(),l=Io();return og(c,l,e,t,n,r,i,mo(l.consts,a),256,o,s),Dg}function Dg(e,t,n,r,i,a,o,s){Id(`NgControlFlow`);let c=T(),l=Io();return og(c,l,e,t,n,r,i,mo(l.consts,a),512,o,s),Dg}function N(e,t){Id(`NgControlFlow`);let n=T(),r=Yo(),i=n[r]===$u?-1:n[r],a=i===-1?void 0:Ng(n,27+i);if(fm(n,r,e)){let r=C(null);try{if(a!==void 0&&Bp(a,0),e!==-1){let r=27+e,i=Ng(n,r),a=Rg(n[1],r),o=rm(i,a,n);zp(i,dp(n,a,t,{dehydratedView:o}),0,fp(a,o))}}finally{C(r)}}else if(a!==void 0){let e=Rp(a,0);e!==void 0&&(e[8]=t)}}var Og=class{lContainer;$implicit;$index;constructor(e,t,n){this.lContainer=e,this.$implicit=t,this.$index=n}get $count(){return this.lContainer.length-10}};function kg(e){return e}function Ag(e,t){return t}var jg=class{hasEmptyBlock;trackByFn;liveCollection;constructor(e,t,n){this.hasEmptyBlock=e,this.trackByFn=t,this.liveCollection=n}};function P(e,t,n,r,i,a,o,s,c,l,u,d,f){Id(`NgControlFlow`);let p=T(),m=Io(),h=c!==void 0,g=T(),_=new jg(h,s?o.bind(g[15][8]):o);g[27+e]=_,og(p,m,e+1,t,n,r,i,mo(m.consts,a),256),h&&og(p,m,e+2,c,l,u,d,mo(m.consts,f),512)}var Mg=class extends bg{lContainer;hostLView;templateTNode;operationsCounter=void 0;needsIndexUpdate=!1;constructor(e,t,n){super(),this.lContainer=e,this.hostLView=t,this.templateTNode=n}get length(){return this.lContainer.length-10}at(e){return this.getLView(e)[8].$implicit}attach(e,t){let n=t[6];this.needsIndexUpdate||=e!==this.length,zp(this.lContainer,t,e,fp(this.templateTNode,n)),Pg(this.lContainer,e)}detach(e){return this.needsIndexUpdate||=e!==this.length-1,Fg(this.lContainer,e),Ig(this.lContainer,e)}create(e,t){let n=nm(this.lContainer,this.templateTNode.tView.ssrId);return dp(this.hostLView,this.templateTNode,new Og(this.lContainer,t,e),{dehydratedView:n})}destroy(e){df(e[1],e)}updateValue(e,t){this.getLView(e)[8].$implicit=t}reset(){this.needsIndexUpdate=!1}updateIndexes(){if(this.needsIndexUpdate)for(let e=0;e0){let e=n[9];qd(e,r),md.delete(n[19]),r.detachedLeaveAnimationFns=void 0}}function Fg(e,t){if(e.length<=10)return;let n=e[10+t],r=n?n[26]:void 0;r&&r.leave&&r.leave.size>0&&(r.detachedLeaveAnimationFns=[])}function Ig(e,t){return Vp(e,t)}function Lg(e,t){return Rp(e,t)}function Rg(e,t){return so(e,t)}function I(e,t,n){let r=T();return fm(r,Yo(),t)&&(Io(),qf(hs(),r,e,t,r[11],n)),I}function zg(e,t,n,r,i){op(t,e,n,i?`class`:`style`,r)}function L(e,t,n,r){let i=T(),a=i[1],o=e+27,s=a.firstCreatePass?Vm(o,i,2,t,$f,Mo(),n,r):a.data[o];if(Za(s)){let n=i[10].tracingService;if(n&&n.componentCreate){let o=a.data[s.directiveStart+s.componentOffset];return n.componentCreate(sm(o),()=>(Bg(e,t,i,s,r),L))}}return Bg(e,t,i,s,r),L}function Bg(e,t,n,r,i){if(rp(r,n,e,t,Hg),Qa(r)){let e=n[1];Uf(e,n,r),lu(e,r,n)}i!=null&&Wf(n,r)}function R(){let e=Io(),t=ip(Lo());return e.firstCreatePass&&Hm(e,t),Po(t)&&Fo(),jo(),t.classesWithoutHost!=null&&Yc(t)&&zg(e,t,T(),t.classesWithoutHost,!0),t.stylesWithoutHost!=null&&Xc(t)&&zg(e,t,T(),t.stylesWithoutHost,!1),R}function z(e,t,n,r){return L(e,t,n,r),R(),z}function B(e,t,n,r){let i=T(),a=i[1],o=e+27,s=a.firstCreatePass?Um(o,a,2,t,n,r):a.data[o];return rp(s,i,e,t,Hg),r!=null&&Wf(i,s),B}function V(){return Po(ip(Lo()))&&Fo(),jo(),V}function Vg(e,t,n,r){return B(e,t,n,r),V(),Vg}var Hg=(e,t,n,r,i)=>(xs(!0),wu(t[11],r,vs()));function Ug(e,t,n){let r=T(),i=r[1],a=e+27,o=i.firstCreatePass?Vm(a,r,8,`ng-container`,$f,Mo(),t,n):i.data[a];if(rp(o,r,e,`ng-container`,Kg),Qa(o)){let e=r[1];Uf(e,r,o),lu(e,o,r)}return n!=null&&Wf(r,o),Ug}function Wg(){let e=Io(),t=ip(Lo());return e.firstCreatePass&&Hm(e,t),Wg}function Gg(e,t,n){return Ug(e,t,n),Wg(),Gg}var Kg=(e,t,n,r,i)=>(xs(!0),Cu(t[11],``));function H(){return T()}function qg(e,t,n){let r=T();return fm(r,Yo(),t)&&(Io(),Jf(hs(),r,e,t,r[11],n)),qg}var Jg=void 0;function Yg(e){let t=Math.floor(Math.abs(e)),n=e.toString().replace(/^[^.]*\.?/,``).length;return t===1&&n===0?1:5}var Xg=[`en`,[[`a`,`p`],[`AM`,`PM`]],[[`AM`,`PM`]],[[`S`,`M`,`T`,`W`,`T`,`F`,`S`],[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],[`Sunday`,`Monday`,`Tuesday`,`Wednesday`,`Thursday`,`Friday`,`Saturday`],[`Su`,`Mo`,`Tu`,`We`,`Th`,`Fr`,`Sa`]],Jg,[[`J`,`F`,`M`,`A`,`M`,`J`,`J`,`A`,`S`,`O`,`N`,`D`],[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],[`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`]],Jg,[[`B`,`A`],[`BC`,`AD`],[`Before Christ`,`Anno Domini`]],0,[6,0],[`M/d/yy`,`MMM d, y`,`MMMM d, y`,`EEEE, MMMM d, y`],[`h:mm a`,`h:mm:ss a`,`h:mm:ss a z`,`h:mm:ss a zzzz`],[`{1}, {0}`,Jg,Jg,Jg],[`.`,`,`,`;`,`%`,`+`,`-`,`E`,`×`,`‰`,`∞`,`NaN`,`:`],[`#,##0.###`,`#,##0%`,`¤#,##0.00`,`#E0`],`USD`,`$`,`US Dollar`,{},`ltr`,Yg],Zg=Object.create(null);function Qg(e){let t=t_(e),n=$g(t);if(n)return n;let r=t.split(`-`)[0];if(n=$g(r),n)return n;if(r===`en`)return Xg;throw new ri(701,!1)}function $g(e){if(!(e in Zg)){let t=Wi.ng&&Wi.ng.common&&Wi.ng.common.locales&&Wi.ng.common.locales[e];return t!==void 0&&(Zg[e]=t),t}return Zg[e]}var e_={LocaleId:0,DayPeriodsFormat:1,DayPeriodsStandalone:2,DaysFormat:3,DaysStandalone:4,MonthsFormat:5,MonthsStandalone:6,Eras:7,FirstDayOfWeek:8,WeekendRange:9,DateFormat:10,TimeFormat:11,DateTimeFormat:12,NumberSymbols:13,NumberFormats:14,CurrencyCode:15,CurrencySymbol:16,CurrencyName:17,Currencies:18,Directionality:19,PluralCase:20,ExtraData:21};function t_(e){return e.toLowerCase().replace(/_/g,`-`)}var n_=`en-US`;function r_(e){typeof e==`string`&&e.toLowerCase().replace(/_/g,`-`)}function U(e,t,n){let r=T(),i=Io(),a=Lo();return i_(i,r,r[11],a,e,t,n),U}function W(e,t,n){let r=T(),i=Io(),a=Lo();return(a.type&3||n)&&vm(a,i,r,n,r[11],e,t,gm(a,r,t)),W}function i_(e,t,n,r,i,a,o){let s=!0,c=null;if((r.type&3||o)&&(c??=gm(r,t,a),vm(r,e,t,o,n,i,a,c)&&(s=!1)),s){let e=r.outputs?.[i],n=r.hostDirectiveOutputs?.[i];if(n&&n.length)for(let e=0;e>17&32767}function m_(e){return(e&2)==2}function h_(e,t){return e&131071|t<<17}function g_(e){return e|2}function __(e){return(e&131068)>>2}function v_(e,t){return e&-131069|t<<2}function y_(e){return(e&1)==1}function b_(e){return e|1}function x_(e,t,n,r,i,a){let o=a?t.classBindings:t.styleBindings,s=p_(o),c=__(o);e[r]=n;let l=!1,u;if(Array.isArray(n)){let e=n;u=e[1],(u===null||ua(e,u)>0)&&(l=!0)}else u=n;if(i){if(c!==0){let t=p_(e[s+1]);e[r+1]=f_(t,s),t!==0&&(e[t+1]=v_(e[t+1],r)),e[s+1]=h_(e[s+1],r)}else e[r+1]=f_(s,0),s!==0&&(e[s+1]=v_(e[s+1],r)),s=r}else e[r+1]=f_(c,0),s===0?s=r:e[c+1]=v_(e[c+1],r),c=r;l&&(e[r+1]=g_(e[r+1])),C_(e,u,r,!0),C_(e,u,r,!1),S_(t,u,e,r,a),o=f_(s,c),a?t.classBindings=o:t.styleBindings=o}function S_(e,t,n,r,i){let a=i?e.residualClasses:e.residualStyles;a!=null&&typeof t==`string`&&ua(a,t)>=0&&(n[r+1]=b_(n[r+1]))}function C_(e,t,n,r){let i=e[n+1],a=t===null,o=r?p_(i):__(i),s=!1;for(;o!==0&&(s===!1||a);){let n=e[o],i=e[o+1];w_(n,t)&&(s=!0,e[o+1]=r?b_(i):g_(i)),o=r?p_(i):__(i)}s&&(e[n+1]=r?g_(i):b_(i))}function w_(e,t){return e===null||t==null||(Array.isArray(e)?e[1]:e)===t?!0:Array.isArray(e)&&typeof t==`string`?ua(e,t)>=0:!1}var T_={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function E_(e){return e.substring(T_.key,T_.keyEnd)}function D_(e){return k_(e),O_(e,A_(e,0,T_.textEnd))}function O_(e,t){let n=T_.textEnd;return n===t?-1:(t=T_.keyEnd=j_(e,T_.key=t,n),A_(e,t,n))}function k_(e){T_.key=0,T_.keyEnd=0,T_.value=0,T_.valueEnd=0,T_.textEnd=e.length}function A_(e,t,n){for(;t32;)t++;return t}function K(e,t,n){return P_(e,t,n,!1),K}function q(e,t){return P_(e,t,null,!0),q}function M_(e){F_(G_,N_,e,!0)}function N_(e,t){for(let n=D_(t);n>=0;n=O_(t,n))ca(e,E_(t),!0)}function P_(e,t,n,r){let i=T(),a=Io(),o=Xo(2);if(a.firstUpdatePass&&L_(a,e,o,r),t!==$u&&fm(i,o,t)){let s=a.data[ps()];q_(a,s,i,i[11],e,i[o+1]=X_(t,n),r,o)}}function F_(e,t,n,r){let i=Io(),a=Xo(2);i.firstUpdatePass&&L_(i,null,a,r);let o=T();if(n!==$u&&fm(o,a,n)){let s=i.data[ps()];if(Z_(s,r)&&!I_(i,a)){let e=r?s.classesWithoutHost:s.stylesWithoutHost;e!==null&&(n=ci(e,n||``)),zg(i,s,o,n,r)}else K_(i,s,o,o[11],o[a+1],o[a+1]=W_(e,t,n),r,a)}}function I_(e,t){return t>=e.expandoStartIndex}function L_(e,t,n,r){let i=e.data;if(i[n+1]===null){let a=i[ps()],o=I_(e,n);Z_(a,r)&&t===null&&!o&&(t=!1),t=R_(i,a,t,r),x_(i,a,t,n,o,r)}}function R_(e,t,n,r){let i=ts(e),a=r?t.residualClasses:t.residualStyles;if(i===null)(r?t.classBindings:t.styleBindings)===0&&(n=H_(null,e,t,n,r),n=U_(n,t.attrs,r),a=null);else{let o=t.directiveStylingLast;if(o===-1||e[o]!==i){if(n=H_(i,e,t,n,r),a===null){let n=z_(e,t,r);n!==void 0&&Array.isArray(n)&&(n=H_(null,e,t,n[1],r),n=U_(n,t.attrs,r),B_(e,t,r,n))}else a=V_(e,t,r)}}return a!==void 0&&(r?t.residualClasses=a:t.residualStyles=a),n}function z_(e,t,n){let r=n?t.classBindings:t.styleBindings;if(__(r)!==0)return e[p_(r)]}function B_(e,t,n,r){let i=n?t.classBindings:t.styleBindings;e[p_(i)]=r}function V_(e,t,n){let r,i=t.directiveEnd;for(let a=1+t.directiveStylingLast;a0;){let t=e[i],a=Array.isArray(t),c=a?t[1]:t,l=c===null,u=n[i+1];u===$u&&(u=l?pa:void 0);let d=l?la(u,r):c===r?u:void 0;if(a&&!Y_(d)&&(d=la(t,r)),Y_(d)&&(s=d,o))return s;let f=e[i+1];i=o?p_(f):__(f)}if(t!==null){let e=a?t.residualClasses:t.residualStyles;e!=null&&(s=la(e,r))}return s}function Y_(e){return e!==void 0}function X_(e,t){return e==null||e===``||(typeof t==`string`?e=fu(e)+t:typeof e==`object`&&(e=si(fu(e)))),e}function Z_(e,t){return!!(e.flags&(t?8:16))}function J(e,t=``){let n=T(),r=Io(),i=e+27,a=r.firstCreatePass?Jp(r,i,1,t,null):r.data[i],o=Q_(r,n,a,t);n[i]=o,bs()&&bf(r,n,o,a),Bo(a,!1)}var Q_=(e,t,n,r)=>(xs(!0),xu(t[11],r));function $_(e,t,n,r=``){return fm(e,Yo(),n)?t+Mi(n)+r:$u}function ev(e,t,n,r,i,a=``){let o=pm(e,qo(),n,i);return Xo(2),o?t+Mi(n)+r+Mi(i)+a:$u}function tv(e,t,n,r,i,a,o,s=``){let c=mm(e,qo(),n,i,o);return Xo(3),c?t+Mi(n)+r+Mi(i)+a+Mi(o)+s:$u}function nv(e,t,n,r,i,a,o,s,c,l=``){let u=hm(e,qo(),n,i,o,c);return Xo(4),u?t+Mi(n)+r+Mi(i)+a+Mi(o)+s+Mi(c)+l:$u}function Y(e){return X(``,e),Y}function X(e,t,n){let r=T(),i=$_(r,e,t,n);return i!==$u&&av(r,ps(),i),X}function Z(e,t,n,r,i){let a=T(),o=ev(a,e,t,n,r,i);return o!==$u&&av(a,ps(),o),Z}function rv(e,t,n,r,i,a,o){let s=T(),c=tv(s,e,t,n,r,i,a,o);return c!==$u&&av(s,ps(),c),rv}function iv(e,t,n,r,i,a,o,s,c){let l=T(),u=nv(l,e,t,n,r,i,a,o,s,c);return u!==$u&&av(l,ps(),u),iv}function av(e,t,n){let r=ao(t,e);Su(e[11],r,n)}function ov(e,t,n){xc(t)&&(t=t());let r=T();return fm(r,Yo(),t)&&(Io(),qf(hs(),r,e,t,r[11],n)),ov}function sv(e,t){let n=xc(e);return n&&e.set(t),n}function cv(e,t){let n=T(),r=Io(),i=Lo();return i_(r,n,n[11],i,e,t),cv}var lv={};function uv(e){Id(`NgLet`);let t=Io(),n=T(),r=e+27;return Bo(Jp(t,r,128,null,null),!1),lo(t,n,r,lv),uv}function dv(e){return lo(Io(),T(),ps(),e),e}function fv(e){let t=co(Uo(),27+e);if(t===lv)throw new ri(314,!1);return t}function pv(e,t,n=``){return $_(T(),e,t,n)}function mv(e,t){let n=Ko()+e,r=T();return r[n]===$u?um(r,n,t()):dm(r,n)}function hv(e,t,n){return vv(T(),Ko(),e,t,n)}function gv(e,t,n,r,i){return bv(T(),Ko(),e,t,n,r,i)}function _v(e,t){let n=e[t];return n===$u?void 0:n}function vv(e,t,n,r,i,a){let o=t+n;return fm(e,o,i)?um(e,o+1,a?r.call(a,i):r(i)):_v(e,o+1)}function yv(e,t,n,r,i,a,o){let s=t+n;return pm(e,s,i,a)?um(e,s+2,o?r.call(o,i,a):r(i,a)):_v(e,s+2)}function bv(e,t,n,r,i,a,o,s){let c=t+n;return mm(e,c,i,a,o)?um(e,c+3,s?r.call(s,i,a,o):r(i,a,o)):_v(e,c+3)}function xv(e,t){let n=Io(),r,i=e+27;n.firstCreatePass?(r=Sv(t,n.pipeRegistry),n.data[i]=r,r.onDestroy&&(n.destroyHooks??=[]).push(i,r.onDestroy)):r=n.data[i];let a=r.factory||(r.factory=ea(r.type,!0)),o=Hi(Em);try{let e=sl(!1),t=a();return sl(e),lo(n,T(),i,t),t}finally{Hi(o)}}function Sv(e,t){if(t)for(let n=t.length-1;n>=0;n--){let r=t[n];if(e===r.name)return r}}function Cv(e,t,n){let r=e+27,i=T(),a=co(i,r);return Tv(i,r)?vv(i,Ko(),t,a.transform,n,a):a.transform(n)}function wv(e,t,n,r){let i=e+27,a=T(),o=co(a,i);return Tv(a,i)?yv(a,Ko(),t,o.transform,n,r,o):o.transform(n,r)}function Tv(e,t){return e[1].data[t].pure}function Ev(e,t){return qp(e,t)}var Dv=(()=>{class e{applicationErrorHandler=w(Zs);appRef=w(mg);taskService=w(As);ngZone=w(Rs);zonelessEnabled=w(cc);tracing=w(Pd,{optional:!0});zoneIsDefined=typeof Zone<`u`&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new gr;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(Is):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(w(lc,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{let e=this.taskService.add();if(!this.runningTick&&(this.cleanup(),!this.zonelessEnabled||this.appRef.includeAllTestViews)){this.taskService.remove(e);return}this.switchToMicrotaskScheduler(),this.taskService.remove(e)})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()}))}switchToMicrotaskScheduler(){this.ngZone.runOutsideAngular(()=>{let e=this.taskService.add();this.useMicrotaskScheduler=!0,queueMicrotask(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(e)})})}notify(e){if(!this.zonelessEnabled&&e===5)return;switch(e){case 0:case 2:this.appRef.dirtyFlags|=2;break;case 3:case 4:case 5:case 1:this.appRef.dirtyFlags|=4;break;case 6:this.appRef.dirtyFlags|=2;break;case 12:this.appRef.dirtyFlags|=16;break;case 13:this.appRef.dirtyFlags|=2;break;case 11:break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick())return;let t=this.useMicrotaskScheduler?Ps:Ns;this.pendingRenderTaskId=this.taskService.add(),this.cancelScheduledCallback=this.scheduleInRootZone?Zone.root.run(()=>t(()=>this.tick())):this.ngZone.runOutsideAngular(()=>t(()=>this.tick()))}shouldScheduleTick(){return!(this.appRef.destroyed||this.pendingRenderTaskId!==null||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(`isAngularZone_ID`+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(this.appRef.dirtyFlags===0){this.cleanup();return}!this.zonelessEnabled&&this.appRef.dirtyFlags&7&&(this.appRef.dirtyFlags|=1);let e=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(e){this.applicationErrorHandler(e)}finally{this.taskService.remove(e),this.cleanup()}}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,this.pendingRenderTaskId!==null){let e=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(e)}}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})}return e})();function Ov(){return[{provide:sc,useExisting:Dv},{provide:Rs,useClass:Ks},{provide:cc,useValue:!0}]}function kv(){return typeof $localize<`u`&&$localize.locale||`en-US`}var Av=new bi(``,{factory:()=>w(Av,{optional:!0,skipSelf:!0})||kv()}),jv=class{destroyed=!1;listeners=null;errorHandler=w(Xs,{optional:!0});isEmitting=!1;hasNullListeners=!1;destroyRef=w(Es);constructor(){this.destroyRef.onDestroy(()=>{this.destroyed=!0,this.listeners=null})}subscribe(e){if(this.destroyed)throw new ri(953,!1);return(this.listeners??=[]).push(e),{unsubscribe:()=>{let t=this.listeners?this.listeners.indexOf(e):-1;t>-1&&(this.isEmitting?(this.hasNullListeners=!0,this.listeners[t]=null):this.listeners.splice(t,1))}}}emit(e){if(this.destroyed){console.warn(ai(953,!1));return}if(this.listeners===null)return;this.isEmitting=!0;let t=C(null);try{for(let t of this.listeners)try{t!==null&&t(e)}catch(e){this.errorHandler?.handleError(e)}}finally{this.hasNullListeners&&(this.hasNullListeners=!1,this.listeners&&Mv(this.listeners)),C(t),this.isEmitting=!1}}};function Mv(e){let t=e.length-1;for(;t>-1;)e[t]===null&&e.splice(t,1),t--}function Q(e,t){return Nn(e,t?.equal)}function Nv(e){return or(e)}(class e extends Error{_brand;constructor(e){super(e)}static IDLE=new e(`IDLE`);static LOADING=new e(`LOADING`)});var Pv=e=>e;function Fv(e,t){return typeof e==`function`?Iv(nr(e,Pv,t?.equal),t?.debugName,t?.set):Iv(nr(e.source,e.computation,e.equal),e.debugName,e.set)}function Iv(e,t,n){let r=e[fn],i=e;if(n!==void 0){let t=e=>rr(r,e);i.set=e=>n(e,t),i.update=r=>n(r(Nv(e)),t)}else i.set=e=>rr(r,e),i.update=e=>ir(r,e);return i.asReadonly=$s.bind(e),i}function Lv(e,t){let n=Object.create(Cc);n.value=e,n.transformFn=t?.transform;function r(){if(hn(n),n.value===Sc)throw new ri(-950,null);return n.value}return r[fn]=n,r}function Rv(e){return new jv}function zv(e,t){return Lv(e,t)}function Bv(e){return Lv(Sc,e)}var $=(zv.required=Bv,zv);function Vv(e,t){let n=Object.create(Cc),r=new jv;n.value=e;function i(){return hn(n),Hv(n.value),n.value}return i[fn]=n,i.asReadonly=$s.bind(i),i.set=e=>{n.equal(n.value,e)||(Gn(n,e),r.emit(e))},i.update=e=>{Hv(n.value),i.set(e(n.value))},i.subscribe=r.subscribe.bind(r),i.destroyRef=r.destroyRef,i}function Hv(e){if(e===Sc)throw new ri(952,!1)}function Uv(e,t){return Vv(e,t)}function Wv(e){return Vv(Sc,e)}var Gv=(Uv.required=Wv,Uv);function Kv(e,t){return Ih(t)}function qv(e,t){return Lh(t)}var Jv=(Kv.required=qv,Kv),Yv=new bi(``),Xv=new bi(``);function Zv(e){return!e.moduleRef}function Qv(e){let t=Zv(e)?e.r3Injector:e.moduleRef.injector,n=t.get(Rs);return n.run(()=>{Zv(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();let r=t.get(Zs),i;if(n.runOutsideAngular(()=>{i=n.onError.subscribe({next:r})}),Zv(e)){let n=()=>t.destroy(),r=e.platformInjector.get(Yv);r.add(n),t.onDestroy(()=>{i.unsubscribe(),r.delete(n)})}else{let t=()=>e.moduleRef.destroy(),n=e.platformInjector.get(Yv);n.add(t),e.moduleRef.onDestroy(()=>{gg(e.allPlatformModules,e.moduleRef),i.unsubscribe(),n.delete(t)})}return ey(r,n,()=>{let n=t.get(As),r=n.add(),i=t.get(rg);return i.runInitializers(),i.donePromise.then(()=>{if(r_(t.get(Av,n_)||`en-US`),!t.get(Xv,!0))return Zv(e)?t.get(mg):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if(Zv(e)){let n=t.get(mg);return e.rootComponent!==void 0&&n.bootstrap(e.rootComponent),n}return $v?.(e.moduleRef,e.allPlatformModules),e.moduleRef}).finally(()=>void n.remove(r))})})}var $v;function ey(e,t,n){try{let r=n();return Bh(r)?r.catch(n=>{throw t.runOutsideAngular(()=>e(n)),n}):r}catch(n){throw t.runOutsideAngular(()=>e(n)),n}}var ty=null;function ny(e=[],t){return ws.create({name:t,providers:[{provide:Oa,useValue:`platform`},{provide:Yv,useValue:new Set([()=>ty=null])},...e]})}function ry(e=[]){if(ty)return ty;let t=ny(e);return ty=t,fg(),iy(t),t}function iy(e){let t=e.get(nc,null);Ga(e,()=>{t?.forEach(e=>e())})}function ay(e){let{rootComponent:t,appProviders:n,platformProviders:r,platformRef:i}=e;Rc(Tc.BootstrapApplicationStart);try{let e=i?.injector??ry(r);return Qv({r3Injector:new Uh({providers:[Ov(),Qs,...n||[]],parent:e,debugName:``,runEnvironmentInitializers:!1}).injector,platformInjector:e,rootComponent:t})}catch(e){return Promise.reject(e)}finally{Rc(Tc.BootstrapApplicationEnd)}}function oy(e){return typeof e==`boolean`?e:e!=null&&e!==`false`}var sy=Symbol(`NOT_SET`),cy=new Set,ly={...qn,kind:`afterRenderEffectPhase`,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,value:sy,cleanup:null,consumerMarkedDirty(){if(this.sequence.impl.executing){if(this.sequence.lastPhase===null||this.sequence.lastPhase(hn(r),r.value),r.signal[fn]=r,r.registerCleanupFn=e=>(r.cleanup??=new Set).add(e),this.nodes[e]=r,this.hooks[e]=e=>r.phaseFn(e)}}afterRun(){super.afterRun(),this.lastPhase=null}destroy(){if(this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();super.destroy();for(let e of this.nodes)if(e)try{for(let t of e.cleanup??cy)t()}finally{Dn(e)}}};function dy(e,t){let n=t?.injector??w(ws),r=n.get(sc),i=n.get(Ld),a=n.get(Pd,null,{optional:!0});i.impl??=n.get(zd);let o=e;typeof o==`function`&&(o={mixedReadWrite:e});let s=n.get(ac,null,{optional:!0}),c=new uy(i.impl,[o.earlyRead,o.write,o.mixedReadWrite,o.read],s?.view,r,n,a?.snapshot(null));return i.impl.register(c),c}var fy=null;function py(){return fy}function my(e){fy??=e}var hy=class{},gy=(function(e){return e[e.Format=0]=`Format`,e[e.Standalone=1]=`Standalone`,e})(gy||{}),_y=(function(e){return e[e.Narrow=0]=`Narrow`,e[e.Abbreviated=1]=`Abbreviated`,e[e.Wide=2]=`Wide`,e[e.Short=3]=`Short`,e})(_y||{}),vy=(function(e){return e[e.Short=0]=`Short`,e[e.Medium=1]=`Medium`,e[e.Long=2]=`Long`,e[e.Full=3]=`Full`,e})(vy||{}),yy={Decimal:0,Group:1,List:2,PercentSign:3,PlusSign:4,MinusSign:5,Exponential:6,SuperscriptingExponent:7,PerMille:8,Infinity:9,NaN:10,TimeSeparator:11,CurrencyDecimal:12,CurrencyGroup:13};function by(e){return Qg(e)[e_.LocaleId]}function xy(e,t,n){let r=Qg(e);return My(My([r[e_.DayPeriodsFormat],r[e_.DayPeriodsStandalone]],t),n)}function Sy(e,t,n){let r=Qg(e);return My(My([r[e_.DaysFormat],r[e_.DaysStandalone]],t),n)}function Cy(e,t,n){let r=Qg(e);return My(My([r[e_.MonthsFormat],r[e_.MonthsStandalone]],t),n)}function wy(e,t){let n=Qg(e)[e_.Eras];return My(n,t)}function Ty(e,t){return My(Qg(e)[e_.DateFormat],t)}function Ey(e,t){return My(Qg(e)[e_.TimeFormat],t)}function Dy(e,t){let n=Qg(e)[e_.DateTimeFormat];return My(n,t)}function Oy(e,t){let n=Qg(e),r=n[e_.NumberSymbols][t];if(r===void 0){if(t===yy.CurrencyDecimal)return n[e_.NumberSymbols][yy.Decimal];if(t===yy.CurrencyGroup)return n[e_.NumberSymbols][yy.Group]}return r}function ky(e){if(!e[e_.ExtraData])throw new ri(2303,!1)}function Ay(e){let t=Qg(e);return ky(t),(t[e_.ExtraData][2]||[]).map(e=>typeof e==`string`?Ny(e):[Ny(e[0]),Ny(e[1])])}function jy(e,t,n){let r=Qg(e);return ky(r),My(My([r[e_.ExtraData][0],r[e_.ExtraData][1]],t)||[],n)||[]}function My(e,t){for(let n=t;n>-1;n--)if(e[n]!==void 0)return e[n];throw new ri(2304,!1)}function Ny(e){let[t,n]=e.split(`:`);return{hours:+t,minutes:+n}}var Py=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,Fy=Object.create(null),Iy=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/,Ly=256;function Ry(e,t,n,r){let i=sb(e);zy(t),t=Vy(n,t)||t;let a=[],o;for(;t;)if(o=Iy.exec(t),o){a=a.concat(o.slice(1));let e=a.pop();if(!e)break;t=e}else{a.push(t);break}let s=i.getTimezoneOffset();r&&(s=ib(r,s),i=ob(i,r));let c=``;return a.forEach(e=>{let t=rb(e);c+=t?t(i,n,s):e===`''`?`'`:e.replace(/(^'|'$)/g,``).replace(/''/g,`'`)}),c}function zy(e){if(e.length>Ly)throw new ri(2300,!1)}function By(e,t,n){let r=new Date(0);return r.setFullYear(e,t,n),r.setHours(0,0,0),r}function Vy(e,t){let n=by(e);if(Fy[n]??=Object.create(null),Fy[n][t])return Fy[n][t];let r=``;switch(t){case`shortDate`:r=Ty(e,vy.Short);break;case`mediumDate`:r=Ty(e,vy.Medium);break;case`longDate`:r=Ty(e,vy.Long);break;case`fullDate`:r=Ty(e,vy.Full);break;case`shortTime`:r=Ey(e,vy.Short);break;case`mediumTime`:r=Ey(e,vy.Medium);break;case`longTime`:r=Ey(e,vy.Long);break;case`fullTime`:r=Ey(e,vy.Full);break;case`short`:let t=Vy(e,`shortTime`),n=Vy(e,`shortDate`);r=Hy(Dy(e,vy.Short),[t,n]);break;case`medium`:let i=Vy(e,`mediumTime`),a=Vy(e,`mediumDate`);r=Hy(Dy(e,vy.Medium),[i,a]);break;case`long`:let o=Vy(e,`longTime`),s=Vy(e,`longDate`);r=Hy(Dy(e,vy.Long),[o,s]);break;case`full`:let c=Vy(e,`fullTime`),l=Vy(e,`fullDate`);r=Hy(Dy(e,vy.Full),[c,l])}return r&&(Fy[n][t]=r),r}function Hy(e,t){return t&&(e=e.replace(/\{([^}]+)}/g,function(e,n){return Object.hasOwn(t,n)?t[n]:e})),e}function Uy(e,t,n=`-`,r,i){let a=``;(e<0||i&&e<=0)&&(i?e=-e+1:(e=-e,a=n));let o=String(e);for(;o.length0||s>-n)&&(s+=n),e===3)s===0&&n===-12&&(s=12);else if(e===6)return Wy(s,t);let c=Oy(o,yy.MinusSign);return Uy(s,t,c,r,i)}}function Ky(e,t){switch(e){case 0:return t.getFullYear();case 1:return t.getMonth();case 2:return t.getDate();case 3:return t.getHours();case 4:return t.getMinutes();case 5:return t.getSeconds();case 6:return t.getMilliseconds();case 7:return t.getDay();default:throw new ri(2301,!1)}}function qy(e,t,n=gy.Format,r=!1){return function(i,a){return Jy(i,a,e,t,n,r)}}function Jy(e,t,n,r,i,a){switch(n){case 2:return Cy(t,i,r)[e.getMonth()];case 1:return Sy(t,i,r)[e.getDay()];case 0:let n=e.getHours(),o=e.getMinutes();if(a){let e=Ay(t),a=jy(t,i,r),s=e.findIndex(e=>{if(Array.isArray(e)){let[t,r]=e,i=n>=t.hours&&o>=t.minutes,a=n0?Math.floor(i/60):Math.ceil(i/60);switch(e){case 0:return(i>=0?`+`:``)+Uy(o,2,a)+Uy(Math.abs(i%60),2,a);case 1:return`GMT`+(i>=0?`+`:``)+Uy(o,1,a);case 2:return`GMT`+(i>=0?`+`:``)+Uy(o,2,a)+`:`+Uy(Math.abs(i%60),2,a);case 3:return r===0?`Z`:(i>=0?`+`:``)+Uy(o,2,a)+`:`+Uy(Math.abs(i%60),2,a);default:throw new ri(2310,!1)}}}var Xy=0,Zy=4;function Qy(e){let t=By(e,Xy,1).getDay();return By(e,0,1+(t<=Zy?Zy:11)-t)}function $y(e){let t=e.getDay(),n=t===0?-3:Zy-t;return By(e.getFullYear(),e.getMonth(),e.getDate()+n)}function eb(e,t=!1){return function(n,r){let i;if(t){let e=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,t=n.getDate();i=1+Math.floor((t+e)/7)}else{let e=$y(n),t=Qy(e.getFullYear()),r=e.getTime()-t.getTime();i=1+Math.round(r/6048e5)}return Uy(i,e,Oy(r,yy.MinusSign))}}function tb(e,t=!1){return function(n,r){return Uy($y(n).getFullYear(),e,Oy(r,yy.MinusSign),t)}}var nb=Object.create(null);function rb(e){if(nb[e])return nb[e];let t;switch(e){case`G`:case`GG`:case`GGG`:t=qy(3,_y.Abbreviated);break;case`GGGG`:t=qy(3,_y.Wide);break;case`GGGGG`:t=qy(3,_y.Narrow);break;case`y`:t=Gy(0,1,0,!1,!0);break;case`yy`:t=Gy(0,2,0,!0,!0);break;case`yyy`:t=Gy(0,3,0,!1,!0);break;case`yyyy`:t=Gy(0,4,0,!1,!0);break;case`Y`:t=tb(1);break;case`YY`:t=tb(2,!0);break;case`YYY`:t=tb(3);break;case`YYYY`:t=tb(4);break;case`M`:case`L`:t=Gy(1,1,1);break;case`MM`:case`LL`:t=Gy(1,2,1);break;case`MMM`:t=qy(2,_y.Abbreviated);break;case`MMMM`:t=qy(2,_y.Wide);break;case`MMMMM`:t=qy(2,_y.Narrow);break;case`LLL`:t=qy(2,_y.Abbreviated,gy.Standalone);break;case`LLLL`:t=qy(2,_y.Wide,gy.Standalone);break;case`LLLLL`:t=qy(2,_y.Narrow,gy.Standalone);break;case`w`:t=eb(1);break;case`ww`:t=eb(2);break;case`W`:t=eb(1,!0);break;case`d`:t=Gy(2,1);break;case`dd`:t=Gy(2,2);break;case`c`:case`cc`:t=Gy(7,1);break;case`ccc`:t=qy(1,_y.Abbreviated,gy.Standalone);break;case`cccc`:t=qy(1,_y.Wide,gy.Standalone);break;case`ccccc`:t=qy(1,_y.Narrow,gy.Standalone);break;case`cccccc`:t=qy(1,_y.Short,gy.Standalone);break;case`E`:case`EE`:case`EEE`:t=qy(1,_y.Abbreviated);break;case`EEEE`:t=qy(1,_y.Wide);break;case`EEEEE`:t=qy(1,_y.Narrow);break;case`EEEEEE`:t=qy(1,_y.Short);break;case`a`:case`aa`:case`aaa`:t=qy(0,_y.Abbreviated);break;case`aaaa`:t=qy(0,_y.Wide);break;case`aaaaa`:t=qy(0,_y.Narrow);break;case`b`:case`bb`:case`bbb`:t=qy(0,_y.Abbreviated,gy.Standalone,!0);break;case`bbbb`:t=qy(0,_y.Wide,gy.Standalone,!0);break;case`bbbbb`:t=qy(0,_y.Narrow,gy.Standalone,!0);break;case`B`:case`BB`:case`BBB`:t=qy(0,_y.Abbreviated,gy.Format,!0);break;case`BBBB`:t=qy(0,_y.Wide,gy.Format,!0);break;case`BBBBB`:t=qy(0,_y.Narrow,gy.Format,!0);break;case`h`:t=Gy(3,1,-12);break;case`hh`:t=Gy(3,2,-12);break;case`H`:t=Gy(3,1);break;case`HH`:t=Gy(3,2);break;case`m`:t=Gy(4,1);break;case`mm`:t=Gy(4,2);break;case`s`:t=Gy(5,1);break;case`ss`:t=Gy(5,2);break;case`S`:t=Gy(6,1);break;case`SS`:t=Gy(6,2);break;case`SSS`:t=Gy(6,3);break;case`Z`:case`ZZ`:case`ZZZ`:t=Yy(0);break;case`ZZZZZ`:t=Yy(3);break;case`O`:case`OO`:case`OOO`:case`z`:case`zz`:case`zzz`:t=Yy(1);break;case`OOOO`:case`ZZZZ`:case`zzzz`:t=Yy(2);break;default:return null}return nb[e]=t,t}function ib(e,t){e=e.replace(/:/g,``);let n=Date.parse(`Jan 01, 1970 00:00:00 `+e)/6e4;return isNaN(n)?t:n}function ab(e,t){return e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+t),e}function ob(e,t,n){let r=e.getTimezoneOffset();return ab(e,-1*(ib(t,r)-r))}function sb(e){if(lb(e))return e;if(typeof e==`number`&&!isNaN(e))return new Date(e);if(typeof e==`string`){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){let[t,n=1,r=1]=e.split(`-`).map(e=>+e);return By(t,n-1,r)}let t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let n;if(n=e.match(Py))return cb(n)}let t=new Date(e);if(!lb(t))throw new ri(2311,!1);return t}function cb(e){let t=new Date(0),n=0,r=0,i=e[8]?t.setUTCFullYear:t.setFullYear,a=e[8]?t.setUTCHours:t.setHours;e[9]&&(n=Number(e[9]+e[10]),r=Number(e[9]+e[11])),i.call(t,Number(e[1]),Number(e[2])-1,Number(e[3]));let o=Number(e[4]||0)-n,s=Number(e[5]||0)-r,c=Number(e[6]||0),l=Math.floor(parseFloat(`0.`+(e[7]||0))*1e3);return a.call(t,o,s,c,l),t}function lb(e){return e instanceof Date&&!isNaN(e.valueOf())}var ub=(()=>{class e{_viewContainerRef;_viewRef=null;ngTemplateOutletContext=null;ngTemplateOutlet=null;ngTemplateOutletInjector=null;injector=w(ws);constructor(e){this._viewContainerRef=e}ngOnChanges(e){if(this._shouldRecreateView(e)){let e=this._viewContainerRef;if(this._viewRef&&e.remove(e.indexOf(this._viewRef)),!this.ngTemplateOutlet){this._viewRef=null;return}let t=this._createContextForwardProxy();this._viewRef=e.createEmbeddedView(this.ngTemplateOutlet,t,{injector:this._getInjector()})}}_getInjector(){return this.ngTemplateOutletInjector===`outlet`?this.injector:this.ngTemplateOutletInjector??void 0}_shouldRecreateView(e){return!!e.ngTemplateOutlet||!!e.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(e,t,n)=>this.ngTemplateOutletContext?Reflect.set(this.ngTemplateOutletContext,t,n):!1,get:(e,t,n)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,t,n)}})}static ɵfac=function(t){return new(t||e)(Em(oh))};static ɵdir=Xh({type:e,selectors:[[``,`ngTemplateOutlet`,``]],inputs:{ngTemplateOutletContext:`ngTemplateOutletContext`,ngTemplateOutlet:`ngTemplateOutlet`,ngTemplateOutletInjector:`ngTemplateOutletInjector`},features:[kc]})}return e})();function db(e,t){return new ri(2100,!1)}var fb=`mediumDate`,pb=new bi(``),mb=new bi(``),hb=(()=>{class e{locale;defaultTimezone;defaultOptions;constructor(e,t,n){this.locale=e,this.defaultTimezone=t,this.defaultOptions=n}transform(t,n,r,i){if(t==null||t===``||t!==t)return null;try{let e=n??this.defaultOptions?.dateFormat??fb,a=r??this.defaultOptions?.timezone??this.defaultTimezone??void 0;return Ry(t,e,i||this.locale,a)}catch(t){throw db(e,t.message)}}static ɵfac=function(t){return new(t||e)(Em(Av,16),Em(pb,24),Em(mb,24))};static ɵpipe=Zh({name:`date`,type:e,pure:!0})}return e})(),gb=(()=>{class e{transform(e){return JSON.stringify(e,null,2)}static ɵfac=function(t){return new(t||e)};static ɵpipe=Zh({name:`json`,type:e,pure:!1})}return e})();function _b(e,t){t=encodeURIComponent(t);for(let n of e.split(`;`)){let e=n.indexOf(`=`),[r,i]=e==-1?[n,``]:[n.slice(0,e),n.slice(e+1)];if(r.trim()!==t)continue;let a=i;try{a=decodeURIComponent(i)}catch{}return a.length>1&&a[0]===`"`&&a[a.length-1]===`"`&&(a=a.slice(1,-1)),a}return null}var vb=`browser`,yb=class{_doc;constructor(e){this._doc=e}manager},bb=(()=>{class e extends yb{constructor(e){super(e)}supports(e){return!0}addEventListener(e,t,n,r){return e.addEventListener(t,n,r),()=>this.removeEventListener(e,t,n,r)}removeEventListener(e,t,n,r){return e.removeEventListener(t,n,r)}static ɵfac=function(t){return new(t||e)(Yi(Ts))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),xb=new bi(``),Sb=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(e,t){this._zone=t,e.forEach(e=>{e.manager=this});let n=e.filter(e=>!(e instanceof bb));this._plugins=n.slice().reverse();let r=e.find(e=>e instanceof bb);r&&this._plugins.push(r)}addEventListener(e,t,n,r){return this._findPluginFor(t).addEventListener(e,t,n,r)}getZone(){return this._zone}_findPluginFor(e){let t=this._eventNameToPlugin.get(e);if(t)return t;if(t=this._plugins.find(t=>t.supports(e)),!t)throw new ri(-5101,!1);return this._eventNameToPlugin.set(e,t),t}static ɵfac=function(t){return new(t||e)(Yi(xb),Yi(Rs))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),Cb=`ng-app-id`;function wb(e){for(let t of e)t.remove()}function Tb(e,t){let n=t.createElement(`style`);return n.textContent=e,n}function Eb(e,t,n,r){let i=e.head?.querySelectorAll(`style[${Cb}="${t}"],link[${Cb}="${t}"]`);if(!i||i.length===0)return!1;for(let e of i)e.removeAttribute(Cb),e instanceof HTMLLinkElement?r.set(e.href.slice(e.href.lastIndexOf(`/`)+1),{usage:0,elements:[e]}):e.textContent&&n.set(e.textContent,{usage:0,elements:[e]});return!0}function Db(e,t){let n=t.createElement(`link`);return n.setAttribute(`rel`,`stylesheet`),n.setAttribute(`href`,e),n}var Ob=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;constructor(e,t,n,r={}){this.doc=e,this.appId=t,this.nonce=n,Eb(e,t,this.inline,this.external)&&this.hosts.add(e.head)}addStyles(e,t){for(let t of e)this.addUsage(t,this.inline,Tb);t?.forEach(e=>this.addUsage(e,this.external,Db))}removeStyles(e,t){for(let t of e)this.removeUsage(t,this.inline);t?.forEach(e=>this.removeUsage(e,this.external))}addUsage(e,t,n){let r=t.get(e);r?r.usage++:t.set(e,{usage:1,elements:[...this.hosts].map(t=>this.addElement(t,n(e,this.doc)))})}removeUsage(e,t){let n=t.get(e);n&&(n.usage--,n.usage<=0&&(wb(n.elements),t.delete(e)))}ngOnDestroy(){for(let[,{elements:e}]of[...this.inline,...this.external])wb(e);this.hosts.clear()}addHost(e){if(!this.hosts.has(e)){this.hosts.add(e);for(let[t,{elements:n}]of this.inline)n.push(this.addElement(e,Tb(t,this.doc)));for(let[t,{elements:n}]of this.external)n.push(this.addElement(e,Db(t,this.doc)))}}removeHost(e){this.hosts.delete(e);for(let t of[...this.inline.values(),...this.external.values()]){let n=[];for(let r of t.elements)r.parentNode===e?r.remove():n.push(r);t.elements=n}}addElement(e,t){return this.nonce&&t.setAttribute(`nonce`,this.nonce),e.appendChild(t)}static ɵfac=function(t){return new(t||e)(Yi(Ts),Yi(ec),Yi(ic,8),Yi(rc))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),kb={svg:`http://www.w3.org/2000/svg`,xhtml:`http://www.w3.org/1999/xhtml`,xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`,xmlns:`http://www.w3.org/2000/xmlns/`,math:`http://www.w3.org/1998/Math/MathML`},Ab=/%COMP%/g,jb=`%COMP%`,Mb=`_nghost-${jb}`,Nb=`_ngcontent-${jb}`,Pb=!0,Fb=new bi(``,{factory:()=>Pb}),Ib=new bi(``);function Lb(e){return Nb.replace(Ab,e)}function Rb(e){return Mb.replace(Ab,e)}function zb(e,t){return t.map(t=>t.replace(Ab,e))}var Bb=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;cssVarNamespace;constructor(e,t,n,r,i,a,o=null,s=null,c=null){this.eventManager=e,this.sharedStylesHost=t,this.appId=n,this.removeStylesOnCompDestroy=r,this.doc=i,this.ngZone=a,this.nonce=o,this.tracingService=s,this.cssVarNamespace=c??``,this.defaultRenderer=new Vb(e,i,a,this.tracingService,this.cssVarNamespace)}createRenderer(e,t){if(!e||!t)return this.defaultRenderer;let n=this.getOrCreateRenderer(e,t);return n instanceof Gb?n.applyToHost(e):n instanceof Wb&&n.applyStyles(),n}getOrCreateRenderer(e,t){let n=this.rendererByCompId,r=n.get(t.id);if(!r){let i=this.doc,a=this.ngZone,o=this.eventManager,s=this.sharedStylesHost,c=this.removeStylesOnCompDestroy,l=this.tracingService;switch(t.encapsulation){case uu.Emulated:r=new Gb(o,s,t,this.appId,c,i,a,l,this.cssVarNamespace);break;case uu.ShadowDom:return new Ub(o,e,t,i,a,this.nonce,l,this.cssVarNamespace,s);case uu.ExperimentalIsolatedShadowDom:return new Ub(o,e,t,i,a,this.nonce,l,this.cssVarNamespace);default:r=new Wb(o,s,t,c,i,a,l,this.cssVarNamespace)}n.set(t.id,r)}return r}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(e){this.rendererByCompId.delete(e)}static ɵfac=function(t){return new(t||e)(Yi(Sb),Yi(wm),Yi(ec),Yi(Fb),Yi(Ts),Yi(Rs),Yi(ic),Yi(Pd,8),Yi(Ib,8))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})(),Vb=class{eventManager;doc;ngZone;tracingService;cssVarNamespace;data=Object.create(null);throwOnSyntheticProps=!0;constructor(e,t,n,r,i=``){this.eventManager=e,this.doc=t,this.ngZone=n,this.tracingService=r,this.cssVarNamespace=i}destroy(){}destroyNode=null;createElement(e,t){return t?this.doc.createElementNS(kb[t]||t,e):this.doc.createElement(e)}createComment(e){return this.doc.createComment(e)}createText(e){return this.doc.createTextNode(e)}appendChild(e,t){(Hb(e)?e.content:e).appendChild(t)}insertBefore(e,t,n){if(e){let r=Hb(e)?e.content:e;if(n!=null&&n.parentNode!==r)throw new ri(-5106,!1);r.insertBefore(t,n)}}removeChild(e,t){t.remove()}selectRootElement(e,t){let n=typeof e==`string`?this.doc.querySelector(e):e;if(!n)throw new ri(-5104,!1);return t||(n.textContent=``),n}parentNode(e){return e.parentNode}nextSibling(e){return e.nextSibling}setAttribute(e,t,n,r){if(r){t=r+`:`+t;let i=kb[r];i?e.setAttributeNS(i,t,n):e.setAttribute(t,n)}else e.setAttribute(t,n)}removeAttribute(e,t,n){if(n){let r=kb[n];r?e.removeAttributeNS(r,t):e.removeAttribute(`${n}:${t}`)}else e.removeAttribute(t)}addClass(e,t){e.classList.add(t)}removeClass(e,t){e.classList.remove(t)}setStyle(e,t,n,r){let i=t.startsWith(`--`);i&&(t=t.replace(`%NS%`,this.cssVarNamespace)),i||r&(ed.DashCase|ed.Important)?e.style.setProperty(t,n,r&ed.Important?`important`:``):e.style[t]=n}removeStyle(e,t,n){let r=t.startsWith(`--`);r&&(t=t.replace(`%NS%`,this.cssVarNamespace)),r||n&ed.DashCase?e.style.removeProperty(t):e.style[t]=``}setProperty(e,t,n){e!=null&&(e[t]=n)}setValue(e,t){e.nodeValue=t}listen(e,t,n,r){if(typeof e==`string`&&(e=py().getGlobalEventTarget(this.doc,e),!e))throw new ri(-5102,!1);let i=this.decoratePreventDefault(n);return this.tracingService?.wrapEventListener&&(i=this.tracingService.wrapEventListener(e,t,i)),this.eventManager.addEventListener(e,t,i,r)}decoratePreventDefault(e){return t=>{if(t===`__ngUnwrap__`)return e;e(t)===!1&&t.preventDefault()}}};function Hb(e){return e.tagName===`TEMPLATE`&&e.content!==void 0}var Ub=class extends Vb{hostEl;sharedStylesHost;shadowRoot;constructor(e,t,n,r,i,a,o,s,c){super(e,r,i,o,s),this.hostEl=t,this.sharedStylesHost=c,this.shadowRoot=t.attachShadow({mode:`open`}),this.sharedStylesHost&&this.sharedStylesHost.addHost(this.shadowRoot);let l=n.styles;l=zb(n.id,l).map(e=>e.replace(/%NS%/g,s));for(let e of l){let t=document.createElement(`style`);a&&t.setAttribute(`nonce`,a),t.textContent=e,this.shadowRoot.appendChild(t)}let u=n.getExternalStyles?.();if(u)for(let e of u){let t=Db(e,r);a&&t.setAttribute(`nonce`,a),this.shadowRoot.appendChild(t)}}nodeOrShadowRoot(e){return e===this.hostEl?this.shadowRoot:e}appendChild(e,t){return super.appendChild(this.nodeOrShadowRoot(e),t)}insertBefore(e,t,n){return super.insertBefore(this.nodeOrShadowRoot(e),t,n)}removeChild(e,t){return super.removeChild(null,t)}parentNode(e){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(e)))}destroy(){this.sharedStylesHost&&this.sharedStylesHost.removeHost(this.shadowRoot)}},Wb=class extends Vb{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(e,t,n,r,i,a,o,s,c){super(e,i,a,o,s),this.sharedStylesHost=t,this.removeStylesOnCompDestroy=r;let l=n.styles,u=c?zb(c,l):l;this.styles=u.map(e=>e.replace(/%NS%/g,s)),this.styleUrls=n.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&md.size===0&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}},Gb=class extends Wb{contentAttr;hostAttr;constructor(e,t,n,r,i,a,o,s,c){let l=r+`-`+n.id;super(e,t,n,i,a,o,s,c,l),this.contentAttr=Lb(l),this.hostAttr=Rb(l)}applyToHost(e){this.applyStyles(),this.setAttribute(e,this.hostAttr,``)}createElement(e,t){let n=super.createElement(e,t);return super.setAttribute(n,this.contentAttr,``),n}},Kb=class e extends hy{supportsDOMEvents=!0;static makeCurrent(){my(new e)}onAndCancel(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}dispatchEvent(e,t){e.dispatchEvent(t)}remove(e){e.remove()}createElement(e,t){return t||=this.getDefaultDocument(),t.createElement(e)}createHtmlDocument(){return document.implementation.createHTMLDocument(`fakeTitle`)}getDefaultDocument(){return document}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}isShadowRoot(e){return e instanceof DocumentFragment}getGlobalEventTarget(e,t){return t===`window`?window:t===`document`?e:t===`body`?e.body:null}getBaseHref(e){let t=Jb();return t==null?null:Yb(t)}resetBaseElement(){qb=null}getUserAgent(){return window.navigator.userAgent}getCookie(e){return _b(document.cookie,e)}},qb=null;function Jb(){return qb||=document.head.querySelector(`base`),qb?qb.getAttribute(`href`):null}function Yb(e){return new URL(e,document.baseURI).pathname}var Xb=[`alt`,`control`,`meta`,`shift`],Zb={"\b":`Backspace`," ":`Tab`,"":`Delete`,"\x1B":`Escape`,Del:`Delete`,Esc:`Escape`,Left:`ArrowLeft`,Right:`ArrowRight`,Up:`ArrowUp`,Down:`ArrowDown`,Menu:`ContextMenu`,Scroll:`ScrollLock`,Win:`OS`},Qb={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey},$b=(()=>{class e extends yb{constructor(e){super(e)}supports(t){return e.parseEventName(t)!=null}addEventListener(t,n,r,i){let a=e.parseEventName(n),o=e.eventCallback(a.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>py().onAndCancel(t,a.domEventName,o,i))}static parseEventName(t){let n=t.toLowerCase().split(`.`),r=n.shift();if(n.length===0||r!==`keydown`&&r!==`keyup`)return null;let i=e._normalizeKey(n.pop()),a=``,o=n.indexOf(`code`);if(o>-1&&(n.splice(o,1),a=`code.`),Xb.forEach(e=>{let t=n.indexOf(e);t>-1&&(n.splice(t,1),a+=e+`.`)}),a+=i,n.length!=0||i.length===0)return null;let s={};return s.domEventName=r,s.fullKey=a,s}static matchEventFullKeyCode(e,t){let n=Zb[e.key]||e.key,r=``;return t.indexOf(`code.`)>-1&&(n=e.code,r=`code.`),n==null||!n?!1:(n=n.toLowerCase(),n===` `?n=`space`:n===`.`&&(n=`dot`),Xb.forEach(t=>{if(t!==n){let n=Qb[t];n(e)&&(r+=t+`.`)}}),r+=n,r===t)}static eventCallback(t,n,r){return i=>{e.matchEventFullKeyCode(i,t)&&r.runGuarded(()=>n(i))}}static _normalizeKey(e){return e===`esc`?`escape`:e}static ɵfac=function(t){return new(t||e)(Yi(Ts))};static ɵprov=pi({token:e,factory:e.ɵfac})}return e})();async function ex(e,t,n){return ay({rootComponent:e,...tx(t,n)})}function tx(e,t){return{platformRef:t?.platformRef,appProviders:[...ox,...e?.providers??[]],platformProviders:ax}}function nx(){Kb.makeCurrent()}function rx(){return new Xs}function ix(){return Ql(document),document}var ax=[{provide:rc,useValue:vb},{provide:nc,useValue:nx,multi:!0},{provide:Ts,useFactory:ix}],ox=[{provide:Oa,useValue:`root`},{provide:Xs,useFactory:rx},{provide:xb,useClass:bb,multi:!0},{provide:xb,useClass:$b,multi:!0},Bb,{provide:wm,useClass:Ob},{provide:Ob,useExisting:wm},Sb,{provide:am,useExisting:Bb},[]];function sx(e,t){let n=`\x1B[${e}m`,r=`\x1B[${t}m`;return((e,...t)=>{if(Array.isArray(e)&&`raw`in e){let i=e,a=``;for(let e=0;e{let r=new dx({code:i,why:lx(a.why,e),fix:lx(a.fix,e),docs:o,cause:e.cause,sources:e.sources,data:lx(a.data,e)},s);for(let e of t)e(r,n);return r};n[i]=s}return n}function mx(e){return t=>{let n=`${e.bold(e.red(`[${t.name}]`))} ${t.message}`,r=[];return t.fix&&r.push(`${e.dim(`fix:`)} ${t.fix}`),t.sources?.length&&r.push(`${e.dim(`sources:`)} ${t.sources.join(`, `)}`),t.docs&&r.push(`${e.dim(`see:`)} ${e.cyan(t.docs)}`),r.length===0?n:[n,...r.map((t,n)=>`${e.dim(n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(t){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,t)},t.prototype._subscribe=function(e){return this._throwIfClosed(),this._checkFinalizedStatuses(e),this._innerSubscribe(e)},t.prototype._innerSubscribe=function(e){var t=this,n=this,r=n.hasError,i=n.isStopped,a=n.observers;return r||i?vr:(this.currentObservers=null,a.push(e),new _r(function(){t.currentObservers=null,gr(a,e)}))},t.prototype._checkFinalizedStatuses=function(e){var t=this,n=t.hasError,r=t.thrownError,i=t.isStopped;n?e.error(r):i&&e.complete()},t.prototype.asObservable=function(){var e=new Wr;return e.source=this,e},t.create=function(e,t){return new ei(e,t)},t}(Wr),ei=function(e){lr(t,e);function t(t,n){var r=e.call(this)||this;return r.destination=t,r.source=n,r}return t.prototype.next=function(e){var t,n;(n=(t=this.destination)?.next)==null||n.call(t,e)},t.prototype.error=function(e){var t,n;(n=(t=this.destination)?.error)==null||n.call(t,e)},t.prototype.complete=function(){var e,t;(t=(e=this.destination)?.complete)==null||t.call(e)},t.prototype._subscribe=function(e){return this.source?.subscribe(e)??vr},t}($r),ti=function(e){lr(t,e);function t(t){var n=e.call(this)||this;return n._value=t,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(t){var n=e.prototype._subscribe.call(this,t);return!n.closed&&t.next(this._value),n},t.prototype.getValue=function(){var e=this,t=e.hasError,n=e.thrownError,r=e._value;if(t)throw n;return this._throwIfClosed(),r},t.prototype.next=function(t){e.prototype.next.call(this,this._value=t)},t}($r);function ni(e,t){return Yr(function(n,r){var i=0;n.subscribe(Xr(r,function(n){r.next(e.call(t,n,i++))}))})}var ri=`https://angular.dev/best-practices/security#preventing-cross-site-scripting-xss`,ii=class extends Error{code;constructor(e,t){super(oi(e,t)),this.code=e}};function ai(e){return`NG0${Math.abs(e)}`}function oi(e,t){return`${ai(e)}${t?`: `+t:``}`}function si(e){for(let t in e)if(e[t]===si)return t;throw Error(``)}function ci(e){if(typeof e==`string`)return e;if(Array.isArray(e))return`[${e.map(ci).join(`, `)}]`;if(e==null)return``+e;let t=e.overriddenName||e.name;if(t)return`${t}`;let n=e.toString();if(n==null)return``+n;let r=n.indexOf(` +`);return r>=0?n.slice(0,r):n}function li(e,t){return e?t?`${e} ${t}`:e:t||``}var ui=si({__forward_ref__:si});function di(e){return e.__forward_ref__=di,e}function fi(e){return pi(e)?e():e}function pi(e){return typeof e==`function`&&Object.hasOwn(e,ui)&&e.__forward_ref__===di}function mi(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function hi(e){return gi(e,yi)}function gi(e,t){return Object.hasOwn(e,t)&&e[t]||null}function _i(e){return(e?.[yi]??null)||null}function vi(e){return e&&Object.hasOwn(e,bi)?e[bi]:null}var yi=si({ɵprov:si}),bi=si({ɵinj:si}),xi=class{_desc;ngMetadataName=`InjectionToken`;ɵprov;constructor(e,t){this._desc=e,this.ɵprov=void 0,typeof t==`number`?this.__NG_ELEMENT_ID__=t:t!==void 0&&(this.ɵprov=mi({token:this,providedIn:t.providedIn||`root`,factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}};function Si(e){return e&&!!e.ɵproviders}var Ci=si({ɵcmp:si}),wi=si({ɵdir:si}),Ti=si({ɵpipe:si}),Ei=si({ɵfac:si}),Di=si({__NG_ELEMENT_ID__:si}),Oi=si({__NG_ENV_ID__:si});function ki(e){return Mi(e,`@Component`),e[Ci]||null}function Ai(e){return Mi(e,`@Directive`),e[wi]||null}function ji(e){return Mi(e,`@Pipe`),e[Ti]||null}function Mi(e,t){if(e==null)throw new ii(-919,!1)}function Ni(e){return typeof e==`string`?e:e==null?``:String(e)}var Pi=si({ngErrorCode:si}),Fi=si({ngErrorMessage:si}),Ii=si({ngTokenPath:si});function Li(e,t){return zi(``,-200,t)}function Ri(e,t){throw new ii(-201,!1)}function zi(e,t,n){let r=new ii(t,e);return r[Pi]=t,r[Fi]=e,n&&(r[Ii]=n),r}function Bi(e){return e[Pi]}var Vi;function Hi(){return Vi}function Ui(e){let t=Vi;return Vi=e,t}function Wi(e,t,n){let r=hi(e);if(r&&r.providedIn==`root`)return r.value===void 0?r.value=r.factory():r.value;if(n&8)return null;if(t!==void 0)return t;Ri(e,``)}var Gi=globalThis,Ki={},qi=`__NG_DI_FLAG__`,Ji=class{injector;constructor(e){this.injector=e}retrieve(e,t){let n=Zi(t)||0;try{return this.injector.get(e,n&8?null:Ki,n)}catch(e){if(nr(e))return e;throw e}}};function Yi(e,t=0){let n=$n();if(n===void 0)throw new ii(-203,!1);if(n===null)return Wi(e,void 0,t);{let r=Qi(t),i=n.retrieve(e,r);if(nr(i)){if(r.optional)return null;throw i}return i}}function Xi(e,t=0){return(Hi()||Yi)(fi(e),t)}function C(e,t){return Xi(e,Zi(t))}function Zi(e){return e===void 0||typeof e==`number`?e:0|(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function Qi(e){return{optional:!!(e&8),host:!!(e&1),self:!!(e&2),skipSelf:!!(e&4)}}function $i(e){let t=[];for(let n=0;nArray.isArray(e)?ia(e,t):t(e))}function aa(e,t,n){t>=e.length?e.push(n):e.splice(t,0,n)}function oa(e,t){return t>=e.length-1?e.pop():e.splice(t,1)[0]}function sa(e,t){let n=[];for(let r=0;rt;){let t=i-2;e[i]=e[t],i--}e[t]=n,e[t+1]=r}}function la(e,t,n){let r=da(e,t);return r>=0?e[r|1]=n:(r=~r,ca(e,r,t,n)),r}function ua(e,t){let n=da(e,t);if(n>=0)return e[n|1]}function da(e,t){return fa(e,t,1)}function fa(e,t,n){let r=0,i=e.length>>n;for(;i!==r;){let a=r+(i-r>>1),o=e[a<t?i=a:r=a+1}return~(i<{n.push(e)};return ia(t,e=>{let t=e;Sa(t,a,[],r)&&(i||=[],i.push(t))}),i!==void 0&&xa(i,a),n}function xa(e,t){for(let n=0;n{t(e,r)})}}function Sa(e,t,n,r){if(e=fi(e),!e)return!1;let i=null,a=vi(e),o=!a&&ki(e);if(!a&&!o){let t=e.ngModule;if(a=vi(t),a)i=t;else return!1}else if(o&&!o.standalone)return!1;else i=e;let s=r.has(i);if(o){if(s)return!1;if(r.add(i),o.dependencies){let e=typeof o.dependencies==`function`?o.dependencies():o.dependencies;for(let i of e)Sa(i,t,n,r)}}else if(a){if(a.imports!=null&&!s){r.add(i);let e;try{ia(a.imports,i=>{Sa(i,t,n,r)&&(e||=[],e.push(i))})}finally{}e!==void 0&&xa(e,t)}if(!s){let e=ta(i)||(()=>new i);t({provide:i,useFactory:e,deps:ma},i),t({provide:_a,useValue:i,multi:!0},i),t({provide:ha,useValue:()=>Xi(i),multi:!0},i)}let o=a.providers;if(o!=null&&!s){let n=e;Ca(o,e=>{t(e,n)})}}else return!1;return i!==e&&e.providers!==void 0}function Ca(e,t){for(let n of e)Si(n)&&(n=n.ɵproviders),Array.isArray(n)?Ca(n,t):t(n)}var wa=si({provide:String,useValue:si});function Ta(e){return typeof e==`object`&&!!e&&wa in e}function Ea(e){return!!(e&&e.useExisting)}function Da(e){return!!(e&&e.useFactory)}function Oa(e){return typeof e==`function`}var ka=new xi(``),Aa={},ja={},Ma=void 0;function Na(){return Ma===void 0&&(Ma=new va),Ma}var Pa=class{},Fa=class extends Pa{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(e,t,n,r){super(),this.parent=t,this.source=n,this.scopes=r,Ga(e,e=>this.processProvider(e)),this.records.set(ga,Va(void 0,this)),r.has(`environment`)&&this.records.set(Pa,Va(void 0,this));let i=this.records.get(ka);i!=null&&typeof i.value==`string`&&this.scopes.add(i.value),this.injectorDefTypes=new Set(this.get(_a,ma,{self:!0}))}retrieve(e,t){let n=Zi(t)||0;try{return this.get(e,Ki,n)}catch(e){if(nr(e))return e;throw e}}destroy(){Ba(this),this._destroyed=!0;let e=pn(null);try{for(let e of this._ngOnDestroyHooks)e.ngOnDestroy();let e=this._onDestroyHooks;this._onDestroyHooks=[];for(let t of e)t()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),pn(e)}}onDestroy(e){return Ba(this),this._onDestroyHooks.push(e),()=>this.removeOnDestroy(e)}runInContext(e){Ba(this);let t=er(this),n=Ui(void 0);try{return e()}finally{er(t),Ui(n)}}get(e,t=Ki,n){if(Ba(this),Object.hasOwn(e,Oi))return e[Oi](this);let r=Zi(n),i=er(this),a=Ui(void 0);try{if(!(r&4)){let t=this.records.get(e);if(t===void 0){let n=Wa(e)&&hi(e);t=n&&this.injectableDefInScope(n)?Va(Ia(e),Aa):null,this.records.set(e,t)}if(t!=null)return this.hydrate(e,t,r)}let n=r&2?Na():this.parent;return t=r&8&&t===Ki?null:t,n.get(e,t)}catch(e){let t=Bi(e);throw t===-200||t===-201?new ii(t,null):e}finally{Ui(a),er(i)}}resolveInjectorInitializers(){let e=pn(null),t=er(this),n=Ui(void 0);try{let e=this.get(ha,ma,{self:!0});for(let t of e)t()}finally{er(t),Ui(n),pn(e)}}toString(){return`R3Injector[...]`}processProvider(e){e=fi(e);let t=Oa(e)?e:fi(e&&e.provide),n=Ra(e);if(!Oa(e)&&e.multi===!0){let n=this.records.get(t);n||(n=Va(void 0,Aa,!0),n.factory=()=>$i(n.multi),this.records.set(t,n)),t=e,n.multi.push(e)}this.records.set(t,n)}hydrate(e,t,n){let r=pn(null);try{if(t.value===ja)throw Li(``);return t.value===Aa&&(t.value=ja,t.value=t.factory(void 0,n)),typeof t.value==`object`&&t.value&&Ua(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}finally{pn(r)}}injectableDefInScope(e){if(!e.providedIn)return!1;let t=fi(e.providedIn);return typeof t==`string`?t===`any`||this.scopes.has(t):this.injectorDefTypes.has(t)}removeOnDestroy(e){let t=this._onDestroyHooks.indexOf(e);t!==-1&&this._onDestroyHooks.splice(t,1)}};function Ia(e){let t=hi(e),n=t===null?ta(e):t.factory;if(n!==null)return n;if(e instanceof xi)throw new ii(-204,!1);if(e instanceof Function)return La(e);throw new ii(-204,!1)}function La(e){if(e.length>0)throw new ii(-204,!1);let t=_i(e);return t===null?()=>new e:()=>t.factory(e)}function Ra(e){return Ta(e)?Va(void 0,e.useValue):Va(za(e),Aa)}function za(e,t,n){let r;if(Oa(e)){let t=fi(e);return ta(t)||Ia(t)}if(Ta(e))r=()=>fi(e.useValue);else if(Da(e))r=()=>e.useFactory(...$i(e.deps||[]));else if(Ea(e))r=(t,n)=>Xi(fi(e.useExisting),n!==void 0&&n&8?8:void 0);else{let t=fi(e&&(e.useClass||e.provide));if(Ha(e))r=()=>new t(...$i(e.deps));else return ta(t)||Ia(t)}return r}function Ba(e){if(e.destroyed)throw new ii(-205,!1)}function Va(e,t,n=!1){return{factory:e,value:t,multi:n?[]:void 0}}function Ha(e){return!!e.deps}function Ua(e){return typeof e==`object`&&!!e&&typeof e.ngOnDestroy==`function`}function Wa(e){return typeof e==`function`||typeof e==`object`&&e.ngMetadataName===`InjectionToken`}function Ga(e,t){for(let n of e)Array.isArray(n)?Ga(n,t):n&&Si(n)?Ga(n.ɵproviders,t):t(n)}function Ka(e,t){let n;e instanceof Fa?(Ba(e),n=e):n=new Ji(e);let r=er(n),i=Ui(void 0);try{return t()}finally{er(r),Ui(i)}}function qa(){return Hi()!==void 0||$n()!=null}var Ja=1;function Ya(e){return Array.isArray(e)&&typeof e[Ja]==`object`}function Xa(e){return Array.isArray(e)&&e[Ja]===!0}function Za(e){return!!(e.flags&4)}function Qa(e){return e.componentOffset>-1}function $a(e){return(e.flags&1)==1}function eo(e){return!!e.template}function to(e){return!!(e[2]&512)}function no(e){return(e[2]&256)==256}var ro=(function(e){return e[e.NONE=0]=`NONE`,e[e.HTML=1]=`HTML`,e[e.STYLE=2]=`STYLE`,e[e.SCRIPT=3]=`SCRIPT`,e[e.URL=4]=`URL`,e[e.RESOURCE_URL=5]=`RESOURCE_URL`,e[e.ATTRIBUTE_NO_BINDING=6]=`ATTRIBUTE_NO_BINDING`,e})(ro||{}),io=`math`;function ao(e){for(;Array.isArray(e);)e=e[0];return e}function oo(e,t){return ao(t[e])}function so(e,t){return ao(t[e.index])}function co(e,t){return e.data[t]}function lo(e,t){return e[t]}function uo(e,t,n,r){n>=e.data.length&&(e.data[n]=null,e.blueprint[n]=null),t[n]=r}function fo(e,t){let n=t[e];return Ya(n)?n:n[0]}function po(e){return(e[2]&128)==128}function mo(e){return Xa(e[3])}function ho(e,t){return t==null?null:e[t]}function go(e){e[17]=0}function _o(e){e[2]&1024||(e[2]|=1024,po(e)&&xo(e))}function vo(e,t){for(;e>0;)t=t[14],e--;return t}function yo(e){return!!(e[2]&9216||e[24]?.dirty)}function bo(e){e[10].changeDetectionScheduler?.notify(8),e[2]&64&&(e[2]|=1024),yo(e)&&xo(e)}function xo(e){e[10].changeDetectionScheduler?.notify(0);let t=wo(e);for(;t!==null&&!(t[2]&8192||(t[2]|=8192,!po(t)));)t=wo(t)}function So(e,t){if(no(e))throw new ii(911,!1);e[21]===null&&(e[21]=[]),e[21].push(t)}function Co(e,t){if(e[21]===null)return;let n=e[21].indexOf(t);n!==-1&&e[21].splice(n,1)}function wo(e){let t=e[3];return Xa(t)?t[3]:t}function To(e){return e[7]??=[]}function Eo(e){return e.cleanup??=[]}function Do(e,t,n,r){let i=To(t);i.push(n),e.firstCreatePass&&Eo(e).push(r,i.length-1)}var Oo={lFrame:ls(null),bindingsEnabled:!0,skipHydrationRootTNode:null},ko=!1;function Ao(){return Oo.lFrame.elementDepthCount}function jo(){Oo.lFrame.elementDepthCount++}function Mo(){Oo.lFrame.elementDepthCount--}function No(){return Oo.bindingsEnabled}function Po(){return Oo.skipHydrationRootTNode!==null}function Fo(e){return Oo.skipHydrationRootTNode===e}function Io(){Oo.skipHydrationRootTNode=null}function w(){return Oo.lFrame.lView}function Lo(){return Oo.lFrame.tView}function T(e){return Oo.lFrame.contextLView=e,e[8]}function E(e){return Oo.lFrame.contextLView=null,e}function Ro(){let e=zo();for(;e!==null&&e.type===64;)e=e.parent;return e}function zo(){return Oo.lFrame.currentTNode}function Bo(){let e=Oo.lFrame,t=e.currentTNode;return e.isParent?t:t.parent}function Vo(e,t){let n=Oo.lFrame;n.currentTNode=e,n.isParent=t}function Ho(){return Oo.lFrame.isParent}function Uo(){Oo.lFrame.isParent=!1}function Wo(){return Oo.lFrame.contextLView}function Go(){return ko}function Ko(e){let t=ko;return ko=e,t}function qo(){let e=Oo.lFrame,t=e.bindingRootIndex;return t===-1&&(t=e.bindingRootIndex=e.tView.bindingStartIndex),t}function Jo(){return Oo.lFrame.bindingIndex}function Yo(e){return Oo.lFrame.bindingIndex=e}function Xo(){return Oo.lFrame.bindingIndex++}function Zo(e){let t=Oo.lFrame,n=t.bindingIndex;return t.bindingIndex+=e,n}function Qo(){return Oo.lFrame.inI18n}function $o(e,t){let n=Oo.lFrame;n.bindingIndex=n.bindingRootIndex=e,ts(t)}function es(){return Oo.lFrame.currentDirectiveIndex}function ts(e){Oo.lFrame.currentDirectiveIndex=e}function ns(e){let t=Oo.lFrame.currentDirectiveIndex;return t===-1?null:e[t]}function rs(){return Oo.lFrame.currentQueryIndex}function is(e){Oo.lFrame.currentQueryIndex=e}function as(e){let t=e[1];return t.type===2?t.declTNode:t.type===1?e[5]:null}function os(e,t,n){if(n&4){let r=t,i=e;for(;r=r.parent,r===null&&!(n&1)&&(r=as(i),!(r===null||(i=i[14],r.type&10))););if(r===null)return!1;t=r,e=i}let r=Oo.lFrame=cs();return r.currentTNode=t,r.lView=e,!0}function ss(e){let t=cs(),n=e[1];Oo.lFrame=t,t.currentTNode=n.firstChild,t.lView=e,t.tView=n,t.contextLView=e,t.bindingIndex=n.bindingStartIndex,t.inI18n=!1}function cs(){let e=Oo.lFrame,t=e===null?null:e.child;return t===null?ls(e):t}function ls(e){let t={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return e!==null&&(e.child=t),t}function us(){let e=Oo.lFrame;return Oo.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}var ds=us;function fs(){let e=us();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function ps(e){return(Oo.lFrame.contextLView=vo(e,Oo.lFrame.contextLView))[8]}function ms(){return Oo.lFrame.selectedIndex}function hs(e){Oo.lFrame.selectedIndex=e}function gs(){let e=Oo.lFrame;return co(e.tView,e.selectedIndex)}function D(){Oo.lFrame.currentNamespace=`svg`}function _s(){vs()}function vs(){Oo.lFrame.currentNamespace=null}function ys(){return Oo.lFrame.currentNamespace}var bs=!0;function xs(){return bs}function Ss(e){bs=e}function Cs(e,t=null,n=null,r){let i=ws(e,t,n,r);return i.resolveInjectorInitializers(),i}function ws(e,t=null,n=null,r,i=new Set){return new Fa([n||ma,ya(e)],t||Na(),null,i)}var Ts=class e{static THROW_IF_NOT_FOUND=Ki;static NULL=new va;static create(e,t){if(Array.isArray(e))return Cs({name:``},t,e,``);{let t=e.name??``;return Cs({name:t},e.parent,e.providers,t)}}static ɵprov=mi({token:e,providedIn:`any`,factory:()=>Xi(ga)});static __NG_ELEMENT_ID__=-1},Es=new xi(``),Ds=class{static __NG_ELEMENT_ID__=ks;static __NG_ENV_ID__=e=>e},Os=class extends Ds{_lView;constructor(e){super(),this._lView=e}get destroyed(){return no(this._lView)}onDestroy(e){let t=this._lView;return So(t,e),()=>Co(t,e)}};function ks(){return new Os(w())}var As=new xi(``),js=(()=>{class e{taskId=0;pendingTasks=new Set;destroyed=!1;pendingTask=new ti(!1);debugTaskTracker=C(As,{optional:!0});get hasPendingTasks(){return!this.destroyed&&this.pendingTask.value}get hasPendingTasksObservable(){return this.destroyed?new Wr(e=>{e.next(!1),e.complete()}):this.pendingTask}add(){!this.hasPendingTasks&&!this.destroyed&&this.pendingTask.next(!0);let e=this.taskId++;return this.pendingTasks.add(e),this.debugTaskTracker?.add(e),e}has(e){return this.pendingTasks.has(e)}remove(e){this.pendingTasks.delete(e),this.debugTaskTracker?.remove(e),this.pendingTasks.size===0&&this.hasPendingTasks&&this.pendingTask.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this.hasPendingTasks&&this.pendingTask.next(!1),this.destroyed=!0,this.pendingTask.unsubscribe()}static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Ms=class extends $r{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(e=!1){super(),this.__isAsync=e,qa()&&(this.destroyRef=C(Ds,{optional:!0})??void 0,this.pendingTasks=C(js,{optional:!0})??void 0)}emit(e){let t=pn(null);try{super.next(e)}finally{pn(t)}}subscribe(e,t,n){let r=e,i=t||(()=>null),a=n;if(e&&typeof e==`object`){let t=e;r=t.next?.bind(t),i=t.error?.bind(t),a=t.complete?.bind(t)}this.__isAsync&&(i=this.wrapInTimeout(i),r&&=this.wrapInTimeout(r),a&&=this.wrapInTimeout(a));let o=super.subscribe({next:r,error:i,complete:a});return e instanceof _r&&e.add(o),o}wrapInTimeout(e){return t=>{let n=this.pendingTasks?.add();setTimeout(()=>{try{e(t)}finally{n!==void 0&&this.pendingTasks?.remove(n)}})}}};function Ns(...e){}function Ps(e){let t,n;function r(){e=Ns;try{n!==void 0&&typeof cancelAnimationFrame==`function`&&cancelAnimationFrame(n),t!==void 0&&clearTimeout(t)}catch{}}return t=setTimeout(()=>{e(),r()}),typeof requestAnimationFrame==`function`&&(n=requestAnimationFrame(()=>{e(),r()})),()=>r()}function Fs(e){return queueMicrotask(()=>e()),()=>{e=Ns}}var Is=`isAngularZone`,Ls=`isAngularZone_ID`,Rs=0,zs=class e{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new Ms(!1);onMicrotaskEmpty=new Ms(!1);onStable=new Ms(!1);onError=new Ms(!1);constructor(e){let{enableLongStackTrace:t=!1,shouldCoalesceEventChangeDetection:n=!1,shouldCoalesceRunChangeDetection:r=!1,scheduleInRootZone:i=!1}=e;if(typeof Zone>`u`)throw new ii(908,!1);Zone.assertZonePatched();let a=this;a._nesting=0,a._outer=a._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(a._inner=a._inner.fork(new Zone.TaskTrackingZoneSpec)),t&&Zone.longStackTraceZoneSpec&&(a._inner=a._inner.fork(Zone.longStackTraceZoneSpec)),a.shouldCoalesceEventChangeDetection=!r&&n,a.shouldCoalesceRunChangeDetection=r,a.callbackScheduled=!1,a.scheduleInRootZone=i,Us(a)}static isInAngularZone(){return typeof Zone<`u`&&Zone.current.get(Is)===!0}static assertInAngularZone(){if(!e.isInAngularZone())throw new ii(909,!1)}static assertNotInAngularZone(){if(e.isInAngularZone())throw new ii(909,!1)}run(e,t,n){return this._inner.run(e,t,n)}runTask(e,t,n,r){let i=this._inner,a=i.scheduleEventTask(`NgZoneEvent: `+r,e,Bs,Ns,Ns);try{return i.runTask(a,t,n)}finally{i.cancelTask(a)}}runGuarded(e,t,n){return this._inner.runGuarded(e,t,n)}runOutsideAngular(e){return this._outer.run(e)}},Bs={};function Vs(e){if(e._nesting==0&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function Hs(e){if(e.isCheckStableRunning||e.callbackScheduled)return;e.callbackScheduled=!0;function t(){Ps(()=>{e.callbackScheduled=!1,Ws(e),e.isCheckStableRunning=!0,Vs(e),e.isCheckStableRunning=!1})}e.scheduleInRootZone?Zone.root.run(()=>{t()}):e._outer.run(()=>{t()}),Ws(e)}function Us(e){let t=()=>{Hs(e)},n=Rs++;e._inner=e._inner.fork({name:`angular`,properties:{[Is]:!0,[Ls]:n,[Ls+n]:!0},onInvokeTask:(n,r,i,a,o,s)=>{if(Js(s))return n.invokeTask(i,a,o,s);try{return Gs(e),n.invokeTask(i,a,o,s)}finally{(e.shouldCoalesceEventChangeDetection&&a.type===`eventTask`||e.shouldCoalesceRunChangeDetection)&&t(),Ks(e)}},onInvoke:(n,r,i,a,o,s,c)=>{try{return Gs(e),n.invoke(i,a,o,s,c)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!Ys(s)&&t(),Ks(e)}},onHasTask:(t,n,r,i)=>{t.hasTask(r,i),n===r&&(i.change==`microTask`?(e._hasPendingMicrotasks=i.microTask,Ws(e),Vs(e)):i.change==`macroTask`&&(e.hasPendingMacrotasks=i.macroTask))},onHandleError:(t,n,r,i)=>(t.handleError(r,i),e.runOutsideAngular(()=>e.onError.emit(i)),!1)})}function Ws(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&e.callbackScheduled===!0)}function Gs(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function Ks(e){e._nesting--,Vs(e)}var qs=class{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new Ms;onMicrotaskEmpty=new Ms;onStable=new Ms;onError=new Ms;run(e,t,n){return e.apply(t,n)}runGuarded(e,t,n){return e.apply(t,n)}runOutsideAngular(e){return e()}runTask(e,t,n,r){return e.apply(t,n)}};function Js(e){return Xs(e,`__ignore_ng_zone__`)}function Ys(e){return Xs(e,`__scheduler_tick__`)}function Xs(e,t){return!Array.isArray(e)||e.length!==1?!1:e[0]?.data?.[t]===!0}var Zs=class{_console=console;handleError(e){this._console.error(`ERROR`,e)}},Qs=new xi(``,{factory:()=>{let e=C(zs),t=C(Pa),n;return r=>{e.runOutsideAngular(()=>{t.destroyed&&!n?setTimeout(()=>{throw r}):(n??=t.get(Zs),n.handleError(r))})}}}),$s={provide:ha,useValue:()=>{C(Zs,{optional:!0})},multi:!0};function O(e,t){let[n,r,i]=Wn(e,t?.equal),a=n;return a[fn],a.set=r,a.update=i,a.asReadonly=ec.bind(a),a}function ec(){let e=this[fn];if(e.readonlyFn===void 0){let t=()=>this();t[fn]=e,e.readonlyFn=t}return e.readonlyFn}var tc=new xi(``,{factory:()=>nc}),nc=`ng`,rc=new xi(``),ic=new xi(``,{providedIn:`platform`,factory:()=>`unknown`}),ac=new xi(``,{factory:()=>C(Es).body?.querySelector(`[ngCspNonce]`)?.getAttribute(`ngCspNonce`)||null}),oc=(()=>{class e{view;node;constructor(e,t){this.view=e,this.node=t}static __NG_ELEMENT_ID__=sc}return e})();function sc(){return new oc(w(),Ro())}var cc=class{},lc=new xi(``,{factory:()=>!0}),uc=new xi(``),dc=(()=>{class e{static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new fc})}return e})(),fc=class{dirtyEffectCount=0;queues=new Map;add(e){this.enqueue(e),this.schedule(e)}schedule(e){e.dirty&&this.dirtyEffectCount++}remove(e){let t=e.zone,n=this.queues.get(t);n.has(e)&&(n.delete(e),e.dirty&&this.dirtyEffectCount--)}enqueue(e){let t=e.zone;this.queues.has(t)||this.queues.set(t,new Set);let n=this.queues.get(t);n.has(e)||n.add(e)}flush(){for(;this.dirtyEffectCount>0;){let e=!1;for(let[t,n]of this.queues)e||=t===null?this.flushQueue(n):t.run(()=>this.flushQueue(n));e||(this.dirtyEffectCount=0)}}flushQueue(e){let t=!1;for(let n of e)n.dirty&&(this.dirtyEffectCount--,t=!0,n.run());return t}},pc=class{[fn];constructor(e){this[fn]=e}destroy(){this[fn].destroy()}};function mc(e,t){let n=t?.injector??C(Ts),r=t?.manualCleanup===!0?null:n.get(Ds),i,a=n.get(oc,null,{optional:!0}),o=n.get(cc);return a===null?i=yc(e,n.get(dc),o):(i=vc(a.view,o,e),r instanceof Os&&r._lView===a.view&&(r=null)),i.injector=n,r!==null&&(i.onDestroyFns=[r.onDestroy(()=>i.destroy())]),new pc(i)}var hc={...Xn,cleanupFns:void 0,zone:null,onDestroyFns:null,run(){let e=Ko(!1);try{Zn(this)}finally{Ko(e)}},cleanup(){if(!this.cleanupFns?.length)return;let e=pn(null);try{for(;this.cleanupFns.length;)this.cleanupFns.pop()()}finally{this.cleanupFns=[],pn(e)}}},gc={...hc,consumerMarkedDirty(){this.scheduler.schedule(this),this.notifier.notify(12)},destroy(){if(On(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.scheduler.remove(this)}},_c={...hc,consumerMarkedDirty(){this.view[2]|=8192,xo(this.view),this.notifier.notify(13)},destroy(){if(On(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.view[23]?.delete(this)}};function vc(e,t,n){let r=Object.create(_c);return r.view=e,r.zone=typeof Zone<`u`?Zone.current:null,r.notifier=t,r.fn=bc(r,n),e[23]??=new Set,e[23].add(r),r.consumerMarkedDirty(r),r}function yc(e,t,n){let r=Object.create(gc);return r.fn=bc(r,e),r.scheduler=t,r.notifier=n,r.zone=typeof Zone<`u`?Zone.current:null,r.scheduler.add(r),r.notifier.notify(12),r}function bc(e,t){return()=>{t(t=>(e.cleanupFns??=[]).push(t))}}function xc(e){return typeof e==`function`&&e[fn]!==void 0}function Sc(e){return xc(e)&&typeof e.set==`function`}var Cc=Symbol(`InputSignalNode#UNSET`),wc={...Jn,transformFn:void 0,applyValueToInputSignal(e,t){Kn(e,t)}};function Tc(e){return{toString:e}.toString()}var Ec=(function(e){return e[e.TemplateCreateStart=0]=`TemplateCreateStart`,e[e.TemplateCreateEnd=1]=`TemplateCreateEnd`,e[e.TemplateUpdateStart=2]=`TemplateUpdateStart`,e[e.TemplateUpdateEnd=3]=`TemplateUpdateEnd`,e[e.LifecycleHookStart=4]=`LifecycleHookStart`,e[e.LifecycleHookEnd=5]=`LifecycleHookEnd`,e[e.OutputStart=6]=`OutputStart`,e[e.OutputEnd=7]=`OutputEnd`,e[e.BootstrapApplicationStart=8]=`BootstrapApplicationStart`,e[e.BootstrapApplicationEnd=9]=`BootstrapApplicationEnd`,e[e.BootstrapComponentStart=10]=`BootstrapComponentStart`,e[e.BootstrapComponentEnd=11]=`BootstrapComponentEnd`,e[e.ChangeDetectionStart=12]=`ChangeDetectionStart`,e[e.ChangeDetectionEnd=13]=`ChangeDetectionEnd`,e[e.ChangeDetectionSyncStart=14]=`ChangeDetectionSyncStart`,e[e.ChangeDetectionSyncEnd=15]=`ChangeDetectionSyncEnd`,e[e.AfterRenderHooksStart=16]=`AfterRenderHooksStart`,e[e.AfterRenderHooksEnd=17]=`AfterRenderHooksEnd`,e[e.ComponentStart=18]=`ComponentStart`,e[e.ComponentEnd=19]=`ComponentEnd`,e[e.DeferBlockStateStart=20]=`DeferBlockStateStart`,e[e.DeferBlockStateEnd=21]=`DeferBlockStateEnd`,e[e.DynamicComponentStart=22]=`DynamicComponentStart`,e[e.DynamicComponentEnd=23]=`DynamicComponentEnd`,e[e.HostBindingsUpdateStart=24]=`HostBindingsUpdateStart`,e[e.HostBindingsUpdateEnd=25]=`HostBindingsUpdateEnd`,e})(Ec||{}),Dc=class{previousValue;currentValue;firstChange;constructor(e,t,n){this.previousValue=e,this.currentValue=t,this.firstChange=n}isFirstChange(){return this.firstChange}};function Oc(e,t,n,r){t===null?e[n]=r:t.applyValueToInputSignal(t,r)}var kc=null,Ac=(()=>{kc=Mc;let e=()=>Mc;return e.ngInherit=!0,e})();function jc(){return kc}function Mc(e){return e.type.prototype.ngOnChanges&&(e.setInput=Pc),Nc}function Nc(){let e=Ic(this),t=e?.current;if(t){let n=e.previous;if(n===pa)e.previous=t;else for(let e in t)n[e]=t[e];e.current=null,this.ngOnChanges(t)}}function Pc(e,t,n,r,i){let a=this.declaredInputs[r],o=Ic(e)||Lc(e,{previous:pa,current:null}),s=o.current||={},c=o.previous,l=c[a];s[a]=new Dc(l&&l.currentValue,n,c===pa),Oc(e,t,i,n)}var Fc=`__ngSimpleChanges__`;function Ic(e){return Object.hasOwn(e,Fc)&&e[Fc]||null}function Lc(e,t){return e[Fc]=t}var Rc=[],zc=function(e,t=null,n){for(let r=0;r=r)break}else t[c]<0&&(e[17]+=65536),(s>14>16&&(e[2]&3)===t&&(e[2]+=16384,Kc(o,a)):Kc(o,a)}var Jc=-1,Yc=class{factory;name;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(e,t,n,r){this.factory=e,this.name=r,this.canSeeViewProviders=t,this.injectImpl=n}};function Xc(e){return!!(e.flags&8)}function Zc(e){return!!(e.flags&16)}function Qc(e,t,n){let r=0;for(;rt){o=a-1;break}}}for(;a>16}function ol(e,t){let n=al(e),r=t;for(;n>0;)r=r[14],n--;return r}var sl=!0;function cl(e){let t=sl;return sl=e,t}var ll=255,ul=5,dl=0,fl={};function pl(e,t,n){let r;typeof n==`string`?r=n.charCodeAt(0)||0:Object.hasOwn(n,Di)&&(r=n[Di]),r??=n[Di]=dl++;let i=r&ll,a=1<>ul)]|=a}function ml(e,t){let n=gl(e,t);if(n!==-1)return n;let r=t[1];r.firstCreatePass&&(e.injectorIndex=t.length,hl(r.data,e),hl(t,null),hl(r.blueprint,null));let i=_l(e,t),a=e.injectorIndex;if(rl(i)){let e=il(i),n=ol(i,t),r=n[1].data;for(let i=0;i<8;i++)t[a+i]=n[e+i]|r[e+i]}return t[a+8]=i,a}function hl(e,t){e.push(0,0,0,0,0,0,0,0,t)}function gl(e,t){return e.injectorIndex===-1||e.parent&&e.parent.injectorIndex===e.injectorIndex||t[e.injectorIndex+8]===null?-1:e.injectorIndex}function _l(e,t){if(e.parent&&e.parent.injectorIndex!==-1)return e.parent.injectorIndex;let n=0,r=null,i=t;for(;i!==null;){if(r=Ml(i),r===null)return Jc;if(n++,i=i[14],r.injectorIndex!==-1)return r.injectorIndex|n<<16}return Jc}function vl(e,t,n){pl(e,t,n)}function yl(e,t,n){if(n&8||e!==void 0)return e;Ri(t,`NodeInjector`)}function bl(e,t,n,r){if(n&8&&r===void 0&&(r=null),!(n&3)){let i=e[9],a=Ui(void 0);try{return i?i.get(t,r,n&8):Wi(t,r,n&8)}finally{Ui(a)}}return yl(r,t,n)}function xl(e,t,n,r=0,i){if(e!==null){if(t[2]&2048&&!(r&2)){let i=jl(e,t,n,r,fl);if(i!==fl)return i}let i=Sl(e,t,n,r,fl);if(i!==fl)return i}return bl(t,n,r,i)}function Sl(e,t,n,r,i){let a=El(n);if(typeof a==`function`){if(!os(t,e,r))return r&1?yl(i,n,r):bl(t,n,r,i);try{let e;if(e=a(r),e==null&&!(r&8))Ri(n);else return e}finally{ds()}}else if(typeof a==`number`){let i=null,o=gl(e,t),s=Jc,c=r&1?t[15][5]:null;for((o===-1||r&4)&&(s=o===-1?_l(e,t):t[o+8],s===Jc||!Ol(r,!1)?o=-1:(i=t[1],o=il(s),t=ol(s,t)));o!==-1;){let e=t[1];if(Dl(a,o,e.data)){let e=Cl(o,t,n,i,r,c);if(e!==fl)return e}s=t[o+8],s!==Jc&&Ol(r,t[1].data[o+8]===c)&&Dl(a,o,t)?(i=e,o=il(s),t=ol(s,t)):o=-1}}return i}function Cl(e,t,n,r,i,a){let o=t[1],s=o.data[e+8],c=wl(s,o,n,r==null?Qa(s)&&sl:r!=o&&!!(s.type&3),i&1&&a===s);return c===null?fl:Tl(t,o,c,s,i)}function wl(e,t,n,r,i){let a=e.providerIndexes,o=t.data,s=a&1048575,c=e.directiveStart,l=e.directiveEnd,u=a>>20,d=r?s:s+u,f=i?s+u:l;for(let e=d;e=c&&t.type===n)return e}if(i){let e=o[c];if(e&&eo(e)&&e.type===n)return c}return null}function Tl(e,t,n,r,i){let a=e[n],o=t.data;if(a instanceof Yc){let s=a;if(s.resolving)throw Li(``);let c=cl(s.canSeeViewProviders);s.resolving=!0,o[n].type||o[n];let l=s.injectImpl?Ui(s.injectImpl):null;os(e,r,0);try{a=e[n]=s.factory(void 0,i,o,e,r),t.firstCreatePass&&n>=r.directiveStart&&Bc(n,o[n],t)}finally{l!==null&&Ui(l),cl(c),s.resolving=!1,ds()}}return a}function El(e){if(typeof e==`string`)return e.charCodeAt(0)||0;let t=Object.hasOwn(e,Di)?e[Di]:void 0;return typeof t==`number`?t>=0?t&ll:Al:t}function Dl(e,t,n){let r=1<>ul)]&r)}function Ol(e,t){return!(e&2)&&!(e&1&&t)}var kl=class{_tNode;_lView;constructor(e,t){this._tNode=e,this._lView=t}get(e,t,n){return xl(this._tNode,this._lView,e,Zi(n),t)}};function Al(){return new kl(Ro(),w())}function jl(e,t,n,r,i){let a=e,o=t;for(;a!==null&&o!==null&&o[2]&2048&&!to(o);){let e=Sl(a,o,n,r|2,fl);if(e!==fl)return e;r&=-5;let t=a.parent;if(!t){let e=o[20];if(e){let t=e.get(n,fl,r);if(t!==fl)return t}t=Ml(o),o=o[14]}a=t}return i}function Ml(e){let t=e[1],n=t.type;return n===2?t.declTNode:n===1?e[5]:null}function Nl(e){return{token:e.token,providedIn:e.autoProvided===!1?null:`root`,factory:e.factory,value:void 0}}function Pl(){return Fl(Ro(),w())}function Fl(e,t){return new Il(so(e,t))}var Il=(()=>{class e{nativeElement;constructor(e){this.nativeElement=e}static __NG_ELEMENT_ID__=Pl}return e})();function Ll(e){return e instanceof Il?e.nativeElement:e}function Rl(){return this._results[Symbol.iterator]()}var zl=class{_emitDistinctChangesOnly;dirty=!0;_onDirty=void 0;_results=[];_changesDetected=!1;_changes=void 0;length=0;first=void 0;last=void 0;get changes(){return this._changes??=new $r}constructor(e=!1){this._emitDistinctChangesOnly=e}get(e){return this._results[e]}map(e){return this._results.map(e)}filter(e){return this._results.filter(e)}find(e){return this._results.find(e)}reduce(e,t){return this._results.reduce(e,t)}forEach(e){this._results.forEach(e)}some(e){return this._results.some(e)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(e,t){this.dirty=!1;let n=ra(e);(this._changesDetected=!na(this._results,n,t))&&(this._results=n,this.length=n.length,this.last=n[this.length-1],this.first=n[0])}notifyOnChanges(){this._changes!==void 0&&(this._changesDetected||!this._emitDistinctChangesOnly)&&this._changes.next(this)}onDirty(e){this._onDirty=e}setDirty(){this.dirty=!0,this._onDirty?.()}destroy(){this._changes!==void 0&&(this._changes.complete(),this._changes.unsubscribe())}[Symbol.iterator]=Rl};function Bl(e){return(e.flags&128)==128}var Vl=(function(e){return e[e.OnPush=0]=`OnPush`,e[e.Eager=1]=`Eager`,e[e.Default=1]=`Default`,e})(Vl||{}),Hl=new Map,Ul=0;function Wl(){return Ul++}function Gl(e){Hl.set(e[19],e)}function Kl(e){Hl.delete(e[19])}var ql=`__ngContext__`;function Jl(e,t){Ya(t)?(e[ql]=t[19],Gl(t)):e[ql]=t}function Yl(e){return Zl(e[12])}function Xl(e){return Zl(e[4])}function Zl(e){for(;e!==null&&!Xa(e);)e=e[4];return e}var Ql=void 0;function $l(e){Ql=e}function eu(){if(Ql!==void 0)return Ql;if(typeof document<`u`)return document;throw new ii(210,!1)}var tu=!1,nu=new xi(``,{factory:()=>tu}),ru=new WeakMap;function iu(e,t){if(typeof e!=`object`||!e)return;let n=ru.get(e);n||(n=new WeakSet,ru.set(e,n)),n.add(t)}function au(e){return(e.flags&32)==32}var ou=()=>null;function su(e,t,n=!1){return ou(e,t,n)}function cu(e,t){let n=e.contentQueries;if(n!==null){let r=pn(null);try{for(let r=0;r|^->||--!>|)/g,bu=`​$1​`;function xu(e){return e.replace(vu,e=>e.replace(yu,bu))}function Su(e,t){return e.createText(t)}function Cu(e,t,n){e.setValue(t,n)}function wu(e,t){return e.createComment(xu(t))}function Tu(e,t,n){return e.createElement(t,n)}function Eu(e,t,n,r,i){e.insertBefore(t,n,r,i)}function Du(e,t,n){e.appendChild(t,n)}function Ou(e,t,n,r,i){r===null?Du(e,t,n):Eu(e,t,n,r,i)}function ku(e,t,n,r){e.removeChild(null,t,n,r)}function Au(e,t,n){e.setAttribute(t,`style`,n)}function ju(e,t,n){n===``?e.removeAttribute(t,`class`):e.setAttribute(t,`class`,n)}function Mu(e,t,n){let{mergedAttrs:r,classes:i,styles:a}=n;r!==null&&Qc(e,t,r),i!==null&&ju(e,t,i),a!==null&&Au(e,t,a)}function Nu(e){let t=Pu();return t?t.sanitize(ro.URL,e)||``:mu(e,`URL`)?pu(e):_u(Ni(e))}function Pu(){let e=w();return e&&e[10].sanitizer}function Fu(e){return e.ownerDocument.defaultView}function Iu(e){return e.ownerDocument}function Lu(e,t,n){let r=e.length;for(;;){let i=e.indexOf(t,n);if(i===-1)return i;if(i===0||e.charCodeAt(i-1)<=32){let n=t.length;if(i+n===r||e.charCodeAt(i+n)<=32)return i}n=i+1}}var Ru=`ng-template`;function zu(e,t,n,r){let i=0;if(r){for(;i-1){let e;for(;++ia?``:i[u+1].toLowerCase(),r&2&&l!==e){if(Uu(r))return!1;o=!0}}}}}return Uu(r)||o}function Uu(e){return!(e&1)}function Wu(e,t,n,r){if(t===null)return-1;let i=0;if(r||!n){let n=!1;for(;i-1)for(n++;n0?`="`+t+`"`:``)+`]`}else r&8?i+=`.`+o:r&4&&(i+=` `+o)}else i!==``&&!Uu(o)&&(t+=Xu(a,i),i=``),r=o,a||=!Uu(r);n++}return i!==``&&(t+=Xu(a,i)),t}function Qu(e){return e.map(Zu).join(`,`)}function $u(e){let t=[],n=[],r=1,i=2;for(;r!1});function ad(e){if(!e)return 0;let t=e.toLowerCase().indexOf(`ms`)>-1?1:1e3;return parseFloat(e)*t}function od(e,t){return e.getPropertyValue(t).split(`,`).map(e=>e.trim())}function sd(e){let t=od(e,`transition-property`),n=od(e,`transition-duration`),r=od(e,`transition-delay`),i={propertyName:``,duration:0,animationName:void 0};for(let e=0;ei.duration&&(i.propertyName=t[e],i.duration=a)}return i}function cd(e){let t=od(e,`animation-name`),n=od(e,`animation-delay`),r=od(e,`animation-duration`),i=od(e,`animation-iteration-count`),a={animationName:``,propertyName:void 0,duration:0};for(let e=0;ea.duration&&s!==`infinite`&&(a.animationName=t[e],a.duration=o)}return a}function ld(e,t){return e!==void 0&&e.duration>t.duration}function ud(e){return(e.animationName!=null||e.propertyName!=null)&&e.duration>0}function dd(e){let t=e.effect?.getTiming();if(t===void 0)return;let n=typeof t.duration==`number`?t.duration:0,r=(t.delay??0)+n,i=e.playbackRate;return i!==void 0&&i!==0&&i!==1&&(r/=Math.abs(i)),r}function fd(e,t){let n=getComputedStyle(e),r=cd(n),i=sd(n),a=r.duration>i.duration?r:i;ld(t.get(e),a)||ud(a)&&t.set(e,a)}function pd(e,t,n){if(!n)return;let r=e.getAnimations();return r.length===0?fd(e,t):md(e,t,r)}function md(e,t,n){let r={animationName:void 0,propertyName:void 0,duration:0};for(let e of n){if(e.effect?.getTiming()?.iterations===1/0)continue;let t=dd(e)??0,n,i;e.animationName?i=e.animationName:n=e.transitionProperty,t>=r.duration&&(r={animationName:i,propertyName:n,duration:t})}ld(t.get(e),r)||ud(r)&&t.set(e,r)}var hd=new Set,gd=!1,_d=1,vd=typeof document<`u`&&typeof document?.documentElement?.getAnimations==`function`;function yd(e){return e[9].get(id,gd)}function bd(e,t,n){let r=Sd.get(e);if(r){for(let e of t)r.classList.push(e);for(let e of n)r.cleanupFns.push(e)}else Sd.set(e,{classList:t,cleanupFns:n})}function xd(e){let t=Sd.get(e);if(t){for(let e of t.cleanupFns)e();Sd.delete(e)}Cd.delete(e)}var Sd=new WeakMap,Cd=new WeakMap,wd=new WeakMap;function Td(e){return e?e[14]??e:null}var Ed=new WeakSet;function Dd(e,t,n){let r=wd.get(e);if(!r||r.length===0)return;let i=t.parentNode,a=t.previousSibling,o=Td(n);for(let e=r.length-1;e>=0;e--){let{el:n,declarationView:s}=r[e],c=n.parentNode;n===t?(r.splice(e,1),Ed.add(n),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}}))):(a&&n===a||c&&i&&c!==i&&(o===null||s===null||o===s))&&(r.splice(e,1),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}})),n.parentNode?.removeChild(n))}}function Od(e,t,n){let r=Td(n),i=wd.get(e);i?i.some(e=>e.el===t)||i.push({el:t,declarationView:r}):wd.set(e,[{el:t,declarationView:r}])}function kd(e){let t=e[26]??={};return t.enter??=new Map}function Ad(e){let t=typeof e==`function`?e():e,n=Array.isArray(t)?t:null;return typeof t==`string`&&(n=t.trim().split(/\s+/).filter(e=>e)),n}function jd(e){return e.composedPath?e.composedPath()[0]:e.target}function Md(e,t){let n=Cd.get(t);if(n===void 0)return!0;if(t!==jd(e))return!1;let r=e.animation;if(r){let e=dd(r);if(e!==void 0&&e+_d{class e{impl=null;execute(){this.impl?.execute()}static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),zd=[0,1,2,3],Bd=(()=>{class e{ngZone=C(zs);scheduler=C(cc);errorHandler=C(Zs,{optional:!0});sequences=new Set;deferredRegistrations=new Set;executing=!1;constructor(){C(Fd,{optional:!0})}execute(){let e=this.sequences.size>0;e&&zc(Ec.AfterRenderHooksStart),this.executing=!0;for(let e of zd)for(let t of this.sequences)if(!t.erroredOrDestroyed&&t.hooks[e])try{t.pipelinedValue=this.ngZone.runOutsideAngular(()=>this.maybeTrace(()=>{let n=t.hooks[e];return n(t.pipelinedValue)},t.snapshot))}catch(e){t.erroredOrDestroyed=!0,this.errorHandler?.handleError(e)}this.executing=!1;for(let e of this.sequences)e.afterRun(),e.once&&(this.sequences.delete(e),e.destroy());for(let e of this.deferredRegistrations)this.sequences.add(e);this.deferredRegistrations.size>0&&this.scheduler.notify(7),this.deferredRegistrations.clear(),e&&zc(Ec.AfterRenderHooksEnd)}register(e){let{view:t}=e;t===void 0?this.executing?this.deferredRegistrations.add(e):this.addSequence(e):((t[25]??=[]).push(e),xo(t),t[2]|=8192)}addSequence(e){this.sequences.add(e),this.scheduler.notify(7)}unregister(e){this.executing&&this.sequences.has(e)?(e.erroredOrDestroyed=!0,e.pipelinedValue=void 0,e.once=!0):(this.sequences.delete(e),this.deferredRegistrations.delete(e))}maybeTrace(e,t){return t?t.run(Pd.AFTER_NEXT_RENDER,e):e()}static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Vd=class{impl;hooks;view;once;snapshot;erroredOrDestroyed=!1;pipelinedValue=void 0;unregisterOnDestroy;constructor(e,t,n,r,i,a=null){this.impl=e,this.hooks=t,this.view=n,this.once=r,this.snapshot=a,this.unregisterOnDestroy=i?.onDestroy(()=>this.destroy())}afterRun(){this.erroredOrDestroyed=!1,this.pipelinedValue=void 0,this.snapshot?.dispose(),this.snapshot=null}destroy(){this.impl.unregister(this),this.unregisterOnDestroy?.();let e=this.view?.[25];e&&(this.view[25]=e.filter(e=>e!==this))}};function Hd(e,t){let n=t?.injector??C(Ts);return Ld(`NgAfterNextRender`),Wd(e,n,t,!0)}function Ud(e){return e instanceof Function?[void 0,void 0,e,void 0]:[e.earlyRead,e.write,e.mixedReadWrite,e.read]}function Wd(e,t,n,r){let i=t.get(Rd);i.impl??=t.get(Bd);let a=t.get(Fd,null,{optional:!0}),o=n?.manualCleanup===!0?null:t.get(Ds),s=t.get(oc,null,{optional:!0}),c=new Vd(i.impl,Ud(e),s?.view,r,o,a?.snapshot(null));return i.impl.register(c),c}var Gd=new xi(``,{factory:()=>{let e=C(Pa),t=new Set;return e.onDestroy(()=>t.clear()),{queue:t,isScheduled:!1,scheduler:null,injector:e}}});function Kd(e,t,n){let r=e.get(Gd);if(Array.isArray(t))for(let e of t)r.queue.add(e),n?.detachedLeaveAnimationFns?.push(e);else r.queue.add(t),n?.detachedLeaveAnimationFns?.push(t);r.scheduler&&r.scheduler(e)}function qd(e,t){let n=e.get(Gd);if(Array.isArray(t))for(let e of t)n.queue.delete(e);else n.queue.delete(t)}function Jd(e,t){let n=e.get(Gd);if(t.detachedLeaveAnimationFns){for(let e of t.detachedLeaveAnimationFns)n.queue.delete(e);t.detachedLeaveAnimationFns=void 0}}function Yd(e){let t=e.get(Gd);t.isScheduled||=(Hd(()=>{t.isScheduled=!1;for(let e of t.queue)e();t.queue.clear()},{injector:t.injector}),!0)}function Xd(e){let t=e.get(Gd);t.scheduler=Yd,t.scheduler(e)}function Zd(e,t){for(let[n,r]of t)Kd(e,r.animateFns)}function Qd(e,t,n,r){let i=e?.[26]?.enter;t!==null&&i&&i.has(n.index)&&Zd(r,i)}function $d(e,t,n,r){try{n.get(ga)}catch{return r(!1)}let i=e?.[26];i?.enter?.has(t.index)&&qd(n,i.enter.get(t.index).animateFns);let a=ef(e,t,i);if(a.size===0){let n=!1;if(e){let r=[];nf(e,t,r),n=r.length>0}if(!n)return r(!1)}e&&hd.add(e[19]),Kd(n,()=>tf(e,t,i||void 0,a,r),i||void 0)}function ef(e,t,n){let r=new Map,i=n?.leave;if(i&&i.has(t.index)&&r.set(t.index,i.get(t.index)),e&&i)for(let[n,a]of i){if(r.has(n))continue;let i=e[1].data[n].parent;for(;i;){if(i===t){r.set(n,a);break}i=i.parent}}return r}function tf(e,t,n,r,i){let a=[];if(n&&n.leave)for(let[e]of r){if(!n.leave.has(e))continue;let t=n.leave.get(e);for(let e of t.animateFns){let{promise:t}=e();a.push(t)}n.detachedLeaveAnimationFns=void 0}if(e&&nf(e,t,a),a.length>0){let t=n||e?.[26];if(t){let n=t.running;n&&a.push(n),t.running=Promise.allSettled(a),af(e,t.running,i)}else Promise.allSettled(a).then(()=>{e&&hd.delete(e[19]),i(!0)})}else e&&hd.delete(e[19]),i(!1)}function nf(e,t,n){if(t.type&12){let r=e[t.index];if(Xa(r))for(let e=10;e{e[26]?.running===t&&(e[26].running=void 0,hd.delete(e[19])),n(!0)})}function of(e,t,n,r,i,a,o,s){if(i!=null){let c,l=!1;Xa(i)?c=i:Ya(i)&&(l=!0,i=i[0]);let u=ao(i);e===0&&r!==null?(Qd(s,r,a,n),o==null?Du(t,r,u):Eu(t,r,u,o||null,!0)):e===1&&r!==null?(Qd(s,r,a,n),Eu(t,r,u,o||null,!0),Dd(a,u,s)):e===2?(s?.[26]?.leave?.has(a.index)&&Od(a,u,s),Ed.delete(u),$d(s,a,n,e=>{if(Ed.has(u)){Ed.delete(u);return}ku(t,u,l,e)})):e===3&&(Ed.delete(u),$d(s,a,n,()=>{t.destroyNode(u)})),c!=null&&Af(t,e,n,c,a,r,o)}}function sf(e,t){lf(e,t),t[0]=null,t[5]=null}function cf(e,t,n,r,i,a){r[0]=i,r[5]=t,Ef(e,r,n,1,i,a)}function lf(e,t){t[10].changeDetectionScheduler?.notify(9),Ef(e,t,t[11],2,null,null)}function uf(e){let t=e[12];if(!t)return pf(e[1],e);for(;t;){let n=null;if(Ya(t))n=t[12];else{let e=t[10];e&&(n=e)}if(!n){for(;t&&!t[4]&&t!==e;)Ya(t)&&pf(t[1],t),t=t[3];t===null&&(t=e),Ya(t)&&pf(t[1],t),n=t&&t[4]}t=n}}function df(e,t){let n=e[9],r=n.indexOf(t);n.splice(r,1)}function ff(e,t){if(no(t))return;let n=t[11];n.destroyNode&&Ef(e,t,n,3,null,null),uf(t)}function pf(e,t){if(no(t))return;let n=pn(null);try{t[2]&=-129,t[2]|=256,t[24]&&On(t[24]),hf(e,t),mf(e,t),t[1].type===1&&t[11].destroy();let n=t[16];if(n!==null&&Xa(t[3])){n!==t[3]&&df(n,t);let r=t[18];r!==null&&r.detachView(e)}Kl(t)}finally{pn(n)}}function mf(e,t){let n=e.cleanup,r=t[7];if(n!==null)for(let e=0;e=0?r[t]():r[-t].unsubscribe(),e+=2}else{let t=r[n[e+1]];n[e].call(t)}r!==null&&(t[7]=null);let i=t[21];if(i!==null){t[21]=null;for(let e=0;e27&&Bf(e,t,27,!1),zc(o?Ec.TemplateUpdateStart:Ec.TemplateCreateStart,i,n),n(r,i)}finally{hs(a),zc(o?Ec.TemplateUpdateEnd:Ec.TemplateCreateEnd,i,n)}}function Wf(e,t,n){Zf(e,t,n),(n.flags&64)==64&&Qf(e,t,n)}function Gf(e,t,n=so){let r=t.localNames;if(r!==null){let i=t.index+1;for(let a=0;a{xo(e.lView)},consumerOnSignalRead(){this.lView[24]=this}};function Sp(e){let t=e[24]??Object.create(Cp);return t.lView=e,t}var Cp={...hn,consumerIsAlwaysLive:!0,kind:`template`,consumerMarkedDirty:e=>{let t=wo(e.lView);for(;t&&!wp(t[1]);)t=wo(t);t&&_o(t)},consumerOnSignalRead(){this.lView[24]=this}};function wp(e){return e.type!==2}function Tp(e){if(e[23]===null)return;let t=!0;for(;t;){let n=!1;for(let t of e[23])if(t.dirty&&(n=!0,t.zone===null||Zone.current===t.zone?t.run():t.zone.run(()=>t.run()),e[23]===null))return;t=n&&!!(e[2]&8192)}}var Ep=100;function Dp(e,t=0){let n=e[10].rendererFactory;n.begin?.();try{Op(e,t)}finally{n.end?.()}}function Op(e,t){let n=Go();try{Ko(!0),Pp(e,t);let n=0;for(;yo(e);){if(n===Ep)throw new ii(103,!1);n++,Pp(e,1)}}finally{Ko(n)}}function kp(e,t,n,r){if(no(t))return;let i=t[2];ss(t);let a=!0,o=null,s=null;wp(e)?(s=vp(t),o=Cn(s)):mn()===null?(a=!1,s=Sp(t),o=Cn(s)):t[24]&&=(On(t[24]),null);try{go(t),Yo(e.bindingStartIndex),n!==null&&Uf(e,t,n,2,r);let a=(i&3)==3;if(a){let n=e.preOrderCheckHooks;n!==null&&Hc(t,n,null)}else{let n=e.preOrderHooks;n!==null&&Uc(t,n,0,null),Wc(t,0)}if(jp(t),Tp(t),Ap(t,0),e.contentQueries!==null&&cu(e,t),a){let n=e.contentCheckHooks;n!==null&&Hc(t,n)}else{let n=e.contentHooks;n!==null&&Uc(t,n,1),Wc(t,1)}Ip(e,t);let o=e.components;o!==null&&Fp(t,o,0);let s=e.viewQuery;if(s!==null&&lu(2,s,r),a){let n=e.viewCheckHooks;n!==null&&Hc(t,n)}else{let n=e.viewHooks;n!==null&&Uc(t,n,2),Wc(t,2)}if(e.firstUpdatePass===!0&&(e.firstUpdatePass=!1),t[22]){for(let e of t[22])e();t[22]=null}gp(t),t[2]&=-73}catch(e){throw xo(t),e}finally{s!==null&&(Tn(s,o),a&&bp(s)),fs()}}function Ap(e,t){for(let n=Yl(e);n!==null;n=Xl(n))for(let e=10;e0&&(e[n-1][4]=r[4]);let a=oa(e,10+t);sf(r[1],r);let o=a[18];o!==null&&o.detachView(a[1]),r[3]=null,r[4]=null,r[2]&=-129}return r}function Up(e,t,n,r){let i=10+r,a=n.length;r>0&&(n[i-1][4]=t),r-1&&(Hp(e,n),oa(t,n))}this._attachedToViewContainer=!1}ff(this._lView[1],this._lView)}onDestroy(e){So(this._lView,e)}markForCheck(){Lp(this._cdRefInjectingView||this._lView,4)}detach(){this._lView[2]&=-129}reattach(){bo(this._lView),this._lView[2]|=128}detectChanges(){this._lView[2]|=1024,Dp(this._lView)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new ii(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;let e=to(this._lView),t=this._lView[16];t!==null&&!e&&df(t,this._lView),lf(this._lView[1],this._lView)}attachToAppRef(e){if(this._attachedToViewContainer)throw new ii(902,!1);this._appRef=e;let t=to(this._lView),n=this._lView[16];n!==null&&!t&&Wp(n,this._lView),bo(this._lView)}},Kp=(()=>{class e{_declarationLView;_declarationTContainer;elementRef;static __NG_ELEMENT_ID__=qp;constructor(e,t,n){this._declarationLView=e,this._declarationTContainer=t,this.elementRef=n}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(e,t){return this.createEmbeddedViewImpl(e,t)}createEmbeddedViewImpl(e,t,n){return new Gp(fp(this._declarationLView,this._declarationTContainer,e,{embeddedViewInjector:t,dehydratedView:n}))}}return e})();function qp(){return Jp(Ro(),w())}function Jp(e,t){return e.type&4?new Kp(t,e,Fl(e,t)):null}function Yp(e,t,n,r,i){let a=e.data[t];if(a===null)a=Xp(e,t,n,r,i),Qo()&&(a.flags|=32);else if(a.type&64){a.type=n,a.value=r,a.attrs=i;let e=Bo();a.injectorIndex=e===null?-1:e.injectorIndex}return Vo(a,!0),a}function Xp(e,t,n,r,i){let a=zo(),o=Ho(),s=o?a:a&&a.parent,c=e.data[t]=Qp(e,s,n,t,r,i);return Zp(e,c,a,o),c}function Zp(e,t,n,r){e.firstChild===null&&(e.firstChild=t),n!==null&&(r?n.child==null&&t.parent!==null&&(n.child=t):n.next===null&&(n.next=t,t.prev=n))}function Qp(e,t,n,r,i,a){let o=t?t.injectorIndex:-1,s=0;return Po()&&(s|=128),{type:n,index:r,insertBeforeIndex:null,injectorIndex:o,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,controlDirectiveIndex:-1,customControlIndex:-1,propertyBindings:null,flags:s,providerIndexes:0,value:i,namespace:ys(),attrs:a,mergedAttrs:null,localNames:null,initialInputs:null,inputs:null,hostDirectiveInputs:null,outputs:null,hostDirectiveOutputs:null,directiveToIndex:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:t,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}function $p(e){let t=e[6]??[],n=e[3][11],r=[];for(let e of t)e.data.di===void 0?em(e,n):r.push(e);e[6]=r}function em(e,t){let n=0,r=e.firstChild;if(r){let i=e.data.r;for(;nnull,nm=()=>null;function rm(e,t){return tm(e,t)}function im(e,t,n){return nm(e,t,n)}var am=class{},om=class{},sm=(()=>{class e{static ɵprov=mi({token:e,providedIn:`root`,factory:()=>null})}return e})();function cm(e){return e.debugInfo?.className||e.type.name||null}var lm={},um=class{injector;parentInjector;constructor(e,t){this.injector=e,this.parentInjector=t}get(e,t,n){let r=this.injector.get(e,lm,n);return r!==lm||t===lm?r:this.parentInjector.get(e,t,n)}};function dm(e,t,n){return e[t]=n}function fm(e,t){return e[t]}function pm(e,t,n){if(n===ed)return!1;let r=e[t];return!Object.is(r,n)&&(e[t]=n,!0)}function mm(e,t,n,r){let i=pm(e,t,n);return pm(e,t+1,r)||i}function hm(e,t,n,r,i){let a=mm(e,t,n,r);return pm(e,t+2,i)||a}function gm(e,t,n,r,i,a){let o=mm(e,t,n,r);return mm(e,t+2,i,a)||o}function _m(e,t,n){return function r(i){let a=r.__ngNativeEl__;a!==void 0&&iu(i,a),Lp(Qa(e)?fo(e.index,t):t,5);let o=t[8],s=vm(t,o,n,i),c=r.__ngNextListenerFn__;for(;c;)s=vm(t,o,c,i)&&s,c=c.__ngNextListenerFn__;return s}}function vm(e,t,n,r){let i=pn(null);try{return zc(Ec.OutputStart,t,n),n(r)!==!1}catch(t){return op(e,t),!1}finally{zc(Ec.OutputEnd,t,n),pn(i)}}function ym(e,t,n,r,i,a,o,s){let c=$a(e),l=!1,u=null;if(!r&&c&&(u=xm(t,n,a,e.index)),u!==null){let e=u.__ngLastListenerFn__||u;e.__ngNextListenerFn__=o,u.__ngLastListenerFn__=o,l=!0}else{let o=so(e,n),c=r?r(o):o;r||(s.__ngNativeEl__=o);let l=i.listen(c,a,s);bm(a)||Sm(r?t=>r(ao(t[e.index])):e.index,t,n,a,s,l,!1)}return l}function bm(e){return e.startsWith(`animation`)||e.startsWith(`transition`)}function xm(e,t,n,r){let i=e.cleanup;if(i!=null)for(let e=0;er?n[r]:null}typeof a==`string`&&(e+=2)}return null}function Sm(e,t,n,r,i,a,o){let s=t.firstCreatePass?Eo(t):null,c=To(n),l=c.length;c.push(i,a),s&&s.push(r,e,l,(l+1)*(o?-1:1))}function Cm(e,t,n,r,i,a){let o=t[n],s=t[1],c=o[s.data[n].outputs[r]].subscribe(a);Sm(e.index,s,t,i,a,c,!0)}var wm=Symbol(`BINDING`),Tm=new xi(``);function Em(e,t,n){let r=n?e.styles:null,i=n?e.classes:null,a=0;if(t!==null)for(let e=0;e0&&(n.directiveToIndex=new Map);for(let c=0;c0;){let n=e[--t];if(typeof n==`number`&&n<0)return n}return 0}function Bm(e,t,n){if(n){if(t.exportAs)for(let r=0;r{let[n,r,i]=e[t],a={propName:n,templateName:t,isSignal:(r&Vf.SignalBased)!==0};return i&&(a.transform=i),a})}function Jm(e){return Object.keys(e).map(t=>({propName:e[t],templateName:t}))}function Ym(e,t,n){let r=t instanceof Pa?t:t?.injector;return r&&e.getStandaloneInjector!==null&&(r=e.getStandaloneInjector(r)||r),r?new um(n,r):n}function Xm(e){let t=e.get(om,null);if(t===null)throw new ii(407,!1);return{rendererFactory:t,sanitizer:e.get(sm,null),changeDetectionScheduler:e.get(cc,null),ngReflect:!1,tracingService:e.get(Fd,null,{optional:!0})}}function Zm(e,t,n){let r=$m(e);return Tu(t,r,r===`svg`?`svg`:r===`math`?io:n)}function Qm(e){if((e&&`localName`in e&&typeof e.localName==`string`?e.localName:e?.tagName)?.toLowerCase()===`script`)throw new ii(905,!1)}function $m(e){return(e.selectors[0][0]||`div`).toLowerCase()}var eh=class{componentDef;ngModule;selector;componentType;ngContentSelectors;isBoundToModule;cachedInputs=null;cachedOutputs=null;get inputs(){return this.cachedInputs??=qm(this.componentDef.inputs),this.cachedInputs}get outputs(){return this.cachedOutputs??=Jm(this.componentDef.outputs),this.cachedOutputs}constructor(e,t){this.componentDef=e,this.ngModule=t,this.componentType=e.type,this.selector=Qu(e.selectors),this.ngContentSelectors=e.ngContentSelectors??[],this.isBoundToModule=!!t}create(e,t,n,r,i,a,o){zc(Ec.DynamicComponentStart);let s=pn(null);try{let s=this.componentDef,c=Ym(s,r||this.ngModule,e),l=Xm(c),u=l.tracingService;return u&&u.componentCreate?u.componentCreate(cm(s),()=>this.createComponentRef(l,c,t,n,i,a,o)):this.createComponentRef(l,c,t,n,i,a,o)}finally{pn(s)}}createComponentRef(e,t,n,r,i,a,o){let s=this.componentDef,c=th(r,s,a,i),l=e.rendererFactory.createRenderer(null,s),u=r?Kf(l,r,s.encapsulation,t):Zm(s,l,o??null);Qm(u);let d=t.get(Tm,null),f=nh(u,()=>t.get(Es,null)??eu());d&&d.addHost(f);let p=a?.some(ih)||i?.some(e=>typeof e!=`function`&&e.bindings.some(ih)),m=Ff(null,c,null,512|Lf(s),null,null,e,l,t,null,su(u,t,!0));d&&Gm&&f instanceof ShadowRoot&&So(m,()=>{d.removeHost(f)}),m[27]=u,ss(m);let h=null;try{let e=Hm(27,m,2,`#host`,()=>c.directiveRegistry,!0,0);Mu(l,u,e),Jl(u,m),Wf(c,m,e),uu(c,e,m),Um(c,e),n!==void 0&&oh(e,this.ngContentSelectors,n),h=fo(e.index,m),m[8]=h[8],up(c,m,null)}catch(e){throw h!==null&&Kl(h),Kl(m),e}finally{zc(Ec.DynamicComponentEnd),fs()}return new ah(this.componentType,m,!!p)}};function th(e,t,n,r){let i=e?[`ng-version`,`22.1.7`]:$u(t.selectors[0]),a=null,o=null,s=0;if(n)for(let e of n)s+=e[wm].requiredVars,e.create&&(e.targetIdx=0,(a??=[]).push(e)),e.update&&(e.targetIdx=0,(o??=[]).push(e));if(r)for(let e=0;e{if(n&1&&e)for(let t of e)t.create();if(n&2&&t)for(let e of t)e.update()}}function ih(e){let t=e[wm].kind;return t===`input`||t===`twoWay`}var ah=class extends am{_rootLView;_hasInputBindings;instance;hostView;changeDetectorRef;componentType;location;previousInputValues=null;_tNode;constructor(e,t,n){super(),this._rootLView=t,this._hasInputBindings=n,this._tNode=co(t[1],27),this.location=Fl(this._tNode,t),this.instance=fo(this._tNode.index,t)[8],this.hostView=this.changeDetectorRef=new Gp(t,void 0),this.componentType=e}setInput(e,t){this._hasInputBindings;let n=this._tNode;if(this.previousInputValues??=new Map,this.previousInputValues.has(e)&&Object.is(this.previousInputValues.get(e),t))return;let r=this._rootLView;sp(n,r[1],r,e,t),this.previousInputValues.set(e,t),Lp(fo(n.index,r),1)}get injector(){return new kl(this._tNode,this._rootLView)}destroy(){this.hostView.destroy()}onDestroy(e){this.hostView.onDestroy(e)}};function oh(e,t,n){let r=e.projection=[];for(let e=0;e{class e{static __NG_ELEMENT_ID__=ch}return e})();function ch(){return fh(Ro(),w())}var lh=class e extends sh{_lContainer;_hostTNode;_hostLView;constructor(e,t,n){super(),this._lContainer=e,this._hostTNode=t,this._hostLView=n}get element(){return Fl(this._hostTNode,this._hostLView)}get injector(){return new kl(this._hostTNode,this._hostLView)}get parentInjector(){let e=_l(this._hostTNode,this._hostLView);if(rl(e)){let t=ol(e,this._hostLView),n=il(e),r=t[1].data[n+8];return new kl(r,t)}return new kl(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(e){let t=uh(this._lContainer);return t!==null&&t[e]||null}get length(){return this._lContainer.length-10}createEmbeddedView(e,t,n){let r,i;typeof n==`number`?r=n:n!=null&&(r=n.index,i=n.injector);let a=rm(this._lContainer,e.ssrId),o=e.createEmbeddedViewImpl(t||{},i,a);return this.insertImpl(o,r,pp(this._hostTNode,a)),o}createComponent(e,t,n,r,i,a,o){let s,c=t||{};s=c.index,n=c.injector,r=c.projectableNodes,i=c.environmentInjector||c.ngModuleRef,a=c.directives,o=c.bindings;let l=new eh(ki(e)),u=n||this.parentInjector;if(!i&&l.ngModule==null){let e=this.parentInjector.get(Pa,null);e&&(i=e)}let d=ki(l.componentType??{}),f=rm(this._lContainer,d?.id??null),p=f?.firstChild??null,m=l.create(u,r,p,i,a,o,this._getHostElementNamespace());return this.insertImpl(m.hostView,s,pp(this._hostTNode,f)),m}_getHostElementNamespace(){if(this._hostTNode.type&2){let e=this._hostTNode.parent??this._hostLView[5];return e!==null&&e.type&2&&typeof e.value==`string`&&e.value.toLowerCase()===`foreignobject`?null:e?.namespace??null}return this._hostTNode.namespace}insert(e,t){return this.insertImpl(e,t,!0)}insertImpl(t,n,r){let i=t._lView;if(mo(i)){let n=this.indexOf(t);if(n!==-1)this.detach(n);else{let n=i[3],r=new e(n,n[5],n[3]);r.detach(r.indexOf(t))}}let a=this._adjustIndex(n),o=this._lContainer;return Bp(o,i,a,r),t.attachToViewContainerRef(),aa(dh(o),a,t),t}move(e,t){return this.insert(e,t)}indexOf(e){let t=uh(this._lContainer);return t===null?-1:t.indexOf(e)}remove(e){let t=this._adjustIndex(e,-1),n=Hp(this._lContainer,t);n&&(oa(dh(this._lContainer),t),ff(n[1],n))}detach(e){let t=this._adjustIndex(e,-1),n=Hp(this._lContainer,t);return n&&oa(dh(this._lContainer),t)!=null?new Gp(n):null}_adjustIndex(e,t=0){return e??this.length+t}};function uh(e){return e[8]}function dh(e){return e[8]||=[]}function fh(e,t){let n,r=t[e.index];return Xa(r)?n=r:(n=Rp(r,t,null,e),t[e.index]=n,zf(t,n)),mh(n,t,e,r),new lh(n,e,t)}function ph(e,t){let n=e[11],r=n.createComment(``),i=so(t,e);return Eu(n,n.parentNode(i),r,n.nextSibling(i),!1),r}var mh=_h,hh=()=>!1;function gh(e,t,n){return hh(e,t,n)}function _h(e,t,n,r){if(e[7])return;let i;i=n.type&8?ao(r):ph(t,n),e[7]=i}var vh=class e{queryList;matches=null;constructor(e){this.queryList=e}clone(){return new e(this.queryList)}setDirty(){this.queryList.setDirty()}},yh=class e{queries;constructor(e=[]){this.queries=e}createEmbeddedView(t){let n=t.queries;if(n!==null){let r=t.contentQueries===null?n.length:t.contentQueries[0],i=[];for(let e=0;e0)r.push(o[e/2]);else{let i=a[e+1],o=t[-n];for(let e=10;ee.trim())}function Nh(e,t,n){e.queries===null&&(e.queries=new xh),e.queries.track(new Sh(t,n))}function Ph(e,t){return e.queries.getByIndex(t)}function Fh(e,t){let n=e[1],r=Ph(n,t);return r.crossesNgTemplate?Oh(n,e,t,[]):Dh(n,e,r,t)}function Ih(e,t,n){let r,i=Pn(()=>{r._dirtyCounter();let n=Bh(r,e);if(t&&n===void 0)throw new ii(-951,!1);return n});return r=i[fn],r._dirtyCounter=O(0),r._flatValue=void 0,i}function Lh(e){return Ih(!0,!1,e)}function Rh(e){return Ih(!0,!0,e)}function zh(e,t){let n=e[fn];n._lView=w(),n._queryIndex=t,n._queryList=kh(n._lView,t),n._queryList.onDirty(()=>n._dirtyCounter.update(e=>e+1))}function Bh(e,t){let n=e._lView,r=e._queryIndex;if(n===void 0||r===void 0||n[2]&4)return t?void 0:ma;let i=kh(n,r),a=Fh(n,r);return i.reset(a,Ll),t?i.first:i._changesDetected||e._flatValue===void 0?e._flatValue=i.toArray():e._flatValue}function Vh(e){return!!e&&typeof e.then==`function`}function Hh(e){return!!e&&typeof e.subscribe==`function`}var Uh=class{},Wh=class extends Uh{injector;instance=null;constructor(e){super();let t=new Fa([...e.providers,{provide:Uh,useValue:this}],e.parent||Na(),e.debugName,new Set([`environment`]));this.injector=t,e.runEnvironmentInitializers&&t.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(e){this.injector.onDestroy(e)}};function Gh(e,t,n=null){return new Wh({providers:e,parent:t,debugName:n,runEnvironmentInitializers:!0}).injector}var Kh=(()=>{class e{_injector;cachedInjectors=new Map;constructor(e){this._injector=e}getOrCreateStandaloneInjector(e){if(!e.standalone)return null;if(!this.cachedInjectors.has(e)){let t=ba(!1,e.type),n=t.length>0?Gh([t],this._injector,``):null;this.cachedInjectors.set(e,n)}return this.cachedInjectors.get(e)}ngOnDestroy(){try{for(let e of this.cachedInjectors.values())e!==null&&e.destroy()}finally{this.cachedInjectors.clear()}}static ɵprov=mi({token:e,providedIn:`environment`,factory:()=>new e(Xi(Pa))})}return e})();function A(e){return Tc(()=>{let t=Qh(e),n={...t,decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection!==Vl.Eager,directiveDefs:null,pipeDefs:null,dependencies:t.standalone&&e.dependencies||null,getStandaloneInjector:t.standalone?e=>e.get(Kh).getOrCreateStandaloneInjector(n):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||du.Emulated,styles:e.styles||ma,_:null,schemas:e.schemas||null,tView:null,id:``};t.standalone&&Ld(`NgStandalone`),$h(n);let r=e.dependencies;return n.directiveDefs=eg(r,qh),n.pipeDefs=eg(r,ji),n.id=tg(n),n})}function qh(e){return ki(e)||Ai(e)}function Jh(e,t){if(e==null)return pa;let n={};for(let r in e)if(Object.hasOwn(e,r)){let i=e[r],a,o,s,c;Array.isArray(i)?(s=i[0],a=i[1],o=i[2]??a,c=i[3]||null):(a=i,o=i,s=Vf.None,c=null),n[a]=[r,s,c],t[a]=o}return n}function Yh(e){if(e==null)return pa;let t={};for(let n in e)Object.hasOwn(e,n)&&(t[e[n]]=n);return t}function Xh(e){return Tc(()=>{let t=Qh(e);return $h(t),t})}function Zh(e){return{type:e.type,name:e.name,factory:null,pure:e.pure!==!1,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function Qh(e){let t={};return{type:e.type,providersResolver:null,viewProvidersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:t,inputConfig:e.inputs||pa,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:e.signals===!0,selectors:e.selectors||ma,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,resolveHostDirectives:null,hostDirectives:null,controlDef:null,signalFormsInputPresence:null,inputs:Jh(e.inputs,t),outputs:Yh(e.outputs),debugInfo:null}}function $h(e){e.features?.forEach(t=>t(e))}function eg(e,t){return e?()=>{let n=typeof e==`function`?e():e,r=[];for(let e of n){let n=t(e);n!==null&&r.push(n)}return r}:null}function tg(e){let t=0,n=typeof e.consts==`function`?``:e.consts,r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,n,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(let e of r.join(`|`))t=Math.imul(31,t)+e.charCodeAt(0)<<0;return t+=2147483648,`c`+t}var ng=new xi(``),rg=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((e,t)=>{this.resolve=e,this.reject=t});appInits=C(ng,{optional:!0})??[];injector=C(Ts);constructor(){}runInitializers(){if(this.initialized)return;let e=[];for(let t of this.appInits){let n=Ka(this.injector,t);if(Vh(n))e.push(n);else if(Hh(n)){let t=new Promise((e,t)=>{n.subscribe({complete:e,error:t})});e.push(t)}}let t=()=>{this.done=!0,this.resolve()};Promise.all(e).then(()=>{t()}).catch(e=>{this.reject(e)}),e.length===0&&t(),this.initialized=!0}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})}return e})();function ig(e,t,n,r,i,a,o,s){if(n.firstCreatePass){e.mergedAttrs=tl(e.mergedAttrs,e.attrs);let t=e.tView=Mf(2,e,i,a,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,n.consts,null);n.queries!==null&&(n.queries.template(n,e),t.queries=n.queries.embeddedTView(e))}s&&(e.flags|=s),Vo(e,!1);let c=cg(n,t,e,r);xs()&&xf(n,t,c,e),Jl(c,t);let l=Rp(c,t,c,e);t[r+27]=l,zf(t,l),gh(l,e,t)}function ag(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;return t.firstCreatePass?(f=Yp(t,d,4,o||null,s||null),No()&&Om(t,e,f,ho(t.consts,l),ep),Vc(t,f)):f=t.data[d],ig(f,e,t,n,r,i,a,c),$a(f)&&Wf(t,e,f),l!=null&&Gf(e,f,u),f}function og(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;if(t.firstCreatePass){if(f=Yp(t,d,4,o||null,s||null),l!=null){let e=ho(t.consts,l);f.localNames=[];for(let t=0;t{throw new ii(600,``)})}var pg=10,mg=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=C(Qs);afterRenderManager=C(Rd);zonelessEnabled=C(lc);rootEffectScheduler=C(dc);dirtyFlags=0;tracingSnapshot=null;allTestViews=new Set;autoDetectTestViews=new Set;includeAllTestViews=!1;afterTick=new $r;get allViews(){return[...(this.includeAllTestViews?this.allTestViews:this.autoDetectTestViews).keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];internalPendingTask=C(js);get isStable(){return this.internalPendingTask.hasPendingTasksObservable.pipe(ni(e=>!e))}constructor(){C(Fd,{optional:!0})}whenStable(){let e;return new Promise(t=>{e=this.isStable.subscribe({next:e=>{e&&t()}})}).finally(()=>{e.unsubscribe()})}_injector=C(Pa);_rendererFactory=null;get injector(){return this._injector}bootstrap(e,t){return this.bootstrapImpl(e,t)}bootstrapImpl(e,t,n=Ts.NULL){return this._injector.get(zs).run(()=>{if(zc(Ec.BootstrapComponentStart),!this._injector.get(rg).done)throw new ii(405,``);let r=ki(e),i=this._injector.get(Uh),a=new eh(r,i);this.componentTypes.push(e);let{hostElement:o,directives:s,bindings:c}=hg(t),l=o||a.selector,u=a.create(n,[],l,i.injector,s,c),d=u.location.nativeElement,f=u.injector.get(ug,null);return f?.registerApplication(d),u.onDestroy(()=>{this.detachView(u.hostView),gg(this.components,u),f?.unregisterApplication(d)}),this._loadComponent(u),zc(Ec.BootstrapComponentEnd,u),u})}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick(){zc(Ec.ChangeDetectionStart),this.tracingSnapshot===null?this.tickImpl():this.tracingSnapshot.run(Pd.CHANGE_DETECTION,this.tickImpl)}tickImpl=()=>{if(this._runningTick)throw zc(Ec.ChangeDetectionEnd),new ii(101,!1);let e=pn(null);try{this._runningTick=!0,this.synchronize()}finally{this._runningTick=!1,this.tracingSnapshot?.dispose(),this.tracingSnapshot=null,pn(e),this.afterTick.next(),zc(Ec.ChangeDetectionEnd)}};synchronize(){this._rendererFactory===null&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(om,null,{optional:!0}));let e=0;for(;this.dirtyFlags!==0&&e++yo(e))){this.dirtyFlags|=2;return}this.dirtyFlags&=-8}attachView(e){let t=e;this._views.push(t),t.attachToAppRef(this)}detachView(e){let t=e;gg(this._views,t),t.detachFromAppRef()}_loadComponent(e){this.attachView(e.hostView);try{this.tick()}catch(e){this.internalErrorHandler(e)}this.components.push(e),this._injector.get(dg,[]).forEach(t=>t(e))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(e=>e()),this._views.slice().forEach(e=>e.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(e){return this._destroyListeners.push(e),()=>gg(this._destroyListeners,e)}destroy(){if(this._destroyed)throw new ii(406,!1);let e=this._injector;e.destroy&&!e.destroyed&&e.destroy()}get viewCount(){return this._views.length}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})}return e})();function hg(e){return e===void 0||typeof e==`string`||e instanceof Element?{hostElement:e}:e}function gg(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}function j(e,t,n,r){let i=w();return pm(i,Xo(),t)&&(Lo(),tp(gs(),i,e,t,n,r)),j}function _g(e){if(Ld(`NgAnimateEnter`),!vd)return _g;let t=w();if(yd(t))return _g;let n=Ro(),r=t[9].get(zs);return Nd(kd(t),n,()=>vg(t,n,e,r)),Xd(t[9]),Zd(t[9],kd(t)),_g}function vg(e,t,n,r){let i=so(t,e),a=e[11],o=Ad(n),s=[],c=!1,l=e=>{if(jd(e)!==i)return;let t=e instanceof AnimationEvent?`animationend`:`transitionend`;r.runOutsideAngular(()=>{a.listen(i,t,u)})},u=e=>{jd(e)===i&&(Md(e,i)&&(c=!0),yg(e,i,a))};if(o&&o.length>0){r.runOutsideAngular(()=>{s.push(a.listen(i,`animationstart`,l)),s.push(a.listen(i,`transitionstart`,l))}),bd(i,o,s);for(let e of o)a.addClass(i,e);r.runOutsideAngular(()=>{requestAnimationFrame(()=>{if(!c&&(pd(i,Cd,vd),!Cd.has(i))){for(let e of o)a.removeClass(i,e);xd(i)}})})}}function yg(e,t,n){let r=Sd.get(t);if(jd(e)===t&&r&&Md(e,t)){e.stopPropagation();for(let e of r.classList)n.removeClass(t,e);xd(t)}}var bg=class{destroy(e){}updateValue(e,t){}swap(e,t){let n=Math.min(e,t),r=Math.max(e,t),i=this.detach(r);if(r-n>1){let e=this.detach(n);this.attach(n,i),this.attach(r,e)}else this.attach(n,i)}move(e,t){this.attach(t,this.detach(e))}};function xg(e,t,n,r,i){return e===n&&Object.is(t,r)?1:Object.is(i(e,t),i(n,r))?-1:0}function Sg(e,t,n,r){let i,a,o=0,s=e.length-1;if(Array.isArray(t)){pn(r);let c=t.length-1;for(pn(null);o<=s&&o<=c;){let r=e.at(o),l=t[o],u=xg(o,r,o,l,n);if(u!==0){u<0&&e.updateValue(o,l),o++;continue}let d=e.at(s),f=t[c],p=xg(s,d,c,f,n);if(p!==0){p<0&&e.updateValue(s,f),s--,c--;continue}let m=n(o,r),h=n(s,d),g=n(o,l);if(Object.is(g,h)){let t=n(c,f);Object.is(t,m)?(e.swap(o,s),e.updateValue(s,f),c--,s--):e.move(s,o),e.updateValue(o,l),o++;continue}if(i??=new Eg,a??=Tg(e,o,s,n),Cg(e,i,o,g))e.updateValue(o,l),o++,s++;else if(a.has(g))i.set(m,e.detach(o)),s--;else{let n=e.create(o,t[o]);e.attach(o,n),o++,s++}}for(;o<=c;)wg(e,i,n,o,t[o]),o++}else if(t!=null){pn(r);let c=t[Symbol.iterator]();pn(null);let l=c.next();for(;!l.done&&o<=s;){let t=e.at(o),r=l.value,u=xg(o,t,o,r,n);if(u!==0)u<0&&e.updateValue(o,r),o++,l=c.next();else{i??=new Eg,a??=Tg(e,o,s,n);let u=n(o,r);if(Cg(e,i,o,u))e.updateValue(o,r),o++,s++,l=c.next();else if(!a.has(u))e.attach(o,e.create(o,r)),o++,s++,l=c.next();else{let r=n(o,t);i.set(r,e.detach(o)),s--}}}for(;!l.done;)wg(e,i,n,e.length,l.value),l=c.next()}for(;o<=s;)e.destroy(e.detach(s--));i?.forEach(t=>{e.destroy(t)})}function Cg(e,t,n,r){return t!==void 0&&t.has(r)?(e.attach(n,t.get(r)),t.delete(r),!0):!1}function wg(e,t,n,r,i){if(Cg(e,t,r,n(r,i)))e.updateValue(r,i);else{let t=e.create(r,i);e.attach(r,t)}}function Tg(e,t,n,r){let i=new Set;for(let a=t;a<=n;a++)i.add(r(a,e.at(a)));return i}var Eg=class{kvMap=new Map;_vMap=void 0;has(e){return this.kvMap.has(e)}delete(e){if(!this.has(e))return!1;let t=this.kvMap.get(e);return this._vMap!==void 0&&this._vMap.has(t)?(this.kvMap.set(e,this._vMap.get(t)),this._vMap.delete(t)):this.kvMap.delete(e),!0}get(e){return this.kvMap.get(e)}set(e,t){if(this.kvMap.has(e)){let n=this.kvMap.get(e);this._vMap===void 0&&(this._vMap=new Map);let r=this._vMap;for(;r.has(n);)n=r.get(n);r.set(n,t)}else this.kvMap.set(e,t)}forEach(e){for(let[t,n]of this.kvMap)if(e(n,t),this._vMap!==void 0){let r=this._vMap;for(;r.has(n);)n=r.get(n),e(n,t)}}};function M(e,t,n,r,i,a,o,s){Ld(`NgControlFlow`);let c=w(),l=Lo();return og(c,l,e,t,n,r,i,ho(l.consts,a),256,o,s),Dg}function Dg(e,t,n,r,i,a,o,s){Ld(`NgControlFlow`);let c=w(),l=Lo();return og(c,l,e,t,n,r,i,ho(l.consts,a),512,o,s),Dg}function N(e,t){Ld(`NgControlFlow`);let n=w(),r=Xo(),i=n[r]===ed?-1:n[r],a=i===-1?void 0:Ng(n,27+i);if(pm(n,r,e)){let r=pn(null);try{if(a!==void 0&&Vp(a,0),e!==-1){let r=27+e,i=Ng(n,r),a=Rg(n[1],r),o=im(i,a,n);Bp(i,fp(n,a,t,{dehydratedView:o}),0,pp(a,o))}}finally{pn(r)}}else if(a!==void 0){let e=zp(a,0);e!==void 0&&(e[8]=t)}}var Og=class{lContainer;$implicit;$index;constructor(e,t,n){this.lContainer=e,this.$implicit=t,this.$index=n}get $count(){return this.lContainer.length-10}};function kg(e){return e}function Ag(e,t){return t}var jg=class{hasEmptyBlock;trackByFn;liveCollection;constructor(e,t,n){this.hasEmptyBlock=e,this.trackByFn=t,this.liveCollection=n}};function P(e,t,n,r,i,a,o,s,c,l,u,d,f){Ld(`NgControlFlow`);let p=w(),m=Lo(),h=c!==void 0,g=w(),_=new jg(h,s?o.bind(g[15][8]):o);g[27+e]=_,og(p,m,e+1,t,n,r,i,ho(m.consts,a),256),h&&og(p,m,e+2,c,l,u,d,ho(m.consts,f),512)}var Mg=class extends bg{lContainer;hostLView;templateTNode;operationsCounter=void 0;needsIndexUpdate=!1;constructor(e,t,n){super(),this.lContainer=e,this.hostLView=t,this.templateTNode=n}get length(){return this.lContainer.length-10}at(e){return this.getLView(e)[8].$implicit}attach(e,t){let n=t[6];this.needsIndexUpdate||=e!==this.length,Bp(this.lContainer,t,e,pp(this.templateTNode,n)),Pg(this.lContainer,e)}detach(e){return this.needsIndexUpdate||=e!==this.length-1,Fg(this.lContainer,e),Ig(this.lContainer,e)}create(e,t){let n=rm(this.lContainer,this.templateTNode.tView.ssrId);return fp(this.hostLView,this.templateTNode,new Og(this.lContainer,t,e),{dehydratedView:n})}destroy(e){ff(e[1],e)}updateValue(e,t){this.getLView(e)[8].$implicit=t}reset(){this.needsIndexUpdate=!1}updateIndexes(){if(this.needsIndexUpdate)for(let e=0;e0){let e=n[9];Jd(e,r),hd.delete(n[19]),r.detachedLeaveAnimationFns=void 0}}function Fg(e,t){if(e.length<=10)return;let n=e[10+t],r=n?n[26]:void 0;r&&r.leave&&r.leave.size>0&&(r.detachedLeaveAnimationFns=[])}function Ig(e,t){return Hp(e,t)}function Lg(e,t){return zp(e,t)}function Rg(e,t){return co(e,t)}function I(e,t,n){let r=w();return pm(r,Xo(),t)&&(Lo(),Jf(gs(),r,e,t,r[11],n)),I}function zg(e,t,n,r,i){sp(t,e,n,i?`class`:`style`,r)}function L(e,t,n,r){let i=w(),a=i[1],o=e+27,s=a.firstCreatePass?Hm(o,i,2,t,ep,No(),n,r):a.data[o];if(Qa(s)){let n=i[10].tracingService;if(n&&n.componentCreate){let o=a.data[s.directiveStart+s.componentOffset];return n.componentCreate(cm(o),()=>(Bg(e,t,i,s,r),L))}}return Bg(e,t,i,s,r),L}function Bg(e,t,n,r,i){if(ip(r,n,e,t,Hg),$a(r)){let e=n[1];Wf(e,n,r),uu(e,r,n)}i!=null&&Gf(n,r)}function R(){let e=Lo(),t=ap(Ro());return e.firstCreatePass&&Um(e,t),Fo(t)&&Io(),Mo(),t.classesWithoutHost!=null&&Xc(t)&&zg(e,t,w(),t.classesWithoutHost,!0),t.stylesWithoutHost!=null&&Zc(t)&&zg(e,t,w(),t.stylesWithoutHost,!1),R}function z(e,t,n,r){return L(e,t,n,r),R(),z}function B(e,t,n,r){let i=w(),a=i[1],o=e+27,s=a.firstCreatePass?Wm(o,a,2,t,n,r):a.data[o];return ip(s,i,e,t,Hg),r!=null&&Gf(i,s),B}function V(){return Fo(ap(Ro()))&&Io(),Mo(),V}function Vg(e,t,n,r){return B(e,t,n,r),V(),Vg}var Hg=(e,t,n,r,i)=>(Ss(!0),Tu(t[11],r,ys()));function Ug(e,t,n){let r=w(),i=r[1],a=e+27,o=i.firstCreatePass?Hm(a,r,8,`ng-container`,ep,No(),t,n):i.data[a];if(ip(o,r,e,`ng-container`,Kg),$a(o)){let e=r[1];Wf(e,r,o),uu(e,o,r)}return n!=null&&Gf(r,o),Ug}function Wg(){let e=Lo(),t=ap(Ro());return e.firstCreatePass&&Um(e,t),Wg}function Gg(e,t,n){return Ug(e,t,n),Wg(),Gg}var Kg=(e,t,n,r,i)=>(Ss(!0),wu(t[11],``));function H(){return w()}function qg(e,t,n){let r=w();return pm(r,Xo(),t)&&(Lo(),Yf(gs(),r,e,t,r[11],n)),qg}var Jg=void 0;function Yg(e){let t=Math.floor(Math.abs(e)),n=e.toString().replace(/^[^.]*\.?/,``).length;return t===1&&n===0?1:5}var Xg=[`en`,[[`a`,`p`],[`AM`,`PM`]],[[`AM`,`PM`]],[[`S`,`M`,`T`,`W`,`T`,`F`,`S`],[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],[`Sunday`,`Monday`,`Tuesday`,`Wednesday`,`Thursday`,`Friday`,`Saturday`],[`Su`,`Mo`,`Tu`,`We`,`Th`,`Fr`,`Sa`]],Jg,[[`J`,`F`,`M`,`A`,`M`,`J`,`J`,`A`,`S`,`O`,`N`,`D`],[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],[`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`]],Jg,[[`B`,`A`],[`BC`,`AD`],[`Before Christ`,`Anno Domini`]],0,[6,0],[`M/d/yy`,`MMM d, y`,`MMMM d, y`,`EEEE, MMMM d, y`],[`h:mm a`,`h:mm:ss a`,`h:mm:ss a z`,`h:mm:ss a zzzz`],[`{1}, {0}`,Jg,Jg,Jg],[`.`,`,`,`;`,`%`,`+`,`-`,`E`,`×`,`‰`,`∞`,`NaN`,`:`],[`#,##0.###`,`#,##0%`,`¤#,##0.00`,`#E0`],`USD`,`$`,`US Dollar`,{},`ltr`,Yg],Zg=Object.create(null);function Qg(e){let t=t_(e),n=$g(t);if(n)return n;let r=t.split(`-`)[0];if(n=$g(r),n)return n;if(r===`en`)return Xg;throw new ii(701,!1)}function $g(e){if(!(e in Zg)){let t=Gi.ng&&Gi.ng.common&&Gi.ng.common.locales&&Gi.ng.common.locales[e];return t!==void 0&&(Zg[e]=t),t}return Zg[e]}var e_={LocaleId:0,DayPeriodsFormat:1,DayPeriodsStandalone:2,DaysFormat:3,DaysStandalone:4,MonthsFormat:5,MonthsStandalone:6,Eras:7,FirstDayOfWeek:8,WeekendRange:9,DateFormat:10,TimeFormat:11,DateTimeFormat:12,NumberSymbols:13,NumberFormats:14,CurrencyCode:15,CurrencySymbol:16,CurrencyName:17,Currencies:18,Directionality:19,PluralCase:20,ExtraData:21};function t_(e){return e.toLowerCase().replace(/_/g,`-`)}var n_=`en-US`;function r_(e){typeof e==`string`&&e.toLowerCase().replace(/_/g,`-`)}function U(e,t,n){let r=w(),i=Lo(),a=Ro();return i_(i,r,r[11],a,e,t,n),U}function W(e,t,n){let r=w(),i=Lo(),a=Ro();return(a.type&3||n)&&ym(a,i,r,n,r[11],e,t,_m(a,r,t)),W}function i_(e,t,n,r,i,a,o){let s=!0,c=null;if((r.type&3||o)&&(c??=_m(r,t,a),ym(r,e,t,o,n,i,a,c)&&(s=!1)),s){let e=r.outputs?.[i],n=r.hostDirectiveOutputs?.[i];if(n&&n.length)for(let e=0;e>17&32767}function m_(e){return(e&2)==2}function h_(e,t){return e&131071|t<<17}function g_(e){return e|2}function __(e){return(e&131068)>>2}function v_(e,t){return e&-131069|t<<2}function y_(e){return(e&1)==1}function b_(e){return e|1}function x_(e,t,n,r,i,a){let o=a?t.classBindings:t.styleBindings,s=p_(o),c=__(o);e[r]=n;let l=!1,u;if(Array.isArray(n)){let e=n;u=e[1],(u===null||da(e,u)>0)&&(l=!0)}else u=n;if(i){if(c!==0){let t=p_(e[s+1]);e[r+1]=f_(t,s),t!==0&&(e[t+1]=v_(e[t+1],r)),e[s+1]=h_(e[s+1],r)}else e[r+1]=f_(s,0),s!==0&&(e[s+1]=v_(e[s+1],r)),s=r}else e[r+1]=f_(c,0),s===0?s=r:e[c+1]=v_(e[c+1],r),c=r;l&&(e[r+1]=g_(e[r+1])),C_(e,u,r,!0),C_(e,u,r,!1),S_(t,u,e,r,a),o=f_(s,c),a?t.classBindings=o:t.styleBindings=o}function S_(e,t,n,r,i){let a=i?e.residualClasses:e.residualStyles;a!=null&&typeof t==`string`&&da(a,t)>=0&&(n[r+1]=b_(n[r+1]))}function C_(e,t,n,r){let i=e[n+1],a=t===null,o=r?p_(i):__(i),s=!1;for(;o!==0&&(s===!1||a);){let n=e[o],i=e[o+1];w_(n,t)&&(s=!0,e[o+1]=r?b_(i):g_(i)),o=r?p_(i):__(i)}s&&(e[n+1]=r?g_(i):b_(i))}function w_(e,t){return e===null||t==null||(Array.isArray(e)?e[1]:e)===t?!0:Array.isArray(e)&&typeof t==`string`?da(e,t)>=0:!1}var T_={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function E_(e){return e.substring(T_.key,T_.keyEnd)}function D_(e){return k_(e),O_(e,A_(e,0,T_.textEnd))}function O_(e,t){let n=T_.textEnd;return n===t?-1:(t=T_.keyEnd=j_(e,T_.key=t,n),A_(e,t,n))}function k_(e){T_.key=0,T_.keyEnd=0,T_.value=0,T_.valueEnd=0,T_.textEnd=e.length}function A_(e,t,n){for(;t32;)t++;return t}function K(e,t,n){return P_(e,t,n,!1),K}function q(e,t){return P_(e,t,null,!0),q}function M_(e){F_(G_,N_,e,!0)}function N_(e,t){for(let n=D_(t);n>=0;n=O_(t,n))la(e,E_(t),!0)}function P_(e,t,n,r){let i=w(),a=Lo(),o=Zo(2);if(a.firstUpdatePass&&L_(a,e,o,r),t!==ed&&pm(i,o,t)){let s=a.data[ms()];q_(a,s,i,i[11],e,i[o+1]=X_(t,n),r,o)}}function F_(e,t,n,r){let i=Lo(),a=Zo(2);i.firstUpdatePass&&L_(i,null,a,r);let o=w();if(n!==ed&&pm(o,a,n)){let s=i.data[ms()];if(Z_(s,r)&&!I_(i,a)){let e=r?s.classesWithoutHost:s.stylesWithoutHost;e!==null&&(n=li(e,n||``)),zg(i,s,o,n,r)}else K_(i,s,o,o[11],o[a+1],o[a+1]=W_(e,t,n),r,a)}}function I_(e,t){return t>=e.expandoStartIndex}function L_(e,t,n,r){let i=e.data;if(i[n+1]===null){let a=i[ms()],o=I_(e,n);Z_(a,r)&&t===null&&!o&&(t=!1),t=R_(i,a,t,r),x_(i,a,t,n,o,r)}}function R_(e,t,n,r){let i=ns(e),a=r?t.residualClasses:t.residualStyles;if(i===null)(r?t.classBindings:t.styleBindings)===0&&(n=H_(null,e,t,n,r),n=U_(n,t.attrs,r),a=null);else{let o=t.directiveStylingLast;if(o===-1||e[o]!==i){if(n=H_(i,e,t,n,r),a===null){let n=z_(e,t,r);n!==void 0&&Array.isArray(n)&&(n=H_(null,e,t,n[1],r),n=U_(n,t.attrs,r),B_(e,t,r,n))}else a=V_(e,t,r)}}return a!==void 0&&(r?t.residualClasses=a:t.residualStyles=a),n}function z_(e,t,n){let r=n?t.classBindings:t.styleBindings;if(__(r)!==0)return e[p_(r)]}function B_(e,t,n,r){let i=n?t.classBindings:t.styleBindings;e[p_(i)]=r}function V_(e,t,n){let r,i=t.directiveEnd;for(let a=1+t.directiveStylingLast;a0;){let t=e[i],a=Array.isArray(t),c=a?t[1]:t,l=c===null,u=n[i+1];u===ed&&(u=l?ma:void 0);let d=l?ua(u,r):c===r?u:void 0;if(a&&!Y_(d)&&(d=ua(t,r)),Y_(d)&&(s=d,o))return s;let f=e[i+1];i=o?p_(f):__(f)}if(t!==null){let e=a?t.residualClasses:t.residualStyles;e!=null&&(s=ua(e,r))}return s}function Y_(e){return e!==void 0}function X_(e,t){return e==null||e===``||(typeof t==`string`?e=pu(e)+t:typeof e==`object`&&(e=ci(pu(e)))),e}function Z_(e,t){return!!(e.flags&(t?8:16))}function J(e,t=``){let n=w(),r=Lo(),i=e+27,a=r.firstCreatePass?Yp(r,i,1,t,null):r.data[i],o=Q_(r,n,a,t);n[i]=o,xs()&&xf(r,n,o,a),Vo(a,!1)}var Q_=(e,t,n,r)=>(Ss(!0),Su(t[11],r));function $_(e,t,n,r=``){return pm(e,Xo(),n)?t+Ni(n)+r:ed}function ev(e,t,n,r,i,a=``){let o=mm(e,Jo(),n,i);return Zo(2),o?t+Ni(n)+r+Ni(i)+a:ed}function tv(e,t,n,r,i,a,o,s=``){let c=hm(e,Jo(),n,i,o);return Zo(3),c?t+Ni(n)+r+Ni(i)+a+Ni(o)+s:ed}function nv(e,t,n,r,i,a,o,s,c,l=``){let u=gm(e,Jo(),n,i,o,c);return Zo(4),u?t+Ni(n)+r+Ni(i)+a+Ni(o)+s+Ni(c)+l:ed}function Y(e){return X(``,e),Y}function X(e,t,n){let r=w(),i=$_(r,e,t,n);return i!==ed&&av(r,ms(),i),X}function Z(e,t,n,r,i){let a=w(),o=ev(a,e,t,n,r,i);return o!==ed&&av(a,ms(),o),Z}function rv(e,t,n,r,i,a,o){let s=w(),c=tv(s,e,t,n,r,i,a,o);return c!==ed&&av(s,ms(),c),rv}function iv(e,t,n,r,i,a,o,s,c){let l=w(),u=nv(l,e,t,n,r,i,a,o,s,c);return u!==ed&&av(l,ms(),u),iv}function av(e,t,n){let r=oo(t,e);Cu(e[11],r,n)}function ov(e,t,n){Sc(t)&&(t=t());let r=w();return pm(r,Xo(),t)&&(Lo(),Jf(gs(),r,e,t,r[11],n)),ov}function sv(e,t){let n=Sc(e);return n&&e.set(t),n}function cv(e,t){let n=w(),r=Lo(),i=Ro();return i_(r,n,n[11],i,e,t),cv}var lv={};function uv(e){Ld(`NgLet`);let t=Lo(),n=w(),r=e+27;return Vo(Yp(t,r,128,null,null),!1),uo(t,n,r,lv),uv}function dv(e){return uo(Lo(),w(),ms(),e),e}function fv(e){let t=lo(Wo(),27+e);if(t===lv)throw new ii(314,!1);return t}function pv(e,t,n=``){return $_(w(),e,t,n)}function mv(e,t){let n=qo()+e,r=w();return r[n]===ed?dm(r,n,t()):fm(r,n)}function hv(e,t,n){return vv(w(),qo(),e,t,n)}function gv(e,t,n,r,i){return bv(w(),qo(),e,t,n,r,i)}function _v(e,t){let n=e[t];return n===ed?void 0:n}function vv(e,t,n,r,i,a){let o=t+n;return pm(e,o,i)?dm(e,o+1,a?r.call(a,i):r(i)):_v(e,o+1)}function yv(e,t,n,r,i,a,o){let s=t+n;return mm(e,s,i,a)?dm(e,s+2,o?r.call(o,i,a):r(i,a)):_v(e,s+2)}function bv(e,t,n,r,i,a,o,s){let c=t+n;return hm(e,c,i,a,o)?dm(e,c+3,s?r.call(s,i,a,o):r(i,a,o)):_v(e,c+3)}function xv(e,t){let n=Lo(),r,i=e+27;n.firstCreatePass?(r=Sv(t,n.pipeRegistry),n.data[i]=r,r.onDestroy&&(n.destroyHooks??=[]).push(i,r.onDestroy)):r=n.data[i];let a=r.factory||(r.factory=ta(r.type,!0)),o=Ui(Dm);try{let e=cl(!1),t=a();return cl(e),uo(n,w(),i,t),t}finally{Ui(o)}}function Sv(e,t){if(t)for(let n=t.length-1;n>=0;n--){let r=t[n];if(e===r.name)return r}}function Cv(e,t,n){let r=e+27,i=w(),a=lo(i,r);return Tv(i,r)?vv(i,qo(),t,a.transform,n,a):a.transform(n)}function wv(e,t,n,r){let i=e+27,a=w(),o=lo(a,i);return Tv(a,i)?yv(a,qo(),t,o.transform,n,r,o):o.transform(n,r)}function Tv(e,t){return e[1].data[t].pure}function Ev(e,t){return Jp(e,t)}var Dv=(()=>{class e{applicationErrorHandler=C(Qs);appRef=C(mg);taskService=C(js);ngZone=C(zs);zonelessEnabled=C(lc);tracing=C(Fd,{optional:!0});zoneIsDefined=typeof Zone<`u`&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new _r;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(Ls):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(C(uc,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{let e=this.taskService.add();if(!this.runningTick&&(this.cleanup(),!this.zonelessEnabled||this.appRef.includeAllTestViews)){this.taskService.remove(e);return}this.switchToMicrotaskScheduler(),this.taskService.remove(e)})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()}))}switchToMicrotaskScheduler(){this.ngZone.runOutsideAngular(()=>{let e=this.taskService.add();this.useMicrotaskScheduler=!0,queueMicrotask(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(e)})})}notify(e){if(!this.zonelessEnabled&&e===5)return;switch(e){case 0:case 2:this.appRef.dirtyFlags|=2;break;case 3:case 4:case 5:case 1:this.appRef.dirtyFlags|=4;break;case 6:this.appRef.dirtyFlags|=2;break;case 12:this.appRef.dirtyFlags|=16;break;case 13:this.appRef.dirtyFlags|=2;break;case 11:break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick())return;let t=this.useMicrotaskScheduler?Fs:Ps;this.pendingRenderTaskId=this.taskService.add(),this.cancelScheduledCallback=this.scheduleInRootZone?Zone.root.run(()=>t(()=>this.tick())):this.ngZone.runOutsideAngular(()=>t(()=>this.tick()))}shouldScheduleTick(){return!(this.appRef.destroyed||this.pendingRenderTaskId!==null||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(`isAngularZone_ID`+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(this.appRef.dirtyFlags===0){this.cleanup();return}!this.zonelessEnabled&&this.appRef.dirtyFlags&7&&(this.appRef.dirtyFlags|=1);let e=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(e){this.applicationErrorHandler(e)}finally{this.taskService.remove(e),this.cleanup()}}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,this.pendingRenderTaskId!==null){let e=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(e)}}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})}return e})();function Ov(){return[{provide:cc,useExisting:Dv},{provide:zs,useClass:qs},{provide:lc,useValue:!0}]}function kv(){return typeof $localize<`u`&&$localize.locale||`en-US`}var Av=new xi(``,{factory:()=>C(Av,{optional:!0,skipSelf:!0})||kv()}),jv=class{destroyed=!1;listeners=null;errorHandler=C(Zs,{optional:!0});isEmitting=!1;hasNullListeners=!1;destroyRef=C(Ds);constructor(){this.destroyRef.onDestroy(()=>{this.destroyed=!0,this.listeners=null})}subscribe(e){if(this.destroyed)throw new ii(953,!1);return(this.listeners??=[]).push(e),{unsubscribe:()=>{let t=this.listeners?this.listeners.indexOf(e):-1;t>-1&&(this.isEmitting?(this.hasNullListeners=!0,this.listeners[t]=null):this.listeners.splice(t,1))}}}emit(e){if(this.destroyed){console.warn(oi(953,!1));return}if(this.listeners===null)return;this.isEmitting=!0;let t=pn(null);try{for(let t of this.listeners)try{t!==null&&t(e)}catch(e){this.errorHandler?.handleError(e)}}finally{this.hasNullListeners&&(this.hasNullListeners=!1,this.listeners&&Mv(this.listeners)),pn(t),this.isEmitting=!1}}};function Mv(e){let t=e.length-1;for(;t>-1;)e[t]===null&&e.splice(t,1),t--}function Q(e,t){return Pn(e,t?.equal)}function Nv(e){return sr(e)}(class e extends Error{_brand;constructor(e){super(e)}static IDLE=new e(`IDLE`);static LOADING=new e(`LOADING`)});var Pv=e=>e;function Fv(e,t){return typeof e==`function`?Iv(rr(e,Pv,t?.equal),t?.debugName,t?.set):Iv(rr(e.source,e.computation,e.equal),e.debugName,e.set)}function Iv(e,t,n){let r=e[fn],i=e;if(n!==void 0){let t=e=>ir(r,e);i.set=e=>n(e,t),i.update=r=>n(r(Nv(e)),t)}else i.set=e=>ir(r,e),i.update=e=>ar(r,e);return i.asReadonly=ec.bind(e),i}function Lv(e,t){let n=Object.create(wc);n.value=e,n.transformFn=t?.transform;function r(){if(gn(n),n.value===Cc)throw new ii(-950,null);return n.value}return r[fn]=n,r}function Rv(e){return new jv}function zv(e,t){return Lv(e,t)}function Bv(e){return Lv(Cc,e)}var $=(zv.required=Bv,zv);function Vv(e,t){let n=Object.create(wc),r=new jv;n.value=e;function i(){return gn(n),Hv(n.value),n.value}return i[fn]=n,i.asReadonly=ec.bind(i),i.set=e=>{n.equal(n.value,e)||(Kn(n,e),r.emit(e))},i.update=e=>{Hv(n.value),i.set(e(n.value))},i.subscribe=r.subscribe.bind(r),i.destroyRef=r.destroyRef,i}function Hv(e){if(e===Cc)throw new ii(952,!1)}function Uv(e,t){return Vv(e,t)}function Wv(e){return Vv(Cc,e)}var Gv=(Uv.required=Wv,Uv);function Kv(e,t){return Lh(t)}function qv(e,t){return Rh(t)}var Jv=(Kv.required=qv,Kv),Yv=new xi(``),Xv=new xi(``);function Zv(e){return!e.moduleRef}function Qv(e){let t=Zv(e)?e.r3Injector:e.moduleRef.injector,n=t.get(zs);return n.run(()=>{Zv(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();let r=t.get(Qs),i;if(n.runOutsideAngular(()=>{i=n.onError.subscribe({next:r})}),Zv(e)){let n=()=>t.destroy(),r=e.platformInjector.get(Yv);r.add(n),t.onDestroy(()=>{i.unsubscribe(),r.delete(n)})}else{let t=()=>e.moduleRef.destroy(),n=e.platformInjector.get(Yv);n.add(t),e.moduleRef.onDestroy(()=>{gg(e.allPlatformModules,e.moduleRef),i.unsubscribe(),n.delete(t)})}return ey(r,n,()=>{let n=t.get(js),r=n.add(),i=t.get(rg);return i.runInitializers(),i.donePromise.then(()=>{if(r_(t.get(Av,n_)||`en-US`),!t.get(Xv,!0))return Zv(e)?t.get(mg):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if(Zv(e)){let n=t.get(mg);return e.rootComponent!==void 0&&n.bootstrap(e.rootComponent),n}return $v?.(e.moduleRef,e.allPlatformModules),e.moduleRef}).finally(()=>void n.remove(r))})})}var $v;function ey(e,t,n){try{let r=n();return Vh(r)?r.catch(n=>{throw t.runOutsideAngular(()=>e(n)),n}):r}catch(n){throw t.runOutsideAngular(()=>e(n)),n}}var ty=null;function ny(e=[],t){return Ts.create({name:t,providers:[{provide:ka,useValue:`platform`},{provide:Yv,useValue:new Set([()=>ty=null])},...e]})}function ry(e=[]){if(ty)return ty;let t=ny(e);return ty=t,fg(),iy(t),t}function iy(e){let t=e.get(rc,null);Ka(e,()=>{t?.forEach(e=>e())})}function ay(e){let{rootComponent:t,appProviders:n,platformProviders:r,platformRef:i}=e;zc(Ec.BootstrapApplicationStart);try{let e=i?.injector??ry(r);return Qv({r3Injector:new Wh({providers:[Ov(),$s,...n||[]],parent:e,debugName:``,runEnvironmentInitializers:!1}).injector,platformInjector:e,rootComponent:t})}catch(e){return Promise.reject(e)}finally{zc(Ec.BootstrapApplicationEnd)}}function oy(e){return typeof e==`boolean`?e:e!=null&&e!==`false`}var sy=Symbol(`NOT_SET`),cy=new Set,ly={...Jn,kind:`afterRenderEffectPhase`,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,value:sy,cleanup:null,consumerMarkedDirty(){if(this.sequence.impl.executing){if(this.sequence.lastPhase===null||this.sequence.lastPhase(gn(r),r.value),r.signal[fn]=r,r.registerCleanupFn=e=>(r.cleanup??=new Set).add(e),this.nodes[e]=r,this.hooks[e]=e=>r.phaseFn(e)}}afterRun(){super.afterRun(),this.lastPhase=null}destroy(){if(this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();super.destroy();for(let e of this.nodes)if(e)try{for(let t of e.cleanup??cy)t()}finally{On(e)}}};function dy(e,t){let n=t?.injector??C(Ts),r=n.get(cc),i=n.get(Rd),a=n.get(Fd,null,{optional:!0});i.impl??=n.get(Bd);let o=e;typeof o==`function`&&(o={mixedReadWrite:e});let s=n.get(oc,null,{optional:!0}),c=new uy(i.impl,[o.earlyRead,o.write,o.mixedReadWrite,o.read],s?.view,r,n,a?.snapshot(null));return i.impl.register(c),c}var fy=null;function py(){return fy}function my(e){fy??=e}var hy=class{},gy=(function(e){return e[e.Format=0]=`Format`,e[e.Standalone=1]=`Standalone`,e})(gy||{}),_y=(function(e){return e[e.Narrow=0]=`Narrow`,e[e.Abbreviated=1]=`Abbreviated`,e[e.Wide=2]=`Wide`,e[e.Short=3]=`Short`,e})(_y||{}),vy=(function(e){return e[e.Short=0]=`Short`,e[e.Medium=1]=`Medium`,e[e.Long=2]=`Long`,e[e.Full=3]=`Full`,e})(vy||{}),yy={Decimal:0,Group:1,List:2,PercentSign:3,PlusSign:4,MinusSign:5,Exponential:6,SuperscriptingExponent:7,PerMille:8,Infinity:9,NaN:10,TimeSeparator:11,CurrencyDecimal:12,CurrencyGroup:13};function by(e){return Qg(e)[e_.LocaleId]}function xy(e,t,n){let r=Qg(e);return My(My([r[e_.DayPeriodsFormat],r[e_.DayPeriodsStandalone]],t),n)}function Sy(e,t,n){let r=Qg(e);return My(My([r[e_.DaysFormat],r[e_.DaysStandalone]],t),n)}function Cy(e,t,n){let r=Qg(e);return My(My([r[e_.MonthsFormat],r[e_.MonthsStandalone]],t),n)}function wy(e,t){let n=Qg(e)[e_.Eras];return My(n,t)}function Ty(e,t){return My(Qg(e)[e_.DateFormat],t)}function Ey(e,t){return My(Qg(e)[e_.TimeFormat],t)}function Dy(e,t){let n=Qg(e)[e_.DateTimeFormat];return My(n,t)}function Oy(e,t){let n=Qg(e),r=n[e_.NumberSymbols][t];if(r===void 0){if(t===yy.CurrencyDecimal)return n[e_.NumberSymbols][yy.Decimal];if(t===yy.CurrencyGroup)return n[e_.NumberSymbols][yy.Group]}return r}function ky(e){if(!e[e_.ExtraData])throw new ii(2303,!1)}function Ay(e){let t=Qg(e);return ky(t),(t[e_.ExtraData][2]||[]).map(e=>typeof e==`string`?Ny(e):[Ny(e[0]),Ny(e[1])])}function jy(e,t,n){let r=Qg(e);return ky(r),My(My([r[e_.ExtraData][0],r[e_.ExtraData][1]],t)||[],n)||[]}function My(e,t){for(let n=t;n>-1;n--)if(e[n]!==void 0)return e[n];throw new ii(2304,!1)}function Ny(e){let[t,n]=e.split(`:`);return{hours:+t,minutes:+n}}var Py=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,Fy=Object.create(null),Iy=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/,Ly=256;function Ry(e,t,n,r){let i=sb(e);zy(t),t=Vy(n,t)||t;let a=[],o;for(;t;)if(o=Iy.exec(t),o){a=a.concat(o.slice(1));let e=a.pop();if(!e)break;t=e}else{a.push(t);break}let s=i.getTimezoneOffset();r&&(s=ib(r,s),i=ob(i,r));let c=``;return a.forEach(e=>{let t=rb(e);c+=t?t(i,n,s):e===`''`?`'`:e.replace(/(^'|'$)/g,``).replace(/''/g,`'`)}),c}function zy(e){if(e.length>Ly)throw new ii(2300,!1)}function By(e,t,n){let r=new Date(0);return r.setFullYear(e,t,n),r.setHours(0,0,0),r}function Vy(e,t){let n=by(e);if(Fy[n]??=Object.create(null),Fy[n][t])return Fy[n][t];let r=``;switch(t){case`shortDate`:r=Ty(e,vy.Short);break;case`mediumDate`:r=Ty(e,vy.Medium);break;case`longDate`:r=Ty(e,vy.Long);break;case`fullDate`:r=Ty(e,vy.Full);break;case`shortTime`:r=Ey(e,vy.Short);break;case`mediumTime`:r=Ey(e,vy.Medium);break;case`longTime`:r=Ey(e,vy.Long);break;case`fullTime`:r=Ey(e,vy.Full);break;case`short`:let t=Vy(e,`shortTime`),n=Vy(e,`shortDate`);r=Hy(Dy(e,vy.Short),[t,n]);break;case`medium`:let i=Vy(e,`mediumTime`),a=Vy(e,`mediumDate`);r=Hy(Dy(e,vy.Medium),[i,a]);break;case`long`:let o=Vy(e,`longTime`),s=Vy(e,`longDate`);r=Hy(Dy(e,vy.Long),[o,s]);break;case`full`:let c=Vy(e,`fullTime`),l=Vy(e,`fullDate`);r=Hy(Dy(e,vy.Full),[c,l])}return r&&(Fy[n][t]=r),r}function Hy(e,t){return t&&(e=e.replace(/\{([^}]+)}/g,function(e,n){return Object.hasOwn(t,n)?t[n]:e})),e}function Uy(e,t,n=`-`,r,i){let a=``;(e<0||i&&e<=0)&&(i?e=-e+1:(e=-e,a=n));let o=String(e);for(;o.length0||s>-n)&&(s+=n),e===3)s===0&&n===-12&&(s=12);else if(e===6)return Wy(s,t);let c=Oy(o,yy.MinusSign);return Uy(s,t,c,r,i)}}function Ky(e,t){switch(e){case 0:return t.getFullYear();case 1:return t.getMonth();case 2:return t.getDate();case 3:return t.getHours();case 4:return t.getMinutes();case 5:return t.getSeconds();case 6:return t.getMilliseconds();case 7:return t.getDay();default:throw new ii(2301,!1)}}function qy(e,t,n=gy.Format,r=!1){return function(i,a){return Jy(i,a,e,t,n,r)}}function Jy(e,t,n,r,i,a){switch(n){case 2:return Cy(t,i,r)[e.getMonth()];case 1:return Sy(t,i,r)[e.getDay()];case 0:let n=e.getHours(),o=e.getMinutes();if(a){let e=Ay(t),a=jy(t,i,r),s=e.findIndex(e=>{if(Array.isArray(e)){let[t,r]=e,i=n>=t.hours&&o>=t.minutes,a=n0?Math.floor(i/60):Math.ceil(i/60);switch(e){case 0:return(i>=0?`+`:``)+Uy(o,2,a)+Uy(Math.abs(i%60),2,a);case 1:return`GMT`+(i>=0?`+`:``)+Uy(o,1,a);case 2:return`GMT`+(i>=0?`+`:``)+Uy(o,2,a)+`:`+Uy(Math.abs(i%60),2,a);case 3:return r===0?`Z`:(i>=0?`+`:``)+Uy(o,2,a)+`:`+Uy(Math.abs(i%60),2,a);default:throw new ii(2310,!1)}}}var Xy=0,Zy=4;function Qy(e){let t=By(e,Xy,1).getDay();return By(e,0,1+(t<=Zy?Zy:11)-t)}function $y(e){let t=e.getDay(),n=t===0?-3:Zy-t;return By(e.getFullYear(),e.getMonth(),e.getDate()+n)}function eb(e,t=!1){return function(n,r){let i;if(t){let e=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,t=n.getDate();i=1+Math.floor((t+e)/7)}else{let e=$y(n),t=Qy(e.getFullYear()),r=e.getTime()-t.getTime();i=1+Math.round(r/6048e5)}return Uy(i,e,Oy(r,yy.MinusSign))}}function tb(e,t=!1){return function(n,r){return Uy($y(n).getFullYear(),e,Oy(r,yy.MinusSign),t)}}var nb=Object.create(null);function rb(e){if(nb[e])return nb[e];let t;switch(e){case`G`:case`GG`:case`GGG`:t=qy(3,_y.Abbreviated);break;case`GGGG`:t=qy(3,_y.Wide);break;case`GGGGG`:t=qy(3,_y.Narrow);break;case`y`:t=Gy(0,1,0,!1,!0);break;case`yy`:t=Gy(0,2,0,!0,!0);break;case`yyy`:t=Gy(0,3,0,!1,!0);break;case`yyyy`:t=Gy(0,4,0,!1,!0);break;case`Y`:t=tb(1);break;case`YY`:t=tb(2,!0);break;case`YYY`:t=tb(3);break;case`YYYY`:t=tb(4);break;case`M`:case`L`:t=Gy(1,1,1);break;case`MM`:case`LL`:t=Gy(1,2,1);break;case`MMM`:t=qy(2,_y.Abbreviated);break;case`MMMM`:t=qy(2,_y.Wide);break;case`MMMMM`:t=qy(2,_y.Narrow);break;case`LLL`:t=qy(2,_y.Abbreviated,gy.Standalone);break;case`LLLL`:t=qy(2,_y.Wide,gy.Standalone);break;case`LLLLL`:t=qy(2,_y.Narrow,gy.Standalone);break;case`w`:t=eb(1);break;case`ww`:t=eb(2);break;case`W`:t=eb(1,!0);break;case`d`:t=Gy(2,1);break;case`dd`:t=Gy(2,2);break;case`c`:case`cc`:t=Gy(7,1);break;case`ccc`:t=qy(1,_y.Abbreviated,gy.Standalone);break;case`cccc`:t=qy(1,_y.Wide,gy.Standalone);break;case`ccccc`:t=qy(1,_y.Narrow,gy.Standalone);break;case`cccccc`:t=qy(1,_y.Short,gy.Standalone);break;case`E`:case`EE`:case`EEE`:t=qy(1,_y.Abbreviated);break;case`EEEE`:t=qy(1,_y.Wide);break;case`EEEEE`:t=qy(1,_y.Narrow);break;case`EEEEEE`:t=qy(1,_y.Short);break;case`a`:case`aa`:case`aaa`:t=qy(0,_y.Abbreviated);break;case`aaaa`:t=qy(0,_y.Wide);break;case`aaaaa`:t=qy(0,_y.Narrow);break;case`b`:case`bb`:case`bbb`:t=qy(0,_y.Abbreviated,gy.Standalone,!0);break;case`bbbb`:t=qy(0,_y.Wide,gy.Standalone,!0);break;case`bbbbb`:t=qy(0,_y.Narrow,gy.Standalone,!0);break;case`B`:case`BB`:case`BBB`:t=qy(0,_y.Abbreviated,gy.Format,!0);break;case`BBBB`:t=qy(0,_y.Wide,gy.Format,!0);break;case`BBBBB`:t=qy(0,_y.Narrow,gy.Format,!0);break;case`h`:t=Gy(3,1,-12);break;case`hh`:t=Gy(3,2,-12);break;case`H`:t=Gy(3,1);break;case`HH`:t=Gy(3,2);break;case`m`:t=Gy(4,1);break;case`mm`:t=Gy(4,2);break;case`s`:t=Gy(5,1);break;case`ss`:t=Gy(5,2);break;case`S`:t=Gy(6,1);break;case`SS`:t=Gy(6,2);break;case`SSS`:t=Gy(6,3);break;case`Z`:case`ZZ`:case`ZZZ`:t=Yy(0);break;case`ZZZZZ`:t=Yy(3);break;case`O`:case`OO`:case`OOO`:case`z`:case`zz`:case`zzz`:t=Yy(1);break;case`OOOO`:case`ZZZZ`:case`zzzz`:t=Yy(2);break;default:return null}return nb[e]=t,t}function ib(e,t){e=e.replace(/:/g,``);let n=Date.parse(`Jan 01, 1970 00:00:00 `+e)/6e4;return isNaN(n)?t:n}function ab(e,t){return e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+t),e}function ob(e,t,n){let r=e.getTimezoneOffset();return ab(e,-1*(ib(t,r)-r))}function sb(e){if(lb(e))return e;if(typeof e==`number`&&!isNaN(e))return new Date(e);if(typeof e==`string`){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){let[t,n=1,r=1]=e.split(`-`).map(e=>+e);return By(t,n-1,r)}let t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let n;if(n=e.match(Py))return cb(n)}let t=new Date(e);if(!lb(t))throw new ii(2311,!1);return t}function cb(e){let t=new Date(0),n=0,r=0,i=e[8]?t.setUTCFullYear:t.setFullYear,a=e[8]?t.setUTCHours:t.setHours;e[9]&&(n=Number(e[9]+e[10]),r=Number(e[9]+e[11])),i.call(t,Number(e[1]),Number(e[2])-1,Number(e[3]));let o=Number(e[4]||0)-n,s=Number(e[5]||0)-r,c=Number(e[6]||0),l=Math.floor(parseFloat(`0.`+(e[7]||0))*1e3);return a.call(t,o,s,c,l),t}function lb(e){return e instanceof Date&&!isNaN(e.valueOf())}var ub=(()=>{class e{_viewContainerRef;_viewRef=null;ngTemplateOutletContext=null;ngTemplateOutlet=null;ngTemplateOutletInjector=null;injector=C(Ts);constructor(e){this._viewContainerRef=e}ngOnChanges(e){if(this._shouldRecreateView(e)){let e=this._viewContainerRef;if(this._viewRef&&e.remove(e.indexOf(this._viewRef)),!this.ngTemplateOutlet){this._viewRef=null;return}let t=this._createContextForwardProxy();this._viewRef=e.createEmbeddedView(this.ngTemplateOutlet,t,{injector:this._getInjector()})}}_getInjector(){return this.ngTemplateOutletInjector===`outlet`?this.injector:this.ngTemplateOutletInjector??void 0}_shouldRecreateView(e){return!!e.ngTemplateOutlet||!!e.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(e,t,n)=>this.ngTemplateOutletContext?Reflect.set(this.ngTemplateOutletContext,t,n):!1,get:(e,t,n)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,t,n)}})}static ɵfac=function(t){return new(t||e)(Dm(sh))};static ɵdir=Xh({type:e,selectors:[[``,`ngTemplateOutlet`,``]],inputs:{ngTemplateOutletContext:`ngTemplateOutletContext`,ngTemplateOutlet:`ngTemplateOutlet`,ngTemplateOutletInjector:`ngTemplateOutletInjector`},features:[Ac]})}return e})();function db(e,t){return new ii(2100,!1)}var fb=`mediumDate`,pb=new xi(``),mb=new xi(``),hb=(()=>{class e{locale;defaultTimezone;defaultOptions;constructor(e,t,n){this.locale=e,this.defaultTimezone=t,this.defaultOptions=n}transform(t,n,r,i){if(t==null||t===``||t!==t)return null;try{let e=n??this.defaultOptions?.dateFormat??fb,a=r??this.defaultOptions?.timezone??this.defaultTimezone??void 0;return Ry(t,e,i||this.locale,a)}catch(t){throw db(e,t.message)}}static ɵfac=function(t){return new(t||e)(Dm(Av,16),Dm(pb,24),Dm(mb,24))};static ɵpipe=Zh({name:`date`,type:e,pure:!0})}return e})(),gb=(()=>{class e{transform(e){return JSON.stringify(e,null,2)}static ɵfac=function(t){return new(t||e)};static ɵpipe=Zh({name:`json`,type:e,pure:!1})}return e})();function _b(e,t){t=encodeURIComponent(t);for(let n of e.split(`;`)){let e=n.indexOf(`=`),[r,i]=e==-1?[n,``]:[n.slice(0,e),n.slice(e+1)];if(r.trim()!==t)continue;let a=i;try{a=decodeURIComponent(i)}catch{}return a.length>1&&a[0]===`"`&&a[a.length-1]===`"`&&(a=a.slice(1,-1)),a}return null}var vb=`browser`,yb=class{_doc;constructor(e){this._doc=e}manager},bb=(()=>{class e extends yb{constructor(e){super(e)}supports(e){return!0}addEventListener(e,t,n,r){return e.addEventListener(t,n,r),()=>this.removeEventListener(e,t,n,r)}removeEventListener(e,t,n,r){return e.removeEventListener(t,n,r)}static ɵfac=function(t){return new(t||e)(Xi(Es))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),xb=new xi(``),Sb=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(e,t){this._zone=t,e.forEach(e=>{e.manager=this});let n=e.filter(e=>!(e instanceof bb));this._plugins=n.slice().reverse();let r=e.find(e=>e instanceof bb);r&&this._plugins.push(r)}addEventListener(e,t,n,r){return this._findPluginFor(t).addEventListener(e,t,n,r)}getZone(){return this._zone}_findPluginFor(e){let t=this._eventNameToPlugin.get(e);if(t)return t;if(t=this._plugins.find(t=>t.supports(e)),!t)throw new ii(-5101,!1);return this._eventNameToPlugin.set(e,t),t}static ɵfac=function(t){return new(t||e)(Xi(xb),Xi(zs))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),Cb=`ng-app-id`;function wb(e){for(let t of e)t.remove()}function Tb(e,t){let n=t.createElement(`style`);return n.textContent=e,n}function Eb(e,t,n,r){let i=e.head?.querySelectorAll(`style[${Cb}="${t}"],link[${Cb}="${t}"]`);if(!i||i.length===0)return!1;for(let e of i)e.removeAttribute(Cb),e instanceof HTMLLinkElement?r.set(e.href.slice(e.href.lastIndexOf(`/`)+1),{usage:0,elements:[e]}):e.textContent&&n.set(e.textContent,{usage:0,elements:[e]});return!0}function Db(e,t){let n=t.createElement(`link`);return n.setAttribute(`rel`,`stylesheet`),n.setAttribute(`href`,e),n}var Ob=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;constructor(e,t,n,r={}){this.doc=e,this.appId=t,this.nonce=n,Eb(e,t,this.inline,this.external)&&this.hosts.add(e.head)}addStyles(e,t){for(let t of e)this.addUsage(t,this.inline,Tb);t?.forEach(e=>this.addUsage(e,this.external,Db))}removeStyles(e,t){for(let t of e)this.removeUsage(t,this.inline);t?.forEach(e=>this.removeUsage(e,this.external))}addUsage(e,t,n){let r=t.get(e);r?r.usage++:t.set(e,{usage:1,elements:[...this.hosts].map(t=>this.addElement(t,n(e,this.doc)))})}removeUsage(e,t){let n=t.get(e);n&&(n.usage--,n.usage<=0&&(wb(n.elements),t.delete(e)))}ngOnDestroy(){for(let[,{elements:e}]of[...this.inline,...this.external])wb(e);this.hosts.clear()}addHost(e){if(!this.hosts.has(e)){this.hosts.add(e);for(let[t,{elements:n}]of this.inline)n.push(this.addElement(e,Tb(t,this.doc)));for(let[t,{elements:n}]of this.external)n.push(this.addElement(e,Db(t,this.doc)))}}removeHost(e){this.hosts.delete(e);for(let t of[...this.inline.values(),...this.external.values()]){let n=[];for(let r of t.elements)r.parentNode===e?r.remove():n.push(r);t.elements=n}}addElement(e,t){return this.nonce&&t.setAttribute(`nonce`,this.nonce),e.appendChild(t)}static ɵfac=function(t){return new(t||e)(Xi(Es),Xi(tc),Xi(ac,8),Xi(ic))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),kb={svg:`http://www.w3.org/2000/svg`,xhtml:`http://www.w3.org/1999/xhtml`,xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`,xmlns:`http://www.w3.org/2000/xmlns/`,math:`http://www.w3.org/1998/Math/MathML`},Ab=/%COMP%/g,jb=`%COMP%`,Mb=`_nghost-${jb}`,Nb=`_ngcontent-${jb}`,Pb=!0,Fb=new xi(``,{factory:()=>Pb}),Ib=new xi(``);function Lb(e){return Nb.replace(Ab,e)}function Rb(e){return Mb.replace(Ab,e)}function zb(e,t){return t.map(t=>t.replace(Ab,e))}var Bb=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;cssVarNamespace;constructor(e,t,n,r,i,a,o=null,s=null,c=null){this.eventManager=e,this.sharedStylesHost=t,this.appId=n,this.removeStylesOnCompDestroy=r,this.doc=i,this.ngZone=a,this.nonce=o,this.tracingService=s,this.cssVarNamespace=c??``,this.defaultRenderer=new Vb(e,i,a,this.tracingService,this.cssVarNamespace)}createRenderer(e,t){if(!e||!t)return this.defaultRenderer;let n=this.getOrCreateRenderer(e,t);return n instanceof Gb?n.applyToHost(e):n instanceof Wb&&n.applyStyles(),n}getOrCreateRenderer(e,t){let n=this.rendererByCompId,r=n.get(t.id);if(!r){let i=this.doc,a=this.ngZone,o=this.eventManager,s=this.sharedStylesHost,c=this.removeStylesOnCompDestroy,l=this.tracingService;switch(t.encapsulation){case du.Emulated:r=new Gb(o,s,t,this.appId,c,i,a,l,this.cssVarNamespace);break;case du.ShadowDom:return new Ub(o,e,t,i,a,this.nonce,l,this.cssVarNamespace,s);case du.ExperimentalIsolatedShadowDom:return new Ub(o,e,t,i,a,this.nonce,l,this.cssVarNamespace);default:r=new Wb(o,s,t,c,i,a,l,this.cssVarNamespace)}n.set(t.id,r)}return r}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(e){this.rendererByCompId.delete(e)}static ɵfac=function(t){return new(t||e)(Xi(Sb),Xi(Tm),Xi(tc),Xi(Fb),Xi(Es),Xi(zs),Xi(ac),Xi(Fd,8),Xi(Ib,8))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),Vb=class{eventManager;doc;ngZone;tracingService;cssVarNamespace;data=Object.create(null);throwOnSyntheticProps=!0;constructor(e,t,n,r,i=``){this.eventManager=e,this.doc=t,this.ngZone=n,this.tracingService=r,this.cssVarNamespace=i}destroy(){}destroyNode=null;createElement(e,t){return t?this.doc.createElementNS(kb[t]||t,e):this.doc.createElement(e)}createComment(e){return this.doc.createComment(e)}createText(e){return this.doc.createTextNode(e)}appendChild(e,t){(Hb(e)?e.content:e).appendChild(t)}insertBefore(e,t,n){if(e){let r=Hb(e)?e.content:e;if(n!=null&&n.parentNode!==r)throw new ii(-5106,!1);r.insertBefore(t,n)}}removeChild(e,t){t.remove()}selectRootElement(e,t){let n=typeof e==`string`?this.doc.querySelector(e):e;if(!n)throw new ii(-5104,!1);return t||(n.textContent=``),n}parentNode(e){return e.parentNode}nextSibling(e){return e.nextSibling}setAttribute(e,t,n,r){if(r){t=r+`:`+t;let i=kb[r];i?e.setAttributeNS(i,t,n):e.setAttribute(t,n)}else e.setAttribute(t,n)}removeAttribute(e,t,n){if(n){let r=kb[n];r?e.removeAttributeNS(r,t):e.removeAttribute(`${n}:${t}`)}else e.removeAttribute(t)}addClass(e,t){e.classList.add(t)}removeClass(e,t){e.classList.remove(t)}setStyle(e,t,n,r){let i=t.startsWith(`--`);i&&(t=t.replace(`%NS%`,this.cssVarNamespace)),i||r&(td.DashCase|td.Important)?e.style.setProperty(t,n,r&td.Important?`important`:``):e.style[t]=n}removeStyle(e,t,n){let r=t.startsWith(`--`);r&&(t=t.replace(`%NS%`,this.cssVarNamespace)),r||n&td.DashCase?e.style.removeProperty(t):e.style[t]=``}setProperty(e,t,n){e!=null&&(e[t]=n)}setValue(e,t){e.nodeValue=t}listen(e,t,n,r){if(typeof e==`string`&&(e=py().getGlobalEventTarget(this.doc,e),!e))throw new ii(-5102,!1);let i=this.decoratePreventDefault(n);return this.tracingService?.wrapEventListener&&(i=this.tracingService.wrapEventListener(e,t,i)),this.eventManager.addEventListener(e,t,i,r)}decoratePreventDefault(e){return t=>{if(t===`__ngUnwrap__`)return e;e(t)===!1&&t.preventDefault()}}};function Hb(e){return e.tagName===`TEMPLATE`&&e.content!==void 0}var Ub=class extends Vb{hostEl;sharedStylesHost;shadowRoot;constructor(e,t,n,r,i,a,o,s,c){super(e,r,i,o,s),this.hostEl=t,this.sharedStylesHost=c,this.shadowRoot=t.attachShadow({mode:`open`}),this.sharedStylesHost&&this.sharedStylesHost.addHost(this.shadowRoot);let l=n.styles;l=zb(n.id,l).map(e=>e.replace(/%NS%/g,s));for(let e of l){let t=document.createElement(`style`);a&&t.setAttribute(`nonce`,a),t.textContent=e,this.shadowRoot.appendChild(t)}let u=n.getExternalStyles?.();if(u)for(let e of u){let t=Db(e,r);a&&t.setAttribute(`nonce`,a),this.shadowRoot.appendChild(t)}}nodeOrShadowRoot(e){return e===this.hostEl?this.shadowRoot:e}appendChild(e,t){return super.appendChild(this.nodeOrShadowRoot(e),t)}insertBefore(e,t,n){return super.insertBefore(this.nodeOrShadowRoot(e),t,n)}removeChild(e,t){return super.removeChild(null,t)}parentNode(e){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(e)))}destroy(){this.sharedStylesHost&&this.sharedStylesHost.removeHost(this.shadowRoot)}},Wb=class extends Vb{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(e,t,n,r,i,a,o,s,c){super(e,i,a,o,s),this.sharedStylesHost=t,this.removeStylesOnCompDestroy=r;let l=n.styles,u=c?zb(c,l):l;this.styles=u.map(e=>e.replace(/%NS%/g,s)),this.styleUrls=n.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&hd.size===0&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}},Gb=class extends Wb{contentAttr;hostAttr;constructor(e,t,n,r,i,a,o,s,c){let l=r+`-`+n.id;super(e,t,n,i,a,o,s,c,l),this.contentAttr=Lb(l),this.hostAttr=Rb(l)}applyToHost(e){this.applyStyles(),this.setAttribute(e,this.hostAttr,``)}createElement(e,t){let n=super.createElement(e,t);return super.setAttribute(n,this.contentAttr,``),n}},Kb=class e extends hy{supportsDOMEvents=!0;static makeCurrent(){my(new e)}onAndCancel(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}dispatchEvent(e,t){e.dispatchEvent(t)}remove(e){e.remove()}createElement(e,t){return t||=this.getDefaultDocument(),t.createElement(e)}createHtmlDocument(){return document.implementation.createHTMLDocument(`fakeTitle`)}getDefaultDocument(){return document}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}isShadowRoot(e){return e instanceof DocumentFragment}getGlobalEventTarget(e,t){return t===`window`?window:t===`document`?e:t===`body`?e.body:null}getBaseHref(e){let t=Jb();return t==null?null:Yb(t)}resetBaseElement(){qb=null}getUserAgent(){return window.navigator.userAgent}getCookie(e){return _b(document.cookie,e)}},qb=null;function Jb(){return qb||=document.head.querySelector(`base`),qb?qb.getAttribute(`href`):null}function Yb(e){return new URL(e,document.baseURI).pathname}var Xb=[`alt`,`control`,`meta`,`shift`],Zb={"\b":`Backspace`," ":`Tab`,"":`Delete`,"\x1B":`Escape`,Del:`Delete`,Esc:`Escape`,Left:`ArrowLeft`,Right:`ArrowRight`,Up:`ArrowUp`,Down:`ArrowDown`,Menu:`ContextMenu`,Scroll:`ScrollLock`,Win:`OS`},Qb={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey},$b=(()=>{class e extends yb{constructor(e){super(e)}supports(t){return e.parseEventName(t)!=null}addEventListener(t,n,r,i){let a=e.parseEventName(n),o=e.eventCallback(a.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>py().onAndCancel(t,a.domEventName,o,i))}static parseEventName(t){let n=t.toLowerCase().split(`.`),r=n.shift();if(n.length===0||r!==`keydown`&&r!==`keyup`)return null;let i=e._normalizeKey(n.pop()),a=``,o=n.indexOf(`code`);if(o>-1&&(n.splice(o,1),a=`code.`),Xb.forEach(e=>{let t=n.indexOf(e);t>-1&&(n.splice(t,1),a+=e+`.`)}),a+=i,n.length!=0||i.length===0)return null;let s={};return s.domEventName=r,s.fullKey=a,s}static matchEventFullKeyCode(e,t){let n=Zb[e.key]||e.key,r=``;return t.indexOf(`code.`)>-1&&(n=e.code,r=`code.`),n==null||!n?!1:(n=n.toLowerCase(),n===` `?n=`space`:n===`.`&&(n=`dot`),Xb.forEach(t=>{if(t!==n){let n=Qb[t];n(e)&&(r+=t+`.`)}}),r+=n,r===t)}static eventCallback(t,n,r){return i=>{e.matchEventFullKeyCode(i,t)&&r.runGuarded(()=>n(i))}}static _normalizeKey(e){return e===`esc`?`escape`:e}static ɵfac=function(t){return new(t||e)(Xi(Es))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})();async function ex(e,t,n){return ay({rootComponent:e,...tx(t,n)})}function tx(e,t){return{platformRef:t?.platformRef,appProviders:[...ox,...e?.providers??[]],platformProviders:ax}}function nx(){Kb.makeCurrent()}function rx(){return new Zs}function ix(){return $l(document),document}var ax=[{provide:ic,useValue:vb},{provide:rc,useValue:nx,multi:!0},{provide:Es,useFactory:ix}],ox=[{provide:ka,useValue:`root`},{provide:Zs,useFactory:rx},{provide:xb,useClass:bb,multi:!0},{provide:xb,useClass:$b,multi:!0},Bb,{provide:Tm,useClass:Ob},{provide:Ob,useExisting:Tm},Sb,{provide:om,useExisting:Bb},[]];function sx(e,t){let n=`\x1B[${e}m`,r=`\x1B[${t}m`;return((e,...t)=>{if(Array.isArray(e)&&`raw`in e){let i=e,a=``;for(let e=0;e{let r=new dx({code:i,why:lx(a.why,e),fix:lx(a.fix,e),docs:o,cause:e.cause,sources:e.sources,data:lx(a.data,e)},s);for(let e of t)e(r,n);return r};n[i]=s}return n}function mx(e){return t=>{let n=`${e.bold(e.red(`[${t.name}]`))} ${t.message}`,r=[];return t.fix&&r.push(`${e.dim(`fix:`)} ${t.fix}`),t.sources?.length&&r.push(`${e.dim(`sources:`)} ${t.sources.join(`, `)}`),t.docs&&r.push(`${e.dim(`see:`)} ${e.cyan(t.docs)}`),r.length===0?n:[n,...r.map((t,n)=>`${e.dim(n{e=n,t=r}),resolve:e,reject:t}}var bx=Math.random.bind(Math),xx=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`;function Sx(e=21){let t=``,n=e;for(;n--;)t+=xx[bx()*64|0];return t}var Cx=6e4,wx=e=>e,Tx=wx,{clearTimeout:Ex,setTimeout:Dx}=globalThis;function Ox(e,t){let{post:n,on:r,off:i=()=>{},eventNames:a=[],serialize:o=wx,deserialize:s=Tx,resolver:c,bind:l=`rpc`,timeout:u=Cx,proxify:d=!0}=t,f=!1,p=new Map,m,h;async function g(e,r,i,a){if(f)throw Error(`[birpc] rpc is closed, cannot call "${e}"`);let s={m:e,a:r,t:`q`};a&&(s.o=!0);let c=async e=>n(o(e));if(i){await c(s);return}if(m)try{await m}finally{m=void 0}let{promise:l,resolve:d,reject:g}=yx(),_=Sx();s.i=_;let ee;async function te(n=s){return u>=0&&(ee=Dx(()=>{try{if(t.onTimeoutError?.call(h,e,r)!==!0)throw Error(`[birpc] timeout on calling "${e}"`)}catch(e){g(e)}p.delete(_)},u),typeof ee==`object`&&(ee=ee.unref?.())),p.set(_,{resolve:d,reject:g,timeoutId:ee,method:e}),await c(n),l}try{t.onRequest?await t.onRequest.call(h,s,te,d):await te()}catch(e){if(t.onGeneralError?.call(h,e)!==!0)throw e;return}finally{Ex(ee),p.delete(_)}return l}let _={$call:(e,...t)=>g(e,t,!1),$callOptional:(e,...t)=>g(e,t,!1,!0),$callEvent:(e,...t)=>g(e,t,!0),$callRaw:e=>g(e.method,e.args,e.event,e.optional),$rejectPendingCalls:te,get $closed(){return f},get $meta(){return t.meta},$close:ee,$functions:e};h=d?new Proxy({},{get(t,n){if(Object.hasOwn(_,n))return _[n];if(n===`then`&&!a.includes(`then`)&&!(`then`in e))return;let r=(...e)=>g(n,e,!0);if(a.includes(n))return r.asEvent=r,r;let i=(...e)=>g(n,e,!1);return i.asEvent=r,i}}):_;function ee(e){f=!0,p.forEach(({reject:t,method:n})=>{let r=Error(`[birpc] rpc is closed, cannot call "${n}"`);if(e)return e.cause??=r,t(e);t(r)}),p.clear(),i(ne)}function te(e){let t=Array.from(p.values()).map(({method:t,reject:n})=>e?e({method:t,reject:n}):n(Error(`[birpc]: rejected pending call "${t}".`)));return p.clear(),t}async function ne(r,...i){let a;try{a=s(r)}catch(e){if(t.onGeneralError?.call(h,e)!==!0)throw e;return}if(a.t===`q`){let{m:r,a:s,o:u}=a,d,f,p=await(c?c.call(h,r,e[r]):e[r]);if(u&&(p||=()=>void 0),!p)f=Error(`[birpc] function "${r}" not found`);else try{d=await p.apply(l===`rpc`?h:e,s)}catch(e){f=e}if(a.i){if(f&&t.onFunctionError&&t.onFunctionError.call(h,f,r,s)===!0)return;if(!f)try{await n(o({t:`s`,i:a.i,r:d}),...i);return}catch(e){if(f=e,t.onGeneralError?.call(h,e,r,s)!==!0)throw e}try{await n(o({t:`s`,i:a.i,e:f}),...i)}catch(e){if(t.onGeneralError?.call(h,e,r,s)!==!0)throw e}}}else{let{i:e,r:t,e:n}=a,r=p.get(e);r&&(Ex(r.timeoutId),n?r.reject(n):r.resolve(t)),p.delete(e)}}return m=r(ne),h}function kx(e,t){return t.safety?t.safety:e===`static`||e===`query`||e==null?`read`:`action`}var Ax=Object.freeze({type:`object`,additionalProperties:!0});function jx(e){let t=e[`~standard`];if(t.jsonSchema)try{return t.jsonSchema.input({target:`draft-2020-12`})}catch{return Ax}return Ax}function Mx(e){if(!e||e.length===0)return{type:`object`,properties:{}};let t={},n=[];for(let r=0;rn[`arg${t}`]);if(`arg0`in n){let e=[];for(;`arg${e.length}`in n;)e.push(n[`arg${e.length}`]);return e}return Object.keys(n).length===0?[]:void 0}function Px(e,t){return Nx(e,t)??[e]}function Fx(e){return typeof e==`string`?`'${e}'`:new zx().serialize(e)}var Ix=` _-,;:!?.'"()[]{}@*/\\&#%\`^+<=>|~$0123456789abcdefghijklmnopqrstuvwxyz`,Lx=(function(){let e=new Uint8Array(128);for(let t=0;t<69;t++)e[Ix.charCodeAt(t)]=t+1;for(let t=65;t<=90;t++)e[t]=e[t+32];return e})();function Rx(e,t){if(e===t)return 0;let n=Math.min(e.length,t.length),r=0;for(let i=0;ia?-1:1)}return e.length===t.length?r:e.lengththis.compare(e[0],t[0])),r=`${e}{`;for(let e=0;ethis.compare(e,t)))}`}$Map(e){return this.serializeObjectEntries(`Map`,e.entries())}}for(let t of[`Error`,`RegExp`,`URL`])e.prototype[`$`+t]=function(e){return`${t}(${e})`};for(let t of[`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float32Array`,`Float64Array`])e.prototype[`$`+t]=function(e){return`${t}[${e.join(`,`)}]`};for(let t of[`BigInt64Array`,`BigUint64Array`])e.prototype[`$`+t]=function(e){return`${t}[${e.join(`n,`)}${e.length>0?`n`:``}]`};return e})(),Bx=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],Vx=[1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998],Hx=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`,Ux=[],Wx=class{_data=new Gx;_hash=new Gx([...Bx]);_nDataBytes=0;_minBufferSize=0;finalize(e){e&&this._append(e);let t=this._nDataBytes*8,n=this._data.sigBytes*8;return this._data.words[n>>>5]|=128<<24-n%32,this._data.words[(n+64>>>9<<4)+14]=Math.floor(t/4294967296),this._data.words[(n+64>>>9<<4)+15]=t,this._data.sigBytes=this._data.words.length*4,this._process(),this._hash}_doProcessBlock(e,t){let n=this._hash.words,r=n[0],i=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],u=n[7];for(let n=0;n<64;n++){if(n<16)Ux[n]=e[t+n]|0;else{let e=Ux[n-15],t=(e<<25|e>>>7)^(e<<14|e>>>18)^e>>>3,r=Ux[n-2],i=(r<<15|r>>>17)^(r<<13|r>>>19)^r>>>10;Ux[n]=t+Ux[n-7]+i+Ux[n-16]}let d=s&c^~s&l,f=r&i^r&a^i&a,p=(r<<30|r>>>2)^(r<<19|r>>>13)^(r<<10|r>>>22),m=(s<<26|s>>>6)^(s<<21|s>>>11)^(s<<7|s>>>25),h=u+m+d+Vx[n]+Ux[n],g=p+f;u=l,l=c,c=s,s=o+h|0,o=a,a=i,i=r,r=h+g|0}n[0]=n[0]+r|0,n[1]=n[1]+i|0,n[2]=n[2]+a|0,n[3]=n[3]+o|0,n[4]=n[4]+s|0,n[5]=n[5]+c|0,n[6]=n[6]+l|0,n[7]=n[7]+u|0}_append(e){typeof e==`string`&&(e=Gx.fromUtf8(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes}_process(e){let t,n=this._data.sigBytes/64;n=e?Math.ceil(n):Math.max((n|0)-this._minBufferSize,0);let r=n*16,i=Math.min(r*4,this._data.sigBytes);if(r){for(let e=0;e>>2]|=(n.charCodeAt(e)&255)<<24-e%4*8;return new e(i,r)}toBase64(){let e=[];for(let t=0;t>>2]>>>24-t%4*8&255,r=this.words[t+1>>>2]>>>24-(t+1)%4*8&255,i=this.words[t+2>>>2]>>>24-(t+2)%4*8&255,a=n<<16|r<<8|i;for(let n=0;n<4&&t*8+n*6>>6*(3-n)&63))}return e.join(``)}concat(e){if(this.words[this.sigBytes>>>2]&=4294967295<<32-this.sigBytes%4*8,this.words.length=Math.ceil(this.sigBytes/4),this.sigBytes%4)for(let t=0;t>>2]>>>24-t%4*8&255;this.words[this.sigBytes+t>>>2]|=n<<24-(this.sigBytes+t)%4*8}else for(let t=0;t>>2]=e.words[t>>>2];this.sigBytes+=e.sigBytes}};function Kx(e){return new Wx().finalize(e).toBase64()}function qx(e){return Kx(Fx(e))}function Jx(e){return qx(e)}function Yx(){let e={};function t(t,...n){let r=e[t]||[];for(let e=0,t=r.length;e{e[t]=e[t]?.filter(e=>n!==e)}}function i(e,t){let n=r(e,((...e)=>(n(),t(...e))));return n}return{_listeners:e,emit:t,emitOnce:n,on:r,once:i}}var Xx=/^[\w+.-]{2,}:\/\//;function Zx(e){return e.endsWith(`/`)?e:`${e}/`}function Qx(e){return(e.endsWith(`/`)?e.slice(0,-1):e)||`/`}function $x(e,...t){let n=e;for(let e of t)e&&e!==`/`&&(n=n?Zx(n)+e.replace(/^\.?\//,``):e);return n}function eS(e,t){if(!t||t===`/`||Xx.test(e))return e;let n=Qx(t);return e.startsWith(n)?e:$x(n,e)}function tS(e,t){let n=e.match(Xx);return t+(n?e.slice(n[0].length):e)}var nS=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`;function rS(e=21){let t=``,n=e;for(;n--;)t+=nS[Math.random()*64|0];return t}var iS=Symbol.for(`immer-nothing`),aS=Symbol.for(`immer-draftable`),oS=Symbol.for(`immer-state`),sS=[function(e){return`The plugin for '${e}' has not been loaded into Immer. To enable the plugin, import and call \`enable${e}()\` when initializing your application.`},function(e){return`produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${e}'`},`This object has been frozen and should not be mutated`,function(e){return`Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? `+e},`An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.`,`Immer forbids circular references`,"The first or second argument to `produce` must be a function","The third argument to `produce` must be a function or undefined","First argument to `createDraft` must be a plain object, an array, or an immerable object","First argument to `finishDraft` must be a draft returned by `createDraft`",function(e){return`'current' expects a draft, got: ${e}`},`Object.defineProperty() cannot be used on an Immer draft`,`Object.setPrototypeOf() cannot be used on an Immer draft`,`Immer only supports deleting array indices`,`Immer only supports setting array indices and the 'length' property`,function(e){return`'original' expects a draft, got: ${e}`}];function cS(e,...t){{let n=sS[e],r=MS(n)?n.apply(null,t):n;throw Error(`[Immer] ${r}`)}}var lS=Object,uS=lS.getPrototypeOf,dS=`constructor`,fS=`prototype`,pS=`configurable`,mS=`enumerable`,hS=`writable`,gS=`value`,_S=e=>!!e&&!!e[oS];function vS(e){return e?xS(e)||OS(e)||!!e[aS]||!!e[dS]?.[aS]||kS(e)||AS(e):!1}var yS=lS[fS][dS].toString(),bS=new WeakMap;function xS(e){if(!e||!jS(e))return!1;let t=uS(e);if(t===null||t===lS[fS])return!0;let n=lS.hasOwnProperty.call(t,dS)&&t[dS];if(n===Object)return!0;if(!MS(n))return!1;let r=bS.get(n);return r===void 0&&(r=Function.toString.call(n),bS.set(n,r)),r===yS}function SS(e,t,n=!0){CS(e)===0?(n?Reflect.ownKeys(e):lS.keys(e)).forEach(n=>{t(n,e[n],e)}):e.forEach((n,r)=>t(r,n,e))}function CS(e){let t=e[oS];return t?t.type_:OS(e)?1:kS(e)?2:AS(e)?3:0}var wS=(e,t,n=CS(e))=>n===2?e.has(t):lS[fS].hasOwnProperty.call(e,t),TS=(e,t,n=CS(e))=>n===2?e.get(t):e[t],ES=(e,t,n,r=CS(e))=>{r===2?e.set(t,n):r===3?e.add(n):e[t]=n};function DS(e,t){return e===t?e!==0||1/e==1/t:e!==e&&t!==t}var OS=Array.isArray,kS=e=>e instanceof Map,AS=e=>e instanceof Set,jS=e=>typeof e==`object`,MS=e=>typeof e==`function`,NS=e=>typeof e==`boolean`;function PS(e){let t=+e;return Number.isInteger(t)&&String(t)===e}var FS=e=>jS(e)?e?.[oS]:null,IS=e=>e.copy_||e.base_,LS=e=>e.modified_?e.copy_:e.base_;function RS(e,t){if(kS(e))return new Map(e);if(AS(e))return new Set(e);if(OS(e))return Array[fS].slice.call(e);let n=xS(e);if(t===!0||t===`class_only`&&!n){let t=lS.getOwnPropertyDescriptors(e);delete t[oS];let n=Reflect.ownKeys(t);for(let r=0;r1&&lS.defineProperties(e,{set:VS,add:VS,clear:VS,delete:VS}),lS.freeze(e),t&&SS(e,(e,t)=>{zS(t,!0)},!1),e)}function BS(){cS(2)}var VS={[gS]:BS};function HS(e){return e===null||!jS(e)||lS.isFrozen(e)}var US=`MapSet`,WS=`Patches`,GS=`ArrayMethods`,KS={};function qS(e){let t=KS[e];return t||cS(0,e),t}var JS=e=>!!KS[e];function YS(e,t){KS[e]||(KS[e]=t)}var XS,ZS=()=>XS,QS=(e,t)=>({drafts_:[],parent_:e,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0,handledSet_:new Set,processedForPatches_:new Set,mapSetPlugin_:JS(US)?qS(US):void 0,arrayMethodsPlugin_:JS(GS)?qS(GS):void 0});function $S(e,t){t&&(e.patchPlugin_=qS(WS),e.patches_=[],e.inversePatches_=[],e.patchListener_=t)}function eC(e){tC(e),e.drafts_.forEach(rC),e.drafts_=null}function tC(e){e===XS&&(XS=e.parent_)}var nC=e=>XS=QS(XS,e);function rC(e){let t=e[oS];t.type_===0||t.type_===1?t.revoke_():t.revoked_=!0}function iC(e,t){t.unfinalizedDrafts_=t.drafts_.length;let n=t.drafts_[0];if(e!==void 0&&e!==n){n[oS].modified_&&(eC(t),cS(4)),vS(e)&&(e=aC(t,e));let{patchPlugin_:r}=t;r&&r.generateReplacementPatches_(n[oS].base_,e,t)}else e=aC(t,n);return oC(t,e,!0),eC(t),t.patches_&&t.patchListener_(t.patches_,t.inversePatches_),e===iS?void 0:e}function aC(e,t){if(HS(t))return t;let n=t[oS];if(!n)return mC(t,e.handledSet_,e);if(!cC(n,e))return t;if(!n.modified_)return n.base_;if(!n.finalized_){let{callbacks_:t}=n;if(t)for(;t.length>0;)t.pop()(e);fC(n,e)}return n.copy_}function oC(e,t,n=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&zS(t,n)}function sC(e){e.finalized_=!0,e.scope_.unfinalizedDrafts_--}var cC=(e,t)=>e.scope_===t,lC=[];function uC(e,t,n,r){let i=IS(e),a=e.type_;if(r!==void 0&&TS(i,r,a)===t){ES(i,r,n,a);return}if(!e.draftLocations_){let t=e.draftLocations_=new Map;SS(i,(e,n)=>{if(_S(n)){let r=t.get(n)||[];r.push(e),t.set(n,r)}})}let o=e.draftLocations_.get(t)??lC;for(let e of o)ES(i,e,n,a)}function dC(e,t,n){e.callbacks_.push(function(r){let i=t;if(!i||!cC(i,r))return;r.mapSetPlugin_?.fixSetContents(i);let a=LS(i);uC(e,i.draft_??i,a,n),fC(i,r)})}function fC(e,t){if(e.modified_&&!e.finalized_&&(e.type_===3||e.type_===1&&e.allIndicesReassigned_||(e.assigned_?.size??0)>0)){let{patchPlugin_:n}=t;if(n){let r=n.getPath(e);r&&n.generatePatches_(e,r,t)}sC(e)}}function pC(e,t,n){let{scope_:r}=e;if(_S(n)){let i=n[oS];cC(i,r)&&i.callbacks_.push(function(){CC(e),uC(e,n,LS(i),t)})}else vS(n)&&e.callbacks_.push(function(){let i=IS(e);e.type_===3?i.has(n)&&mC(n,r.handledSet_,r):TS(i,t,e.type_)===n&&r.drafts_.length>1&&(e.assigned_.get(t)??!1)===!0&&e.copy_&&mC(TS(e.copy_,t,e.type_),r.handledSet_,r)})}function mC(e,t,n){return!n.immer_.autoFreeze_&&n.unfinalizedDrafts_<1||_S(e)||t.has(e)||!vS(e)||HS(e)?e:(t.add(e),SS(e,(r,i)=>{if(_S(i)){let t=i[oS];cC(t,n)&&(ES(e,r,LS(t),e.type_),sC(t))}else vS(i)&&mC(i,t,n)}),e)}function hC(e,t){let n=OS(e),r={type_:+!!n,scope_:t?t.scope_:ZS(),modified_:!1,finalized_:!1,assigned_:void 0,parent_:t,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1,callbacks_:void 0},i=r,a=gC;n&&(i=[r],a=_C);let{revoke:o,proxy:s}=Proxy.revocable(i,a);return r.draft_=s,r.revoke_=o,[s,r]}var gC={get(e,t){if(t===oS)return e;let n=e.scope_.arrayMethodsPlugin_,r=e.type_===1&&typeof t==`string`;if(r&&n?.isArrayOperationMethod(t))return n.createMethodInterceptor(e,t);let i=IS(e);if(!wS(i,t,e.type_))return bC(e,i,t);let a=i[t];if(e.finalized_||!vS(a)||r&&e.operationMethod&&n?.isMutatingArrayMethod(e.operationMethod)&&PS(t))return a;if(a===vC(e.base_,t)||yC(e,t,a)){CC(e);let n=e.type_===1?+t:t,r=TC(e.scope_,a,e,n);return e.copy_[n]=r}return a},has(e,t){return t in IS(e)},ownKeys(e){return Reflect.ownKeys(IS(e))},set(e,t,n){let r=xC(IS(e),t);if(r?.set)return r.set.call(e.draft_,n),!0;if(!e.modified_){let r=vC(IS(e),t),i=r?.[oS];if(i&&i.base_===n)return e.copy_[t]=n,e.assigned_.delete(t),!0;if(DS(n,r)&&(n!==void 0||wS(e.base_,t,e.type_)))return!0;CC(e),SC(e)}return e.copy_[t]===n&&(n!==void 0||wS(e.copy_,t,e.type_))||Number.isNaN(n)&&Number.isNaN(e.copy_[t])?!0:(e.copy_[t]=n,e.assigned_.set(t,!0),pC(e,t,n),!0)},deleteProperty(e,t){return CC(e),vC(e.base_,t)!==void 0||t in e.base_?(e.assigned_.set(t,!1),SC(e)):e.assigned_.delete(t),e.copy_&&delete e.copy_[t],!0},getOwnPropertyDescriptor(e,t){let n=IS(e),r=Reflect.getOwnPropertyDescriptor(n,t);return r&&{[hS]:!0,[pS]:e.type_!==1||t!==`length`,[mS]:r[mS],[gS]:n[t]}},defineProperty(){cS(11)},getPrototypeOf(e){return uS(e.base_)},setPrototypeOf(){cS(12)}},_C={};for(let e in gC){let t=gC[e];_C[e]=function(){let e=arguments;return e[0]=e[0][0],t.apply(this,e)}}_C.deleteProperty=function(e,t){return isNaN(parseInt(t))&&cS(13),_C.set.call(this,e,t,void 0)},_C.set=function(e,t,n){return t!==`length`&&isNaN(parseInt(t))&&cS(14),gC.set.call(this,e[0],t,n,e[0])};function vC(e,t){let n=e[oS];return(n?IS(n):e)[t]}function yC(e,t,n){return e.type_!==1||!e.allIndicesReassigned_||e.assigned_?.get(t)||!vS(n)||n[oS]?!1:e.baseRefs_.has(n)}function bC(e,t,n){let r=xC(t,n);return r?gS in r?r[gS]:r.get?.call(e.draft_):void 0}function xC(e,t){if(!(t in e))return;let n=uS(e);for(;n;){let e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=uS(n)}}function SC(e){e.modified_||(e.modified_=!0,e.parent_&&SC(e.parent_))}function CC(e){e.copy_||=(e.assigned_=new Map,RS(e.base_,e.scope_.immer_.useStrictShallowCopy_))}var wC=class{constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.useStrictIteration_=!1,this.produce=(e,t,n)=>{if(MS(e)&&!MS(t)){let n=t;t=e;let r=this;return function(e=n,...i){return r.produce(e,e=>t.call(this,e,...i))}}MS(t)||cS(6),n!==void 0&&!MS(n)&&cS(7);let r;if(vS(e)){let i=nC(this),a=TC(i,e,void 0),o=!0;try{r=t(a),o=!1}finally{o?eC(i):tC(i)}return $S(i,n),iC(r,i)}if(!e||!jS(e)){if(r=t(e),r===void 0&&(r=e),r===iS&&(r=void 0),this.autoFreeze_&&zS(r,!0),n){let t=[],i=[];qS(WS).generateReplacementPatches_(e,r,{patches_:t,inversePatches_:i}),n(t,i)}return r}cS(1,e)},this.produceWithPatches=(e,t)=>{if(MS(e))return(t,...n)=>this.produceWithPatches(t,t=>e(t,...n));let n,r;return[this.produce(e,t,(e,t)=>{n=e,r=t}),n,r]},NS(e?.autoFreeze)&&this.setAutoFreeze(e.autoFreeze),NS(e?.useStrictShallowCopy)&&this.setUseStrictShallowCopy(e.useStrictShallowCopy),NS(e?.useStrictIteration)&&this.setUseStrictIteration(e.useStrictIteration)}createDraft(e){vS(e)||cS(8),_S(e)&&(e=EC(e));let t=nC(this),n=TC(t,e,void 0);return n[oS].isManual_=!0,tC(t),n}finishDraft(e,t){let n=e&&e[oS];(!n||!n.isManual_)&&cS(9);let{scope_:r}=n;return $S(r,t),iC(void 0,r)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}setUseStrictIteration(e){this.useStrictIteration_=e}shouldUseStrictIteration(){return this.useStrictIteration_}applyPatches(e,t){let n;for(n=t.length-1;n>=0;n--){let r=t[n];if(r.path.length===0&&r.op===`replace`){e=r.value;break}}n>-1&&(t=t.slice(n+1));let r=qS(WS).applyPatches_;return _S(e)?r(e,t):this.produce(e,e=>r(e,t))}};function TC(e,t,n,r){let[i,a]=kS(t)?qS(US).proxyMap_(t,n):AS(t)?qS(US).proxySet_(t,n):hC(t,n);return(n?.scope_??ZS()).drafts_.push(i),a.callbacks_=n?.callbacks_??[],a.key_=r,n&&r!==void 0?dC(n,a,r):a.callbacks_.push(function(e){e.mapSetPlugin_?.fixSetContents(a);let{patchPlugin_:t}=e;a.modified_&&t&&t.generatePatches_(a,[],e)}),i}function EC(e){return _S(e)||cS(10,e),DC(e)}function DC(e){if(!vS(e)||HS(e))return e;let t=e[oS],n,r=!0;if(t){if(!t.modified_)return t.base_;t.finalized_=!0,n=RS(e,t.scope_.immer_.useStrictShallowCopy_),r=t.scope_.immer_.shouldUseStrictIteration()}else n=RS(e,!0);return SS(n,(e,t)=>{ES(n,e,DC(t))},r),t&&(t.finalized_=!1),n}function OC(){sS.push(`Sets cannot have "replace" patches.`,function(e){return`Unsupported patch operation: `+e},function(e){return`Cannot apply patch, path doesn't resolve: `+e},`Patching reserved attributes like __proto__, prototype and constructor is not allowed`);function e(n,r=[]){if(n.key_!==void 0){let e=n.parent_.copy_??n.parent_.base_,t=FS(TS(e,n.key_)),i=TS(e,n.key_);if(i===void 0||i!==n.draft_&&i!==n.base_&&i!==n.copy_||t!=null&&t.base_!==n.base_)return null;let a=n.parent_.type_===3,o;if(a){let e=n.parent_;o=Array.from(e.drafts_.keys()).indexOf(n.key_)}else o=n.key_;if(!(a&&e.size>o||wS(e,o)))return null;r.push(o)}if(n.parent_)return e(n.parent_,r);r.reverse();try{t(n.copy_,r)}catch{return null}return r}function t(e,t){let n=e;for(let e=0;e{let u=TS(o,e,c),f=TS(s,e,c),p=l?wS(o,e)?n:`add`:r;if(u===f&&p===n)return;let m=t.concat(e);i.push(p===r?{op:p,path:m}:{op:p,path:m,value:d(f)}),a.push(p===`add`?{op:r,path:m}:p===r?{op:`add`,path:m,value:d(u)}:{op:n,path:m,value:d(u)})})}function s(e,t,n,i){let{base_:a,copy_:o}=e,s=0;a.forEach(e=>{if(!o.has(e)){let a=t.concat([s]);n.push({op:r,path:a,value:e}),i.unshift({op:`add`,path:a,value:e})}s++}),s=0,o.forEach(e=>{if(!a.has(e)){let a=t.concat([s]);n.push({op:`add`,path:a,value:e}),i.unshift({op:r,path:a,value:e})}s++})}function c(e,t,r){let{patches_:i,inversePatches_:a}=r;i.push({op:n,path:[],value:t===iS?void 0:t}),a.push({op:n,path:[],value:e})}function l(e,t){return t.forEach(t=>{let{path:i,op:a}=t,o=e;for(let e=0;e[e,u(t)]));if(AS(e))return new Set(Array.from(e).map(u));let t=Object.create(uS(e));for(let n in e)t[n]=u(e[n]);return wS(e,aS)&&(t[aS]=e[aS]),t}function d(e){return _S(e)?u(e):e}YS(WS,{applyPatches_:l,generatePatches_:i,generateReplacementPatches_:c,getPath:e})}globalThis.Iterator?.from;var kC=new wC,AC=kC.produce,jC=kC.produceWithPatches.bind(kC),MC=kC.applyPatches.bind(kC),NC=1e3;function PC(e,t){if(e.add(t),e.size>NC){let t=e.values().next().value;t!==void 0&&e.delete(t)}}function FC(e){let{enablePatches:t=!1}=e;t&&OC();let n=Yx(),r=e.initialValue,i=new Set;return{on:n.on,value:()=>r,patch:(e,t=rS())=>{i.has(t)||(OC(),r=MC(r,e),PC(i,t),n.emit(`updated`,r,void 0,t))},mutate:(e,a=rS())=>{if(!i.has(a)){if(PC(i,a),t){let[t,i]=jC(r,e);if(t===r)return;r=t,n.emit(`updated`,r,i,a)}else{let t=AC(r,e);if(t===r)return;r=t,n.emit(`updated`,r,void 0,a)}}},syncIds:i}}var IC=typeof self==`object`?self:globalThis,LC=new Set([`Error`,`EvalError`,`RangeError`,`ReferenceError`,`SyntaxError`,`TypeError`,`URIError`,`AggregateError`]),RC=new Set([`Boolean`,`Number`,`String`,`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float16Array`,`Float32Array`,`Float64Array`,`BigInt64Array`,`BigUint64Array`]);function zC(e,t){let n=(t,n)=>(e.set(n,t),t),r=i=>{if(e.has(i))return e.get(i);let[a,o]=t[i];switch(a){case 0:case-1:return n(o,i);case 1:{let e=n([],i);for(let t of o)e.push(r(t));return e}case 2:{let e=n({},i);for(let[t,n]of o)e[r(t)]=r(n);return e}case 3:return n(new Date(o),i);case 4:{let{source:e,flags:t}=o;return n(new RegExp(e,t),i)}case 5:{let e=n(new Map,i);for(let[t,n]of o)e.set(r(t),r(n));return e}case 6:{let e=n(new Set,i);for(let t of o)e.add(r(t));return e}case 7:{let{name:e,message:t}=o,r=LC.has(e)?IC[e]:void 0;return n(new(r??IC.Error)(t),i)}case 8:return n(BigInt(o),i);case`BigInt`:return n(Object(BigInt(o)),i);case`ArrayBuffer`:return n(new Uint8Array(o).buffer,o);case`DataView`:{let{buffer:e}=new Uint8Array(o);return n(new DataView(e),o)}}if(typeof a==`string`&&RC.has(a))return n(new IC[a](o),i);throw TypeError(`unable to deserialize unsafe or unknown type: ${String(a)}`)};return r}function BC(e){return zC(new Map,e)(0)}var VC=``,{toString:HC}={},{keys:UC}=Object;function WC(e){let t=typeof e;if(t!==`object`||!e)return[0,t];let n=HC.call(e).slice(8,-1);switch(n){case`Array`:return[1,VC];case`Object`:return[2,VC];case`Date`:return[3,VC];case`RegExp`:return[4,VC];case`Map`:return[5,VC];case`Set`:return[6,VC];case`DataView`:return[1,n]}return n.includes(`Array`)?[1,n]:n.includes(`Error`)?[7,n]:[2,n]}function GC([e,t]){return e===0&&(t===`function`||t===`symbol`)}function KC(e,t,n,r){let i=(e,t)=>{let i=r.push(e)-1;return n.set(t,i),i},a=r=>{if(n.has(r))return n.get(r);let[o,s]=WC(r);switch(o){case 0:{let t=r;switch(s){case`bigint`:o=8,t=r.toString();break;case`function`:case`symbol`:if(e)throw TypeError(`unable to serialize ${s}`);t=null;break;case`undefined`:return i([-1],r)}return i([o,t],r)}case 1:{if(s){let e=r;return s===`DataView`?e=new Uint8Array(r.buffer):s===`ArrayBuffer`&&(e=new Uint8Array(r)),i([s,[...e]],r)}let e=[],t=i([o,e],r);for(let t of r)e.push(a(t));return t}case 2:{if(s)switch(s){case`BigInt`:return i([s,r.toString()],r);case`Boolean`:case`Number`:case`String`:return i([s,r.valueOf()],r)}if(t&&`toJSON`in r)return a(r.toJSON());let n=[],c=i([o,n],r);for(let t of UC(r))(e||!GC(WC(r[t])))&&n.push([a(t),a(r[t])]);return c}case 3:return i([o,r.toISOString()],r);case 4:{let{source:e,flags:t}=r;return i([o,{source:e,flags:t}],r)}case 5:{let t=[],n=i([o,t],r);for(let[n,i]of r)(e||!(GC(WC(n))||GC(WC(i))))&&t.push([a(n),a(i)]);return n}case 6:{let t=[],n=i([o,t],r);for(let n of r)(e||!GC(WC(n)))&&t.push(a(n));return n}}let{message:c}=r;return i([o,{name:s,message:c}],r)};return a}function qC(e,t={}){let n=[];return KC(!(t.json||t.lossy),!!t.json,new Map,n)(e),n}var{parse:JC,stringify:YC}=JSON,XC={json:!0,lossy:!0};function ZC(e){return BC(JC(e))}function QC(e){return YC(qC(e,XC))}function $C(e){return BC(e)}function ew(e){return QC(e)}function tw(e){return ZC(e)}var nw=256,rw=class extends Error{name=`StreamClosedError`};function iw(e={}){let t=e.id??rS(),n=Math.max(0,e.replayWindow??0),r=Yx(),i=new AbortController,a=[],o=!1,s=0;function c(e){if(o)throw new rw(`Cannot write to a closed stream "${t}"`);s+=1,n>0&&(a.push({seq:s,chunk:e}),a.length>n&&(a.length-n===1?a.shift():a.splice(0,a.length-n))),r.emit(`chunk`,s,e)}function l(e){if(o)return;o=!0;let t=ow(e);i.abort(e),r.emit(`end`,t)}function u(){o||(o=!0,i.signal.aborted||i.abort(`stream closed`),r.emit(`end`,void 0))}function d(e){o||i.signal.aborted||i.abort(e??`aborted`)}let f=new WritableStream({write(e){c(e)},close(){u()},abort(e){l(e)}});return{id:t,signal:i.signal,get closed(){return o},get lastSeq(){return s},write:c,error:l,close:u,abort:d,writable:f,events:r,buffer:a}}function aw(e={}){let t=e.id??rS(),n=Math.max(1,e.highWaterMark??nw),r=[],i=0,a=!1,o=!1,s,c,l,u;function d(){if(c){if(r.length>0){let e=r.shift(),t=c;c=void 0,t.resolve({value:e,done:!1});return}if(a){let e=c;if(c=void 0,s){let t=Error(s.message);t.name=s.name,e.reject(t)}else e.resolve({value:void 0,done:!0})}}}function f(){if(l){for(;r.length>0;){let e=r.shift();try{l.enqueue(e)}catch{break}}if(a&&l){try{if(s){let e=Error(s.message);e.name=s.name,l.error(e)}else l.close()}catch{}l=void 0}}}function p(t,s){if(!(a||o)&&!(t<=i)){if(i=t,r.push(s),r.length>n){let t=r.length-n;r.splice(0,t),e.onOverflow?.(t)}d(),u&&f()}}function m(e){a||(a=!0,s=e,d(),u&&f())}function h(){o||a||(o=!0,e.onCancel?.(),m(void 0))}function g(){return u||(u=new ReadableStream({start(e){l=e,f()},cancel(){h()}}),u)}return{id:t,get cancelled(){return o},get done(){return a},get lastSeenSeq(){return i},get readable(){return g()},cancel:h,_push:p,_end:m,[Symbol.asyncIterator](){return{next(){if(r.length>0)return Promise.resolve({value:r.shift(),done:!1});if(a){if(s){let e=Error(s.message);return e.name=s.name,Promise.reject(e)}return Promise.resolve({value:void 0,done:!0})}return new Promise((e,t)=>{c={resolve:e,reject:t}})},return(){return h(),Promise.resolve({value:void 0,done:!0})}}}}}function ow(e){if(e instanceof Error)return{name:e.name||`Error`,message:e.message};if(typeof e==`string`)return{name:`Error`,message:e};try{return{name:`Error`,message:JSON.stringify(e)}}catch{return{name:`Error`,message:String(e)}}}var sw=128;function cw(e){return e.replace(/[^\w-]+/g,`_`).slice(0,sw)}var lw=`modulepreload`,uw=function(e,t){return new URL(e,t).href},dw={},fw=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=uw(t,n),t=s(t),t in dw)return;dw[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:lw,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},pw=`__connection.json`,mw=`__DEVFRAME_CONNECTION__`,hw=`x-birpc-session`,gw=`__rpc-dump/index.json`,_w=`devframe:services`,vw=`devframe_otp`,yw=`devframe_auth_token`;hx.postMessage.remoteAssetsError;var bw=class{cacheMap=new Map;options;keySerializer;constructor(e){this.options=e,this.keySerializer=e.keySerializer||(e=>Jx(e))}updateOptions(e){this.options={...this.options,...e}}cached(e,t){let n=this.cacheMap.get(e);if(n)return n.get(this.keySerializer(t))}has(e,t){return this.cacheMap.get(e)?.has(this.keySerializer(t))??!1}apply(e,t){let n=this.cacheMap.get(e.m)||new Map;n.set(this.keySerializer(e.a),t),this.cacheMap.set(e.m,n)}validate(e){return this.options.functions.includes(e)}clear(e){e?this.cacheMap.delete(e):this.cacheMap.clear()}},xw=vx({docsBase:`https://devfra.me/errors`,codes:{DF0019:{why:e=>`RPC function "${e.name}" has \`agent\` set but \`jsonSerializable\` is \`false\`; MCP requires JSON-serializable data.`,fix:"Remove `jsonSerializable: false`, or remove `agent` to keep it RPC-only."},DF0020:{why:e=>`RPC function "${e.name}" declares \`jsonSerializable: true\` but the value at "${e.path}" is a ${e.type}.`,fix:"Either drop `jsonSerializable: true` (falls back to structured-clone) or change the value to a JSON-safe shape."},DF0021:{why:e=>`RPC function "${e.name}" is already registered`,fix:"Use the `force` parameter to overwrite an existing registration."},DF0022:{why:e=>`RPC function "${e.name}" is not registered. Use register() to add new functions.`},DF0023:{why:e=>`RPC function "${e.name}" is not registered`},DF0024:{why:e=>`Either handler or setup function must be provided for RPC function "${e.name}"`},DF0025:{why:e=>`Function "${e.name}" not found in dump store`},DF0026:{why:e=>`No dump match for "${e.name}" with args: ${e.args}`},DF0027:{why:e=>`Function "${e.name}" with type "${e.type}" cannot have dump configuration. Only "static" and "query" types support dumps.`},DF0028:{why:e=>`Function "${e.name}" with type "${e.type}" cannot use \`snapshot: true\`. Only "query" functions support this sugar; "static" functions have equivalent default behavior already.`,fix:"Remove `snapshot: true`, or change the function type to `query`."},DF0043:{why:e=>`RPC function "${e.name}" received an invalid argument at position ${e.index}: ${e.issues}`,fix:"Pass a value that satisfies the `args` schema declared for this function."},DF0044:{why:e=>`RPC function "${e.name}" returned a value that failed its \`returns\` schema: ${e.issues}`,fix:"Make the handler return a value that satisfies the `returns` schema, or relax the schema."}}});function Sw(e){if(e.agent&&e.jsonSerializable===!1)throw xw.DF0019({name:e.name});e.agent&&!e.jsonSerializable&&(e.jsonSerializable=!0)}async function Cw(e,t){let n=e[`~standard`].validate(t);return n instanceof Promise?await n:n}function ww(e){return e.map(e=>{let t=e.path?.map(e=>typeof e==`object`?e.key:e).join(`.`);return t?`${t}: ${e.message}`:e.message}).join(`; `)}async function Tw(e,t,n){let r=n.slice();if(!t||t.length===0)return r;for(let r=0;r{n.get(t)===r&&n.delete(t)}),n.set(t,r)),await r}if(!e.__promise){let n=Promise.resolve(e.setup(t));n.catch(()=>{e.__promise===n&&(e.__promise=void 0)}),e.__promise=n}return await e.__promise}async function Ow(e,t){let n=e.handler;if(!n){let r=await Dw(e,t);if(!r.handler)throw xw.DF0024({name:e.name});n=r.handler}let r=e.args,i=e.returns;if(!r&&!i)return n;let a=n;return async(...t)=>{let n=await Tw(e.name,r,t),o=await a(...n);return await Ew(e.name,i,o)}}var kw=class{context;definitions=new Map;functions;_onChanged=[];constructor(e){this.context=e;let t=this.definitions,n=this;this.functions=new Proxy({},{get(e,r){let i=t.get(r);if(i)return Ow(i,n.context)},has(e,n){return t.has(n)},getOwnPropertyDescriptor(e,n){return{value:t.get(n)?.handler,configurable:!0,enumerable:!0}},ownKeys(){return Array.from(t.keys())}})}register(e,t=!1){if(this.definitions.has(e.name)&&!t)throw xw.DF0021({name:e.name});Sw(e),this.definitions.set(e.name,e),this._onChanged.forEach(t=>t(e.name))}update(e,t=!1){if(!this.definitions.has(e.name)&&!t)throw xw.DF0022({name:e.name});Sw(e),this.definitions.set(e.name,e),this._onChanged.forEach(t=>t(e.name))}onChanged(e){return this._onChanged.push(e),()=>{let t=this._onChanged.indexOf(e);t!==-1&&this._onChanged.splice(t,1)}}async getHandler(e){return await Ow(this.definitions.get(e),this.context)}getSchema(e){let t=this.definitions.get(e);if(!t)throw xw.DF0023({name:String(e)});return{args:t.args,returns:t.returns}}has(e){return this.definitions.has(e)}get(e){return this.definitions.get(e)}list(){return Array.from(this.definitions.keys())}};function Aw(e,t=``){return JSON.stringify(e,function(e,n){let r=this,i=r==null?n:r[e];if(i===void 0){if(Array.isArray(r))throw Mw(t,`undefined`,r,e);return n}return i!==null&&jw(i,r,e,t),n})}function jw(e,t,n,r){if(typeof e==`bigint`)throw Mw(r,`BigInt`,t,n);if(typeof e!=`object`)return;if(e instanceof Map)throw Mw(r,`Map`,t,n);if(e instanceof Set)throw Mw(r,`Set`,t,n);if(e instanceof Date)throw Mw(r,`Date`,t,n);if(Array.isArray(e))return;let i=Object.getPrototypeOf(e);if(i!==null&&i!==Object.prototype)throw Mw(r,e.constructor?.name??`class instance`,t,n)}function Mw(e,t,n,r){let i=Nw(n,r);return xw.DF0020({name:e||``,type:t,path:i})}function Nw(e,t){return Array.isArray(e)?`[${t}]`:t===``?``:t}var Pw=`__DEVFRAME_CONNECTION_META__`,Fw=`__DEVFRAME_CONNECTION_AUTH_TOKEN__`;function Iw(e){let t=[()=>window?.[e],()=>globalThis?.[e],()=>parent.window?.[e]];for(let e of t)try{let t=e();if(t)return t}catch{}}function Lw(){return Iw(mw)}function Rw(){return Iw(Pw)}function zw(e){if(e)return e;try{let e=localStorage.getItem(Fw);if(e)return e}catch{}return Iw(Fw)}function Bw(e){globalThis[mw]=e,globalThis[Pw]={...e.connectionMeta,baseUrl:e.metaBaseUrl},e.authToken&&Vw(e.authToken)}function Vw(e){try{localStorage.setItem(Fw,e)}catch{}globalThis[Fw]=e;let t=Lw();t&&(globalThis[mw]={...t,authToken:e})}function Hw(e){let t=eS(pw,e);try{return new URL(t,globalThis.location?.href).href}catch{return t}}function Uw(e,t){return t&&t!==e.authToken?{...e,authToken:t}:e}function Ww(){let e=Lw();if(e)return Uw(e,zw()??e.authToken??e.connectionMeta.authToken);let t=Rw();if(t)return{connectionMeta:t,metaBaseUrl:t.baseUrl??Hw(`./`),authToken:zw(t.authToken)}}async function Gw(e={}){if(e.connection){let t=Uw(e.connection,zw(e.authToken??e.connection.authToken??e.connection.connectionMeta.authToken));return Bw(t),t}let t=Array.isArray(e.baseURL)?e.baseURL:[e.baseURL??`./`];if(e.connectionMeta){let n={connectionMeta:e.connectionMeta,metaBaseUrl:Hw(t[0]??`./`),authToken:zw(e.authToken??e.connectionMeta.authToken)};return Bw(n),n}let n=Ww();if(n){let t=Uw(n,zw(e.authToken??n.authToken??n.connectionMeta.authToken));return Bw(t),t}let r=[];for(let n of t){let t=eS(pw,n),i=Hw(n);try{let n=await fetch(t);if(!n.ok)throw Error(`Failed to fetch connection meta from ${i}: ${n.status}`);let r=await n.json(),a=n.url||i,o={connectionMeta:r,metaBaseUrl:r.baseUrl?new URL(r.baseUrl,a).href:a,authToken:zw(e.authToken??r.authToken)};return Bw(o),o}catch(e){r.push(e)}}throw Error(`Failed to get connection meta from ${t.join(`, `)}`,{cause:r})}var Kw=class extends Error{name=`DevframeConnectionError`;kind;constructor(e,t,n){super(t,n),this.kind=e}};function qw(e=vw){try{let t=globalThis.location?.hash?.replace(/^#/,``)??``;return new URLSearchParams(t).get(e)||void 0}catch{return}}function Jw(e){try{let t=new URL(globalThis.location.href),n=new URLSearchParams(t.hash.replace(/^#/,``));if(!n.has(e))return;n.delete(e),t.hash=n.toString(),globalThis.history?.replaceState(globalThis.history.state,``,t.href)}catch{}}function Yw(e=vw){let t=qw(e);return t&&Jw(e),t}async function Xw(e,t={}){let n=Yw(t.param??`devframe_otp`);return n?e.isTrusted?!0:e.requestTrustWithCode(n):!1}function Zw(e){let t={},n=new WeakMap,r,i=()=>(r??=e.sharedState.get(_w,{initialValue:{}}).then(e=>(t=e.value(),e.on(`updated`,e=>{t=e}),e)),r);return i(),{state:i,has:e=>e in t,keys:()=>Object.keys(t),get:r=>{let i=t[r];if(!i)return;let a=n.get(i);return a||(a={...i,rpc:e.scope(i.scope).rpc},n.set(i,a)),a}}}function Qw(e){let t=new Map,n=new Map,r=new Map,i=new Set,a=e.connectionMeta.backend===`static`;function o(e,t){let n=r.get(e);return n&&typeof n==`object`&&!Array.isArray(n)&&typeof t==`object`&&!Array.isArray(t)?{...n,...t}:t}e.client.register({name:hx.broadcast.clientStateUpdated,type:`event`,handler:(e,n,r)=>{let i=t.get(e);i&&!i.syncIds.has(r)&&i.mutate(()=>o(e,n),r)}}),e.client.register({name:hx.broadcast.clientStatePatch,type:`event`,handler:(e,n,r)=>{let i=t.get(e);i&&!i.syncIds.has(r)&&i.patch(n,r)}});function s(t,n){let r=[];return r.push(n.on(`updated`,(n,r,i)=>{a||(r?e.callEvent(`devframe:rpc:server-state:patch`,t,r,i):e.callEvent(`devframe:rpc:server-state:set`,t,n,i))})),()=>{for(let e of r)e()}}return{keys:()=>Array.from(t.keys()),onKeyAdded(e){return i.add(e),()=>{i.delete(e)}},delete(e){let i=n.get(e);n.delete(e);let a=t.delete(e);return r.delete(e),i?.(),a},get:async(c,l)=>{if(l?.initialValue!==void 0&&r.set(c,l.initialValue),t.has(c))return t.get(c);let u=FC({initialValue:l?.initialValue,enablePatches:!1});async function d(){if(a||e.callEvent(`devframe:rpc:server-state:subscribe`,c),l?.initialValue!==void 0){t.set(c,u);for(let e of i)e(c);return e.call(`devframe:rpc:server-state:get`,c).then(e=>{e!==void 0&&u.mutate(()=>o(c,e))}).catch(e=>{console.error(`Error getting server state`,e)}),n.set(c,s(c,u)),u}{let r=await e.call(`devframe:rpc:server-state:get`,c);u.mutate(()=>o(c,r)),t.set(c,u);for(let e of i)e(c);return n.set(c,s(c,u)),u}}return new Promise(t=>{if(e.isTrusted)d().then(t);else{t(u);let n=!1;e.events.on(hx.client.isTrustedUpdated,e=>{e&&!n&&(n=!0,d())})}})}}}var $w=new Map;function eT(e=$w){let t=new Map;return{serialize:n=>{let r;return n.t===`q`?r=n.m:(r=t.get(n.i),t.delete(n.i)),!(n.t===`s`&&`e`in n)&&r&&e.get(r)?.jsonSerializable===!0?Aw(n,r??``):`s:${ew(n)}`},deserialize:e=>{let n=e.startsWith(`s:`)?tw(e.slice(2)):JSON.parse(e);return n.t===`q`&&n.i&&n.m&&t.set(n.i,n.m),n}}}function tT(){}function nT(e){let t=e.search(/\n\n|\r\n\r\n/);if(!(t<0))return{frame:e.slice(0,t),rest:e.slice(t+(e[t]===`\r`?4:2))}}function rT(e){let t=`message`,n=[];for(let r of e.split(/\r?\n/))r.startsWith(`:`)||(r.startsWith(`event:`)?t=r.slice(6).trimStart():r.startsWith(`data:`)&&n.push(r.slice(5).replace(/^ /,``)));return{event:t,data:n}}function iT(e){let{onConnected:t=tT,onError:n=tT,onDisconnected:r=tT,definitions:i,fetch:a=globalThis.fetch.bind(globalThis)}=e,o=e.url;e.authToken&&(o=`${o}${o.includes(`?`)?`&`:`?`}${yw}=${encodeURIComponent(e.authToken)}`);let s=eT(i),c=new AbortController,l=!1,u,d,f,p,m=new Promise((e,t)=>{f=e,p=t});m.catch(()=>{});function h(e){l||(l=!0,p(e),n(e),r())}function g(){l||(l=!0,p(Error(`Devframe SSE stream closed`)),r())}function _(e,n){if(e===`session`){f(n),t();return}u?.(n)}async function ee(e){let t=e.getReader();d=t;let n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;for(r+=n.decode(i,{stream:!0});;){let e=nT(r);if(!e)break;r=e.rest;let{event:t,data:n}=rT(e.frame);n.length>0&&_(t,n.join(` -`))}}g()}return(async()=>{try{let e=await a(o,{headers:{accept:`text/event-stream`},signal:c.signal});if(!e.ok||!e.body)throw Error(`Devframe SSE stream request failed: ${e.status}`);await ee(e.body)}catch(e){if(c.signal.aborted){g();return}h(e instanceof Error?e:Error(String(e)))}})(),{close:()=>{l=!0,c.abort(),d?.cancel().catch(()=>{})},on:e=>{u=e},post:async e=>{let t;try{t=await m}catch{return}if(l){n(Error(`Devframe SSE channel is closed; message dropped`));return}try{let n=await a(o,{method:`POST`,headers:{"content-type":`text/plain; charset=utf-8`,[hw]:t},body:e});if(n.status===200){let e=await n.text();e&&u?.(e);return}if(!n.ok)throw Error(`Devframe SSE POST failed: ${n.status}`)}catch(e){n(e instanceof Error?e:Error(String(e)))}},serialize:s.serialize,deserialize:s.deserialize}}function aT(e,t){let{channel:n,rpcOptions:r={}}=t;return Ox(e,{...n,timeout:-1,...r,proxify:!1})}function oT(e){let{transport:t,authToken:n,connectionMeta:r,events:i,clientRpc:a,rpcOptions:o={},callTimeout:s=0}=e,c=!1,l=`connecting`,u=null,d=Promise.withResolvers();function f(e,t=null){if(t?u=t:e===`connected`&&(u=null),e===l)return;let n=l;l=e,i.emit(hx.client.connectionStatus,e,n)}let p=new Set;function m(e){for(let t of[...p])t.reject(e)}function h(){return l===`disconnected`||l===`error`?new Kw(`connection`,`[devframe] Not connected to the devframe server`,{cause:u??void 0}):l===`unauthorized`?new Kw(`auth`,`[devframe] Not authorized by the devframe server`,{cause:u??void 0}):null}function g(e,t){return new Promise((n,r)=>{let a=!1,o,c={reject(e){a||(l(),i.emit(hx.client.error,e,t),r(e))}};function l(){a=!0,p.delete(c),o&&clearTimeout(o)}p.add(c),s>0&&(o=setTimeout(()=>{c.reject(new Kw(`timeout`,`[devframe] RPC call "${t}" timed out after ${s}ms`))},s)),e.then(e=>{a||(l(),n(e))},e=>{if(a)return;l();let n=e instanceof Error?e:Error(String(e));i.emit(hx.client.error,n,t),r(n)})})}let _=new Map;for(let e of r.jsonSerializableMethods??[])_.set(e,{jsonSerializable:!0});let ee=e.createChannel({definitions:_,onError(e){f(`error`,e),i.emit(hx.client.connectionError,e),m(new Kw(`connection`,`[devframe] Connection to the devframe server failed`,{cause:e}))},onDisconnected(){l!==`error`&&f(`disconnected`),m(new Kw(`connection`,`[devframe] Disconnected from the devframe server`,{cause:u??void 0}))}}),te=aT(a.functions,{channel:ee,rpcOptions:o});a.register({name:hx.broadcast.authRevoked,type:`event`,handler:()=>{c=!1;let e=new Kw(`auth`,`[devframe] The devframe server revoked this client's trust`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e),m(e),i.emit(hx.client.isTrustedUpdated,!1)}});let ne=n;async function re(e){ne=e;let t=await te.$call(`anonymous:devframe:auth`,{authToken:e,ua:navigator.userAgent,origin:location.origin});if(c=t.isTrusted,c)d.resolve(!0),f(`connected`);else{let e=new Kw(`auth`,`[devframe] The devframe server refused this client's credentials`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e)}return i.emit(hx.client.isTrustedUpdated,c),t.isTrusted}async function ie(e){let t=(await te.$call(`anonymous:devframe:auth:exchange`,{code:e,ua:navigator.userAgent,origin:location.origin}))?.authToken??null;return t&&(ne=t,c=!0,d.resolve(!0),f(`connected`),i.emit(hx.client.isTrustedUpdated,!0)),t}async function ae(e={}){await te.$call(`anonymous:devframe:auth:request-code`,{ua:navigator.userAgent,origin:location.origin,...e.reissue?{reissue:!0}:{}})}async function oe(){return c?!0:re(ne??``)}async function se(e=6e4){if(c&&d.resolve(!0),e<=0)return d.promise;let t;try{return await Promise.race([d.promise,new Promise((n,r)=>{t=setTimeout(()=>{r(Error(`[devframe] Timeout waiting for rpc to be trusted`))},e)})]),c}finally{clearTimeout(t)}}return{transport:t,get isTrusted(){return c},get status(){return l},get connectionError(){return u},requestTrust:oe,requestTrustWithToken:re,requestTrustWithCode:ie,requestAuthCode:ae,ensureTrusted:se,call:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$call(...e),t)},callEvent:(...e)=>{let t=h();if(t){i.emit(hx.client.error,t,String(e[0]));return}return te.$callEvent(...e)},callOptional:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$callOptional(...e),t)},close:()=>{ee.close()}}}function sT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})();if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`;return new URL(e.path??`/`,`${r.protocol}//${t}`).href}return new URL(e.path??``,r).href}let i=e??``;return/^https?:\/\//i.test(i)?i:new URL(i,r).href}function cT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},sseOptions:s={},callTimeout:c=0}=e,l=sT(n.sse,r??`./`,location);return oT({transport:`sse`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>iT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(){s.onConnected?.()},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(){e.onDisconnected(),s.onDisconnected?.()}})})}function lT(e){let{name:t,message:n,cause:r,...i}=e,a=r instanceof Error?r:uT(r)?lT(r):r,o=a===void 0?Error(n):Error(n,{cause:a});return o.name=t,Object.assign(o,i),o}function uT(e){return typeof e==`object`&&!!e&&typeof e.message==`string`&&typeof e.name==`string`}function dT(e){return typeof e==`object`&&!!e&&e.type===`static`&&typeof e.path==`string`}function fT(e){return typeof e==`object`&&!!e&&e.type===`query`&&typeof e.records==`object`&&e.records!==null}function pT(e){return typeof e==`object`&&!!e&&(`output`in e||`error`in e)}function mT(e){if(e.error)throw lT(e.error);return e.output}function hT(e){return e.some(e=>e!=null)}function gT(e){return typeof e==`object`&&e&&`serialization`in e&&`data`in e?e.data:e}function _T(e,t){let n=new Map,r=new Map;function i(e,t){return t===`structured-clone`&&Array.isArray(e)?$C(e):e}function a(e,t){return i(gT(e),t)}async function o(e){n.has(e.path)||n.set(e.path,t(e.path).then(t=>a(t,e.serialization)));let r=await n.get(e.path);return pT(r)?mT(r):r}async function s(e,n){return r.has(e)||r.set(e,t(e).then(e=>a(e,n))),await r.get(e)}async function c(t,n){if(!(t in e))throw Error(`[devframe-rpc] Function "${t}" not found in dump store`);let r=e[t];if(dT(r)){if(hT(n))throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`);return await o(r)}if(fT(r)){let e=Jx(n),i=r.records[e];if(i)return mT(await s(i,r.serialization));if(r.fallback)return mT(await s(r.fallback,r.serialization));throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}if(!hT(n))return r;throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}return{call:async(e,t)=>await c(e,t),callOptional:async(t,n)=>{if(t in e)return await c(t,n)},callEvent:async(e,t)=>{}}}async function vT(e){let t=_T(await e.fetchJsonFromBases(gw),e.fetchJsonFromBases);return{transport:`static`,isTrusted:!0,status:`connected`,connectionError:null,requestTrust:async()=>!0,requestTrustWithToken:async()=>!0,requestTrustWithCode:async()=>null,requestAuthCode:async()=>{},ensureTrusted:async()=>!0,call:(...e)=>t.call(e[0],e.slice(1)),callEvent:(...e)=>t.callEvent(e[0],e.slice(1)),callOptional:(...e)=>t.callOptional(e[0],e.slice(1)),close:()=>{}}}var yT=``;function bT(e,t){return`${e}${yT}${t}`}function xT(e){let t=new Map,n=new Map;e.client.register({name:hx.broadcast.streamingChunk,type:`event`,handler(e,n,r,i){t.get(bT(e,n))?._push(r,i)}}),e.client.register({name:hx.broadcast.streamingEnd,type:`event`,handler(e,n,r){let i=bT(e,n),a=t.get(i);a&&(a._end(r),t.delete(i))}}),e.client.register({name:hx.broadcast.streamingUploadCancel,type:`event`,handler(e,t){let r=bT(e,t),i=n.get(r);i&&(i.abort(`server cancelled upload`),n.delete(r))}}),e.events.on(hx.client.isTrustedUpdated,n=>{if(n)for(let[n,r]of t){if(r.cancelled||r.done)continue;let t=n.indexOf(yT);if(t<0)continue;let i=n.slice(0,t),a=n.slice(t+1);e.callEvent(`devframe:streaming:subscribe`,i,a,{afterSeq:r.lastSeenSeq})}});function r(n,r,i={}){let a=bT(n,r),o=t.get(a);if(o)return o;let s=aw({id:r,highWaterMark:i.highWaterMark,onOverflow(e){console.warn(`[devframe] DF0029: Stream "${n}#${r}" dropped ${e} chunk(s) after exceeding the client high-water mark.`)},onCancel(){e.callEvent(`devframe:streaming:cancel`,n,r),t.delete(a)}});if(t.set(a,s),e.isTrusted)e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:0});else{let i=e.events.on(hx.client.isTrustedUpdated,o=>{o&&(i(),t.has(a)&&!s.cancelled&&!s.done&&e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:s.lastSeenSeq}))})}return s}function i(t,r){let i=bT(t,r),a=n.get(i);if(a)return a;let o=iw({id:r});return o.events.on(`chunk`,(n,i)=>{e.callEvent(`devframe:streaming:upload-chunk`,t,r,n,i)}),o.events.on(`end`,a=>{e.callEvent(`devframe:streaming:upload-end`,t,r,a),n.delete(i)}),n.set(i,o),o}return{subscribe:r,upload:i}}function ST(){}var CT=new Map;function wT(e){let t=e.url;e.authToken&&(t=`${t}?${yw}=${encodeURIComponent(e.authToken)}`);let n=new WebSocket(t),{onConnected:r=ST,onError:i=ST,onDisconnected:a=ST,definitions:o=CT}=e;n.addEventListener(`open`,e=>{r(e)}),n.addEventListener(`error`,e=>{let t=e instanceof Error?e:Error(e.type);i(t)}),n.addEventListener(`close`,e=>{a(e)});let s=eT(o);return{close:()=>{n.close()},on:e=>{n.addEventListener(`message`,t=>{e(t.data)})},post:e=>{if(n.readyState===WebSocket.OPEN){n.send(e);return}if(n.readyState===WebSocket.CONNECTING){let t=()=>{i(),n.readyState===WebSocket.OPEN&&n.send(e)},r=()=>i();function i(){n.removeEventListener(`open`,t),n.removeEventListener(`close`,r)}n.addEventListener(`open`,t),n.addEventListener(`close`,r);return}i(Error(`Devframe WebSocket is not open; message dropped`))},serialize:s.serialize,deserialize:s.deserialize}}function TT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})(),i=r.protocol===`https:`?`wss:`:`ws:`;if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`,n=new URL(e.path??`/`,`${i}//${t}`);return n.protocol=i,n.href}let t=new URL(e.path??``,r);return t.protocol=i,t.href}if(typeof e==`number`)return`${i}//${r.hostname}:${e}`;let a=e??``;if(/^wss?:\/\//i.test(a))return a;if(/^https?:\/\//i.test(a))return tS(a,/^https/i.test(a)?`wss://`:`ws://`);let o=new URL(a,r);return o.protocol=i,o.href}function ET(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},wsOptions:s={},callTimeout:c=0}=e,l=TT(n.websocket,r??`./`,location);return oT({transport:`websocket`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>wT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(e){s.onConnected?.(e)},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(t){e.onDisconnected(),s.onDisconnected?.(t)}})})}function DT(e){return e.includes(`:`)}function OT(e,t){return DT(t)?t:`${e}:${t}`}function kT(e){return{async get(t){return(await e()).value()[t]},async set(t,n){(await e()).mutate(e=>{e[t]=n})},async delete(t){(await e()).mutate(e=>{delete e[t]})},async all(){return(await e()).value()},async onChange(t){return(await e()).on(`updated`,e=>t(e))}}}function AT(e,t,n){let r=`devframe:settings:${n}:${t}`,i;function a(){return i||=e.sharedState.get(r,{initialValue:{}}),i}return kT(a)}function jT(e,t){return{global:AT(e,t,`global`),project:AT(e,t,`project`)}}function MT(e,t){return{namespace:t,base:e,rpc:{namespace:t,register(n){if(DT(n.name))throw Error(`[devframe] Scoped client RPC registration for namespace "${t}" received an already-namespaced function name "${n.name}". Pass a bare name without a ":" separator.`);e.client.register({...n,name:`${t}:${n.name}`})},call:((n,...r)=>e.call(OT(t,n),...r)),callEvent:((n,...r)=>e.callEvent(OT(t,n),...r)),callOptional:((n,...r)=>e.callOptional(OT(t,n),...r)),sharedState:((n,r)=>e.sharedState.get(OT(t,n),r)),streaming:{subscribe:(n,r,i)=>e.streaming.subscribe(OT(t,n),r,i),upload:(n,r)=>e.streaming.upload(OT(t,n),r)}},settings:jT(e,t),scope:e.scope}}function NT(){if(typeof document<`u`){let e=document.modelContext;if(e)return e}if(typeof navigator<`u`){let e=navigator.modelContext;if(e)return e}}function PT(e,t={}){let n=t.modelContext??NT();if(!n)return()=>{};let r=n,i=new Map,a=new Map;function o(t,n){let o=cw(t.name),s=a.get(o);if(s&&s!==t.name){console.warn(`[devframe] WebMCP tool name "${o}" (from "${t.name}") collides with "${s}"; keeping the first registration.`);return}let c=new AbortController,l=kx(t.type,n),u=r.registerTool({name:o,description:n.description,inputSchema:Mx(t.args),annotations:{title:n.title??t.name,readOnlyHint:l===`read`,destructiveHint:l===`destructive`},execute:n=>FT(t,e.context,n)},{signal:c.signal});u&&`then`in u&&u.then(()=>{},()=>{}),a.set(o,t.name),i.set(t.name,()=>{c.abort(),u&&`unregister`in u&&typeof u.unregister==`function`&&u.unregister(),a.delete(o)})}function s(t){let n=t?[t]:[...e.definitions.keys()];for(let t of n){i.get(t)?.(),i.delete(t);let n=e.definitions.get(t),r=n?.agent;n&&r&&o(n,r)}}s();let c=e.onChanged(e=>s(e));return()=>{c();for(let e of i.values())e();i.clear()}}async function FT(e,t,n){try{let r=Px(n,e.args?.length);return{content:[{type:`text`,text:IT(await(await Ow(e,t))(...r))}]}}catch(e){return{isError:!0,content:[{type:`text`,text:LT(e)}]}}}function IT(e){return e===void 0?`undefined`:typeof e==`string`?e:JSON.stringify(e,null,2)}function LT(e){if(!(e instanceof Error))return String(e);let t=e.cause instanceof Error?` (cause: ${e.cause.message})`:``;return`${e.name}: ${e.message}${t}`}function RT(e,t){if(t.backend===`static`)return`static`;let n=t.websocket!==void 0,r=t.sse!==void 0;if(e===`websocket`){if(!n)throw Error(`[devframe] transport: 'websocket' was requested, but this server does not advertise a WebSocket endpoint`);return`websocket`}if(e===`sse`){if(!r)throw Error(`[devframe] transport: 'sse' was requested, but this server does not advertise an SSE endpoint`);return`sse`}if(t.backend===`sse`&&r)return`sse`;if(n)return`websocket`;if(r)return`sse`;throw Error(`[devframe] This server advertises no RPC transport (backend "none"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.`)}async function zT(e={}){let{baseURL:t=`./`,rpcOptions:n={},cacheOptions:r=!1}=e,i=Yx(),a=Array.isArray(t)?t:[t],o=await Gw(e),{connectionMeta:s,metaBaseUrl:c,authToken:l}=o,u=a[0]??`./`;try{u=new URL(`.`,c).href}catch{}let d=new bw({functions:[],...typeof e.cacheOptions==`object`?e.cacheOptions:{}}),f={rpc:void 0},p=new kw(f),m=e.webmcp===!1?void 0:PT(p),h,g=!1;async function _(e){let t=[u,...a.filter(e=>e!==u)].filter(e=>e!=null),n=[];for(let r of t)try{return await fetch(eS(e,r)).then(t=>{if(!t.ok)throw Error(`Failed to fetch ${e} from ${r}: ${t.status}`);return t.json()})}catch(e){n.push(e)}throw Error(`Failed to load ${e} from ${t.join(`, `)}`,{cause:n})}let ee={authToken:l,connectionMeta:s,metaBaseUrl:c,events:i,clientRpc:p,callTimeout:e.callTimeout,rpcOptions:{...n,async onRequest(e,t,i){if(await n.onRequest?.call(this,e,t,i),r&&d?.validate(e.m)){if(d.has(e.m,e.a))return i(d.cached(e.m,e.a));let n=await t(e);d.apply(e,n)}else await t(e)}}},te=RT(e.transport??`auto`,s),ne=te===`static`?await vT({fetchJsonFromBases:_}):te===`sse`?cT({...ee,sseOptions:e.sseOptions}):ET({...ee,wsOptions:e.wsOptions}),re;try{re=new BroadcastChannel(`devframe-auth`)}catch{}let ie,ae=!1;function oe(e){return((...t)=>ae||!ie?e(...t):ie.then(()=>e(...t)))}function se(){g=!0;try{h?.(),m?.()}finally{try{re?.close()}finally{ne.close?.()}}}let ce={events:i,get isTrusted(){return ne.isTrusted},get status(){return ne.status},get connectionError(){return ne.connectionError},get transport(){return ne.transport??te},get connection(){return o},connectionMeta:s,ensureTrusted:ne.ensureTrusted,requestTrust:ne.requestTrust,requestTrustWithToken:async e=>(Vw(e),o={...o,authToken:e},ne.requestTrustWithToken(e)),requestTrustWithCode:async e=>{let t=await ne.requestTrustWithCode(e);if(!t)return!1;Vw(t),o={...o,authToken:t};try{re?.postMessage({type:`auth-update`,authToken:t})}catch{}return!0},requestAuthCode:e=>ne.requestAuthCode(e),call:oe(ne.call),callEvent:oe(ne.callEvent),callOptional:oe(ne.callOptional),client:p,sharedState:void 0,services:void 0,streaming:void 0,cacheManager:d,scope:void 0,close:se};ce.sharedState=Qw(ce),ce.streaming=xT(ce),ce.services=Zw(ce);let le=new Map;ce.scope=(e=>{if(!e)return ce;let t=le.get(e);return t||(t=MT(ce,e),le.set(e,t)),t}),f.rpc=ce;function ue(){try{return typeof window<`u`&&window.self===window.top}catch{return!1}}async function de(){if(e.simpleAuth!==!1&&ue()&&typeof globalThis.prompt==`function`)for(await ce.requestAuthCode().catch(()=>{});!ce.isTrusted;){let e=globalThis.prompt(`devframe: enter the authentication code shown in your terminal`);if(e==null)return;let t=e.trim();if(t&&await ce.requestTrustWithCode(t))return}}async function fe(){let t=await ne.requestTrust(),n=e.otpParam??`devframe_otp`,r=n?await Xw(ce,{param:n}):!1;t||r||ce.isTrusted||await de()}return ie=fe().then(()=>{ae=!0},()=>{ae=!0}),s.mcp&&fw(async()=>{let{setupBrowserAgentRpcBridge:e}=await import(`./browser-agent-rpc-BXhoSh1z-C7rzNywl.js`);return{setupBrowserAgentRpcBridge:e}},[],import.meta.url).then(({setupBrowserAgentRpcBridge:e})=>{g||(h=e(ce))}).catch(()=>{}),re&&(re.onmessage=e=>{e.data?.type===`auth-update`&&e.data.authToken&&ce.requestTrustWithToken(e.data.authToken)}),ce}var BT=zT,VT=[`components`,`injectors`,`signals`,`ngrx`,`forms`,`router`,`pipes`,`http`,`analog`,`capacitor`,`errors`],HT=[`angular`,`ngrx`,`analog`,`angular-native`,`nativescript`,`capacitor`];function UT(e){return`pangular:${e}`}var WT=[`forms`,`router`,`ngrx`,`http`,`analog`,`components`],GT={refreshMs:{default:3e3,min:500,max:8e3},navigations:{default:50,min:5,max:500},formTimeline:{default:200,min:10,max:2e3},httpCalls:{default:200,min:10,max:2e3},changeLog:{default:200,min:10,max:2e3},cdCycles:{default:200,min:10,max:2e3},capacitorCalls:{default:200,min:10,max:2e3},idleAfterMs:{default:6e4,min:0,max:6e5}},KT={"opted-out":`the request sets transferCache: false`,post:`POST requests are left out unless includePostRequests is set`,method:`only GET, HEAD and POST requests are cached`,"auth-headers":`it sends an Authorization, Proxy-Authorization or Cookie header`,credentials:`it sends credentials (withCredentials or credentials: include/same-origin)`,"no-cache-request":`the request asks for no-store, no-cache or private`,"no-cache-response":`the response has Cache-Control no-store, no-cache or private`,"set-cookie":`the response sets a cookie`,error:`failed responses are not stored`,mocked:`a fault rule answered before the transfer cache ran`,"cache-off-or-filter":`the transfer cache is off, or its filter (or another withHttpTransferCacheOptions setting) left it out`},qT=[[200,`OK`],[201,`Created`],[202,`Accepted`],[203,`Non-Authoritative Information`],[204,`No Content`],[205,`Reset Content`],[206,`Partial Content`],[207,`Multi-Status`],[208,`Already Reported`],[226,`IM Used`],[300,`Multiple Choices`],[301,`Moved Permanently`],[302,`Found`],[303,`See Other`],[304,`Not Modified`],[307,`Temporary Redirect`],[308,`Permanent Redirect`],[400,`Bad Request`],[401,`Unauthorized`],[402,`Payment Required`],[403,`Forbidden`],[404,`Not Found`],[405,`Method Not Allowed`],[406,`Not Acceptable`],[407,`Proxy Authentication Required`],[408,`Request Timeout`],[409,`Conflict`],[410,`Gone`],[411,`Length Required`],[412,`Precondition Failed`],[413,`Content Too Large`],[414,`URI Too Long`],[415,`Unsupported Media Type`],[416,`Range Not Satisfiable`],[417,`Expectation Failed`],[418,`I'm a Teapot`],[421,`Misdirected Request`],[422,`Unprocessable Content`],[423,`Locked`],[424,`Failed Dependency`],[425,`Too Early`],[426,`Upgrade Required`],[428,`Precondition Required`],[429,`Too Many Requests`],[431,`Request Header Fields Too Large`],[451,`Unavailable For Legal Reasons`],[499,`Client Closed Request`],[500,`Internal Server Error`],[501,`Not Implemented`],[502,`Bad Gateway`],[503,`Service Unavailable`],[504,`Gateway Timeout`],[505,`HTTP Version Not Supported`],[506,`Variant Also Negotiates`],[507,`Insufficient Storage`],[508,`Loop Detected`],[510,`Not Extended`],[511,`Network Authentication Required`],[520,`Web Server Returned an Unknown Error`],[521,`Web Server Is Down`],[522,`Connection Timed Out`],[523,`Origin Is Unreachable`],[524,`A Timeout Occurred`]];function JT(e){return qT.some(([t])=>t===e)}var YT=`pangular`,XT={mod:`Mod`,ctrl:`Ctrl`,control:`Ctrl`,meta:`Meta`,cmd:`Meta`,command:`Meta`,alt:`Alt`,option:`Alt`,opt:`Alt`,shift:`Shift`},ZT=[`Mod`,`Ctrl`,`Meta`,`Alt`,`Shift`];function QT(e){if(typeof e!=`string`||e.length>40)return;let t=e.split(`+`).map(e=>e.trim());if(t.some(e=>!e))return;let n=new Set,r;for(let e of t){let t=XT[e.toLowerCase()];if(t){if(n.has(t))return;n.add(t);continue}if(r!==void 0)return;if(/^[a-z0-9]$/i.test(e))r=e.toUpperCase();else if(/^f([1-9]|1[0-2])$/i.test(e))r=e.toUpperCase();else return}if(r&&[...n].some(e=>e!==`Shift`)&&!(n.has(`Mod`)&&(n.has(`Ctrl`)||n.has(`Meta`))))return[...ZT.filter(e=>n.has(e)),r].join(`+`)}function $T(e,t,n){let r=t.split(`+`),i=r.pop(),a=new Set(r),o=a.has(`Ctrl`)||a.has(`Mod`)&&!n,s=a.has(`Meta`)||a.has(`Mod`)&&n;if(e.ctrlKey!==o||e.metaKey!==s||e.altKey!==a.has(`Alt`)||e.shiftKey!==a.has(`Shift`))return!1;if(/^F\d+$/.test(i))return e.key.toUpperCase()===i;let c=/^\d$/.test(i)?`Digit${i}`:`Key${i}`;return e.code?e.code===c:e.key.toUpperCase()===i}function eE(e,t){if(!t)return e.replace(/^Mod\b/,`Ctrl`);let n={Mod:`⌘`,Meta:`⌘`,Ctrl:`⌃`,Alt:`⌥`,Shift:`⇧`};return e.split(`+`).map(e=>n[e]??e).join(``)}var tE=[{id:`dashboard`,label:`Dashboard`},{id:`timeline`,label:`Timeline`},{id:`analog`,label:`Analog`,inspector:`analog`},{id:`components`,label:`Components`,inspector:`components`},{id:`routes`,label:`Routes`,inspector:`router`},{id:`signals`,label:`Signals`,inspector:`signals`},{id:`injectors`,label:`Injectors`,inspector:`injectors`},{id:`store`,label:`Store`,inspector:`ngrx`},{id:`forms`,label:`Forms`,inspector:`forms`},{id:`pipes`,label:`Pipes`,inspector:`pipes`},{id:`network`,label:`SSR & HTTP`,inspector:`http`},{id:`errors`,label:`Errors`,inspector:`errors`},{id:`capacitor`,label:`Capacitor`,inspector:`capacitor`}];function nE(e){return tE.filter(t=>!(`inspector`in t)||e.inspectors[t.inspector])}var rE={components:`a component instance, by its id in the component tree`,injectors:`a component's element injector, by the component's id`,forms:`a form, by its id`},iE=200;function aE(e){let t=new URLSearchParams({tab:e.tab});return e.id&&t.set(`id`,e.id),e.page&&t.set(`page`,e.page),`#${t.toString()}`}function oE(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=e=>{let n=t.get(e)?.trim();return n&&n.length<=iE?n:void 0},r=n(`tab`);if(!r)return null;let i=n(`id`),a=n(`page`);return{tab:r,...i?{id:i}:{},...a?{page:a}:{}}}var sE=[{id:`settings`,title:`Open settings`,group:`Go to`,keywords:`preferences tabs`},{id:`pick-component`,title:`Pick component on page`,group:`Actions`,keywords:`select inspect element`,inspector:`components`},{id:`cd-record-start`,title:`Start recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-record-stop`,title:`Stop recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-clear`,title:`Clear change detection recording`,group:`Actions`,keywords:`reset recordings cycles`,inspector:`components`},{id:`theme:system`,title:`Theme: follow the system`,group:`Theme`,keywords:`auto`},{id:`theme:light`,title:`Theme: light`,group:`Theme`},{id:`theme:dark`,title:`Theme: dark`,group:`Theme`},{id:`dock:float`,title:`Popup: float`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:bottom`,title:`Popup: dock to the bottom`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:right`,title:`Popup: dock to the right`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:reset-size`,title:`Popup: reset the docked size`,group:`Popup`,keywords:`splitter resize height width`,popupOnly:!0},{id:`popout`,title:`Popup: open in its own window`,group:`Popup`,keywords:`pop out detach new window`,popupOnly:!0},{id:`popout:return`,title:`Popup: back into the page`,group:`Popup`,keywords:`pop in attach dock window`,popupOnly:!0}];function cE(e){let t=nE(e).map(e=>({id:`tab:${e.id}`,title:`Go to ${e.label}`,group:`Go to`,keywords:`tab open`})),n=sE.filter(t=>!t.inspector||e.inspectors[t.inspector]).map(({inspector:e,...t})=>t);return[...t,...n]}function lE(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function uE(e,t){return typeof e==`boolean`?e:t}var dE=100,fE=100;function pE(e){if(!Array.isArray(e))return[];let t=e.filter(e=>typeof e==`string`).map(e=>e.trim()).filter(e=>e&&e.length<=fE);return[...new Set(t)].slice(0,dE)}function mE(e,t){let{default:n,min:r,max:i}=GT[t];return typeof e!=`number`||!Number.isFinite(e)?n:Math.min(i,Math.max(r,Math.round(e)))}function hE(e,t){return Object.fromEntries(e.map(e=>[e,t(e)]))}function gE(e){let t=lE(e),n=lE(t.agent),r=lE(t.inspectors),i=lE(n.tools),a=lE(t.actions),o=uE(t.actions,!0),s=lE(t.redaction),c=lE(t.limits),l=hE(VT,e=>uE(r[e],!0));return{inspectors:l,agent:{readOnly:uE(n.readOnly,!1),tools:hE(VT,e=>l[e]&&uE(i[e],!0))},actions:hE(WT,e=>l[e]&&uE(a[e],o)),redaction:{secretNames:pE(s.secretNames),unmask:pE(s.unmask)},limits:Object.fromEntries(Object.keys(GT).map(e=>[e,mE(c[e],e)])),popup:{hotkey:_E(lE(t.popup).hotkey)}}}function _E(e){return e===!1?!1:QT(e)??`Alt+Shift+P`}function vE(e){let t=e?.configs;return gE(t?.[YT])}function yE(e){return`${{forms:`Writing to forms`,router:`Navigating and clearing navigations`,ngrx:`Restoring NgRx state and dispatching actions`,http:`Changing HTTP mock rules and clearing HTTP calls`,analog:`Calling API routes and clearing server calls`,components:`Editing component properties and signals`}[e]} is turned off in the devtools config (actions.${e}).`}var bE={components:`Components`,injectors:`Injectors`,signals:`Signals`,ngrx:`NgRx`,forms:`Forms`,router:`Router`,pipes:`Pipes`,http:`HTTP`,analog:`Analog`,capacitor:`Capacitor`,errors:`Errors`},xE={forms:`Form writes`,router:`Navigation`,ngrx:`NgRx restore and dispatch`,http:`HTTP mocking`,analog:`Analog API calls`,components:`Component edits`},SE={refreshMs:e=>`poll every ${e} ms`,navigations:e=>`${e} navigations`,formTimeline:e=>`${e} form events`,httpCalls:e=>`${e} HTTP calls`,changeLog:e=>`${e} NgRx changes`,cdCycles:e=>`${e} change detection cycles`,capacitorCalls:e=>`${e} Capacitor plugin calls`,idleAfterMs:e=>e?`idle ${e/1e3} s after the last agent call`:`never idle`};function CE(e){let t=[],n=(e,n)=>{n.length&&t.push({label:e,value:n.join(`, `)})},r=VT.filter(t=>e.inspectors[t]);return n(`Inspectors off`,VT.filter(t=>!e.inspectors[t]).map(e=>bE[e])),n(`Agent`,e.agent.readOnly?[`Read-only`]:[]),n(`Hidden from the agent`,r.filter(t=>!e.agent.tools[t]).map(e=>bE[e])),n(`Blocked actions`,WT.filter(t=>e.inspectors[t]&&!e.actions[t]).map(e=>xE[e])),n(`Extra secret names`,e.redaction.secretNames),n(`Unmasked names`,e.redaction.unmask),n(`Limits`,Object.keys(GT).filter(t=>e.limits[t]!==GT[t].default).map(t=>SE[t](e.limits[t]))),e.popup.hotkey!==`Alt+Shift+P`&&n(`Popup shortcut`,[e.popup.hotkey===!1?`Off`:e.popup.hotkey]),t}function wE(e){let t={tags:[],directives:[],text:``},n=e.toLowerCase();return n=n.replace(/<\s*([^<>\s]+)\s*>/g,(e,n)=>(t.tags.push({value:n,exact:!0}),` `)),n=n.replace(/\[\s*([^[\]\s]+)\s*\]/g,(e,n)=>(t.directives.push({value:n,exact:!0}),` `)),n=n.replace(/(^|\s)([<[])([^<>[\]\s]*)$/,(e,n,r,i)=>(i&&(r===`<`?t.tags:t.directives).push({value:i,exact:!1}),n)),t.text=n.replace(/\s+/g,` `).trim(),t}function TE(e){return!e.tags.length&&!e.directives.length&&!e.text}function EE(e,t){let n=e.tag.toLowerCase(),r=(e.directives??[]).map(e=>e.toLowerCase()),i=(e.attributes??[]).map(e=>e.toLowerCase()),a=[...r,...r.map(e=>e.replace(/directive$/,``)),...i];for(let{value:e,exact:r}of t.tags)if(r?n!==e:!n.startsWith(e))return!1;for(let{value:e,exact:n}of t.directives)if(!a.some(t=>n?t===e:t.includes(e)))return!1;if(t.text){let a=t.text;if(!(e.name.toLowerCase().includes(a)||n.includes(a)||r.some(e=>e.includes(a))||i.some(e=>e.includes(a))))return!1}return!0}var DE={debugApi:{subject:`Live data`,since:`12.0`},injectorProviders:{subject:`Reading providers and environment injectors`,since:`16.2`},injectorMetadata:{subject:`The full injector tree`,since:`17.0`},isSignal:{subject:`Telling signals apart in component values`,since:`17.1`},signalGraph:{subject:`The live signal graph`,since:`20.1`},deferBlocks:{subject:`Listing @defer blocks`,since:`19.1`},forBlocks:{subject:`Listing @for blocks`,since:`22.0`},profiler:{subject:`Recording change detection`,since:`20.0`},angularProfiling:{subject:`Angular profiling`,since:`20.0`},routerInstance:{subject:`The router debug util`,since:`20.3`}};function OE(e){let t=/^(\d+)\.(\d+)/.exec(e.trim());return t?`${t[1]}.${t[2]}`:e.trim()}function kE(e){let t=/^(\d+)(?:\.(\d+))?/.exec(e.trim());return t?[Number(t[1]),Number(t[2]??0)]:null}function AE(e,t){let n=kE(e),r=kE(t);return!n||!r?!1:n[0]===r[0]?n[1]>=r[1]:n[0]>r[0]}function jE(e,t){return e?.capabilities?.[t]===!1}function ME(e,t){let n=DE[e],r=`${n.subject} needs Angular ${n.since} or later`;if(!t)return`${r}; this page's Angular version is unknown.`;let i=OE(t);return AE(t,n.since)?`${r} in a development build; this page runs Angular ${i} without it, which usually means a production build.`:`${r}; this page runs Angular ${i}.`}var NE=`pangular-page-id`,PE=null;function FE(e){PE=e}function IE(){if(PE)return PE;try{return new URLSearchParams(location.search).get(`pageId`)||(window.top===window?null:sessionStorage.getItem(NE)||null)}catch{return null}}function LE(e,t){if(t.chosen&&e[t.chosen])return t.chosen;if(t.host)return t.host;if(t.previous&&e[t.previous])return t.previous;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n?.pageId??null}function RE(e,t){return e?t?e.pages?.[t]??null:e:null}function zE(e,t){return e?t?e.pages?.[t]??null:e.graph??null:null}function BE(e,t,n){return e?e.scope(`pangular`).rpc.call(t,...n===void 0?[]:[n]):Promise.resolve(null)}function VE(e,t,n){return BE(e,t,n).then(e=>e,()=>null)}function HE(e){return e?.connectionMeta.backend===`static`}function UE(e){let t=()=>{let t=e()?.scope(`pangular`).rpc;t&&(t.callEvent(`request-page-highlight`,null),t.callEvent(`request-form-highlight`,null))};return addEventListener(`pagehide`,t),()=>{removeEventListener(`pagehide`,t),t()}}function WE(e){return e.split(`@`)[1]??``}var GE={signal:`Signal Forms`,reactive:`Reactive`,template:`Template-driven`},KE={own:`validator`,directive:`template attribute`,tree:`cross-field rule`,async:`async`,parse:`parse`,submission:`server`,schema:`schema`,manual:`setErrors`},qE=VE,JE={key:`name looks secret`,"input-type":`password input`,autocomplete:`autocomplete is a secret kind`,marker:`marked as mask`,parent:`inside a secret group`,config:`listed in mask`};function YE(e){return JE[e]??e}var XE=`https://pangular-inspector.dev/security/#opt-fields-in-or-out`;async function ZE(e,t){return await qE(e,`request-form-action`,t)??{ok:!1,error:`The devtools server did not answer.`}}function QE(e){return`${e.ok?e.message??`Done.`:e.error??`Failed.`}${e.skipped?.length?` Skipped: ${e.skipped.map(e=>`${e.path} (${e.reason})`).join(`, `)}.`:``}${e.status?` Status: ${e.status}.`:``}`}var $E=/"(?:[^"\\\n]|\\.)*"|`([^`\n]*)`|\*\*/g;function eD(e){return(e??``).replace(/^_Labels, paths.*_\n\n/,``).replace($E,(e,t)=>t??(e===`**`?``:e))}function tD(e){return vE(e?.connectionMeta)}function nD(e,t){return tD(e).actions[t]}var rD={components:`components`,routes:`router`,signals:`signals`,injectors:`injectors`,store:`ngrx`,forms:`forms`,pipes:`pipes`,network:`http`,analog:`analog`,capacitor:`capacitor`,errors:`errors`};function iD(e){return rD[e]}var aD=`https://pangular-inspector.dev/getting-started/configuration/#inspectors-and-agent-tools`;function oD(e,t){let n=rD[e];return!n||t.inspectors[n]}function sD(e,t){e&1&&(O(),Vg(0,`rect`,4)(1,`rect`,5)(2,`rect`,6)(3,`rect`,7))}function cD(e,t){e&1&&(O(),Vg(0,`path`,8)(1,`circle`,9)(2,`circle`,10)(3,`path`,11))}function lD(e,t){e&1&&(O(),Vg(0,`path`,12)(1,`path`,13)(2,`path`,14))}function uD(e,t){e&1&&(O(),Vg(0,`circle`,15)(1,`path`,16)(2,`circle`,17))}function dD(e,t){e&1&&(O(),Vg(0,`path`,1))}function fD(e,t){e&1&&(O(),Vg(0,`path`,18)(1,`path`,19)(2,`path`,20)(3,`path`,21))}function pD(e,t){e&1&&(O(),Vg(0,`ellipse`,22)(1,`path`,23)(2,`path`,24))}function mD(e,t){e&1&&(O(),Vg(0,`rect`,25)(1,`path`,26)(2,`path`,27)(3,`path`,28))}function hD(e,t){e&1&&(O(),Vg(0,`circle`,29)(1,`path`,8)(2,`path`,30))}function gD(e,t){e&1&&(O(),Vg(0,`path`,31)(1,`path`,32)(2,`path`,33)(3,`path`,34)(4,`circle`,35))}function _D(e,t){e&1&&(O(),Vg(0,`circle`,36)(1,`path`,37))}function vD(e,t){e&1&&(O(),Vg(0,`circle`,29)(1,`path`,38)(2,`path`,39))}function yD(e,t){e&1&&(O(),Vg(0,`path`,2))}function bD(e,t){e&1&&(O(),Vg(0,`path`,3))}var xD=class e{name=$.required();static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-tab-icon`]],inputs:{name:[1,`name`]},decls:15,vars:1,consts:[[`viewBox`,`0 0 24 24`,`width`,`16`,`height`,`16`,`fill`,`none`,`stroke`,`currentColor`,`stroke-width`,`1.8`,`stroke-linecap`,`round`,`stroke-linejoin`,`round`,`aria-hidden`,`true`],[`d`,`M22 12h-4l-3 9L9 3l-3 9H2`],[`d`,`m8 3 4 8 5-5 5 15H2L8 3z`],[`fill`,`currentColor`,`stroke`,`none`,`transform`,`translate(1.8 1.8) scale(0.85)`,`d`,`M24 3.7l-5.766 5.766 5.725 5.736-3.713 3.712L5.073 3.742 8.786.03l5.736 5.726L20.284 0 24 3.7zM.029 8.785l3.713-3.713 15.173 15.173-3.713 3.714-5.732-5.726L3.7 24 0 20.285l5.754-5.764L.029 8.785z`],[`x`,`3`,`y`,`3`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`14`,`y`,`3`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`x`,`14`,`y`,`12`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`3`,`y`,`16`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`d`,`M3 12h18`],[`cx`,`7`,`cy`,`12`,`r`,`2`],[`cx`,`14`,`cy`,`12`,`r`,`2`],[`d`,`M18 7v10`],[`d`,`M12 2 3 7l9 5 9-5-9-5Z`],[`d`,`m3 12 9 5 9-5`],[`d`,`m3 17 9 5 9-5`],[`cx`,`6`,`cy`,`19`,`r`,`3`],[`d`,`M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15`],[`cx`,`18`,`cy`,`5`,`r`,`3`],[`d`,`M12 22v-5`],[`d`,`M9 8V2`],[`d`,`M15 8V2`],[`d`,`M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z`],[`cx`,`12`,`cy`,`5`,`rx`,`9`,`ry`,`3`],[`d`,`M3 5v14a9 3 0 0 0 18 0V5`],[`d`,`M3 12a9 3 0 0 0 18 0`],[`x`,`3`,`y`,`4`,`width`,`18`,`height`,`16`,`rx`,`2`],[`d`,`M7 9h10`],[`d`,`M7 13h6`],[`d`,`M7 17h8`],[`cx`,`12`,`cy`,`12`,`r`,`9`],[`d`,`M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18Z`],[`d`,`M4 7h10`],[`d`,`M4 17h6`],[`d`,`m14 13 4 4-4 4`],[`d`,`M10 17h8`],[`cx`,`18`,`cy`,`7`,`r`,`3`],[`cx`,`12`,`cy`,`12`,`r`,`3`],[`d`,`M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z`],[`d`,`M12 7v6`],[`d`,`M12 16.5v.01`]],template:function(e,t){if(e&1&&(O(),B(0,`svg`,0),M(1,sD,4,0)(2,cD,4,0)(3,lD,3,0)(4,uD,3,0)(5,dD,1,0,`:svg:path`,1)(6,fD,4,0)(7,pD,3,0)(8,mD,4,0)(9,hD,3,0)(10,gD,5,0)(11,_D,2,0)(12,vD,3,0)(13,yD,1,0,`:svg:path`,2)(14,bD,1,0,`:svg:path`,3),V()),e&2){let e;A(),N((e=t.name())===`dashboard`?1:e===`timeline`?2:e===`components`?3:e===`routes`?4:e===`signals`?5:e===`injectors`?6:e===`store`?7:e===`forms`?8:e===`network`?9:e===`pipes`?10:e===`settings`?11:e===`errors`?12:e===`analog`?13:e===`capacitor`?14:-1)}},styles:[`[_nghost-%COMP%] { +`))}}g()}return(async()=>{try{let e=await a(o,{headers:{accept:`text/event-stream`},signal:c.signal});if(!e.ok||!e.body)throw Error(`Devframe SSE stream request failed: ${e.status}`);await ee(e.body)}catch(e){if(c.signal.aborted){g();return}h(e instanceof Error?e:Error(String(e)))}})(),{close:()=>{l=!0,c.abort(),d?.cancel().catch(()=>{})},on:e=>{u=e},post:async e=>{let t;try{t=await m}catch{return}if(l){n(Error(`Devframe SSE channel is closed; message dropped`));return}try{let n=await a(o,{method:`POST`,headers:{"content-type":`text/plain; charset=utf-8`,[hw]:t},body:e});if(n.status===200){let e=await n.text();e&&u?.(e);return}if(!n.ok)throw Error(`Devframe SSE POST failed: ${n.status}`)}catch(e){n(e instanceof Error?e:Error(String(e)))}},serialize:s.serialize,deserialize:s.deserialize}}function aT(e,t){let{channel:n,rpcOptions:r={}}=t;return Ox(e,{...n,timeout:-1,...r,proxify:!1})}function oT(e){let{transport:t,authToken:n,connectionMeta:r,events:i,clientRpc:a,rpcOptions:o={},callTimeout:s=0}=e,c=!1,l=`connecting`,u=null,d=Promise.withResolvers();function f(e,t=null){if(t?u=t:e===`connected`&&(u=null),e===l)return;let n=l;l=e,i.emit(hx.client.connectionStatus,e,n)}let p=new Set;function m(e){for(let t of[...p])t.reject(e)}function h(){return l===`disconnected`||l===`error`?new Kw(`connection`,`[devframe] Not connected to the devframe server`,{cause:u??void 0}):l===`unauthorized`?new Kw(`auth`,`[devframe] Not authorized by the devframe server`,{cause:u??void 0}):null}function g(e,t){return new Promise((n,r)=>{let a=!1,o,c={reject(e){a||(l(),i.emit(hx.client.error,e,t),r(e))}};function l(){a=!0,p.delete(c),o&&clearTimeout(o)}p.add(c),s>0&&(o=setTimeout(()=>{c.reject(new Kw(`timeout`,`[devframe] RPC call "${t}" timed out after ${s}ms`))},s)),e.then(e=>{a||(l(),n(e))},e=>{if(a)return;l();let n=e instanceof Error?e:Error(String(e));i.emit(hx.client.error,n,t),r(n)})})}let _=new Map;for(let e of r.jsonSerializableMethods??[])_.set(e,{jsonSerializable:!0});let ee=e.createChannel({definitions:_,onError(e){f(`error`,e),i.emit(hx.client.connectionError,e),m(new Kw(`connection`,`[devframe] Connection to the devframe server failed`,{cause:e}))},onDisconnected(){l!==`error`&&f(`disconnected`),m(new Kw(`connection`,`[devframe] Disconnected from the devframe server`,{cause:u??void 0}))}}),te=aT(a.functions,{channel:ee,rpcOptions:o});a.register({name:hx.broadcast.authRevoked,type:`event`,handler:()=>{c=!1;let e=new Kw(`auth`,`[devframe] The devframe server revoked this client's trust`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e),m(e),i.emit(hx.client.isTrustedUpdated,!1)}});let ne=n;async function re(e){ne=e;let t=await te.$call(`anonymous:devframe:auth`,{authToken:e,ua:navigator.userAgent,origin:location.origin});if(c=t.isTrusted,c)d.resolve(!0),f(`connected`);else{let e=new Kw(`auth`,`[devframe] The devframe server refused this client's credentials`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e)}return i.emit(hx.client.isTrustedUpdated,c),t.isTrusted}async function ie(e){let t=(await te.$call(`anonymous:devframe:auth:exchange`,{code:e,ua:navigator.userAgent,origin:location.origin}))?.authToken??null;return t&&(ne=t,c=!0,d.resolve(!0),f(`connected`),i.emit(hx.client.isTrustedUpdated,!0)),t}async function ae(e={}){await te.$call(`anonymous:devframe:auth:request-code`,{ua:navigator.userAgent,origin:location.origin,...e.reissue?{reissue:!0}:{}})}async function oe(){return c?!0:re(ne??``)}async function se(e=6e4){if(c&&d.resolve(!0),e<=0)return d.promise;let t;try{return await Promise.race([d.promise,new Promise((n,r)=>{t=setTimeout(()=>{r(Error(`[devframe] Timeout waiting for rpc to be trusted`))},e)})]),c}finally{clearTimeout(t)}}return{transport:t,get isTrusted(){return c},get status(){return l},get connectionError(){return u},requestTrust:oe,requestTrustWithToken:re,requestTrustWithCode:ie,requestAuthCode:ae,ensureTrusted:se,call:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$call(...e),t)},callEvent:(...e)=>{let t=h();if(t){i.emit(hx.client.error,t,String(e[0]));return}return te.$callEvent(...e)},callOptional:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$callOptional(...e),t)},close:()=>{ee.close()}}}function sT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})();if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`;return new URL(e.path??`/`,`${r.protocol}//${t}`).href}return new URL(e.path??``,r).href}let i=e??``;return/^https?:\/\//i.test(i)?i:new URL(i,r).href}function cT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},sseOptions:s={},callTimeout:c=0}=e,l=sT(n.sse,r??`./`,location);return oT({transport:`sse`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>iT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(){s.onConnected?.()},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(){e.onDisconnected(),s.onDisconnected?.()}})})}function lT(e){let{name:t,message:n,cause:r,...i}=e,a=r instanceof Error?r:uT(r)?lT(r):r,o=a===void 0?Error(n):Error(n,{cause:a});return o.name=t,Object.assign(o,i),o}function uT(e){return typeof e==`object`&&!!e&&typeof e.message==`string`&&typeof e.name==`string`}function dT(e){return typeof e==`object`&&!!e&&e.type===`static`&&typeof e.path==`string`}function fT(e){return typeof e==`object`&&!!e&&e.type===`query`&&typeof e.records==`object`&&e.records!==null}function pT(e){return typeof e==`object`&&!!e&&(`output`in e||`error`in e)}function mT(e){if(e.error)throw lT(e.error);return e.output}function hT(e){return e.some(e=>e!=null)}function gT(e){return typeof e==`object`&&e&&`serialization`in e&&`data`in e?e.data:e}function _T(e,t){let n=new Map,r=new Map;function i(e,t){return t===`structured-clone`&&Array.isArray(e)?$C(e):e}function a(e,t){return i(gT(e),t)}async function o(e){n.has(e.path)||n.set(e.path,t(e.path).then(t=>a(t,e.serialization)));let r=await n.get(e.path);return pT(r)?mT(r):r}async function s(e,n){return r.has(e)||r.set(e,t(e).then(e=>a(e,n))),await r.get(e)}async function c(t,n){if(!(t in e))throw Error(`[devframe-rpc] Function "${t}" not found in dump store`);let r=e[t];if(dT(r)){if(hT(n))throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`);return await o(r)}if(fT(r)){let e=Jx(n),i=r.records[e];if(i)return mT(await s(i,r.serialization));if(r.fallback)return mT(await s(r.fallback,r.serialization));throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}if(!hT(n))return r;throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}return{call:async(e,t)=>await c(e,t),callOptional:async(t,n)=>{if(t in e)return await c(t,n)},callEvent:async(e,t)=>{}}}async function vT(e){let t=_T(await e.fetchJsonFromBases(gw),e.fetchJsonFromBases);return{transport:`static`,isTrusted:!0,status:`connected`,connectionError:null,requestTrust:async()=>!0,requestTrustWithToken:async()=>!0,requestTrustWithCode:async()=>null,requestAuthCode:async()=>{},ensureTrusted:async()=>!0,call:(...e)=>t.call(e[0],e.slice(1)),callEvent:(...e)=>t.callEvent(e[0],e.slice(1)),callOptional:(...e)=>t.callOptional(e[0],e.slice(1)),close:()=>{}}}var yT=``;function bT(e,t){return`${e}${yT}${t}`}function xT(e){let t=new Map,n=new Map;e.client.register({name:hx.broadcast.streamingChunk,type:`event`,handler(e,n,r,i){t.get(bT(e,n))?._push(r,i)}}),e.client.register({name:hx.broadcast.streamingEnd,type:`event`,handler(e,n,r){let i=bT(e,n),a=t.get(i);a&&(a._end(r),t.delete(i))}}),e.client.register({name:hx.broadcast.streamingUploadCancel,type:`event`,handler(e,t){let r=bT(e,t),i=n.get(r);i&&(i.abort(`server cancelled upload`),n.delete(r))}}),e.events.on(hx.client.isTrustedUpdated,n=>{if(n)for(let[n,r]of t){if(r.cancelled||r.done)continue;let t=n.indexOf(yT);if(t<0)continue;let i=n.slice(0,t),a=n.slice(t+1);e.callEvent(`devframe:streaming:subscribe`,i,a,{afterSeq:r.lastSeenSeq})}});function r(n,r,i={}){let a=bT(n,r),o=t.get(a);if(o)return o;let s=aw({id:r,highWaterMark:i.highWaterMark,onOverflow(e){console.warn(`[devframe] DF0029: Stream "${n}#${r}" dropped ${e} chunk(s) after exceeding the client high-water mark.`)},onCancel(){e.callEvent(`devframe:streaming:cancel`,n,r),t.delete(a)}});if(t.set(a,s),e.isTrusted)e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:0});else{let i=e.events.on(hx.client.isTrustedUpdated,o=>{o&&(i(),t.has(a)&&!s.cancelled&&!s.done&&e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:s.lastSeenSeq}))})}return s}function i(t,r){let i=bT(t,r),a=n.get(i);if(a)return a;let o=iw({id:r});return o.events.on(`chunk`,(n,i)=>{e.callEvent(`devframe:streaming:upload-chunk`,t,r,n,i)}),o.events.on(`end`,a=>{e.callEvent(`devframe:streaming:upload-end`,t,r,a),n.delete(i)}),n.set(i,o),o}return{subscribe:r,upload:i}}function ST(){}var CT=new Map;function wT(e){let t=e.url;e.authToken&&(t=`${t}?${yw}=${encodeURIComponent(e.authToken)}`);let n=new WebSocket(t),{onConnected:r=ST,onError:i=ST,onDisconnected:a=ST,definitions:o=CT}=e;n.addEventListener(`open`,e=>{r(e)}),n.addEventListener(`error`,e=>{let t=e instanceof Error?e:Error(e.type);i(t)}),n.addEventListener(`close`,e=>{a(e)});let s=eT(o);return{close:()=>{n.close()},on:e=>{n.addEventListener(`message`,t=>{e(t.data)})},post:e=>{if(n.readyState===WebSocket.OPEN){n.send(e);return}if(n.readyState===WebSocket.CONNECTING){let t=()=>{i(),n.readyState===WebSocket.OPEN&&n.send(e)},r=()=>i();function i(){n.removeEventListener(`open`,t),n.removeEventListener(`close`,r)}n.addEventListener(`open`,t),n.addEventListener(`close`,r);return}i(Error(`Devframe WebSocket is not open; message dropped`))},serialize:s.serialize,deserialize:s.deserialize}}function TT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})(),i=r.protocol===`https:`?`wss:`:`ws:`;if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`,n=new URL(e.path??`/`,`${i}//${t}`);return n.protocol=i,n.href}let t=new URL(e.path??``,r);return t.protocol=i,t.href}if(typeof e==`number`)return`${i}//${r.hostname}:${e}`;let a=e??``;if(/^wss?:\/\//i.test(a))return a;if(/^https?:\/\//i.test(a))return tS(a,/^https/i.test(a)?`wss://`:`ws://`);let o=new URL(a,r);return o.protocol=i,o.href}function ET(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},wsOptions:s={},callTimeout:c=0}=e,l=TT(n.websocket,r??`./`,location);return oT({transport:`websocket`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>wT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(e){s.onConnected?.(e)},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(t){e.onDisconnected(),s.onDisconnected?.(t)}})})}function DT(e){return e.includes(`:`)}function OT(e,t){return DT(t)?t:`${e}:${t}`}function kT(e){return{async get(t){return(await e()).value()[t]},async set(t,n){(await e()).mutate(e=>{e[t]=n})},async delete(t){(await e()).mutate(e=>{delete e[t]})},async all(){return(await e()).value()},async onChange(t){return(await e()).on(`updated`,e=>t(e))}}}function AT(e,t,n){let r=`devframe:settings:${n}:${t}`,i;function a(){return i||=e.sharedState.get(r,{initialValue:{}}),i}return kT(a)}function jT(e,t){return{global:AT(e,t,`global`),project:AT(e,t,`project`)}}function MT(e,t){return{namespace:t,base:e,rpc:{namespace:t,register(n){if(DT(n.name))throw Error(`[devframe] Scoped client RPC registration for namespace "${t}" received an already-namespaced function name "${n.name}". Pass a bare name without a ":" separator.`);e.client.register({...n,name:`${t}:${n.name}`})},call:((n,...r)=>e.call(OT(t,n),...r)),callEvent:((n,...r)=>e.callEvent(OT(t,n),...r)),callOptional:((n,...r)=>e.callOptional(OT(t,n),...r)),sharedState:((n,r)=>e.sharedState.get(OT(t,n),r)),streaming:{subscribe:(n,r,i)=>e.streaming.subscribe(OT(t,n),r,i),upload:(n,r)=>e.streaming.upload(OT(t,n),r)}},settings:jT(e,t),scope:e.scope}}function NT(){if(typeof document<`u`){let e=document.modelContext;if(e)return e}if(typeof navigator<`u`){let e=navigator.modelContext;if(e)return e}}function PT(e,t={}){let n=t.modelContext??NT();if(!n)return()=>{};let r=n,i=new Map,a=new Map;function o(t,n){let o=cw(t.name),s=a.get(o);if(s&&s!==t.name){console.warn(`[devframe] WebMCP tool name "${o}" (from "${t.name}") collides with "${s}"; keeping the first registration.`);return}let c=new AbortController,l=kx(t.type,n),u=r.registerTool({name:o,description:n.description,inputSchema:Mx(t.args),annotations:{title:n.title??t.name,readOnlyHint:l===`read`,destructiveHint:l===`destructive`},execute:n=>FT(t,e.context,n)},{signal:c.signal});u&&`then`in u&&u.then(()=>{},()=>{}),a.set(o,t.name),i.set(t.name,()=>{c.abort(),u&&`unregister`in u&&typeof u.unregister==`function`&&u.unregister(),a.delete(o)})}function s(t){let n=t?[t]:[...e.definitions.keys()];for(let t of n){i.get(t)?.(),i.delete(t);let n=e.definitions.get(t),r=n?.agent;n&&r&&o(n,r)}}s();let c=e.onChanged(e=>s(e));return()=>{c();for(let e of i.values())e();i.clear()}}async function FT(e,t,n){try{let r=Px(n,e.args?.length);return{content:[{type:`text`,text:IT(await(await Ow(e,t))(...r))}]}}catch(e){return{isError:!0,content:[{type:`text`,text:LT(e)}]}}}function IT(e){return e===void 0?`undefined`:typeof e==`string`?e:JSON.stringify(e,null,2)}function LT(e){if(!(e instanceof Error))return String(e);let t=e.cause instanceof Error?` (cause: ${e.cause.message})`:``;return`${e.name}: ${e.message}${t}`}function RT(e,t){if(t.backend===`static`)return`static`;let n=t.websocket!==void 0,r=t.sse!==void 0;if(e===`websocket`){if(!n)throw Error(`[devframe] transport: 'websocket' was requested, but this server does not advertise a WebSocket endpoint`);return`websocket`}if(e===`sse`){if(!r)throw Error(`[devframe] transport: 'sse' was requested, but this server does not advertise an SSE endpoint`);return`sse`}if(t.backend===`sse`&&r)return`sse`;if(n)return`websocket`;if(r)return`sse`;throw Error(`[devframe] This server advertises no RPC transport (backend "none"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.`)}async function zT(e={}){let{baseURL:t=`./`,rpcOptions:n={},cacheOptions:r=!1}=e,i=Yx(),a=Array.isArray(t)?t:[t],o=await Gw(e),{connectionMeta:s,metaBaseUrl:c,authToken:l}=o,u=a[0]??`./`;try{u=new URL(`.`,c).href}catch{}let d=new bw({functions:[],...typeof e.cacheOptions==`object`?e.cacheOptions:{}}),f={rpc:void 0},p=new kw(f),m=e.webmcp===!1?void 0:PT(p),h,g=!1;async function _(e){let t=[u,...a.filter(e=>e!==u)].filter(e=>e!=null),n=[];for(let r of t)try{return await fetch(eS(e,r)).then(t=>{if(!t.ok)throw Error(`Failed to fetch ${e} from ${r}: ${t.status}`);return t.json()})}catch(e){n.push(e)}throw Error(`Failed to load ${e} from ${t.join(`, `)}`,{cause:n})}let ee={authToken:l,connectionMeta:s,metaBaseUrl:c,events:i,clientRpc:p,callTimeout:e.callTimeout,rpcOptions:{...n,async onRequest(e,t,i){if(await n.onRequest?.call(this,e,t,i),r&&d?.validate(e.m)){if(d.has(e.m,e.a))return i(d.cached(e.m,e.a));let n=await t(e);d.apply(e,n)}else await t(e)}}},te=RT(e.transport??`auto`,s),ne=te===`static`?await vT({fetchJsonFromBases:_}):te===`sse`?cT({...ee,sseOptions:e.sseOptions}):ET({...ee,wsOptions:e.wsOptions}),re;try{re=new BroadcastChannel(`devframe-auth`)}catch{}let ie,ae=!1;function oe(e){return((...t)=>ae||!ie?e(...t):ie.then(()=>e(...t)))}function se(){g=!0;try{h?.(),m?.()}finally{try{re?.close()}finally{ne.close?.()}}}let ce={events:i,get isTrusted(){return ne.isTrusted},get status(){return ne.status},get connectionError(){return ne.connectionError},get transport(){return ne.transport??te},get connection(){return o},connectionMeta:s,ensureTrusted:ne.ensureTrusted,requestTrust:ne.requestTrust,requestTrustWithToken:async e=>(Vw(e),o={...o,authToken:e},ne.requestTrustWithToken(e)),requestTrustWithCode:async e=>{let t=await ne.requestTrustWithCode(e);if(!t)return!1;Vw(t),o={...o,authToken:t};try{re?.postMessage({type:`auth-update`,authToken:t})}catch{}return!0},requestAuthCode:e=>ne.requestAuthCode(e),call:oe(ne.call),callEvent:oe(ne.callEvent),callOptional:oe(ne.callOptional),client:p,sharedState:void 0,services:void 0,streaming:void 0,cacheManager:d,scope:void 0,close:se};ce.sharedState=Qw(ce),ce.streaming=xT(ce),ce.services=Zw(ce);let le=new Map;ce.scope=(e=>{if(!e)return ce;let t=le.get(e);return t||(t=MT(ce,e),le.set(e,t)),t}),f.rpc=ce;function ue(){try{return typeof window<`u`&&window.self===window.top}catch{return!1}}async function de(){if(e.simpleAuth!==!1&&ue()&&typeof globalThis.prompt==`function`)for(await ce.requestAuthCode().catch(()=>{});!ce.isTrusted;){let e=globalThis.prompt(`devframe: enter the authentication code shown in your terminal`);if(e==null)return;let t=e.trim();if(t&&await ce.requestTrustWithCode(t))return}}async function fe(){let t=await ne.requestTrust(),n=e.otpParam??`devframe_otp`,r=n?await Xw(ce,{param:n}):!1;t||r||ce.isTrusted||await de()}return ie=fe().then(()=>{ae=!0},()=>{ae=!0}),s.mcp&&fw(async()=>{let{setupBrowserAgentRpcBridge:e}=await import(`./browser-agent-rpc-BXhoSh1z-DD97nExW.js`);return{setupBrowserAgentRpcBridge:e}},[],import.meta.url).then(({setupBrowserAgentRpcBridge:e})=>{g||(h=e(ce))}).catch(()=>{}),re&&(re.onmessage=e=>{e.data?.type===`auth-update`&&e.data.authToken&&ce.requestTrustWithToken(e.data.authToken)}),ce}var BT=zT,VT=[`components`,`injectors`,`signals`,`ngrx`,`forms`,`router`,`pipes`,`http`,`analog`,`capacitor`,`errors`],HT=[`angular`,`ngrx`,`analog`,`angular-native`,`nativescript`,`capacitor`];function UT(e){return`pangular:${e}`}var WT=[`forms`,`router`,`ngrx`,`http`,`analog`,`components`],GT={refreshMs:{default:3e3,min:500,max:8e3},navigations:{default:50,min:5,max:500},formTimeline:{default:200,min:10,max:2e3},httpCalls:{default:200,min:10,max:2e3},changeLog:{default:200,min:10,max:2e3},cdCycles:{default:200,min:10,max:2e3},capacitorCalls:{default:200,min:10,max:2e3},idleAfterMs:{default:6e4,min:0,max:6e5}},KT={"opted-out":`the request sets transferCache: false`,post:`POST requests are left out unless includePostRequests is set`,method:`only GET, HEAD and POST requests are cached`,"auth-headers":`it sends an Authorization, Proxy-Authorization or Cookie header`,credentials:`it sends credentials (withCredentials or credentials: include/same-origin)`,"no-cache-request":`the request asks for no-store, no-cache or private`,"no-cache-response":`the response has Cache-Control no-store, no-cache or private`,"set-cookie":`the response sets a cookie`,error:`failed responses are not stored`,mocked:`a fault rule answered before the transfer cache ran`,"cache-off-or-filter":`the transfer cache is off, or its filter (or another withHttpTransferCacheOptions setting) left it out`},qT=[[200,`OK`],[201,`Created`],[202,`Accepted`],[203,`Non-Authoritative Information`],[204,`No Content`],[205,`Reset Content`],[206,`Partial Content`],[207,`Multi-Status`],[208,`Already Reported`],[226,`IM Used`],[300,`Multiple Choices`],[301,`Moved Permanently`],[302,`Found`],[303,`See Other`],[304,`Not Modified`],[307,`Temporary Redirect`],[308,`Permanent Redirect`],[400,`Bad Request`],[401,`Unauthorized`],[402,`Payment Required`],[403,`Forbidden`],[404,`Not Found`],[405,`Method Not Allowed`],[406,`Not Acceptable`],[407,`Proxy Authentication Required`],[408,`Request Timeout`],[409,`Conflict`],[410,`Gone`],[411,`Length Required`],[412,`Precondition Failed`],[413,`Content Too Large`],[414,`URI Too Long`],[415,`Unsupported Media Type`],[416,`Range Not Satisfiable`],[417,`Expectation Failed`],[418,`I'm a Teapot`],[421,`Misdirected Request`],[422,`Unprocessable Content`],[423,`Locked`],[424,`Failed Dependency`],[425,`Too Early`],[426,`Upgrade Required`],[428,`Precondition Required`],[429,`Too Many Requests`],[431,`Request Header Fields Too Large`],[451,`Unavailable For Legal Reasons`],[499,`Client Closed Request`],[500,`Internal Server Error`],[501,`Not Implemented`],[502,`Bad Gateway`],[503,`Service Unavailable`],[504,`Gateway Timeout`],[505,`HTTP Version Not Supported`],[506,`Variant Also Negotiates`],[507,`Insufficient Storage`],[508,`Loop Detected`],[510,`Not Extended`],[511,`Network Authentication Required`],[520,`Web Server Returned an Unknown Error`],[521,`Web Server Is Down`],[522,`Connection Timed Out`],[523,`Origin Is Unreachable`],[524,`A Timeout Occurred`]];function JT(e){return qT.some(([t])=>t===e)}var YT=`pangular`,XT={mod:`Mod`,ctrl:`Ctrl`,control:`Ctrl`,meta:`Meta`,cmd:`Meta`,command:`Meta`,alt:`Alt`,option:`Alt`,opt:`Alt`,shift:`Shift`},ZT=[`Mod`,`Ctrl`,`Meta`,`Alt`,`Shift`];function QT(e){if(typeof e!=`string`||e.length>40)return;let t=e.split(`+`).map(e=>e.trim());if(t.some(e=>!e))return;let n=new Set,r;for(let e of t){let t=XT[e.toLowerCase()];if(t){if(n.has(t))return;n.add(t);continue}if(r!==void 0)return;if(/^[a-z0-9]$/i.test(e))r=e.toUpperCase();else if(/^f([1-9]|1[0-2])$/i.test(e))r=e.toUpperCase();else return}if(r&&[...n].some(e=>e!==`Shift`)&&!(n.has(`Mod`)&&(n.has(`Ctrl`)||n.has(`Meta`))))return[...ZT.filter(e=>n.has(e)),r].join(`+`)}function $T(e,t,n){let r=t.split(`+`),i=r.pop(),a=new Set(r),o=a.has(`Ctrl`)||a.has(`Mod`)&&!n,s=a.has(`Meta`)||a.has(`Mod`)&&n;if(e.ctrlKey!==o||e.metaKey!==s||e.altKey!==a.has(`Alt`)||e.shiftKey!==a.has(`Shift`))return!1;if(/^F\d+$/.test(i))return e.key.toUpperCase()===i;let c=/^\d$/.test(i)?`Digit${i}`:`Key${i}`;return e.code?e.code===c:e.key.toUpperCase()===i}function eE(e,t){if(!t)return e.replace(/^Mod\b/,`Ctrl`);let n={Mod:`⌘`,Meta:`⌘`,Ctrl:`⌃`,Alt:`⌥`,Shift:`⇧`};return e.split(`+`).map(e=>n[e]??e).join(``)}var tE=[{id:`dashboard`,label:`Dashboard`},{id:`timeline`,label:`Timeline`},{id:`analog`,label:`Analog`,inspector:`analog`},{id:`components`,label:`Components`,inspector:`components`},{id:`routes`,label:`Routes`,inspector:`router`},{id:`signals`,label:`Signals`,inspector:`signals`},{id:`injectors`,label:`Injectors`,inspector:`injectors`},{id:`store`,label:`Store`,inspector:`ngrx`},{id:`forms`,label:`Forms`,inspector:`forms`},{id:`pipes`,label:`Pipes`,inspector:`pipes`},{id:`network`,label:`SSR & HTTP`,inspector:`http`},{id:`errors`,label:`Errors`,inspector:`errors`},{id:`capacitor`,label:`Capacitor`,inspector:`capacitor`}],nE=1e4;function rE(e){return tE.filter(t=>!(`inspector`in t)||e.inspectors[t.inspector])}var iE={components:`a component instance, by its id in the component tree`,injectors:`a component's element injector, by the component's id`,forms:`a form, by its id`},aE=200;function oE(e){let t=new URLSearchParams({tab:e.tab});return e.id&&t.set(`id`,e.id),e.page&&t.set(`page`,e.page),`#${t.toString()}`}function sE(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=e=>{let n=t.get(e)?.trim();return n&&n.length<=aE?n:void 0},r=n(`tab`);if(!r)return null;let i=n(`id`),a=n(`page`);return{tab:r,...i?{id:i}:{},...a?{page:a}:{}}}var cE=[{id:`settings`,title:`Open settings`,group:`Go to`,keywords:`preferences tabs`},{id:`pick-component`,title:`Pick component on page`,group:`Actions`,keywords:`select inspect element`,inspector:`components`},{id:`cd-record-start`,title:`Start recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-record-stop`,title:`Stop recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-clear`,title:`Clear change detection recording`,group:`Actions`,keywords:`reset recordings cycles`,inspector:`components`},{id:`theme:system`,title:`Theme: follow the system`,group:`Theme`,keywords:`auto`},{id:`theme:light`,title:`Theme: light`,group:`Theme`},{id:`theme:dark`,title:`Theme: dark`,group:`Theme`},{id:`dock:float`,title:`Popup: float`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:bottom`,title:`Popup: dock to the bottom`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:right`,title:`Popup: dock to the right`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:reset-size`,title:`Popup: reset the docked size`,group:`Popup`,keywords:`splitter resize height width`,popupOnly:!0},{id:`popout`,title:`Popup: open in its own window`,group:`Popup`,keywords:`pop out detach new window`,popupOnly:!0},{id:`popout:return`,title:`Popup: back into the page`,group:`Popup`,keywords:`pop in attach dock window`,popupOnly:!0}];function lE(e){let t=rE(e).map(e=>({id:`tab:${e.id}`,title:`Go to ${e.label}`,group:`Go to`,keywords:`tab open`})),n=cE.filter(t=>!t.inspector||e.inspectors[t.inspector]).map(({inspector:e,...t})=>t);return[...t,...n]}function uE(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function dE(e,t){return typeof e==`boolean`?e:t}var fE=100,pE=100;function mE(e){if(!Array.isArray(e))return[];let t=e.filter(e=>typeof e==`string`).map(e=>e.trim()).filter(e=>e&&e.length<=pE);return[...new Set(t)].slice(0,fE)}function hE(e,t){let{default:n,min:r,max:i}=GT[t];return typeof e!=`number`||!Number.isFinite(e)?n:Math.min(i,Math.max(r,Math.round(e)))}function gE(e,t){return Object.fromEntries(e.map(e=>[e,t(e)]))}function _E(e){let t=uE(e),n=uE(t.agent),r=uE(t.inspectors),i=uE(n.tools),a=uE(t.actions),o=dE(t.actions,!0),s=uE(t.redaction),c=uE(t.limits),l=gE(VT,e=>dE(r[e],!0));return{inspectors:l,agent:{readOnly:dE(n.readOnly,!1),tools:gE(VT,e=>l[e]&&dE(i[e],!0))},actions:gE(WT,e=>l[e]&&dE(a[e],o)),redaction:{secretNames:mE(s.secretNames),unmask:mE(s.unmask)},limits:Object.fromEntries(Object.keys(GT).map(e=>[e,hE(c[e],e)])),popup:{hotkey:vE(uE(t.popup).hotkey)}}}function vE(e){return e===!1?!1:QT(e)??`Alt+Shift+P`}function yE(e){let t=e?.configs;return _E(t?.[YT])}function bE(e){return`${{forms:`Writing to forms`,router:`Navigating and clearing navigations`,ngrx:`Restoring NgRx state and dispatching actions`,http:`Changing HTTP mock rules and clearing HTTP calls`,analog:`Calling API routes and clearing server calls`,components:`Editing component properties and signals`}[e]} is turned off in the devtools config (actions.${e}).`}var xE={components:`Components`,injectors:`Injectors`,signals:`Signals`,ngrx:`NgRx`,forms:`Forms`,router:`Router`,pipes:`Pipes`,http:`HTTP`,analog:`Analog`,capacitor:`Capacitor`,errors:`Errors`},SE={forms:`Form writes`,router:`Navigation`,ngrx:`NgRx restore and dispatch`,http:`HTTP mocking`,analog:`Analog API calls`,components:`Component edits`},CE={refreshMs:e=>`poll every ${e} ms`,navigations:e=>`${e} navigations`,formTimeline:e=>`${e} form events`,httpCalls:e=>`${e} HTTP calls`,changeLog:e=>`${e} NgRx changes`,cdCycles:e=>`${e} change detection cycles`,capacitorCalls:e=>`${e} Capacitor plugin calls`,idleAfterMs:e=>e?`idle ${e/1e3} s after the last agent call`:`never idle`};function wE(e){let t=[],n=(e,n)=>{n.length&&t.push({label:e,value:n.join(`, `)})},r=VT.filter(t=>e.inspectors[t]);return n(`Inspectors off`,VT.filter(t=>!e.inspectors[t]).map(e=>xE[e])),n(`Agent`,e.agent.readOnly?[`Read-only`]:[]),n(`Hidden from the agent`,r.filter(t=>!e.agent.tools[t]).map(e=>xE[e])),n(`Blocked actions`,WT.filter(t=>e.inspectors[t]&&!e.actions[t]).map(e=>SE[e])),n(`Extra secret names`,e.redaction.secretNames),n(`Unmasked names`,e.redaction.unmask),n(`Limits`,Object.keys(GT).filter(t=>e.limits[t]!==GT[t].default).map(t=>CE[t](e.limits[t]))),e.popup.hotkey!==`Alt+Shift+P`&&n(`Popup shortcut`,[e.popup.hotkey===!1?`Off`:e.popup.hotkey]),t}function TE(e){let t={tags:[],directives:[],text:``},n=e.toLowerCase();return n=n.replace(/<\s*([^<>\s]+)\s*>/g,(e,n)=>(t.tags.push({value:n,exact:!0}),` `)),n=n.replace(/\[\s*([^[\]\s]+)\s*\]/g,(e,n)=>(t.directives.push({value:n,exact:!0}),` `)),n=n.replace(/(^|\s)([<[])([^<>[\]\s]*)$/,(e,n,r,i)=>(i&&(r===`<`?t.tags:t.directives).push({value:i,exact:!1}),n)),t.text=n.replace(/\s+/g,` `).trim(),t}function EE(e){return!e.tags.length&&!e.directives.length&&!e.text}function DE(e,t){let n=e.tag.toLowerCase(),r=(e.directives??[]).map(e=>e.toLowerCase()),i=(e.attributes??[]).map(e=>e.toLowerCase()),a=[...r,...r.map(e=>e.replace(/directive$/,``)),...i];for(let{value:e,exact:r}of t.tags)if(r?n!==e:!n.startsWith(e))return!1;for(let{value:e,exact:n}of t.directives)if(!a.some(t=>n?t===e:t.includes(e)))return!1;if(t.text){let a=t.text;if(!(e.name.toLowerCase().includes(a)||n.includes(a)||r.some(e=>e.includes(a))||i.some(e=>e.includes(a))))return!1}return!0}var OE={debugApi:{subject:`Live data`,since:`12.0`},injectorProviders:{subject:`Reading providers and environment injectors`,since:`16.2`},injectorMetadata:{subject:`The full injector tree`,since:`17.0`},isSignal:{subject:`Telling signals apart in component values`,since:`17.1`},signalGraph:{subject:`The live signal graph`,since:`20.1`},deferBlocks:{subject:`Listing @defer blocks`,since:`19.1`},forBlocks:{subject:`Listing @for blocks`,since:`22.0`},profiler:{subject:`Recording change detection`,since:`20.0`},angularProfiling:{subject:`Angular profiling`,since:`20.0`},routerInstance:{subject:`The router debug util`,since:`20.3`}};function kE(e){let t=/^(\d+)\.(\d+)/.exec(e.trim());return t?`${t[1]}.${t[2]}`:e.trim()}function AE(e){let t=/^(\d+)(?:\.(\d+))?/.exec(e.trim());return t?[Number(t[1]),Number(t[2]??0)]:null}function jE(e,t){let n=AE(e),r=AE(t);return!n||!r?!1:n[0]===r[0]?n[1]>=r[1]:n[0]>r[0]}function ME(e,t){return e?.capabilities?.[t]===!1}function NE(e,t){let n=OE[e],r=`${n.subject} needs Angular ${n.since} or later`;if(!t)return`${r}; this page's Angular version is unknown.`;let i=kE(t);return jE(t,n.since)?`${r} in a development build; this page runs Angular ${i} without it, which usually means a production build.`:`${r}; this page runs Angular ${i}.`}var PE=`pangular-page-id`,FE=null;function IE(e){FE=e}function LE(){if(FE)return FE;try{return new URLSearchParams(location.search).get(`pageId`)||(window.top===window?null:sessionStorage.getItem(PE)||null)}catch{return null}}function RE(e,t){if(t.chosen&&e[t.chosen])return t.chosen;if(t.host)return t.host;if(t.previous&&e[t.previous])return t.previous;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n?.pageId??null}function zE(e,t){return e?t?e.pages?.[t]??null:e:null}function BE(e,t){return e?t?e.pages?.[t]??null:e.graph??null:null}function VE(e,t,n){return e?e.scope(`pangular`).rpc.call(t,...n===void 0?[]:[n]):Promise.resolve(null)}function HE(e,t,n){return VE(e,t,n).then(e=>e,()=>null)}function UE(e){return e?.connectionMeta.backend===`static`}function WE(e){let t=()=>{let t=e()?.scope(`pangular`).rpc;t&&(t.callEvent(`request-page-highlight`,null),t.callEvent(`request-form-highlight`,null))};return addEventListener(`pagehide`,t),()=>{removeEventListener(`pagehide`,t),t()}}function GE(e){return e.split(`@`)[1]??``}var KE={signal:`Signal Forms`,reactive:`Reactive`,template:`Template-driven`},qE={own:`validator`,directive:`template attribute`,tree:`cross-field rule`,async:`async`,parse:`parse`,submission:`server`,schema:`schema`,manual:`setErrors`},JE=HE,YE={key:`name looks secret`,"input-type":`password input`,autocomplete:`autocomplete is a secret kind`,marker:`marked as mask`,parent:`inside a secret group`,config:`listed in mask`};function XE(e){return YE[e]??e}var ZE=`https://pangular-inspector.dev/security/#opt-fields-in-or-out`;async function QE(e,t){return await JE(e,`request-form-action`,t)??{ok:!1,error:`The devtools server did not answer.`}}function $E(e){return`${e.ok?e.message??`Done.`:e.error??`Failed.`}${e.skipped?.length?` Skipped: ${e.skipped.map(e=>`${e.path} (${e.reason})`).join(`, `)}.`:``}${e.status?` Status: ${e.status}.`:``}`}var eD=/"(?:[^"\\\n]|\\.)*"|`([^`\n]*)`|\*\*/g;function tD(e){return(e??``).replace(/^_Labels, paths.*_\n\n/,``).replace(eD,(e,t)=>t??(e===`**`?``:e))}function nD(e){return yE(e?.connectionMeta)}function rD(e,t){return nD(e).actions[t]}var iD={components:`components`,routes:`router`,signals:`signals`,injectors:`injectors`,store:`ngrx`,forms:`forms`,pipes:`pipes`,network:`http`,analog:`analog`,capacitor:`capacitor`,errors:`errors`};function aD(e){return iD[e]}var oD=`https://pangular-inspector.dev/getting-started/configuration/#inspectors-and-agent-tools`;function sD(e,t){let n=iD[e];return!n||t.inspectors[n]}function cD(e,t){e&1&&(D(),Vg(0,`rect`,4)(1,`rect`,5)(2,`rect`,6)(3,`rect`,7))}function lD(e,t){e&1&&(D(),Vg(0,`path`,8)(1,`circle`,9)(2,`circle`,10)(3,`path`,11))}function uD(e,t){e&1&&(D(),Vg(0,`path`,12)(1,`path`,13)(2,`path`,14))}function dD(e,t){e&1&&(D(),Vg(0,`circle`,15)(1,`path`,16)(2,`circle`,17))}function fD(e,t){e&1&&(D(),Vg(0,`path`,1))}function pD(e,t){e&1&&(D(),Vg(0,`path`,18)(1,`path`,19)(2,`path`,20)(3,`path`,21))}function mD(e,t){e&1&&(D(),Vg(0,`ellipse`,22)(1,`path`,23)(2,`path`,24))}function hD(e,t){e&1&&(D(),Vg(0,`rect`,25)(1,`path`,26)(2,`path`,27)(3,`path`,28))}function gD(e,t){e&1&&(D(),Vg(0,`circle`,29)(1,`path`,8)(2,`path`,30))}function _D(e,t){e&1&&(D(),Vg(0,`path`,31)(1,`path`,32)(2,`path`,33)(3,`path`,34)(4,`circle`,35))}function vD(e,t){e&1&&(D(),Vg(0,`circle`,36)(1,`path`,37))}function yD(e,t){e&1&&(D(),Vg(0,`circle`,29)(1,`path`,38)(2,`path`,39))}function bD(e,t){e&1&&(D(),Vg(0,`path`,2))}function xD(e,t){e&1&&(D(),Vg(0,`path`,3))}var SD=class e{name=$.required();static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-tab-icon`]],inputs:{name:[1,`name`]},decls:15,vars:1,consts:[[`viewBox`,`0 0 24 24`,`width`,`16`,`height`,`16`,`fill`,`none`,`stroke`,`currentColor`,`stroke-width`,`1.8`,`stroke-linecap`,`round`,`stroke-linejoin`,`round`,`aria-hidden`,`true`],[`d`,`M22 12h-4l-3 9L9 3l-3 9H2`],[`d`,`m8 3 4 8 5-5 5 15H2L8 3z`],[`fill`,`currentColor`,`stroke`,`none`,`transform`,`translate(1.8 1.8) scale(0.85)`,`d`,`M24 3.7l-5.766 5.766 5.725 5.736-3.713 3.712L5.073 3.742 8.786.03l5.736 5.726L20.284 0 24 3.7zM.029 8.785l3.713-3.713 15.173 15.173-3.713 3.714-5.732-5.726L3.7 24 0 20.285l5.754-5.764L.029 8.785z`],[`x`,`3`,`y`,`3`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`14`,`y`,`3`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`x`,`14`,`y`,`12`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`3`,`y`,`16`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`d`,`M3 12h18`],[`cx`,`7`,`cy`,`12`,`r`,`2`],[`cx`,`14`,`cy`,`12`,`r`,`2`],[`d`,`M18 7v10`],[`d`,`M12 2 3 7l9 5 9-5-9-5Z`],[`d`,`m3 12 9 5 9-5`],[`d`,`m3 17 9 5 9-5`],[`cx`,`6`,`cy`,`19`,`r`,`3`],[`d`,`M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15`],[`cx`,`18`,`cy`,`5`,`r`,`3`],[`d`,`M12 22v-5`],[`d`,`M9 8V2`],[`d`,`M15 8V2`],[`d`,`M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z`],[`cx`,`12`,`cy`,`5`,`rx`,`9`,`ry`,`3`],[`d`,`M3 5v14a9 3 0 0 0 18 0V5`],[`d`,`M3 12a9 3 0 0 0 18 0`],[`x`,`3`,`y`,`4`,`width`,`18`,`height`,`16`,`rx`,`2`],[`d`,`M7 9h10`],[`d`,`M7 13h6`],[`d`,`M7 17h8`],[`cx`,`12`,`cy`,`12`,`r`,`9`],[`d`,`M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18Z`],[`d`,`M4 7h10`],[`d`,`M4 17h6`],[`d`,`m14 13 4 4-4 4`],[`d`,`M10 17h8`],[`cx`,`18`,`cy`,`7`,`r`,`3`],[`cx`,`12`,`cy`,`12`,`r`,`3`],[`d`,`M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z`],[`d`,`M12 7v6`],[`d`,`M12 16.5v.01`]],template:function(e,t){if(e&1&&(D(),B(0,`svg`,0),M(1,cD,4,0)(2,lD,4,0)(3,uD,3,0)(4,dD,3,0)(5,fD,1,0,`:svg:path`,1)(6,pD,4,0)(7,mD,3,0)(8,hD,4,0)(9,gD,3,0)(10,_D,5,0)(11,vD,2,0)(12,yD,3,0)(13,bD,1,0,`:svg:path`,2)(14,xD,1,0,`:svg:path`,3),V()),e&2){let e;k(),N((e=t.name())===`dashboard`?1:e===`timeline`?2:e===`components`?3:e===`routes`?4:e===`signals`?5:e===`injectors`?6:e===`store`?7:e===`forms`?8:e===`network`?9:e===`pipes`?10:e===`settings`?11:e===`errors`?12:e===`analog`?13:e===`capacitor`?14:-1)}},styles:[`[_nghost-%COMP%] { display: inline-flex; flex-shrink: 0; -}`]})},SD=(e,t)=>t.tab,CD=(e,t)=>t.label;function wD(e,t){e&1&&J(0),e&2&&X(` `,G().meta()?.projectName,` `)}function TD(e,t){e&1&&J(0,` Project details unavailable `)}function ED(e,t){e&1&&J(0,` Loading… `)}function DD(e,t){e&1&&(J(0,` Run `),L(1,`code`),J(2,`pangular build`),R(),J(3,` again to rebuild the report. `))}function OD(e,t){e&1&&J(0,` Check that the dev server is running. `)}function kD(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return E(e),D(G(2).loadMeta())}),J(1,`Try again`),R()}}function AD(e,t){if(e&1&&(L(0,`p`,10),M(1,DD,4,0)(2,OD,1,0),R(),M(3,kD,2,0,`button`,11)),e&2){let e=G();A(),N(e.staticReport()?1:2),A(2),N(e.staticReport()?-1:3)}}function jD(e,t){e&1&&(L(0,`li`,5)(1,`span`),J(2,`Analog`),R(),J(3),R()),e&2&&(A(3),Y(t))}function MD(e,t){e&1&&(L(0,`li`)(1,`span`),J(2,`Change detection`),R(),J(3),R()),e&2&&(A(3),Y(t))}function ND(e,t){if(e&1&&(L(0,`span`,19),J(1),R(),L(2,`span`,20),J(3),R()),e&2){let e=G().$implicit,t=G();A(),Y(t.cards()[e.tab]?.value),A(2),Y(t.cards()[e.tab]?.sub)}}function PD(e,t){e&1&&(L(0,`span`,21),J(1,`–`),R(),L(2,`span`,20),J(3,`Count unavailable`),R())}function FD(e,t){e&1&&(z(0,`span`,22),L(1,`span`,20),J(2,`Counting…`),R())}function ID(e,t){if(e&1){let e=H();L(0,`button`,13),U(`click`,function(){let t=E(e).$implicit;return D(G().navigate.emit(t.tab))}),L(1,`span`,14)(2,`span`,15),z(3,`app-tab-icon`,16),R(),L(4,`span`,17),J(5,`→`),R()(),L(6,`span`,18),J(7),R(),M(8,ND,4,2)(9,PD,4,0)(10,FD,3,0),R()}if(e&2){let e,n=t.$implicit,r=t.$index,i=G().stateOf(n.tab);K(`animation-delay`,60*r,`ms`),j(`aria-busy`,i===`loading`),A(3),I(`name`,n.tab),A(4),Y(n.label),A(),N((e=i)===`ready`?8:e===`error`?9:10)}}function LD(e,t){e&1&&(L(0,`p`),J(1,`Loading…`),R())}function RD(e,t){if(e&1&&(L(0,`div`)(1,`dt`),J(2),R(),L(3,`dd`),J(4),R()()),e&2){let e=t.$implicit;A(2),Y(e.label),A(2),Y(e.value)}}function zD(e,t){if(e&1&&(L(0,`dl`),P(1,RD,5,2,`div`,null,CD),R()),e&2){let e=G();A(),F(e.configItems())}}function BD(e,t){e&1&&(L(0,`p`),J(1,`Defaults`),R())}var VD=[{tab:`components`,label:`Components`},{tab:`routes`,label:`Routes`},{tab:`signals`,label:`Signals`},{tab:`injectors`,label:`Injectors`},{tab:`store`,label:`NgRx declarations`},{tab:`pipes`,label:`Pipes`},{tab:`forms`,label:`Forms`},{tab:`network`,label:`SSR & HTTP`}];function HD(e){return VD.filter(t=>oD(t.tab,e))}var UD={zoneless:`Zoneless`,zone:`zone.js`,"zone-unused":`Zoneless, zone.js loaded`};function WD(e){return e&&Object.hasOwn(UD,e)?UD[e]:null}var GD=new Set([`signal`,`computed`,`linkedSignal`,`effect`]),KD={action:[`action`,`actions`],reducer:[`reducer`,`reducers`],effect:[`effect`,`effects`],selector:[`selector`,`selectors`],feature:[`feature`,`features`],"store-setup":[`setup call`,`setup calls`],"signal-store":[`signal store`,`signal stores`],"signal-state":[`signal state`,`signal states`],"signal-method":[`signal method`,`signal methods`]};function qD(e,t,n){return`${e} ${e===1?t:n}`}function JD(e,t){for(let n of e??[])t(n),JD(n.children,t)}function YD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`discovered in source`};let t=e.filter(e=>e.kind===`directive`).length;return{value:e.length-t,sub:`components · ${qD(t,`directive`,`directives`)}`}}function XD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`route entries in source`};let t=e.filter(e=>e.kind===`redirect`).length;return{value:new Set(e.filter(e=>e.kind===`page`).map(e=>e.fullPath??e.path??``)).size,sub:`navigable paths · ${qD(t,`redirect`,`redirects`)}`}}function ZD(e){let t=new Map;for(let n of e)n.kind&&t.set(n.kind,(t.get(n.kind)??0)+1);if(!t.size)return{value:e.length,sub:`declarations in source`};let n=[...t].sort((e,t)=>t[1]-e[1]).map(([e,t])=>{let[n,r]=KD[e]??[e,e];return qD(t,n,r)});return{value:e.length,sub:n.join(` · `)}}function QD(e,t){let n=e?.forms??[],r=t?n.filter(e=>WE(e.id)===t):n;if(!r.length)return{value:0,sub:`no forms on the page yet`};let i=r.filter(e=>e.root?.status===`INVALID`).length;return{value:r.length,sub:`${r.length===1?`form`:`forms`} · ${i} invalid`}}function $D(e){return e.cancelled||e.status===void 0?!1:e.status===0||e.status>=400}function eO(e,t){let n=e?.pages??[],r=t?n.find(e=>e.pageId===t)??null:n.reduce((e,t)=>!e||t.reportedAt>e.reportedAt?t:e,null),i=t&&!r?[]:e?.serverCalls??[],a=r?.initialUrl,o=[...a?i.filter(e=>!e.pageUrl||e.pageUrl===a):i,...r?.calls??[]];if(!o.length)return{value:0,sub:`no calls recorded yet`};let s=o.filter($D).length;return{value:o.length,sub:`${o.length===1?`call`:`calls`} · ${s} failed`}}var tO=class e{rpc=$(null);navigate=Rv();staticReport=Q(()=>HE(this.rpc()));meta=k(null);config=Q(()=>tD(this.rpc()));stats=Q(()=>this.rpc()?HD(this.config()):[]);configItems=Q(()=>CE(this.config()));metaState=k(`loading`);states=k({});rows=k({});injectorTree=k(null);signalGraph=k(null);formsState=k(null);httpState=k(null);pageId=IE();destroyRef=w(Es);stopLive=[];zone=Q(()=>WD(RE(this.injectorTree(),this.pageId)?.zone));liveInjectors=Q(()=>{let e=RE(this.injectorTree(),this.pageId);if(!e?.roots?.length)return null;let t=0,n=0,r=e=>{t++,n+=e.providers?.length??0};return JD(e.roots,r),JD(e.environment,r),{injectors:t,providers:n}});liveSignals=Q(()=>{let e=zE(this.signalGraph(),this.pageId);return e?.nodes?.length?e.nodes.filter(e=>GD.has(e.kind??``)).length:null});cards=Q(()=>{let e=this.rows(),t={};if(e.components&&(t.components=YD(e.components)),e.routes&&(t.routes=XD(e.routes)),e.store&&(t.store=ZD(e.store)),e.pipes){let n=e.pipes.filter(e=>e.builtin).length;t.pipes={value:e.pipes.length-n,sub:n?`custom pipes · ${n} built-in in use`:`custom pipes in source`}}let n=this.liveSignals();n===null?e.signals&&(t.signals={value:e.signals.length,sub:`signal declarations in source`}):t.signals={value:n,sub:e.signals?`live on the page · ${e.signals.length} declared in source`:`live on the page`};let r=this.liveInjectors();r?t.injectors={value:r.injectors,sub:`live injectors · ${qD(r.providers,`provider`,`providers`)}`}:e.injectors&&(t.injectors={value:e.injectors.filter(e=>e.type!==`injection`).length,sub:`provider declarations in source`});let i=this.formsState();i&&(t.forms=QD(i,this.pageId));let a=this.httpState();return a&&(t.network=eO(a,this.pageId)),t});loadMeta(e=this.rpc()){e&&(this.metaState.set(`loading`),e.scope(`pangular`).rpc.call(`build-meta`).then(t=>{this.rpc()===e&&(this.meta.set(t),this.metaState.set(`ready`))}).catch(()=>{this.rpc()===e&&this.metaState.set(`error`)}))}constructor(){pc(()=>{let e=this.rpc();if(!e)return;let t=e.scope(`pangular`);this.states.set({}),this.rows.set({}),this.formsState.set(null),this.httpState.set(null),this.loadMeta(e);let n=tD(e),r=e=>oD(e,n);r(`components`)&&this.load(t.rpc.call(`get-components`),`components`),r(`routes`)&&this.load(t.rpc.call(`get-routes`),`routes`),r(`signals`)&&this.load(t.rpc.call(`get-signals`),`signals`),r(`injectors`)&&this.load(t.rpc.call(`get-providers`),`injectors`),r(`store`)&&this.load(t.rpc.call(`get-ngrx-store`),`store`),r(`pipes`)&&this.load(t.rpc.call(`get-pipes`),`pipes`),this.watchLive(e,n)}),this.destroyRef.onDestroy(()=>this.unwatch())}stateOf(e){return(e===`signals`?this.liveSignals():e===`injectors`?this.liveInjectors():null)===null?this.states()[e]??`loading`:`ready`}load(e,t){let n=e=>this.states.update(n=>({...n,[t]:e}));e.then(e=>{this.rows.update(n=>({...n,[t]:Array.isArray(e)?e:[]})),n(`ready`)}).catch(()=>n(`error`))}async watchLive(e,t){this.unwatch();let n=e.scope(`pangular`).rpc,r=async(t,r,i)=>{let a=e=>i&&this.states.update(t=>({...t,[i]:e}));try{let i=await n.sharedState(t);if(this.destroyRef.destroyed||this.rpc()!==e)return;r(i.value()),a(`ready`),this.stopLive.push(i.on(`updated`,e=>r(e)))}catch{if(this.destroyRef.destroyed||this.rpc()!==e)return;r(null),a(`error`)}};await Promise.all([t.inspectors.injectors&&r(`injector-tree`,e=>this.injectorTree.set(e)),t.inspectors.signals&&r(`signal-graph`,e=>this.signalGraph.set(e)),oD(`forms`,t)&&r(`forms`,e=>this.formsState.set(e??{}),`forms`),oD(`network`,t)&&r(`http`,e=>this.httpState.set(e??{}),`network`)])}unwatch(){for(let e of this.stopLive.splice(0))e()}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-dashboard`]],inputs:{rpc:[1,`rpc`]},outputs:{navigate:`navigate`},decls:33,vars:14,consts:[[`aria-labelledby`,`project-title`,1,`project`],[1,`project-head`],[1,`eyebrow`],[`id`,`project-title`],[1,`chips`],[1,`analog`],[1,`grid`],[`type`,`button`,1,`stat`,3,`animation-delay`],[`aria-labelledby`,`config-title`,1,`config`],[`id`,`config-title`],[1,`hint`],[`type`,`button`,1,`retry`],[`type`,`button`,1,`retry`,3,`click`],[`type`,`button`,1,`stat`,3,`click`],[1,`top`],[1,`icon`],[3,`name`],[`aria-hidden`,`true`,1,`go`],[1,`label`],[1,`big`],[1,`sub`],[1,`big`,`muted`],[`aria-hidden`,`true`,1,`big`,`skeleton`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`p`,2),J(3,`Project`),R(),L(4,`h2`,3),M(5,wD,1,1)(6,TD,1,0)(7,ED,1,0),R(),M(8,AD,4,2),R(),L(9,`ul`,4)(10,`li`)(11,`span`),J(12,`Angular`),R(),J(13),R(),L(14,`li`)(15,`span`),J(16,`TypeScript`),R(),J(17),R(),L(18,`li`)(19,`span`),J(20,`SSR`),R(),J(21),R(),M(22,jD,4,1,`li`,5),M(23,MD,4,1,`li`),R()(),L(24,`div`,6),P(25,ID,11,6,`button`,7,SD),R(),L(27,`section`,8)(28,`h2`,9),J(29,`Configuration`),R(),M(30,LD,2,0,`p`)(31,zD,3,0,`dl`)(32,BD,2,0,`p`),R()),e&2){let e,n,r;j(`aria-busy`,t.metaState()===`loading`),A(4),q(`muted`,t.metaState()!==`ready`),A(),N((e=t.metaState())===`ready`?5:e===`error`?6:7),A(3),N(t.metaState()===`error`?8:-1),A(),q(`pending`,t.metaState()===`loading`),A(4),Y(t.meta()?.angularVersion??`…`),A(4),Y(t.meta()?.typescript??`…`),A(4),Y(t.meta()?t.meta()?.ssr?`On`:`Off`:`…`),A(),N((n=t.meta()?.analog)?22:-1,n),A(),N((r=t.zone())?23:-1,r),A(2),F(t.stats()),A(2),j(`aria-busy`,!t.rpc()),A(3),N(t.rpc()?t.configItems().length?31:32:30)}},dependencies:[xD],styles:[`[_nghost-%COMP%] { +}`]})},CD=(e,t)=>t.tab,wD=(e,t)=>t.label;function TD(e,t){e&1&&J(0),e&2&&X(` `,G().meta()?.projectName,` `)}function ED(e,t){e&1&&J(0,` Project details unavailable `)}function DD(e,t){e&1&&J(0,` Loading… `)}function OD(e,t){e&1&&(J(0,` Run `),L(1,`code`),J(2,`pangular build`),R(),J(3,` again to rebuild the report. `))}function kD(e,t){e&1&&J(0,` Check that the dev server is running. `)}function AD(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return T(e),E(G(2).loadMeta())}),J(1,`Try again`),R()}}function jD(e,t){if(e&1&&(L(0,`p`,10),M(1,OD,4,0)(2,kD,1,0),R(),M(3,AD,2,0,`button`,11)),e&2){let e=G();k(),N(e.staticReport()?1:2),k(2),N(e.staticReport()?-1:3)}}function MD(e,t){e&1&&(L(0,`li`,5)(1,`span`),J(2,`Analog`),R(),J(3),R()),e&2&&(k(3),Y(t))}function ND(e,t){e&1&&(L(0,`li`)(1,`span`),J(2,`Change detection`),R(),J(3),R()),e&2&&(k(3),Y(t))}function PD(e,t){if(e&1&&(L(0,`span`,19),J(1),R(),L(2,`span`,20),J(3),R()),e&2){let e=G().$implicit,t=G();k(),Y(t.cards()[e.tab]?.value),k(2),Y(t.cards()[e.tab]?.sub)}}function FD(e,t){e&1&&(L(0,`span`,21),J(1,`–`),R(),L(2,`span`,20),J(3,`Count unavailable`),R())}function ID(e,t){e&1&&(z(0,`span`,22),L(1,`span`,20),J(2,`Counting…`),R())}function LD(e,t){if(e&1){let e=H();L(0,`button`,13),U(`click`,function(){let t=T(e).$implicit;return E(G().navigate.emit(t.tab))}),L(1,`span`,14)(2,`span`,15),z(3,`app-tab-icon`,16),R(),L(4,`span`,17),J(5,`→`),R()(),L(6,`span`,18),J(7),R(),M(8,PD,4,2)(9,FD,4,0)(10,ID,3,0),R()}if(e&2){let e,n=t.$implicit,r=t.$index,i=G().stateOf(n.tab);K(`animation-delay`,60*r,`ms`),j(`aria-busy`,i===`loading`),k(3),I(`name`,n.tab),k(4),Y(n.label),k(),N((e=i)===`ready`?8:e===`error`?9:10)}}function RD(e,t){e&1&&(L(0,`p`),J(1,`Loading…`),R())}function zD(e,t){if(e&1&&(L(0,`div`)(1,`dt`),J(2),R(),L(3,`dd`),J(4),R()()),e&2){let e=t.$implicit;k(2),Y(e.label),k(2),Y(e.value)}}function BD(e,t){if(e&1&&(L(0,`dl`),P(1,zD,5,2,`div`,null,wD),R()),e&2){let e=G();k(),F(e.configItems())}}function VD(e,t){e&1&&(L(0,`p`),J(1,`Defaults`),R())}var HD=[{tab:`components`,label:`Components`},{tab:`routes`,label:`Routes`},{tab:`signals`,label:`Signals`},{tab:`injectors`,label:`Injectors`},{tab:`store`,label:`NgRx declarations`},{tab:`pipes`,label:`Pipes`},{tab:`forms`,label:`Forms`},{tab:`network`,label:`SSR & HTTP`}];function UD(e){return HD.filter(t=>sD(t.tab,e))}var WD={zoneless:`Zoneless`,zone:`zone.js`,"zone-unused":`Zoneless, zone.js loaded`};function GD(e){return e&&Object.hasOwn(WD,e)?WD[e]:null}var KD=new Set([`signal`,`computed`,`linkedSignal`,`effect`]),qD={action:[`action`,`actions`],reducer:[`reducer`,`reducers`],effect:[`effect`,`effects`],selector:[`selector`,`selectors`],feature:[`feature`,`features`],"store-setup":[`setup call`,`setup calls`],"signal-store":[`signal store`,`signal stores`],"signal-state":[`signal state`,`signal states`],"signal-method":[`signal method`,`signal methods`]};function JD(e,t,n){return`${e} ${e===1?t:n}`}function YD(e,t){for(let n of e??[])t(n),YD(n.children,t)}function XD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`discovered in source`};let t=e.filter(e=>e.kind===`directive`).length;return{value:e.length-t,sub:`components · ${JD(t,`directive`,`directives`)}`}}function ZD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`route entries in source`};let t=e.filter(e=>e.kind===`redirect`).length;return{value:new Set(e.filter(e=>e.kind===`page`).map(e=>e.fullPath??e.path??``)).size,sub:`navigable paths · ${JD(t,`redirect`,`redirects`)}`}}function QD(e){let t=new Map;for(let n of e)n.kind&&t.set(n.kind,(t.get(n.kind)??0)+1);if(!t.size)return{value:e.length,sub:`declarations in source`};let n=[...t].sort((e,t)=>t[1]-e[1]).map(([e,t])=>{let[n,r]=qD[e]??[e,e];return JD(t,n,r)});return{value:e.length,sub:n.join(` · `)}}function $D(e,t){let n=e?.forms??[],r=t?n.filter(e=>GE(e.id)===t):n;if(!r.length)return{value:0,sub:`no forms on the page yet`};let i=r.filter(e=>e.root?.status===`INVALID`).length;return{value:r.length,sub:`${r.length===1?`form`:`forms`} · ${i} invalid`}}function eO(e){return e.cancelled||e.status===void 0?!1:e.status===0||e.status>=400}function tO(e,t){let n=e?.pages??[],r=t?n.find(e=>e.pageId===t)??null:n.reduce((e,t)=>!e||t.reportedAt>e.reportedAt?t:e,null),i=t&&!r?[]:e?.serverCalls??[],a=r?.initialUrl,o=[...a?i.filter(e=>!e.pageUrl||e.pageUrl===a):i,...r?.calls??[]];if(!o.length)return{value:0,sub:`no calls recorded yet`};let s=o.filter(eO).length;return{value:o.length,sub:`${o.length===1?`call`:`calls`} · ${s} failed`}}var nO=class e{rpc=$(null);navigate=Rv();staticReport=Q(()=>UE(this.rpc()));meta=O(null);config=Q(()=>nD(this.rpc()));stats=Q(()=>this.rpc()?UD(this.config()):[]);configItems=Q(()=>wE(this.config()));metaState=O(`loading`);states=O({});rows=O({});injectorTree=O(null);signalGraph=O(null);formsState=O(null);httpState=O(null);pageId=LE();destroyRef=C(Ds);stopLive=[];zone=Q(()=>GD(zE(this.injectorTree(),this.pageId)?.zone));liveInjectors=Q(()=>{let e=zE(this.injectorTree(),this.pageId);if(!e?.roots?.length)return null;let t=0,n=0,r=e=>{t++,n+=e.providers?.length??0};return YD(e.roots,r),YD(e.environment,r),{injectors:t,providers:n}});liveSignals=Q(()=>{let e=BE(this.signalGraph(),this.pageId);return e?.nodes?.length?e.nodes.filter(e=>KD.has(e.kind??``)).length:null});cards=Q(()=>{let e=this.rows(),t={};if(e.components&&(t.components=XD(e.components)),e.routes&&(t.routes=ZD(e.routes)),e.store&&(t.store=QD(e.store)),e.pipes){let n=e.pipes.filter(e=>e.builtin).length;t.pipes={value:e.pipes.length-n,sub:n?`custom pipes · ${n} built-in in use`:`custom pipes in source`}}let n=this.liveSignals();n===null?e.signals&&(t.signals={value:e.signals.length,sub:`signal declarations in source`}):t.signals={value:n,sub:e.signals?`live on the page · ${e.signals.length} declared in source`:`live on the page`};let r=this.liveInjectors();r?t.injectors={value:r.injectors,sub:`live injectors · ${JD(r.providers,`provider`,`providers`)}`}:e.injectors&&(t.injectors={value:e.injectors.filter(e=>e.type!==`injection`).length,sub:`provider declarations in source`});let i=this.formsState();i&&(t.forms=$D(i,this.pageId));let a=this.httpState();return a&&(t.network=tO(a,this.pageId)),t});loadMeta(e=this.rpc()){e&&(this.metaState.set(`loading`),e.scope(`pangular`).rpc.call(`build-meta`).then(t=>{this.rpc()===e&&(this.meta.set(t),this.metaState.set(`ready`))}).catch(()=>{this.rpc()===e&&this.metaState.set(`error`)}))}constructor(){mc(()=>{let e=this.rpc();if(!e)return;let t=e.scope(`pangular`);this.states.set({}),this.rows.set({}),this.formsState.set(null),this.httpState.set(null),this.loadMeta(e);let n=nD(e),r=e=>sD(e,n);r(`components`)&&this.load(t.rpc.call(`get-components`),`components`),r(`routes`)&&this.load(t.rpc.call(`get-routes`),`routes`),r(`signals`)&&this.load(t.rpc.call(`get-signals`),`signals`),r(`injectors`)&&this.load(t.rpc.call(`get-providers`),`injectors`),r(`store`)&&this.load(t.rpc.call(`get-ngrx-store`),`store`),r(`pipes`)&&this.load(t.rpc.call(`get-pipes`),`pipes`),this.watchLive(e,n)}),this.destroyRef.onDestroy(()=>this.unwatch())}stateOf(e){return(e===`signals`?this.liveSignals():e===`injectors`?this.liveInjectors():null)===null?this.states()[e]??`loading`:`ready`}load(e,t){let n=e=>this.states.update(n=>({...n,[t]:e}));e.then(e=>{this.rows.update(n=>({...n,[t]:Array.isArray(e)?e:[]})),n(`ready`)}).catch(()=>n(`error`))}async watchLive(e,t){this.unwatch();let n=e.scope(`pangular`).rpc,r=async(t,r,i)=>{let a=e=>i&&this.states.update(t=>({...t,[i]:e}));try{let i=await n.sharedState(t);if(this.destroyRef.destroyed||this.rpc()!==e)return;r(i.value()),a(`ready`),this.stopLive.push(i.on(`updated`,e=>r(e)))}catch{if(this.destroyRef.destroyed||this.rpc()!==e)return;r(null),a(`error`)}};await Promise.all([t.inspectors.injectors&&r(`injector-tree`,e=>this.injectorTree.set(e)),t.inspectors.signals&&r(`signal-graph`,e=>this.signalGraph.set(e)),sD(`forms`,t)&&r(`forms`,e=>this.formsState.set(e??{}),`forms`),sD(`network`,t)&&r(`http`,e=>this.httpState.set(e??{}),`network`)])}unwatch(){for(let e of this.stopLive.splice(0))e()}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-dashboard`]],inputs:{rpc:[1,`rpc`]},outputs:{navigate:`navigate`},decls:33,vars:14,consts:[[`aria-labelledby`,`project-title`,1,`project`],[1,`project-head`],[1,`eyebrow`],[`id`,`project-title`],[1,`chips`],[1,`analog`],[1,`grid`],[`type`,`button`,1,`stat`,3,`animation-delay`],[`aria-labelledby`,`config-title`,1,`config`],[`id`,`config-title`],[1,`hint`],[`type`,`button`,1,`retry`],[`type`,`button`,1,`retry`,3,`click`],[`type`,`button`,1,`stat`,3,`click`],[1,`top`],[1,`icon`],[3,`name`],[`aria-hidden`,`true`,1,`go`],[1,`label`],[1,`big`],[1,`sub`],[1,`big`,`muted`],[`aria-hidden`,`true`,1,`big`,`skeleton`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`p`,2),J(3,`Project`),R(),L(4,`h2`,3),M(5,TD,1,1)(6,ED,1,0)(7,DD,1,0),R(),M(8,jD,4,2),R(),L(9,`ul`,4)(10,`li`)(11,`span`),J(12,`Angular`),R(),J(13),R(),L(14,`li`)(15,`span`),J(16,`TypeScript`),R(),J(17),R(),L(18,`li`)(19,`span`),J(20,`SSR`),R(),J(21),R(),M(22,MD,4,1,`li`,5),M(23,ND,4,1,`li`),R()(),L(24,`div`,6),P(25,LD,11,6,`button`,7,CD),R(),L(27,`section`,8)(28,`h2`,9),J(29,`Configuration`),R(),M(30,RD,2,0,`p`)(31,BD,3,0,`dl`)(32,VD,2,0,`p`),R()),e&2){let e,n,r;j(`aria-busy`,t.metaState()===`loading`),k(4),q(`muted`,t.metaState()!==`ready`),k(),N((e=t.metaState())===`ready`?5:e===`error`?6:7),k(3),N(t.metaState()===`error`?8:-1),k(),q(`pending`,t.metaState()===`loading`),k(4),Y(t.meta()?.angularVersion??`…`),k(4),Y(t.meta()?.typescript??`…`),k(4),Y(t.meta()?t.meta()?.ssr?`On`:`Off`:`…`),k(),N((n=t.meta()?.analog)?22:-1,n),k(),N((r=t.zone())?23:-1,r),k(2),F(t.stats()),k(2),j(`aria-busy`,!t.rpc()),k(3),N(t.rpc()?t.configItems().length?31:32:30)}},dependencies:[SD],styles:[`[_nghost-%COMP%] { display: block; max-width: 1200px; } @@ -325,7 +325,7 @@ h2.muted[_ngcontent-%COMP%] { .skeleton[_ngcontent-%COMP%] { animation: none; } -}`]})},nO=`pangular:panel-action-result`,rO=6e3,iO=0;function aO(e=window){return e.location.protocol===`chrome-extension:`&&e.parent!==e}function oO(e,t=window){let n=`pa-${Date.now().toString(36)}-${++iO}`;return new Promise(r=>{let i=e=>{t.clearTimeout(o),t.removeEventListener(`message`,a),r(e)},a=({source:e,origin:r,data:a})=>{if(e!==t.parent||r!==t.location.origin)return;let o=a;if(o?.type!==nO||o.requestId!==n)return;let{opened:s,error:c}=a;i({ok:o.ok===!0,...s===`file`||s===`class`?{opened:s}:{},...typeof c==`string`?{error:c}:{}})},o=t.setTimeout(()=>i({ok:!1,error:`timeout`}),rO);t.addEventListener(`message`,a),t.parent.postMessage({...e,requestId:n},t.location.origin)})}var sO=class e{available=aO();reveal(e,t){return oO({type:`pangular:reveal-element`,pageId:e,id:t})}openSource(e,t,n){return oO({type:`pangular:open-source`,pageId:e,id:t,...n?{file:n.file,line:n.line}:{}})}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})};function cO(e){let t=e?.pages;return t&&typeof t==`object`?t:{}}function lO(e){let t=w(Es),n=k({}),r=null,i=null,a=async e=>{i?.(),i=null,r=e;try{let a=await e.scope(`pangular`).rpc.sharedState(`page-angular`);if(t.destroyed||r!==e)return;let o=e=>n.set(cO(e));o(a.value()),i=a.on(`updated`,o)}catch{r===e&&n.set({})}};return pc(()=>{let t=e();t&&t!==r&&Nv(()=>void a(t))}),t.onDestroy(()=>i?.()),n.asReadonly()}function uO(e,t){if(t)return e[t]??null;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n}var dO=[`*`];function fO(e,t){if(e&1&&(B(0,`div`,1)(1,`p`,2),J(2),V(),B(3,`p`,3),J(4),s_(5),B(6,`a`,4),J(7,`Supported versions`),V()()()),e&2){let e=G();q(`compact`,e.compact()),A(2),Y(e.title()),A(2),X(` `,t,` `),A(2),qg(`href`,e.docsUrl,Mu)}}var pO=`https://pangular-inspector.dev/getting-started/installation/#supported-angular-versions`,mO=class e{page=$(null);capability=$.required();missing=$(!1,{transform:oy});compact=$(!1,{transform:oy});docsUrl=pO;text=Q(()=>{let e=this.page();return!this.missing()&&!jE(e,this.capability())?null:ME(this.capability(),e?.version)});title=Q(()=>{let e=this.page()?.version;return e?`Not available on Angular ${OE(e)}`:`Not available on this page`});static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-angular-unavailable`]],inputs:{page:[1,`page`],capability:[1,`capability`],missing:[1,`missing`],compact:[1,`compact`]},ngContentSelectors:dO,decls:1,vars:1,consts:[[`role`,`status`,1,`unavailable`,3,`compact`],[`role`,`status`,1,`unavailable`],[1,`title`],[1,`hint`],[`target`,`_blank`,`rel`,`noopener noreferrer`,3,`href`]],template:function(e,t){if(e&1&&(o_(),M(0,fO,8,5,`div`,0)),e&2){let e;N((e=t.text())?0:-1,e)}},styles:[`[_nghost-%COMP%] { +}`]})},rO=`pangular:panel-action-result`,iO=6e3,aO=0;function oO(e=window){return e.location.protocol===`chrome-extension:`&&e.parent!==e}function sO(e,t=window){let n=`pa-${Date.now().toString(36)}-${++aO}`;return new Promise(r=>{let i=e=>{t.clearTimeout(o),t.removeEventListener(`message`,a),r(e)},a=({source:e,origin:r,data:a})=>{if(e!==t.parent||r!==t.location.origin)return;let o=a;if(o?.type!==rO||o.requestId!==n)return;let{opened:s,error:c}=a;i({ok:o.ok===!0,...s===`file`||s===`class`?{opened:s}:{},...typeof c==`string`?{error:c}:{}})},o=t.setTimeout(()=>i({ok:!1,error:`timeout`}),iO);t.addEventListener(`message`,a),t.parent.postMessage({...e,requestId:n},t.location.origin)})}var cO=class e{available=oO();reveal(e,t){return sO({type:`pangular:reveal-element`,pageId:e,id:t})}openSource(e,t,n){return sO({type:`pangular:open-source`,pageId:e,id:t,...n?{file:n.file,line:n.line}:{}})}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})};function lO(e){let t=e?.pages;return t&&typeof t==`object`?t:{}}function uO(e){let t=C(Ds),n=O({}),r=null,i=null,a=async e=>{i?.(),i=null,r=e;try{let a=await e.scope(`pangular`).rpc.sharedState(`page-angular`);if(t.destroyed||r!==e)return;let o=e=>n.set(lO(e));o(a.value()),i=a.on(`updated`,o)}catch{r===e&&n.set({})}};return mc(()=>{let t=e();t&&t!==r&&Nv(()=>void a(t))}),t.onDestroy(()=>i?.()),n.asReadonly()}function dO(e,t){if(t)return e[t]??null;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n}var fO=[`*`];function pO(e,t){if(e&1&&(B(0,`div`,1)(1,`p`,2),J(2),V(),B(3,`p`,3),J(4),s_(5),B(6,`a`,4),J(7,`Supported versions`),V()()()),e&2){let e=G();q(`compact`,e.compact()),k(2),Y(e.title()),k(2),X(` `,t,` `),k(2),qg(`href`,e.docsUrl,Nu)}}var mO=`https://pangular-inspector.dev/getting-started/installation/#supported-angular-versions`,hO=class e{page=$(null);capability=$.required();missing=$(!1,{transform:oy});compact=$(!1,{transform:oy});docsUrl=mO;text=Q(()=>{let e=this.page();return!this.missing()&&!ME(e,this.capability())?null:NE(this.capability(),e?.version)});title=Q(()=>{let e=this.page()?.version;return e?`Not available on Angular ${kE(e)}`:`Not available on this page`});static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-angular-unavailable`]],inputs:{page:[1,`page`],capability:[1,`capability`],missing:[1,`missing`],compact:[1,`compact`]},ngContentSelectors:fO,decls:1,vars:1,consts:[[`role`,`status`,1,`unavailable`,3,`compact`],[`role`,`status`,1,`unavailable`],[1,`title`],[1,`hint`],[`target`,`_blank`,`rel`,`noopener noreferrer`,3,`href`]],template:function(e,t){if(e&1&&(o_(),M(0,pO,8,5,`div`,0)),e&2){let e;N((e=t.text())?0:-1,e)}},styles:[`[_nghost-%COMP%] { display: block; } @@ -372,7 +372,7 @@ a[_ngcontent-%COMP%] { a[_ngcontent-%COMP%]:focus-visible { outline: 2px solid var(--%NS%accent); outline-offset: 2px; -}`]})};function hO(e){return e?.platform===`angular-native`}function gO(e){return hO(e)||e?.platform===`nativescript`}function _O(e,t){let n=Object.values(e??{}).filter(hO);if(t&&n.some(e=>e.pageId===t))return t;let r=null;for(let e of n)(!r||e.reportedAt>r.reportedAt)&&(r=e);return r?.pageId??null}var vO=[`trigger`],yO=[`list`],bO=(e,t)=>t.value;function xO(e,t){if(e&1&&(B(0,`span`,4),J(1),V()),e&2){let e=G();A(),Y(e.current().hint)}}function SO(e,t){if(e&1&&(B(0,`span`,15),J(1),V()),e&2){let e=G().$implicit;A(),Y(e.hint)}}function CO(e,t){if(e&1){let e=H();B(0,`li`,11),W(`pointerenter`,function(){let t=E(e).$index;return D(G(2).active.set(t))})(`pointerdown`,function(e){return e.preventDefault()})(`click`,function(){let t=E(e).$index;return D(G(2).choose(t))}),O(),B(1,`svg`,12),Vg(2,`path`,13),V(),gs(),B(3,`span`,14),J(4),V(),M(5,SO,2,1,`span`,15),V()}if(e&2){let e=t.$implicit,n=t.$index,r=G(2);q(`active`,n===r.active())(`selected`,e.value===r.value()),j(`id`,r.uid+`-opt-`+n)(`aria-selected`,e.value===r.value())(`aria-disabled`,e.disabled||null),A(4),Y(e.label),A(),N(e.hint?5:-1)}}function wO(e,t){if(e&1&&(B(0,`li`,10),J(1),V()),e&2){let e=G(2);A(),Y(e.emptyText())}}function TO(e,t){if(e&1&&(B(0,`ul`,8,1),_g(`list-in`),W(`pointerdown`,function(e){return e.preventDefault()}),P(2,CO,6,9,`li`,9,bO,!1,wO,2,1,`li`,10),V()),e&2){let e=G();q(`up`,e.dropUp()),j(`id`,e.uid+`-list`)(`aria-labelledby`,e.labelledBy()||e.uid+`-trigger`),A(2),F(e.options())}}var EO=0,DO=class e{options=$.required();value=Gv(null);placeholder=$(`Select…`);ariaLabel=$(``);labelledBy=$(``);describedBy=$(``);disabled=$(!1);emptyText=$(`Nothing to choose`);uid=`app-select-${++EO}`;open=k(!1);active=k(-1);dropUp=k(!1);current=Q(()=>this.options().find(e=>e.value===this.value())??null);host=w(Fl);injector=w(ws);trigger=Jv.required(`trigger`);list=Jv(`list`);typed=``;typedAt=0;toggle(){this.open()?this.close():this.show()}choose(e){let t=this.options()[e];t&&!t.disabled&&(this.value.set(t.value),this.close(),this.trigger().nativeElement.focus())}onKey(e){let t=this.options(),n=this.open();switch(e.key){case`ArrowDown`:case`ArrowUp`:if(e.preventDefault(),!n){this.show();return}this.move(e.key===`ArrowDown`?1:-1);return;case`Home`:case`End`:if(!n)return;e.preventDefault(),this.setActive(e.key===`Home`?this.firstEnabled(0,1):this.firstEnabled(t.length-1,-1));return;case`Enter`:case` `:e.preventDefault(),n&&this.active()>=0?this.choose(this.active()):this.show();return;case`Escape`:if(!n)return;e.preventDefault(),e.stopPropagation(),this.close();return;case`Tab`:n&&this.close();return;default:e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&this.typeAhead(e.key)}}onBlur(e){let t=e.relatedTarget;t&&this.host.nativeElement.contains(t)||this.close()}onOutside(e){this.open()&&!this.host.nativeElement.contains(e.target)&&this.close()}show(){if(this.disabled())return;let e=this.host.nativeElement.getBoundingClientRect(),t=window.innerHeight-e.bottom;this.dropUp.set(t<220&&e.top>t);let n=this.options().findIndex(e=>e.value===this.value());this.open.set(!0),this.setActive(n>=0?n:this.firstEnabled(0,1))}close(){this.open.set(!1),this.active.set(-1)}move(e){let t=this.firstEnabled(this.active()+e,e);t>=0&&this.setActive(t)}firstEnabled(e,t){let n=this.options();for(let r=e;r>=0&&r{(this.list()?.nativeElement.querySelector(`#${this.uid}-opt-${e}`))?.scrollIntoView({block:`nearest`})},{injector:this.injector})}typeAhead(e){let t=performance.now();this.typed=t-this.typedAt>600?e.toLowerCase():this.typed+e.toLowerCase(),this.typedAt=t;let n=this.options().findIndex(e=>!e.disabled&&e.label.toLowerCase().startsWith(this.typed));n<0||(this.open()?this.setActive(n):this.value.set(this.options()[n].value))}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-select`]],viewQuery:function(e,t){e&1&&l_(t.trigger,vO,5)(t.list,yO,5),e&2&&u_(2)},hostAttrs:[1,`app-select`],hostVars:2,hostBindings:function(e,t){e&1&&U(`pointerdown`,function(e){return t.onOutside(e)},Fu),e&2&&q(`open`,t.open())},inputs:{options:[1,`options`],value:[1,`value`],placeholder:[1,`placeholder`],ariaLabel:[1,`ariaLabel`],labelledBy:[1,`labelledBy`],describedBy:[1,`describedBy`],disabled:[1,`disabled`],emptyText:[1,`emptyText`]},outputs:{value:`valueChange`},decls:8,vars:13,consts:[[`trigger`,``],[`list`,``],[`type`,`button`,`role`,`combobox`,`aria-haspopup`,`listbox`,1,`trigger`,3,`click`,`keydown`,`blur`,`disabled`],[1,`value`],[1,`value-hint`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m6 9 6 6 6-6`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`up`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`pointerdown`],[`role`,`option`,3,`active`,`selected`],[`role`,`option`,`aria-disabled`,`true`,1,`empty`],[`role`,`option`,3,`pointerenter`,`pointerdown`,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`check`],[`d`,`m5 12 5 5 9-10`],[1,`label`],[1,`hint`]],template:function(e,t){e&1&&(B(0,`button`,2,0),W(`click`,function(){return t.toggle()})(`keydown`,function(e){return t.onKey(e)})(`blur`,function(e){return t.onBlur(e)}),B(2,`span`,3),J(3),V(),M(4,xO,2,1,`span`,4),O(),B(5,`svg`,5),Vg(6,`path`,6),V()(),M(7,TO,5,5,`ul`,7)),e&2&&(qg(`disabled`,t.disabled()),j(`id`,t.uid+`-trigger`)(`aria-controls`,t.uid+`-list`)(`aria-expanded`,t.open())(`aria-label`,t.ariaLabel()||null)(`aria-labelledby`,t.labelledBy()||null)(`aria-describedby`,t.describedBy()||null)(`aria-activedescendant`,t.open()&&t.active()>=0?t.uid+`-opt-`+t.active():null),A(2),q(`placeholder`,!t.current()),A(),X(` `,t.current()?.label??t.placeholder(),` `),A(),N(t.current()?.hint?4:-1),A(3),N(t.open()?7:-1))},styles:[`[_nghost-%COMP%] { +}`]})};function gO(e){return e?.platform===`angular-native`}function _O(e){return gO(e)||e?.platform===`nativescript`}function vO(e,t){let n=Object.values(e??{}).filter(gO);if(t&&n.some(e=>e.pageId===t))return t;let r=null;for(let e of n)(!r||e.reportedAt>r.reportedAt)&&(r=e);return r?.pageId??null}var yO=[`trigger`],bO=[`list`],xO=(e,t)=>t.value;function SO(e,t){if(e&1&&(B(0,`span`,4),J(1),V()),e&2){let e=G();k(),Y(e.current().hint)}}function CO(e,t){if(e&1&&(B(0,`span`,15),J(1),V()),e&2){let e=G().$implicit;k(),Y(e.hint)}}function wO(e,t){if(e&1){let e=H();B(0,`li`,11),W(`pointerenter`,function(){let t=T(e).$index;return E(G(2).active.set(t))})(`pointerdown`,function(e){return e.preventDefault()})(`click`,function(){let t=T(e).$index;return E(G(2).choose(t))}),D(),B(1,`svg`,12),Vg(2,`path`,13),V(),_s(),B(3,`span`,14),J(4),V(),M(5,CO,2,1,`span`,15),V()}if(e&2){let e=t.$implicit,n=t.$index,r=G(2);q(`active`,n===r.active())(`selected`,e.value===r.value()),j(`id`,r.uid+`-opt-`+n)(`aria-selected`,e.value===r.value())(`aria-disabled`,e.disabled||null),k(4),Y(e.label),k(),N(e.hint?5:-1)}}function TO(e,t){if(e&1&&(B(0,`li`,10),J(1),V()),e&2){let e=G(2);k(),Y(e.emptyText())}}function EO(e,t){if(e&1&&(B(0,`ul`,8,1),_g(`list-in`),W(`pointerdown`,function(e){return e.preventDefault()}),P(2,wO,6,9,`li`,9,xO,!1,TO,2,1,`li`,10),V()),e&2){let e=G();q(`up`,e.dropUp()),j(`id`,e.uid+`-list`)(`aria-labelledby`,e.labelledBy()||e.uid+`-trigger`),k(2),F(e.options())}}var DO=0,OO=class e{options=$.required();value=Gv(null);placeholder=$(`Select…`);ariaLabel=$(``);labelledBy=$(``);describedBy=$(``);disabled=$(!1);emptyText=$(`Nothing to choose`);uid=`app-select-${++DO}`;open=O(!1);active=O(-1);dropUp=O(!1);current=Q(()=>this.options().find(e=>e.value===this.value())??null);host=C(Il);injector=C(Ts);trigger=Jv.required(`trigger`);list=Jv(`list`);typed=``;typedAt=0;toggle(){this.open()?this.close():this.show()}choose(e){let t=this.options()[e];t&&!t.disabled&&(this.value.set(t.value),this.close(),this.trigger().nativeElement.focus())}onKey(e){let t=this.options(),n=this.open();switch(e.key){case`ArrowDown`:case`ArrowUp`:if(e.preventDefault(),!n){this.show();return}this.move(e.key===`ArrowDown`?1:-1);return;case`Home`:case`End`:if(!n)return;e.preventDefault(),this.setActive(e.key===`Home`?this.firstEnabled(0,1):this.firstEnabled(t.length-1,-1));return;case`Enter`:case` `:e.preventDefault(),n&&this.active()>=0?this.choose(this.active()):this.show();return;case`Escape`:if(!n)return;e.preventDefault(),e.stopPropagation(),this.close();return;case`Tab`:n&&this.close();return;default:e.key.length===1&&!e.metaKey&&!e.ctrlKey&&!e.altKey&&this.typeAhead(e.key)}}onBlur(e){let t=e.relatedTarget;t&&this.host.nativeElement.contains(t)||this.close()}onOutside(e){this.open()&&!this.host.nativeElement.contains(e.target)&&this.close()}show(){if(this.disabled())return;let e=this.host.nativeElement.getBoundingClientRect(),t=window.innerHeight-e.bottom;this.dropUp.set(t<220&&e.top>t);let n=this.options().findIndex(e=>e.value===this.value());this.open.set(!0),this.setActive(n>=0?n:this.firstEnabled(0,1))}close(){this.open.set(!1),this.active.set(-1)}move(e){let t=this.firstEnabled(this.active()+e,e);t>=0&&this.setActive(t)}firstEnabled(e,t){let n=this.options();for(let r=e;r>=0&&r{(this.list()?.nativeElement.querySelector(`#${this.uid}-opt-${e}`))?.scrollIntoView({block:`nearest`})},{injector:this.injector})}typeAhead(e){let t=performance.now();this.typed=t-this.typedAt>600?e.toLowerCase():this.typed+e.toLowerCase(),this.typedAt=t;let n=this.options().findIndex(e=>!e.disabled&&e.label.toLowerCase().startsWith(this.typed));n<0||(this.open()?this.setActive(n):this.value.set(this.options()[n].value))}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-select`]],viewQuery:function(e,t){e&1&&l_(t.trigger,yO,5)(t.list,bO,5),e&2&&u_(2)},hostAttrs:[1,`app-select`],hostVars:2,hostBindings:function(e,t){e&1&&U(`pointerdown`,function(e){return t.onOutside(e)},Iu),e&2&&q(`open`,t.open())},inputs:{options:[1,`options`],value:[1,`value`],placeholder:[1,`placeholder`],ariaLabel:[1,`ariaLabel`],labelledBy:[1,`labelledBy`],describedBy:[1,`describedBy`],disabled:[1,`disabled`],emptyText:[1,`emptyText`]},outputs:{value:`valueChange`},decls:8,vars:13,consts:[[`trigger`,``],[`list`,``],[`type`,`button`,`role`,`combobox`,`aria-haspopup`,`listbox`,1,`trigger`,3,`click`,`keydown`,`blur`,`disabled`],[1,`value`],[1,`value-hint`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m6 9 6 6 6-6`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`up`],[`role`,`listbox`,`tabindex`,`-1`,1,`list`,3,`pointerdown`],[`role`,`option`,3,`active`,`selected`],[`role`,`option`,`aria-disabled`,`true`,1,`empty`],[`role`,`option`,3,`pointerenter`,`pointerdown`,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`check`],[`d`,`m5 12 5 5 9-10`],[1,`label`],[1,`hint`]],template:function(e,t){e&1&&(B(0,`button`,2,0),W(`click`,function(){return t.toggle()})(`keydown`,function(e){return t.onKey(e)})(`blur`,function(e){return t.onBlur(e)}),B(2,`span`,3),J(3),V(),M(4,SO,2,1,`span`,4),D(),B(5,`svg`,5),Vg(6,`path`,6),V()(),M(7,EO,5,5,`ul`,7)),e&2&&(qg(`disabled`,t.disabled()),j(`id`,t.uid+`-trigger`)(`aria-controls`,t.uid+`-list`)(`aria-expanded`,t.open())(`aria-label`,t.ariaLabel()||null)(`aria-labelledby`,t.labelledBy()||null)(`aria-describedby`,t.describedBy()||null)(`aria-activedescendant`,t.open()&&t.active()>=0?t.uid+`-opt-`+t.active():null),k(2),q(`placeholder`,!t.current()),k(),X(` `,t.current()?.label??t.placeholder(),` `),k(),N(t.current()?.hint?4:-1),k(3),N(t.open()?7:-1))},styles:[`[_nghost-%COMP%] { position: relative; display: inline-flex; min-width: 0; @@ -567,7 +567,7 @@ li.selected[_ngcontent-%COMP%] .check[_ngcontent-%COMP%] { .chevron[_ngcontent-%COMP%] { transition: none; } -}`]})};function OO(e,t){let n=wE(t);if(TE(n))return{nodes:e,matches:0};let r=0,i=e=>e.flatMap(e=>{let t=EE(e,n);t&&r++;let a=i(e.children);return t||a.length?[{...e,children:a}]:[]});return{nodes:i(e),matches:r}}function kO(e){return e.flatMap(e=>e.kind===`directive`?kO(e.children):[{...e,children:kO(e.children)}])}function AO(e){return(e.attributes?.length?e.attributes:e.directives??[e.name]).map(e=>`[${e}]`).join(` `)}var jO={hydrated:`Hydrated`,skipped:`Skipped`,mismatched:`Mismatch`,client:`Client`};function MO(e){return jO[e]}function NO(e,t,n,r=!1,i=0){let a=r?`${e}+`:`${e}`;if(n)return`${t} of ${r?`${e+i}+`:e+i}`;let o=i?` · ${i} directive ${i===1?`host`:`hosts`}`:``;return`${a} ${e===1&&!r?`instance`:`instances`}${o}`}function PO(e,t,n,r=!1,i=0){if(!n.trim())return``;if(!t)return`No components match.`;let a=e+i,o=r?`${a}+`:`${a}`,s=!r&&a===1;return`${t} of ${o} ${i?s?`row`:`rows`:s?`instance`:`instances`} match.`}function FO(e){let t=e?.components,n=e?.depth;return t&&n?`Showing the first ${t} component instances, and none nested more than ${n} elements deep. Others are not listed or searchable.`:t?`Showing the first ${t} component instances. Others are not listed or searchable.`:n?`Components nested more than ${n} elements deep are not listed or searchable.`:`The page has more components than the tree shows.`}function IO(e,t){let n=t?.detail?.id??null,r=t?.pageId??null;if(r!==e.pageId)return{pageId:r,selectedId:n,detailId:n,destroyed:null};let i=e.selectedId;return n&&n!==e.detailId&&n!==i&&(i=n),i&&t&&!t.truncated&&!LO(t.roots,i)?{pageId:r,selectedId:null,detailId:n,destroyed:i}:{pageId:r,selectedId:i,detailId:n,destroyed:null}}function LO(e,t){return e.some(e=>e.id===t||LO(e.children,t))}function RO(e,t,n){let r=e.indexOf(n);if(r<0)return null;for(let n=r+1;n=0;n--)if(t.has(e[n]))return e[n];return null}var zO=(e,t)=>t.key,BO=(e,t)=>t.id;function VO(e,t){e&1&&(B(0,`p`,2),J(1,` The HTML came from the server, but no component was hydrated, so the app rendered again on the client. Add `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,` and use a development build to see each component's status. `),V())}function HO(e,t){if(e&1&&(B(0,`li`)(1,`span`,9),J(2),V(),J(3),V()),e&2){let e=t.$implicit;M_(`count count-`+e.key),A(2),Y(e.value),A(),X(` `,e.label,` `)}}function UO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Expected `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;A(3),Y(e.expected)}}function WO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Found `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;A(3),Y(e.actual)}}function GO(e,t){if(e&1){let e=H();B(0,`li`)(1,`button`,12),W(`click`,function(){let t=E(e).$implicit;return D(G(4).showNode.emit(t.id))})(`focus`,function(){let t=E(e).$implicit;return D(G(4).highlight.emit(t.id))})(`blur`,function(){return E(e),D(G(4).highlight.emit(null))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(4).highlight.emit(t.id))})(`mouseleave`,function(){return E(e),D(G(4).highlight.emit(null))}),B(2,`span`,13),J(3),V(),B(4,`span`,14),J(5),V(),M(6,UO,4,1,`span`,15),M(7,WO,4,1,`span`,15),V()()}if(e&2){let e=t.$implicit;A(3),Y(e.name),A(2),X(`<`,e.tag,`>`),A(),N(e.expected?6:-1),A(),N(e.actual?7:-1)}}function KO(e,t){if(e&1&&(B(0,`h3`,10),J(1,`Mismatches`),V(),B(2,`ul`,11),P(3,GO,8,4,`li`,null,BO),V()),e&2){let e=G(2);A(3),F(e.mismatches)}}function qO(e,t){if(e&1){let e=H();B(0,`div`,3)(1,`ul`,4),P(2,HO,4,4,`li`,5,zO),V(),B(4,`button`,6),W(`click`,function(){return E(e),D(G(2).toggleOverlay())}),O(),B(5,`svg`,7),Vg(6,`rect`,8),V(),J(7,` Outline on page `),V()(),M(8,KO,5,0)}if(e&2){let e=G(),t=G();A(2),F(t.counts()),A(2),j(`aria-pressed`,t.overlayOn()),A(4),N(e.mismatches.length?8:-1)}}function JO(e,t){e&1&&M(0,VO,5,0,`p`,2)(1,qO,9,2),e&2&&N(+!!t.hydrated)}function YO(e,t){e&1&&(B(0,`p`,2),J(1,` This page was not rendered on the server, so there is nothing to hydrate. With server-side rendering and `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,`, each component shows whether it was hydrated, skipped or mismatched. `),V())}var XO=class e{report=$(void 0);overlay=Rv();showNode=Rv();highlight=Rv();overlayOn=Fv(()=>this.report()?.overlay===!0);counts=Q(()=>{let e=this.report()?.counts;return e?[{key:`hydrated`,label:`hydrated`,value:e.hydrated},{key:`skipped`,label:`skipped`,value:e.skipped},{key:`mismatched`,label:`mismatched`,value:e.mismatched},{key:`client`,label:`created on the client`,value:e.client},{key:`dehydratedBlocks`,label:e.dehydratedBlocks===1?`dehydrated @defer block`:`dehydrated @defer blocks`,value:e.dehydratedBlocks}]:[]});toggleOverlay(){let e=!this.overlayOn();this.overlayOn.set(e),this.overlay.emit(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-hydration-section`]],inputs:{report:[1,`report`]},outputs:{overlay:`overlay`,showNode:`showNode`,highlight:`highlight`},decls:5,vars:1,consts:[[`aria-labelledby`,`ct-hydration-title`,1,`hydration`],[`id`,`ct-hydration-title`,1,`title`],[1,`empty`],[1,`summary`],[`aria-label`,`Hydration summary`,1,`counts`],[3,`class`],[`type`,`button`,1,`outline`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`],[`x`,`3`,`y`,`3`,`width`,`18`,`height`,`18`,`rx`,`2`,`stroke-dasharray`,`4 3`],[1,`num`],[1,`label`],[1,`mismatches`],[`type`,`button`,1,`mismatch`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`mono`,`muted`],[1,`detail-line`]],template:function(e,t){if(e&1&&(B(0,`section`,0)(1,`h2`,1),J(2,`Hydration`),V(),M(3,JO,2,1)(4,YO,5,0,`p`,2),V()),e&2){let e;A(3),N((e=t.report())?3:4,e)}},styles:[`.hydration[_ngcontent-%COMP%] { +}`]})};function kO(e,t){let n=TE(t);if(EE(n))return{nodes:e,matches:0};let r=0,i=e=>e.flatMap(e=>{let t=DE(e,n);t&&r++;let a=i(e.children);return t||a.length?[{...e,children:a}]:[]});return{nodes:i(e),matches:r}}function AO(e){return e.flatMap(e=>e.kind===`directive`?AO(e.children):[{...e,children:AO(e.children)}])}function jO(e){return(e.attributes?.length?e.attributes:e.directives??[e.name]).map(e=>`[${e}]`).join(` `)}var MO={hydrated:`Hydrated`,skipped:`Skipped`,mismatched:`Mismatch`,client:`Client`};function NO(e){return MO[e]}function PO(e,t,n,r=!1,i=0){let a=r?`${e}+`:`${e}`;if(n)return`${t} of ${r?`${e+i}+`:e+i}`;let o=i?` · ${i} directive ${i===1?`host`:`hosts`}`:``;return`${a} ${e===1&&!r?`instance`:`instances`}${o}`}function FO(e,t,n,r=!1,i=0){if(!n.trim())return``;if(!t)return`No components match.`;let a=e+i,o=r?`${a}+`:`${a}`,s=!r&&a===1;return`${t} of ${o} ${i?s?`row`:`rows`:s?`instance`:`instances`} match.`}function IO(e){let t=e?.components,n=e?.depth;return t&&n?`Showing the first ${t} component instances, and none nested more than ${n} elements deep. Others are not listed or searchable.`:t?`Showing the first ${t} component instances. Others are not listed or searchable.`:n?`Components nested more than ${n} elements deep are not listed or searchable.`:`The page has more components than the tree shows.`}function LO(e,t){let n=t?.detail?.id??null,r=t?.pageId??null;if(r!==e.pageId)return{pageId:r,selectedId:n,detailId:n,destroyed:null};let i=e.selectedId;return n&&n!==e.detailId&&n!==i&&(i=n),i&&t&&!t.truncated&&!RO(t.roots,i)?{pageId:r,selectedId:null,detailId:n,destroyed:i}:{pageId:r,selectedId:i,detailId:n,destroyed:null}}function RO(e,t){return e.some(e=>e.id===t||RO(e.children,t))}function zO(e,t,n){let r=e.indexOf(n);if(r<0)return null;for(let n=r+1;n=0;n--)if(t.has(e[n]))return e[n];return null}var BO=(e,t)=>t.key,VO=(e,t)=>t.id;function HO(e,t){e&1&&(B(0,`p`,2),J(1,` The HTML came from the server, but no component was hydrated, so the app rendered again on the client. Add `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,` and use a development build to see each component's status. `),V())}function UO(e,t){if(e&1&&(B(0,`li`)(1,`span`,9),J(2),V(),J(3),V()),e&2){let e=t.$implicit;M_(`count count-`+e.key),k(2),Y(e.value),k(),X(` `,e.label,` `)}}function WO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Expected `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;k(3),Y(e.expected)}}function GO(e,t){if(e&1&&(B(0,`span`,15),J(1,`Found `),B(2,`code`),J(3),V()()),e&2){let e=G().$implicit;k(3),Y(e.actual)}}function KO(e,t){if(e&1){let e=H();B(0,`li`)(1,`button`,12),W(`click`,function(){let t=T(e).$implicit;return E(G(4).showNode.emit(t.id))})(`focus`,function(){let t=T(e).$implicit;return E(G(4).highlight.emit(t.id))})(`blur`,function(){return T(e),E(G(4).highlight.emit(null))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(4).highlight.emit(t.id))})(`mouseleave`,function(){return T(e),E(G(4).highlight.emit(null))}),B(2,`span`,13),J(3),V(),B(4,`span`,14),J(5),V(),M(6,WO,4,1,`span`,15),M(7,GO,4,1,`span`,15),V()()}if(e&2){let e=t.$implicit;k(3),Y(e.name),k(2),X(`<`,e.tag,`>`),k(),N(e.expected?6:-1),k(),N(e.actual?7:-1)}}function qO(e,t){if(e&1&&(B(0,`h3`,10),J(1,`Mismatches`),V(),B(2,`ul`,11),P(3,KO,8,4,`li`,null,VO),V()),e&2){let e=G(2);k(3),F(e.mismatches)}}function JO(e,t){if(e&1){let e=H();B(0,`div`,3)(1,`ul`,4),P(2,UO,4,4,`li`,5,BO),V(),B(4,`button`,6),W(`click`,function(){return T(e),E(G(2).toggleOverlay())}),D(),B(5,`svg`,7),Vg(6,`rect`,8),V(),J(7,` Outline on page `),V()(),M(8,qO,5,0)}if(e&2){let e=G(),t=G();k(2),F(t.counts()),k(2),j(`aria-pressed`,t.overlayOn()),k(4),N(e.mismatches.length?8:-1)}}function YO(e,t){e&1&&M(0,HO,5,0,`p`,2)(1,JO,9,2),e&2&&N(+!!t.hydrated)}function XO(e,t){e&1&&(B(0,`p`,2),J(1,` This page was not rendered on the server, so there is nothing to hydrate. With server-side rendering and `),B(2,`code`),J(3,`provideClientHydration()`),V(),J(4,`, each component shows whether it was hydrated, skipped or mismatched. `),V())}var ZO=class e{report=$(void 0);overlay=Rv();showNode=Rv();highlight=Rv();overlayOn=Fv(()=>this.report()?.overlay===!0);counts=Q(()=>{let e=this.report()?.counts;return e?[{key:`hydrated`,label:`hydrated`,value:e.hydrated},{key:`skipped`,label:`skipped`,value:e.skipped},{key:`mismatched`,label:`mismatched`,value:e.mismatched},{key:`client`,label:`created on the client`,value:e.client},{key:`dehydratedBlocks`,label:e.dehydratedBlocks===1?`dehydrated @defer block`:`dehydrated @defer blocks`,value:e.dehydratedBlocks}]:[]});toggleOverlay(){let e=!this.overlayOn();this.overlayOn.set(e),this.overlay.emit(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-hydration-section`]],inputs:{report:[1,`report`]},outputs:{overlay:`overlay`,showNode:`showNode`,highlight:`highlight`},decls:5,vars:1,consts:[[`aria-labelledby`,`ct-hydration-title`,1,`hydration`],[`id`,`ct-hydration-title`,1,`title`],[1,`empty`],[1,`summary`],[`aria-label`,`Hydration summary`,1,`counts`],[3,`class`],[`type`,`button`,1,`outline`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`],[`x`,`3`,`y`,`3`,`width`,`18`,`height`,`18`,`rx`,`2`,`stroke-dasharray`,`4 3`],[1,`num`],[1,`label`],[1,`mismatches`],[`type`,`button`,1,`mismatch`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`mono`,`muted`],[1,`detail-line`]],template:function(e,t){if(e&1&&(B(0,`section`,0)(1,`h2`,1),J(2,`Hydration`),V(),M(3,YO,2,1)(4,XO,5,0,`p`,2),V()),e&2){let e;k(3),N((e=t.report())?3:4,e)}},styles:[`.hydration[_ngcontent-%COMP%] { margin-top: 16px; } @@ -738,7 +738,7 @@ svg[_ngcontent-%COMP%] { button[_ngcontent-%COMP%] { transition: none; } -}`]})};function ZO(e){return new Date(e).toLocaleTimeString()}var QO=/[ \t\n\r]/;function $O(e){let t=e.trim(),n;try{n=JSON.parse(t)}catch{return null}if(typeof n!=`object`||!n)return null;let r=``,i=0,a=()=>`\n${` `.repeat(i)}`;for(let e=0;e0?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})};function QO(e){return new Date(e).toLocaleTimeString()}var $O=/[ \t\n\r]/;function ek(e){let t=e.trim(),n;try{n=JSON.parse(t)}catch{return null}if(typeof n!=`object`||!n)return null;let r=``,i=0,a=()=>`\n${` `.repeat(i)}`;for(let e=0;e0?0:-1)},styles:[`[_nghost-%COMP%] { display: block; } @@ -765,7 +765,86 @@ a[_ngcontent-%COMP%] { a[_ngcontent-%COMP%]:focus-visible { outline: 2px solid var(--%NS%accent); outline-offset: 2px; -}`]})},rk=16.6;function ik(e){return e.ms>rk}function ak(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}function ok(e,t){if(!t)return[...e];let n=Math.min(t.from,t.to),r=Math.max(t.from,t.to),i=e.filter(e=>e.id>=n&&e.id<=r);return i.length?i:[...e]}function sk(e){let t=new Map;for(let n of e)for(let e of n.components){let n=t.get(e.name);n?(n.checks+=e.checks,n.ms+=e.ms,n.maxMs=Math.max(n.maxMs,e.ms),n.cycles+=1):t.set(e.name,{name:e.name,checks:e.checks,ms:e.ms,maxMs:e.ms,cycles:1})}return[...t.values()].sort((e,t)=>t.ms-e.ms||e.name.localeCompare(t.name))}function ck(e){let t=e.reduce((e,t)=>Math.max(e,t.ms),0);return Math.max(t,rk*1.25)}function lk(e,t,n=3){let r=e.map(e=>({item:e,value:t(e)})).filter(e=>e.value>0).sort((e,t)=>t.value-e.value),i=r.reduce((e,t)=>e+t.value,0);if(!i)return[];let a=n/i,o=[],s=0,c=0,l=n,u=1,d=[],f=(e,t)=>{let n=e.reduce((e,t)=>e+t,0),r=Math.max(...e),i=Math.min(...e);return Math.max(t*t*r/(n*n),n*n/(t*t*i))},p=()=>{let e=d.reduce((e,t)=>e+t.area,0);if(l>=u){let t=e/u,n=c;for(let e of d){let r=e.area/t;o.push({item:e.item,x:s,y:n,w:t,h:r}),n+=r}s+=t,l-=t}else{let t=e/l,n=s;for(let e of d){let r=e.area/t;o.push({item:e.item,x:n,y:c,w:r,h:t}),n+=r}c+=t,u-=t}d=[]};for(let e of r){let t=e.value*a,n=Math.min(l,u),r=d.map(e=>e.area);d.length&&f([...r,t],n)>f(r,n)&&p(),d.push({item:e.item,area:t})}return d.length&&p(),o.map(e=>({item:e.item,x:e.x/n*100,y:e.y*100,w:e.w/n*100,h:e.h*100}))}var uk={c:`component`,h:`hook`,r:`afterRender`,o:`output`};function dk(e,t){if(t===`c`)return e||null;if(t===`h`){let t=e.lastIndexOf(`.`);return t>0?e.slice(0,t):null}if(t===`o`){let t=e.indexOf(` (`),n=t>0?e.slice(0,t):e;return n&&n!==`?`?n:null}return null}function fk(e,t){let n=e.filter(e=>e.spans?.length);if(!n.length)return null;let r=n.map(e=>{let t=e.spans,n=Math.min(0,...t.map(e=>e[1])),r=Math.max(e.ms,...t.map(e=>e[1]+e[2]));return{cycle:e,spans:t,from:n,width:Math.max(r-n,.001)}}),i=r.reduce((e,t)=>e+t.width,0),a=[],o=[],s=0,c=0;for(let{cycle:e,spans:n,from:l,width:u}of r){o.push({id:e.id,x:s/i*100,w:u/i*100,droppedSpans:e.droppedSpans??0});let r=[...n].sort((e,t)=>e[1]-t[1]||e[3]-t[3]),d=[];for(let[n,o,u,f,p]of r){let r=t[n]??`unknown`,m=d[f-1],h=f>0&&m!==void 0&&ot.cycle.id,mk=(e,t)=>t.id;function hk(e,t){if(e&1){let e=H();B(0,`button`,27),W(`click`,function(){return E(e),D(G().showAll())}),J(1,`Show all cycles`),V()}}function gk(e,t){if(e&1&&Vg(0,`div`,28),e&2){let e=t;K(`left`,e.left,`%`)(`width`,e.width,`%`)}}function _k(e,t){if(e&1&&(B(0,`div`,29),Vg(1,`span`,30),V()),e&2){let e=t.$implicit,n=G();q(`over`,e.over)(`out`,!n.inRange(e.index)&&!!n.range())(`active`,n.focused()&&n.active()===e.index),qg(`id`,n.optionId(e.index)),j(`data-index`,e.index)(`aria-selected`,n.inRange(e.index))(`aria-label`,e.label),A(),K(`height`,e.height,`%`)}}function vk(e,t){e&1&&(B(0,`span`,33),J(1,`over budget`),V())}function yk(e,t){if(e&1&&(B(0,`p`),J(1,` after `),B(2,`span`,35),J(3),V()()),e&2){let e=G();A(3),Y(e.cycle.trigger)}}function bk(e,t){if(e&1&&(B(0,`p`,34)(1,`span`,36),J(2),V(),B(3,`span`),J(4),V()()),e&2){let e=t.$implicit,n=G(2);A(2),Y(e.name),A(2),Y(n.fmt(e.ms))}}function xk(e,t){if(e&1&&(B(0,`div`,31)(1,`p`,32)(2,`strong`),J(3),V(),B(4,`span`),J(5),V(),M(6,vk,2,0,`span`,33),V(),M(7,yk,4,1,`p`),B(8,`p`),J(9),V(),P(10,bk,5,2,`p`,34,kg),V()),e&2){let e=t,n=G();K(`left`,e.left)(`right`,e.right),A(3),Y(n.fmt(e.cycle.ms)),A(2),X(`cycle `,e.cycle.id),A(),N(e.over?6:-1),A(),N(e.cycle.trigger?7:-1),A(2),iv(` `,e.cycle.checks,` `,e.cycle.checks===1?`check`:`checks`,`, `,e.cycle.passes,` `,e.cycle.passes===1?`pass`:`passes`,` `),A(),F(e.top)}}function Sk(e,t){if(e&1&&Vg(0,`span`),e&2){let e=t.$implicit;q(`over`,e.over)}}function Ck(e,t){if(e&1&&J(0),e&2){let e=t,n=G(2);Z(` `,e.name,` (`,n.fmt(e.ms),`) `)}}function wk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,37),J(2),V(),B(3,`td`,37),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,37),J(8),V(),B(9,`td`,37),J(10),V(),B(11,`td`,35),J(12),V(),B(13,`td`,35),M(14,Ck,1,2),V()()),e&2){let e,n=t.$implicit,r=G();A(2),Y(n.id),A(2),Y(r.fmt(n.ms)),A(2),Y(r.isOver(n)?`Over`:`Within`),A(2),Y(n.checks),A(2),Y(n.passes),A(2),Y(n.trigger??``),A(2),N((e=n.components[0])?14:-1,e)}}var Tk=0,Ek=80,Dk=10,Ok=class e{cycles=$([]);range=Gv(null);gapUntil=Ek;budgetLabel=`${rk} ms budget`;uid=`cd-chart-${Tk++}`;hintId=`${this.uid}-hint`;active=k(null);anchor=null;dragging=!1;hover=k(null);focused=k(!1);max=Q(()=>ck(this.cycles()));budgetAt=Q(()=>rk/this.max()*100);bars=Q(()=>{let e=this.max();return this.cycles().map((t,n)=>({cycle:t,index:n,height:t.ms/e*100,over:ik(t),label:this.describe(t)}))});firstId=Q(()=>this.cycles()[0]?.id??0);lastId=Q(()=>this.cycles().at(-1)?.id??0);span=Q(()=>{let e=this.range();if(!e)return null;let t=this.cycles(),n=Math.min(e.from,e.to),r=Math.max(e.from,e.to),i=t.findIndex(e=>e.id>=n),a=-1;for(let e=t.length-1;e>=0;e--)if(t[e].id<=r){a=e;break}return i<0||aok(this.cycles(),this.range()));startId=Q(()=>this.selected()[0]?.id??``);endId=Q(()=>this.selected().at(-1)?.id??``);band=Q(()=>{let e=this.span(),t=this.cycles().length;return!e||!t?null:{left:e.start/t*100,width:(e.end-e.start+1)/t*100}});summary=Q(()=>{let e=this.selected(),t=e.filter(ik).length;return`${this.span()?e.length===1?`Cycle ${e[0].id}`:`Cycles ${e[0].id} to ${e.at(-1).id} (${e.length})`:`All ${e.length} ${e.length===1?`cycle`:`cycles`}`}. ${t} over the ${rk} ms budget.`});tableLabel=Q(()=>this.span()?`Picked cycles, ${this.summary()}`:`All recorded cycles`);activeOptionId=Q(()=>{let e=this.active();return this.focused()&&e!==null&&e{let e=this.hover()??(this.focused()?this.active():null),t=e===null?void 0:this.cycles()[e];return!t||e===null?null:{cycle:t,over:ik(t),top:t.components.slice(0,3),...this.tipSide(e)}});tipSide(e){let t=this.cycles().length;return e+.5=t.start&&e<=t.end}describe(e){let t=[`Cycle ${e.id}`,ak(e.ms)];ik(e)&&t.push(`over budget`),e.trigger&&t.push(`after ${e.trigger}`),t.push(`${e.checks} ${e.checks===1?`check`:`checks`}`);let n=e.components[0];return n&&t.push(`slowest ${n.name} ${ak(n.ms)}`),t.join(`, `)}select(e,t){let n=this.cycles(),r=n[Math.min(e,t)],i=n[Math.max(e,t)];r&&i&&this.range.set({from:r.id,to:i.id})}showAll(){this.range.set(null),this.anchor=null}setEnd(e,t){if(!this.cycles().length)return;let n=t.target,r=Number.parseInt(n.value,10);if(Number.isNaN(r)){n.value=String(e===`from`?this.startId():this.endId());return}let i=Math.min(Math.max(r,this.firstId()),this.lastId()),a=this.selected(),o=e===`from`?i:a[0]?.id??this.firstId(),s=e===`to`?i:a.at(-1)?.id??this.lastId();this.range.set({from:Math.min(o,s),to:Math.max(o,s)}),n.value=String(e===`from`?Math.min(o,s):Math.max(o,s))}onFocus(){this.focused.set(!0),(this.active()===null||this.active()>=this.cycles().length)&&this.active.set(this.span()?.start??Math.max(this.cycles().length-1,0)),this.anchor??=this.active()}onKey(e){let t=this.cycles().length;if(!t)return;let n=Math.min(this.active()??t-1,t-1),r=null;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=n+1;break;case`ArrowLeft`:case`ArrowUp`:r=n-1;break;case`PageDown`:r=n+Dk;break;case`PageUp`:r=n-Dk;break;case`Home`:r=0;break;case`End`:r=t-1;break;case`Enter`:case` `:e.preventDefault(),this.anchor=n,this.select(n,n);return;case`Escape`:this.range()&&(e.preventDefault(),this.showAll());return;default:return}e.preventDefault(),r=Math.min(Math.max(r,0),t-1),this.active.set(r),this.hover.set(null),e.shiftKey?(this.anchor??=n,this.select(this.anchor,r)):this.anchor=r}indexAt(e){let t=e.target?.closest?.(`[data-index]`);if(t)return Number(t.getAttribute(`data-index`));let n=e.currentTarget?.getBoundingClientRect(),r=this.cycles().length;if(!n?.width||!r)return null;let i=(e.clientX-n.left)/n.width;return Math.min(Math.max(Math.floor(i*r),0),r-1)}startDrag(e){if(e.button!==0)return;let t=this.indexAt(e);t!==null&&(this.dragging=!0,this.anchor=t,this.active.set(t),this.select(t,t))}onPointerMove(e){let t=this.indexAt(e);this.hover.set(t),this.dragging&&t!==null&&this.anchor!==null&&(this.active.set(t),this.select(this.anchor,t))}endDrag(){this.dragging=!1}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-cycle-chart`]],hostBindings:function(e,t){e&1&&U(`pointerup`,function(){return t.endDrag()},Pu)(`pointercancel`,function(){return t.endDrag()},Pu)},inputs:{cycles:[1,`cycles`],range:[1,`range`]},outputs:{range:`rangeChange`},decls:69,vars:25,consts:[[1,`range`],[`type`,`number`,`inputmode`,`numeric`,3,`change`,`min`,`max`,`value`],[`type`,`button`],[1,`summary`],[1,`hint`,3,`id`],[1,`plot`],[`aria-hidden`,`true`,1,`axis`],[1,`tick`,`top`],[1,`tick`,`zero`],[1,`area`],[`aria-hidden`,`true`,1,`band`,3,`left`,`width`],[`aria-hidden`,`true`,1,`budget`],[`role`,`listbox`,`aria-multiselectable`,`true`,`aria-orientation`,`horizontal`,`tabindex`,`0`,1,`bars`,3,`keydown`,`focus`,`blur`,`pointerdown`,`pointermove`,`pointerleave`],[`role`,`option`,1,`col`,3,`id`,`over`,`out`,`active`],[`aria-hidden`,`true`,1,`tip`,3,`left`,`right`],[`aria-hidden`,`true`,1,`markers`],[3,`over`],[`aria-label`,`Chart key`,1,`legend`],[`aria-hidden`,`true`,1,`key`,`ok`],[`aria-hidden`,`true`,1,`key`,`over`],[`aria-hidden`,`true`,1,`key-marker`],[`aria-hidden`,`true`,1,`key`,`line`],[1,`table`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[`type`,`button`,3,`click`],[`aria-hidden`,`true`,1,`band`],[`role`,`option`,1,`col`,3,`id`],[1,`bar`],[`aria-hidden`,`true`,1,`tip`],[1,`tip-head`],[1,`flag`],[1,`tip-row`],[1,`mono`],[1,`mono`,`name`],[1,`num`]],template:function(e,t){if(e&1&&(B(0,`div`,0)(1,`label`)(2,`span`),J(3,`Start`),V(),B(4,`input`,1),W(`change`,function(e){return t.setEnd(`from`,e)}),V()(),B(5,`label`)(6,`span`),J(7,`End`),V(),B(8,`input`,1),W(`change`,function(e){return t.setEnd(`to`,e)}),V()(),M(9,hk,2,0,`button`,2),B(10,`p`,3),J(11),V()(),B(12,`p`,4),J(13,` Drag across the bars to pick a range of cycles. With the chart focused, the arrow keys move between cycles, Shift with an arrow key extends the range, Enter picks one cycle and Escape shows all cycles again. `),V(),B(14,`div`,5)(15,`div`,6)(16,`span`,7),J(17),V(),B(18,`span`,8),J(19,`0 ms`),V()(),B(20,`div`,9),M(21,gk,1,4,`div`,10),B(22,`div`,11)(23,`span`),J(24),V()(),B(25,`div`,12),W(`keydown`,function(e){return t.onKey(e)})(`focus`,function(){return t.onFocus()})(`blur`,function(){return t.focused.set(!1)})(`pointerdown`,function(e){return t.startDrag(e)})(`pointermove`,function(e){return t.onPointerMove(e)})(`pointerleave`,function(){return t.hover.set(null)}),P(26,_k,2,12,`div`,13,pk),V(),M(28,xk,12,12,`div`,14),V()(),B(29,`div`,15),P(30,Sk,1,2,`span`,16,pk),V(),B(32,`ul`,17)(33,`li`),Vg(34,`span`,18),J(35,`Within budget`),V(),B(36,`li`),Vg(37,`span`,19)(38,`span`,20),J(39,`Over budget `),V(),B(40,`li`),Vg(41,`span`,21),J(42),V()(),B(43,`details`,22)(44,`summary`),J(45,`Show the cycles as a table`),V(),B(46,`div`,23)(47,`table`)(48,`caption`,24),J(49),V(),B(50,`thead`)(51,`tr`)(52,`th`,25),J(53,`Cycle`),V(),B(54,`th`,25),J(55,`Duration`),V(),B(56,`th`,26),J(57,`Budget`),V(),B(58,`th`,25),J(59,`Checks`),V(),B(60,`th`,25),J(61,`Passes`),V(),B(62,`th`,26),J(63,`After`),V(),B(64,`th`,26),J(65,`Slowest component`),V()()(),B(66,`tbody`),P(67,wk,15,7,`tr`,null,mk),V()()()()),e&2){let e,n;A(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.startId()),A(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.endId()),A(),N(t.range()?9:-1),A(2),Y(t.summary()),A(),qg(`id`,t.hintId),A(2),q(`flush`,t.bars().length>t.gapUntil),A(3),Y(t.fmt(t.max())),A(4),N((e=t.band())?21:-1,e),A(),K(`bottom`,t.budgetAt(),`%`),A(2),Y(t.budgetLabel),A(),j(`aria-label`,`Change detection cycles, `+t.summary())(`aria-describedby`,t.hintId)(`aria-activedescendant`,t.activeOptionId()),A(),F(t.bars()),A(2),N((n=t.tip())?28:-1,n),A(),q(`flush`,t.bars().length>t.gapUntil),A(),F(t.bars()),A(12),Y(t.budgetLabel),A(4),j(`aria-label`,t.tableLabel()),A(3),X(` `,t.tableLabel(),` `),A(18),F(t.selected())}},styles:[`[_nghost-%COMP%] { +}`]})},ik=864e13,ak=200,ok=300,sk=100,ck=10,lk=100,uk=2e3,dk=2e3,fk=4e3,pk=1e3,mk=100,hk=3,gk=50,_k={component:`c`,hook:`h`,afterRender:`r`,output:`o`},vk=Object.values(_k),yk=e=>!!e&&typeof e==`object`&&!Array.isArray(e),bk=e=>typeof e==`number`&&Number.isFinite(e)&&e>=0?e:0,xk=(e,t)=>typeof e==`string`?e.slice(0,t):``,Sk=e=>bk(e)>0?bk(e):void 0,Ck=(e,t)=>Array.isArray(e)?e.slice(0,t):[];function wk(e){if(!yk(e))return null;let t=xk(e.name,ak);return t?{name:t,checks:bk(e.checks),ms:bk(e.ms)}:null}function Tk(e,t){if(!Array.isArray(e)||e.length!==5)return null;let[n,r,i,a,o]=e;return typeof n!=`number`||!Number.isInteger(n)||n<0||n>=t||typeof r!=`number`||!Number.isFinite(r)||Math.abs(r)>1e7||typeof a!=`number`||!Number.isInteger(a)||a<0||a>pk||typeof o!=`string`||!vk.includes(o)?null:[n,r,bk(i),a,o]}function Ek(e,t){if(!yk(e)||typeof e.id!=`number`)return null;let n=Ck(e.components,ck).map(wk).filter(e=>!!e),r=xk(e.trigger,ok),i=Ck(e.spans,40).map(e=>Tk(e,t)).filter(e=>!!e),a=Array.isArray(e.spans)?e.spans.length-40:0,o=Math.floor(bk(e.droppedSpans))+Math.max(0,a),s={t:typeof e.t==`number`?bk(e.t):void 0,hookMs:Sk(e.hookMs),afterRenderMs:Sk(e.afterRenderMs),outputMs:Sk(e.outputMs)},c=Ak(e.cause),l=Sk(e.refreshed),u=Sk(e.unchanged);return{id:bk(e.id),at:bk(e.at),ms:bk(e.ms),passes:bk(e.passes),...r?{trigger:r}:{},checks:bk(e.checks),components:n,...Object.fromEntries(Object.entries(s).filter(([,e])=>e!==void 0)),...i.length?{spans:i}:{},...o?{droppedSpans:o}:{},...c?{cause:c}:{},...l?{refreshed:l}:{},...u?{unchanged:u}:{}}}var Dk=[`event`,`http`,`timer`,`signal`,`effect`,`markForCheck`,`input`,`view`,`tick`,`zone`,`unknown`],Ok={event:`Event`,http:`HTTP response`,timer:`Timer`,signal:`Signal write`,effect:`Effect`,markForCheck:`markForCheck`,input:`setInput`,view:`View change`,tick:`ApplicationRef.tick`,zone:`zone.js only`,unknown:`Unknown`},kk=e=>typeof e==`string`&&Dk.includes(e);function Ak(e){if(!yk(e)||!kk(e.kind))return;let t=[`component`,`listener`,`event`,`target`,`signal`,`task`],n={kind:e.kind};kk(e.via)&&(n.via=e.via);for(let r of t){let t=xk(e[r],ak);t&&(n[r]=t)}e.zone===!0&&(n.zone=!0);let r=Ck(e.stack,hk).map(e=>xk(e,ok)).filter(Boolean);r.length&&(n.stack=r);let i=Math.floor(bk(e.more));return i&&(n.more=i),n}function jk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=e.strategy;return{name:t,refreshed:Math.floor(bk(e.refreshed)),unchanged:Math.floor(bk(e.unchanged)),...n===`OnPush`||n===`Eager`?{strategy:n}:{}}}function Mk(e){if(!yk(e))return null;let t=xk(e.name,ak),n=xk(e.input,ak);if(!t||!n)return null;let r=xk(e.parent,ak);return{name:t,input:n,...r?{parent:r}:{},inPlace:Math.floor(bk(e.inPlace)),sameContents:Math.floor(bk(e.sameContents))}}function Nk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=Ck(e.tasks,3).map(e=>xk(e,ak)).filter(Boolean);return{name:t,ticks:Math.floor(bk(e.ticks)),...n.length?{tasks:n}:{}}}function Pk(e){if(!yk(e))return;let t={};if(yk(e.causes))for(let n of Dk){let r=Math.floor(bk(e.causes[n]));r&&(t[n]=r)}let n=Ck(e.components,lk).map(jk).filter(e=>!!e),r=Ck(e.inputs,gk).map(Mk).filter(e=>!!e),i=Ck(e.zone,gk).map(Nk).filter(e=>!!e),a=Math.floor(bk(e.major));return{triggers:e.triggers===!0,waste:e.waste===!0,...a&&a<1e3?{major:a}:{},causes:t,components:n,...r.length?{inputs:r}:{},...i.length?{zone:i}:{}}}function Fk(e){let t=[],n=e.component?` in ${e.component}${e.listener?` (${e.listener})`:``}`:``;switch(e.kind){case`event`:t.push(`${e.event??`Template listener`}${e.target?` on ${e.target}`:``}${n}`);break;case`http`:t.push(`HTTP response${n}`);break;case`timer`:t.push(`${e.task??`Timer`}${n}`);break;case`zone`:t.push(`zone.js tick with no Angular notification${e.task?` after ${e.task}`:``}`);break;case`tick`:t.push(`ApplicationRef.tick()${n}`);break;default:t.push(`${Ok[e.kind]}${n}`)}return e.signal?t.push(`wrote signal ${e.signal}`):e.via&&e.via!==e.kind&&t.push(`via ${Ok[e.via]}`),e.zone&&e.kind!==`zone`&&t.push(`run by zone.js`),e.more&&t.push(`${e.more} more notification${e.more===1?``:`s`}`),t.join(`, `)}function Ik(e){if(!e)return[];let t=[],n=(e.major??0)>=22;for(let r of e.components){if(r.refreshed<10)continue;let e=r.refreshed-r.unchanged;if(e/r.refreshed>.2)continue;let i=`refreshed ${r.refreshed} times and changed something in ${e}`;r.strategy===`Eager`?t.push({name:r.name,kind:`on-push`,text:n?`${r.name} was ${i}. It opts out of OnPush, which is the default from Angular 22: remove \`changeDetection: ChangeDetectionStrategy.Eager\` (or \`Default\`) so Angular skips it until an input, event, signal or markForCheck marks it.`:`${r.name} was ${i}. Add \`changeDetection: ChangeDetectionStrategy.OnPush\` so Angular skips it until an input, event, signal or markForCheck marks it.`}):r.strategy===`OnPush`&&t.push({name:r.name,kind:`already-on-push`,text:`${r.name} was ${i}, and it is already OnPush${n?` (the default from Angular 22)`:``}. Something keeps marking it: an input that gets a new reference each time, an event or output in it, markForCheck, or a signal it reads that is set to an equal value.`})}for(let n of e.inputs??[]){let e=n.parent?` set by ${n.parent}`:``;n.inPlace&&t.push({name:n.name,kind:`in-place`,text:`Input ${n.input} of ${n.name}${e} changed in place ${n.inPlace} time${n.inPlace===1?``:`s`}: same reference, different contents. OnPush components, computed and signal equality don't see that. Pass a new object or array instead of mutating it.`}),n.sameContents&&t.push({name:n.name,kind:`same-contents`,text:`Input ${n.input} of ${n.name}${e} got a new reference with the same contents ${n.sameContents} time${n.sameContents===1?``:`s`}, so Angular refreshed ${n.name} for nothing. Keep the reference when nothing changed, for example with a computed instead of a method call in the template.`})}for(let n of e.zone??[]){let e=n.tasks?.length?` (after ${n.tasks.join(`, `)})`:``;t.push({name:n.name,kind:`zone`,text:`${n.name} changed in ${n.ticks} tick${n.ticks===1?``:`s`} that only zone.js started${e}. Without zone.js it would not update: keep that state in a signal, or call markForCheck after changing it.`})}return t}function Lk(e){let t=wk(e);return!t||!yk(e)?null:{...t,maxMs:bk(e.maxMs),cycles:bk(e.cycles)}}function Rk(e){if(!yk(e))return null;let t=xk(e.name,ak),n=xk(e.hook,sk);if(!t||!n)return null;let{calls:r,ms:i,maxMs:a}=e;return{name:t,hook:n,calls:bk(r),ms:bk(i),maxMs:bk(a)}}function zk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=xk(e.listener,ak);return{name:t,...n?{listener:n}:{},calls:bk(e.calls),ms:bk(e.ms),maxMs:bk(e.maxMs)}}function Bk(e){if(yk(e)&&bk(e.runs))return{runs:bk(e.runs),ms:bk(e.ms),maxMs:bk(e.maxMs)}}function Vk(e,t){if(!yk(e))return null;let n=Ck(e.spanNames,fk).map(e=>xk(e,ok)),r=Array.isArray(e.cycles)?e.cycles.slice(-Math.min(t,dk)).map(e=>Ek(e,n.length)).filter(e=>!!e):[],i={},a=0;if(yk(e.hosts)){let t=Object.entries(e.hosts);a=Math.max(0,t.length-uk);for(let[e,n]of t.slice(0,uk))e.length<50&&bk(n)&&(i[e]=bk(n))}let o=Array.isArray(e.components)?e.components:[],s=Math.floor(bk(e.droppedClasses))+Math.max(0,o.length-lk),c=Math.floor(bk(e.droppedHosts))+a,l=Ck(e.hooks,mk).map(Rk).filter(e=>!!e),u=Ck(e.outputs,mk).map(zk).filter(e=>!!e),d=Math.max(0,Ck(e.hooks,1/0).length-mk)+Math.max(0,Ck(e.outputs,1/0).length-mk),f=Math.floor(bk(e.droppedTimings))+d,p=Bk(e.afterRender),m=r.some(e=>e.spans?.length),h=Pk(e.diagnosis);return{recording:e.recording===!0,startedAt:typeof e.startedAt==`number`&&e.startedAt<=ik?bk(e.startedAt):null,dropped:bk(e.dropped),cycles:r,components:o.slice(0,lk).map(Lk).filter(e=>!!e),...s?{droppedClasses:s}:{},hosts:i,...c?{droppedHosts:c}:{},...l.length?{hooks:l}:{},...u.length?{outputs:u}:{},...f?{droppedTimings:f}:{},...p?{afterRender:p}:{},...m?{spanNames:n}:{},...h?{diagnosis:h}:{}}}var Hk=`pangular-inspector/change-detection`;function Uk(e,t,n=Date.now()){return{format:Hk,version:1,exportedAt:n,pageId:t,recording:{...Vk(e,dk)??e,recording:!1,hosts:{}}}}function Wk(e,t){if(e.length>2e7||e.length*3>2e7&&new TextEncoder().encode(e).byteLength>2e7)return{ok:!1,error:`The file is larger than 20 MB.`};let n;try{n=JSON.parse(e)}catch{return{ok:!1,error:`The file is not valid JSON.`}}if(!yk(n))return{ok:!1,error:`The file is not a recording.`};if(n.format!==void 0&&n.format!==`pangular-inspector/change-detection`)return{ok:!1,error:`The file is not a change detection recording.`};let r=yk(n.recording)?n.recording:n;if(!Array.isArray(r.cycles))return{ok:!1,error:`The file has no change detection cycles.`};let i=Vk(r,t);if(!i)return{ok:!1,error:`The file is not a recording.`};let a=xk(n.pageId??r.pageId,49)||`imported`,o=Sk(n.exportedAt);return{ok:!0,pageId:a,...o?{exportedAt:o}:{},recording:{...i,recording:!1}}}var Gk=1,Kk=1,qk=2,Jk={c:`component`,h:`lifecycle-hook`,r:`after-render`,o:`output`},Yk=e=>Math.round(e*1e6)/1e3;function Xk(e,t){let n=e.spanNames??[],r=e.cycles[0]?.at??0,i=e.startedAt??r,a=[],o=0,s=0;for(let t of e.cycles){let e=t.t??Math.max(0,t.at-i),r=e+t.ms;a.push({name:`Change detection #${t.id}`,cat:`change-detection`,ph:`X`,pid:Gk,tid:Kk,ts:Yk(e),dur:Yk(t.ms),args:{checks:t.checks,passes:t.passes,...t.trigger?{trigger:t.trigger}:{},...t.hookMs?{hookMs:t.hookMs}:{},...t.afterRenderMs?{afterRenderMs:t.afterRenderMs}:{},...t.outputMs?{outputMs:t.outputMs}:{},...t.cause?{cause:Fk(t.cause)}:{},...t.unchanged?{unchanged:t.unchanged}:{},slowest:t.components.map(e=>`${e.name} ${e.checks}x ${e.ms}ms`)}}),s+=t.droppedSpans??0;let c=[{end:r}],l=[...t.spans??[]].sort((e,t)=>e[1]-t[1]||t[2]-e[2]);for(let[r,i,s,u,d]of l){o++;let l=n[r]??`?`;if(d===_k.output){let n=e+i;a.push({name:l,cat:Jk[d],ph:`X`,pid:Gk,tid:qk,ts:Yk(n),dur:Yk(i<0?Math.max(0,Math.min(s,-i)):s),args:{cycle:t.id}});continue}let f=Math.max(e,e+i);for(;c.length>1&&c.at(-1).end<=f;)c.pop();let p=c.at(-1).end,m=Math.min(f+s,p);me.ts??0));if(c<0)for(let e of a)e.ts=Yk((e.ts-c)/1e3);a.sort((e,t)=>e.ts-t.ts||t.dur-e.dur);let l=(e,t,n)=>({name:t,ph:`M`,pid:Gk,tid:e,args:{name:n}});return{traceEvents:[l(0,`process_name`,`Angular change detection (page ${t})`),l(Kk,`thread_name`,`Change detection`),l(qk,`thread_name`,`Outputs`),...a],displayTimeUnit:`ms`,otherData:{source:`Pangular Inspector change detection recording`,pageId:t,cycles:e.cycles.length,droppedCycles:e.dropped,spans:o,droppedSpans:s,...e.startedAt&&e.startedAt<=ik?{startedAt:new Date(e.startedAt).toISOString()}:{}}}}var Zk=16.6;function Qk(e){return e.ms>Zk}function $k(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}function eA(e,t){if(!t)return[...e];let n=Math.min(t.from,t.to),r=Math.max(t.from,t.to),i=e.filter(e=>e.id>=n&&e.id<=r);return i.length?i:[...e]}function tA(e){let t=new Map;for(let n of e)for(let e of n.components){let n=t.get(e.name);n?(n.checks+=e.checks,n.ms+=e.ms,n.maxMs=Math.max(n.maxMs,e.ms),n.cycles+=1):t.set(e.name,{name:e.name,checks:e.checks,ms:e.ms,maxMs:e.ms,cycles:1})}return[...t.values()].sort((e,t)=>t.ms-e.ms||e.name.localeCompare(t.name))}function nA(e){let t=e.reduce((e,t)=>Math.max(e,t.ms),0);return Math.max(t,Zk*1.25)}function rA(e,t,n=3){let r=e.map(e=>({item:e,value:t(e)})).filter(e=>e.value>0).sort((e,t)=>t.value-e.value),i=r.reduce((e,t)=>e+t.value,0);if(!i)return[];let a=n/i,o=[],s=0,c=0,l=n,u=1,d=[],f=(e,t)=>{let n=e.reduce((e,t)=>e+t,0),r=Math.max(...e),i=Math.min(...e);return Math.max(t*t*r/(n*n),n*n/(t*t*i))},p=()=>{let e=d.reduce((e,t)=>e+t.area,0);if(l>=u){let t=e/u,n=c;for(let e of d){let r=e.area/t;o.push({item:e.item,x:s,y:n,w:t,h:r}),n+=r}s+=t,l-=t}else{let t=e/l,n=s;for(let e of d){let r=e.area/t;o.push({item:e.item,x:n,y:c,w:r,h:t}),n+=r}c+=t,u-=t}d=[]};for(let e of r){let t=e.value*a,n=Math.min(l,u),r=d.map(e=>e.area);d.length&&f([...r,t],n)>f(r,n)&&p(),d.push({item:e.item,area:t})}return d.length&&p(),o.map(e=>({item:e.item,x:e.x/n*100,y:e.y*100,w:e.w/n*100,h:e.h*100}))}var iA={c:`component`,h:`hook`,r:`afterRender`,o:`output`};function aA(e,t){if(t===`c`)return e||null;if(t===`h`){let t=e.lastIndexOf(`.`);return t>0?e.slice(0,t):null}if(t===`o`){let t=e.indexOf(` (`),n=t>0?e.slice(0,t):e;return n&&n!==`?`?n:null}return null}function oA(e,t){let n=e.filter(e=>e.spans?.length);if(!n.length)return null;let r=n.map(e=>{let t=e.spans,n=Math.min(0,...t.map(e=>e[1])),r=Math.max(e.ms,...t.map(e=>e[1]+e[2]));return{cycle:e,spans:t,from:n,width:Math.max(r-n,.001)}}),i=r.reduce((e,t)=>e+t.width,0),a=[],o=[],s=0,c=0;for(let{cycle:e,spans:n,from:l,width:u}of r){o.push({id:e.id,x:s/i*100,w:u/i*100,droppedSpans:e.droppedSpans??0});let r=[...n].sort((e,t)=>e[1]-t[1]||e[3]-t[3]),d=[];for(let[n,o,u,f,p]of r){let r=t[n]??`unknown`,m=d[f-1],h=f>0&&m!==void 0&&ot.kind,cA=(e,t)=>t.name,lA=(e,t)=>t.name+`.`+t.input;function uA(e,t){e&1&&(B(0,`p`,3),J(1,` The page has no Angular change detection scheduler the overlay could find (it needs Angular 18 or later), so cycles have no cause. `),V())}function dA(e,t){if(e&1&&(B(0,`tr`)(1,`td`),J(2),V(),B(3,`td`,6),J(4),V()()),e&2){let e=t.$implicit;k(2),Y(e.label),k(2),Y(e.count)}}function fA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Trigger`),V(),B(5,`th`,5),J(6,`Cycles`),V()()(),B(7,`tbody`),P(8,dA,5,2,`tr`,null,sA),V()()),e&2){let e=G(2);k(8),F(e.causes())}}function pA(e,t){e&1&&(B(0,`p`,3),J(1,`No cycle has a cause yet.`),V())}function mA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,7),J(6),V()()),e&2){let e=t.$implicit;k(2),Y(e.name),k(2),Y(e.ticks),k(2),Y(e.tasks?.join(`, `))}}function hA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Component`),V(),B(5,`th`,5),J(6,`Zone-only ticks`),V(),B(7,`th`,4),J(8,`After`),V()()(),B(9,`tbody`),P(10,mA,7,3,`tr`,null,cA),V()()),e&2){let e=G(2);k(10),F(e.zone())}}function gA(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G(2);k(),Y(e.zoneNote())}}function _A(e,t){e&1&&(B(0,`p`,3),J(1,`The page can't watch DOM updates, so wasted checks are not counted.`),V())}function vA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`),J(8),V()()),e&2){let e=t.$implicit,n=G(3);k(2),Y(e.name),k(2),Y(e.refreshed),k(2),Z(``,e.unchanged,` (`,n.share(e.unchanged,e.refreshed),`)`),k(2),Y(e.strategy??`Unknown`)}}function yA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Component`),V(),B(5,`th`,5),J(6,`Refreshed`),V(),B(7,`th`,5),J(8,`Changed nothing`),V(),B(9,`th`,4),J(10,`Strategy`),V()()(),B(11,`tbody`),P(12,vA,9,5,`tr`,null,cA),V()()),e&2){let e=G(2);k(12),F(e.wasted())}}function bA(e,t){e&1&&(B(0,`p`,3),J(1,`Every refreshed check changed something.`),V())}function xA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,7),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit;k(2),Z(``,e.name,`.`,e.input),k(2),Y(e.parent??`Unknown`),k(2),Y(e.inPlace),k(2),Y(e.sameContents)}}function SA(e,t){if(e&1&&(B(0,`h4`),J(1,`Inputs that break OnPush`),V(),B(2,`table`)(3,`thead`)(4,`tr`)(5,`th`,4),J(6,`Input`),V(),B(7,`th`,4),J(8,`Set by`),V(),B(9,`th`,5),J(10,`Changed in place`),V(),B(11,`th`,5),J(12,`Same contents, new reference`),V()()(),B(13,`tbody`),P(14,xA,9,5,`tr`,null,lA),V()()),e&2){let e=G(2);k(14),F(e.inputs())}}function CA(e,t){if(e&1&&(B(0,`li`),J(1),V()),e&2){let e=t.$implicit;k(),Y(e.text)}}function wA(e,t){if(e&1&&(B(0,`h4`),J(1,`Hints`),V(),B(2,`ul`,8),P(3,CA,2,1,`li`,null,kg),V()),e&2){let e=G(2);k(3),F(e.hints())}}function TA(e,t){if(e&1&&(B(0,`section`,0)(1,`h3`,1),J(2,`Why it ran and what it wasted`),V(),B(3,`div`,2)(4,`div`)(5,`h4`),J(6,`What started the cycles`),V(),M(7,uA,2,0,`p`,3)(8,fA,10,0,`table`)(9,pA,2,0,`p`,3),V(),B(10,`div`)(11,`h4`),J(12,`Depends on zone.js`),V(),M(13,hA,12,0,`table`)(14,gA,2,1,`p`,3),V()(),B(15,`h4`),J(16,`Wasted checks`),V(),M(17,_A,2,0,`p`,3)(18,yA,14,0,`table`)(19,bA,2,0,`p`,3),M(20,SA,16,0),M(21,wA,5,0),V()),e&2){let e=t,n=G();k(7),N(e.triggers?n.causes().length?8:9:7),k(6),N(n.zone().length?13:e.triggers?14:-1),k(4),N(e.waste?n.wasted().length?18:19:17),k(3),N(n.inputs().length?20:-1),k(),N(n.hints().length?21:-1)}}var EA=10,DA=class e{page=$(null);diagnosis=Q(()=>this.page()?.diagnosis??null);causes=Q(()=>{let e=this.diagnosis()?.causes??{};return Dk.filter(t=>e[t]).map(t=>({kind:t,label:Ok[t],count:e[t]}))});zone=Q(()=>(this.diagnosis()?.zone??[]).slice(0,EA));zoneNote=Q(()=>{let e=this.diagnosis()?.causes.zone??0;return e?`${e} ${e===1?`tick`:`ticks`} came from zone.js alone, and no component changed in them.`:`No component changed in a tick only zone.js started.`});wasted=Q(()=>(this.diagnosis()?.components??[]).filter(e=>e.unchanged>0).slice(0,EA));inputs=Q(()=>(this.diagnosis()?.inputs??[]).slice(0,EA));hints=Q(()=>Ik(this.diagnosis()??void 0).slice(0,EA));share(e,t){return t?`${Math.round(e/t*100)}%`:`0%`}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-diagnosis`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[`aria-labelledby`,`cd-diagnosis-heading`,1,`diagnosis`],[`id`,`cd-diagnosis-heading`],[1,`grid`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`num`],[1,`mono`],[1,`hints`]],template:function(e,t){if(e&1&&M(0,TA,22,5,`section`,0),e&2){let e;N((e=t.diagnosis())?0:-1,e)}},styles:[`[_nghost-%COMP%] { + display: block; +} + +h3[_ngcontent-%COMP%] { + color: var(--%NS%text-3); + font-size: 11px; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; + margin: 16px 0 6px; +} + +h4[_ngcontent-%COMP%] { + margin: 12px 0 6px; + color: var(--%NS%text-2); + font-size: 12px; + font-weight: 600; +} + +.grid[_ngcontent-%COMP%] { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 0 16px; +} + +@media (min-width: 880px) { + .grid[_ngcontent-%COMP%] { + grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); + } +} +table[_ngcontent-%COMP%] { + width: 100%; + border-collapse: collapse; + font-size: 12px; +} + +th[_ngcontent-%COMP%], +td[_ngcontent-%COMP%] { + padding: 4px 6px; + border-bottom: 1px solid var(--%NS%border); + text-align: left; +} + +th[_ngcontent-%COMP%] { + color: var(--%NS%text-2); + font-weight: 500; +} + +td.mono[_ngcontent-%COMP%] { + overflow-wrap: anywhere; +} + +.num[_ngcontent-%COMP%] { + text-align: right; + font-variant-numeric: tabular-nums; +} + +.mono[_ngcontent-%COMP%] { + font-family: var(--%NS%font-mono); +} + +.note[_ngcontent-%COMP%] { + margin: 4px 0 8px; + color: var(--%NS%text-2); + font-size: 12px; + line-height: 1.5; +} + +.hints[_ngcontent-%COMP%] { + margin: 0; + padding-left: 18px; + color: var(--%NS%text); + font-size: 12px; + line-height: 1.5; +} + +.hints[_ngcontent-%COMP%] li[_ngcontent-%COMP%] + li[_ngcontent-%COMP%] { + margin-top: 4px; +}`]})},OA=(e,t)=>t.cycle.id,kA=(e,t)=>t.id;function AA(e,t){if(e&1){let e=H();B(0,`button`,27),W(`click`,function(){return T(e),E(G().showAll())}),J(1,`Show all cycles`),V()}}function jA(e,t){if(e&1&&Vg(0,`div`,28),e&2){let e=t;K(`left`,e.left,`%`)(`width`,e.width,`%`)}}function MA(e,t){if(e&1&&(B(0,`div`,29),Vg(1,`span`,30),V()),e&2){let e=t.$implicit,n=G();q(`over`,e.over)(`out`,!n.inRange(e.index)&&!!n.range())(`active`,n.focused()&&n.active()===e.index),qg(`id`,n.optionId(e.index)),j(`data-index`,e.index)(`aria-selected`,n.inRange(e.index))(`aria-label`,e.label),k(),K(`height`,e.height,`%`)}}function NA(e,t){e&1&&(B(0,`span`,33),J(1,`over budget`),V())}function PA(e,t){if(e&1&&(B(0,`p`),J(1,` after `),B(2,`span`,35),J(3),V()()),e&2){let e=G();k(3),Y(e.cycle.trigger)}}function FA(e,t){if(e&1&&(B(0,`p`,34)(1,`span`,36),J(2),V(),B(3,`span`),J(4),V()()),e&2){let e=t.$implicit,n=G(2);k(2),Y(e.name),k(2),Y(n.fmt(e.ms))}}function IA(e,t){if(e&1&&(B(0,`div`,31)(1,`p`,32)(2,`strong`),J(3),V(),B(4,`span`),J(5),V(),M(6,NA,2,0,`span`,33),V(),M(7,PA,4,1,`p`),B(8,`p`),J(9),V(),P(10,FA,5,2,`p`,34,kg),V()),e&2){let e=t,n=G();K(`left`,e.left)(`right`,e.right),k(3),Y(n.fmt(e.cycle.ms)),k(2),X(`cycle `,e.cycle.id),k(),N(e.over?6:-1),k(),N(e.cycle.trigger?7:-1),k(2),iv(` `,e.cycle.checks,` `,e.cycle.checks===1?`check`:`checks`,`, `,e.cycle.passes,` `,e.cycle.passes===1?`pass`:`passes`,` `),k(),F(e.top)}}function LA(e,t){if(e&1&&Vg(0,`span`),e&2){let e=t.$implicit;q(`over`,e.over)}}function RA(e,t){if(e&1&&J(0),e&2){let e=t,n=G(2);Z(` `,e.name,` (`,n.fmt(e.ms),`) `)}}function zA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,37),J(2),V(),B(3,`td`,37),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,37),J(8),V(),B(9,`td`,37),J(10),V(),B(11,`td`,35),J(12),V(),B(13,`td`,35),M(14,RA,1,2),V()()),e&2){let e,n=t.$implicit,r=G();k(2),Y(n.id),k(2),Y(r.fmt(n.ms)),k(2),Y(r.isOver(n)?`Over`:`Within`),k(2),Y(n.checks),k(2),Y(n.passes),k(2),Y(n.trigger??``),k(2),N((e=n.components[0])?14:-1,e)}}var BA=0,VA=80,HA=10,UA=class e{cycles=$([]);range=Gv(null);gapUntil=VA;budgetLabel=`${Zk} ms budget`;uid=`cd-chart-${BA++}`;hintId=`${this.uid}-hint`;active=O(null);anchor=null;dragging=!1;hover=O(null);focused=O(!1);max=Q(()=>nA(this.cycles()));budgetAt=Q(()=>Zk/this.max()*100);bars=Q(()=>{let e=this.max();return this.cycles().map((t,n)=>({cycle:t,index:n,height:t.ms/e*100,over:Qk(t),label:this.describe(t)}))});firstId=Q(()=>this.cycles()[0]?.id??0);lastId=Q(()=>this.cycles().at(-1)?.id??0);span=Q(()=>{let e=this.range();if(!e)return null;let t=this.cycles(),n=Math.min(e.from,e.to),r=Math.max(e.from,e.to),i=t.findIndex(e=>e.id>=n),a=-1;for(let e=t.length-1;e>=0;e--)if(t[e].id<=r){a=e;break}return i<0||aeA(this.cycles(),this.range()));startId=Q(()=>this.selected()[0]?.id??``);endId=Q(()=>this.selected().at(-1)?.id??``);band=Q(()=>{let e=this.span(),t=this.cycles().length;return!e||!t?null:{left:e.start/t*100,width:(e.end-e.start+1)/t*100}});summary=Q(()=>{let e=this.selected(),t=e.filter(Qk).length;return`${this.span()?e.length===1?`Cycle ${e[0].id}`:`Cycles ${e[0].id} to ${e.at(-1).id} (${e.length})`:`All ${e.length} ${e.length===1?`cycle`:`cycles`}`}. ${t} over the ${Zk} ms budget.`});tableLabel=Q(()=>this.span()?`Picked cycles, ${this.summary()}`:`All recorded cycles`);activeOptionId=Q(()=>{let e=this.active();return this.focused()&&e!==null&&e{let e=this.hover()??(this.focused()?this.active():null),t=e===null?void 0:this.cycles()[e];return!t||e===null?null:{cycle:t,over:Qk(t),top:t.components.slice(0,3),...this.tipSide(e)}});tipSide(e){let t=this.cycles().length;return e+.5=t.start&&e<=t.end}describe(e){let t=[`Cycle ${e.id}`,$k(e.ms)];Qk(e)&&t.push(`over budget`),e.trigger&&t.push(`after ${e.trigger}`),t.push(`${e.checks} ${e.checks===1?`check`:`checks`}`);let n=e.components[0];return n&&t.push(`slowest ${n.name} ${$k(n.ms)}`),t.join(`, `)}select(e,t){let n=this.cycles(),r=n[Math.min(e,t)],i=n[Math.max(e,t)];r&&i&&this.range.set({from:r.id,to:i.id})}showAll(){this.range.set(null),this.anchor=null}setEnd(e,t){if(!this.cycles().length)return;let n=t.target,r=Number.parseInt(n.value,10);if(Number.isNaN(r)){n.value=String(e===`from`?this.startId():this.endId());return}let i=Math.min(Math.max(r,this.firstId()),this.lastId()),a=this.selected(),o=e===`from`?i:a[0]?.id??this.firstId(),s=e===`to`?i:a.at(-1)?.id??this.lastId();this.range.set({from:Math.min(o,s),to:Math.max(o,s)}),n.value=String(e===`from`?Math.min(o,s):Math.max(o,s))}onFocus(){this.focused.set(!0),(this.active()===null||this.active()>=this.cycles().length)&&this.active.set(this.span()?.start??Math.max(this.cycles().length-1,0)),this.anchor??=this.active()}onKey(e){let t=this.cycles().length;if(!t)return;let n=Math.min(this.active()??t-1,t-1),r=null;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=n+1;break;case`ArrowLeft`:case`ArrowUp`:r=n-1;break;case`PageDown`:r=n+HA;break;case`PageUp`:r=n-HA;break;case`Home`:r=0;break;case`End`:r=t-1;break;case`Enter`:case` `:e.preventDefault(),this.anchor=n,this.select(n,n);return;case`Escape`:this.range()&&(e.preventDefault(),this.showAll());return;default:return}e.preventDefault(),r=Math.min(Math.max(r,0),t-1),this.active.set(r),this.hover.set(null),e.shiftKey?(this.anchor??=n,this.select(this.anchor,r)):this.anchor=r}indexAt(e){let t=e.target?.closest?.(`[data-index]`);if(t)return Number(t.getAttribute(`data-index`));let n=e.currentTarget?.getBoundingClientRect(),r=this.cycles().length;if(!n?.width||!r)return null;let i=(e.clientX-n.left)/n.width;return Math.min(Math.max(Math.floor(i*r),0),r-1)}startDrag(e){if(e.button!==0)return;let t=this.indexAt(e);t!==null&&(this.dragging=!0,this.anchor=t,this.active.set(t),this.select(t,t))}onPointerMove(e){let t=this.indexAt(e);this.hover.set(t),this.dragging&&t!==null&&this.anchor!==null&&(this.active.set(t),this.select(this.anchor,t))}endDrag(){this.dragging=!1}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-cycle-chart`]],hostBindings:function(e,t){e&1&&U(`pointerup`,function(){return t.endDrag()},Fu)(`pointercancel`,function(){return t.endDrag()},Fu)},inputs:{cycles:[1,`cycles`],range:[1,`range`]},outputs:{range:`rangeChange`},decls:69,vars:25,consts:[[1,`range`],[`type`,`number`,`inputmode`,`numeric`,3,`change`,`min`,`max`,`value`],[`type`,`button`],[1,`summary`],[1,`hint`,3,`id`],[1,`plot`],[`aria-hidden`,`true`,1,`axis`],[1,`tick`,`top`],[1,`tick`,`zero`],[1,`area`],[`aria-hidden`,`true`,1,`band`,3,`left`,`width`],[`aria-hidden`,`true`,1,`budget`],[`role`,`listbox`,`aria-multiselectable`,`true`,`aria-orientation`,`horizontal`,`tabindex`,`0`,1,`bars`,3,`keydown`,`focus`,`blur`,`pointerdown`,`pointermove`,`pointerleave`],[`role`,`option`,1,`col`,3,`id`,`over`,`out`,`active`],[`aria-hidden`,`true`,1,`tip`,3,`left`,`right`],[`aria-hidden`,`true`,1,`markers`],[3,`over`],[`aria-label`,`Chart key`,1,`legend`],[`aria-hidden`,`true`,1,`key`,`ok`],[`aria-hidden`,`true`,1,`key`,`over`],[`aria-hidden`,`true`,1,`key-marker`],[`aria-hidden`,`true`,1,`key`,`line`],[1,`table`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[`type`,`button`,3,`click`],[`aria-hidden`,`true`,1,`band`],[`role`,`option`,1,`col`,3,`id`],[1,`bar`],[`aria-hidden`,`true`,1,`tip`],[1,`tip-head`],[1,`flag`],[1,`tip-row`],[1,`mono`],[1,`mono`,`name`],[1,`num`]],template:function(e,t){if(e&1&&(B(0,`div`,0)(1,`label`)(2,`span`),J(3,`Start`),V(),B(4,`input`,1),W(`change`,function(e){return t.setEnd(`from`,e)}),V()(),B(5,`label`)(6,`span`),J(7,`End`),V(),B(8,`input`,1),W(`change`,function(e){return t.setEnd(`to`,e)}),V()(),M(9,AA,2,0,`button`,2),B(10,`p`,3),J(11),V()(),B(12,`p`,4),J(13,` Drag across the bars to pick a range of cycles. With the chart focused, the arrow keys move between cycles, Shift with an arrow key extends the range, Enter picks one cycle and Escape shows all cycles again. `),V(),B(14,`div`,5)(15,`div`,6)(16,`span`,7),J(17),V(),B(18,`span`,8),J(19,`0 ms`),V()(),B(20,`div`,9),M(21,jA,1,4,`div`,10),B(22,`div`,11)(23,`span`),J(24),V()(),B(25,`div`,12),W(`keydown`,function(e){return t.onKey(e)})(`focus`,function(){return t.onFocus()})(`blur`,function(){return t.focused.set(!1)})(`pointerdown`,function(e){return t.startDrag(e)})(`pointermove`,function(e){return t.onPointerMove(e)})(`pointerleave`,function(){return t.hover.set(null)}),P(26,MA,2,12,`div`,13,OA),V(),M(28,IA,12,12,`div`,14),V()(),B(29,`div`,15),P(30,LA,1,2,`span`,16,OA),V(),B(32,`ul`,17)(33,`li`),Vg(34,`span`,18),J(35,`Within budget`),V(),B(36,`li`),Vg(37,`span`,19)(38,`span`,20),J(39,`Over budget `),V(),B(40,`li`),Vg(41,`span`,21),J(42),V()(),B(43,`details`,22)(44,`summary`),J(45,`Show the cycles as a table`),V(),B(46,`div`,23)(47,`table`)(48,`caption`,24),J(49),V(),B(50,`thead`)(51,`tr`)(52,`th`,25),J(53,`Cycle`),V(),B(54,`th`,25),J(55,`Duration`),V(),B(56,`th`,26),J(57,`Budget`),V(),B(58,`th`,25),J(59,`Checks`),V(),B(60,`th`,25),J(61,`Passes`),V(),B(62,`th`,26),J(63,`After`),V(),B(64,`th`,26),J(65,`Slowest component`),V()()(),B(66,`tbody`),P(67,zA,15,7,`tr`,null,kA),V()()()()),e&2){let e,n;k(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.startId()),k(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.endId()),k(),N(t.range()?9:-1),k(2),Y(t.summary()),k(),qg(`id`,t.hintId),k(2),q(`flush`,t.bars().length>t.gapUntil),k(3),Y(t.fmt(t.max())),k(4),N((e=t.band())?21:-1,e),k(),K(`bottom`,t.budgetAt(),`%`),k(2),Y(t.budgetLabel),k(),j(`aria-label`,`Change detection cycles, `+t.summary())(`aria-describedby`,t.hintId)(`aria-activedescendant`,t.activeOptionId()),k(),F(t.bars()),k(2),N((n=t.tip())?28:-1,n),k(),q(`flush`,t.bars().length>t.gapUntil),k(),F(t.bars()),k(12),Y(t.budgetLabel),k(4),j(`aria-label`,t.tableLabel()),k(3),X(` `,t.tableLabel(),` `),k(18),F(t.selected())}},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1145,7 +1224,7 @@ td.mono[_ngcontent-%COMP%] { .bar[_ngcontent-%COMP%] { transition: none; } -}`]})},kk=(e,t)=>t.id,Ak=(e,t)=>t.index,jk=(e,t)=>t.kind;function Mk(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(2);A(),Z(` Pick `,e.max,` cycles or fewer to see their spans. `,e.count(),` are picked. `)}}function Nk(e,t){if(e&1&&(B(0,`span`),J(1),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`width`,e.w,`%`),A(),X(`cycle `,e.id)}}function Pk(e,t){if(e&1){let e=H();B(0,`button`,11),W(`focus`,function(){let t=E(e).$implicit;return D(G(3).current.set(t.index))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(3).hover.set(t.index))})(`mouseleave`,function(){return E(e),D(G(3).hover.set(null))})(`click`,function(){let t=E(e).$implicit;return D(G(3).choose(t))}),B(1,`span`,12),J(2),V()()}if(e&2){let e=t.$implicit,n=G(3);M_(pv(`block kind-`,e.kind)),K(`left`,e.x,`%`)(`width`,e.w,`%`)(`top`,e.depth*n.row,`px`),q(`narrow`,e.w<4),j(`tabindex`,e.index===n.tabStop()?0:-1)(`data-index`,e.index)(`aria-label`,n.describe(e))(`aria-disabled`,e.component?null:`true`),A(2),Y(e.name)}}function Fk(e,t){if(e&1&&(B(0,`li`),Vg(1,`span`,13),J(2),V()),e&2){let e=t.$implicit;A(),M_(pv(`key kind-`,e.kind)),A(),Y(e.label)}}function Ik(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(3);A(),Z(` Each cycle keeps its longest spans. `,e.dropped(),` shorter `,e.dropped()===1?`span was`:`spans were`,` left out. `)}}function Lk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,17),J(2),V(),B(3,`td`,18),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,17),J(8),V(),B(9,`td`,17),J(10),V(),B(11,`td`,17),J(12),V(),B(13,`td`,17),J(14),V()()),e&2){let e=t.$implicit,n=G(4);A(2),Y(e.cycleId),A(),K(`padding-left`,6+e.depth*8,`px`),A(),Y(e.name),A(2),Y(n.kindLabel(e)),A(2),Y(e.depth),A(2),Y(n.fmt(e.start)),A(2),Y(n.fmt(e.ms)),A(2),Y(n.fmt(e.selfMs))}}function Rk(e,t){if(e&1&&(B(0,`div`,10)(1,`table`)(2,`caption`,14),J(3),V(),B(4,`thead`)(5,`tr`)(6,`th`,15),J(7,`Cycle`),V(),B(8,`th`,16),J(9,`Span`),V(),B(10,`th`,16),J(11,`Kind`),V(),B(12,`th`,15),J(13,`Depth`),V(),B(14,`th`,15),J(15,`Start`),V(),B(16,`th`,15),J(17,`Total`),V(),B(18,`th`,15),J(19,`Self`),V()()(),B(20,`tbody`),P(21,Lk,15,9,`tr`,null,Ak),V()()()),e&2){let e=G(),t=G(2);j(`aria-label`,t.tableLabel()),A(3),X(` `,t.tableLabel(),` `),A(18),F(e.blocks)}}function zk(e,t){if(e&1){let e=H();B(0,`div`,1),W(`keydown`,function(t){return E(e),D(G(2).onKey(t))}),B(1,`div`,2),P(2,Nk,2,5,`span`,3,kk),V(),B(4,`div`,4),P(5,Pk,3,16,`button`,5,Ak),V()(),B(7,`p`,6),J(8),V(),B(9,`ul`,7),P(10,Fk,3,4,`li`,null,jk),V(),B(12,`p`,8),J(13,` Arrow keys move along a row, Up goes to the enclosing span and Down to the first nested one. Enter on a component shows it in the tree. `),V(),M(14,Ik,2,2,`p`,0),B(15,`details`,9),W(`toggle`,function(t){return E(e),D(G(2).onToggle(t))}),B(16,`summary`),J(17,`Show the spans as a table`),V(),M(18,Rk,23,2,`div`,10),V()}if(e&2){let e=t,n=G(2);j(`aria-label`,n.label()),A(2),F(e.cycles),A(2),K(`height`,e.depth*n.row,`px`),A(),F(e.blocks),A(3),Y(n.readout()),A(2),F(n.kinds),A(4),N(n.dropped()?14:-1),A(4),N(n.tableOpen()?18:-1)}}function Bk(e,t){if(e&1&&(B(0,`h3`),J(1,`Spans in the picked cycles`),V(),M(2,Mk,2,2,`p`,0)(3,zk,19,6)),e&2){let e,t=G();A(2),N(t.tooMany()?2:(e=t.graph())?3:-1,e)}}var Vk=22;function Hk(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return e[n]}var Uk=class e{cycles=$([]);names=$([]);scope=$(`the recording`);pick=Rv();row=Vk;max=30;kinds=[`c`,`h`,`r`,`o`].map(e=>({kind:e,label:uk[e]}));current=k(0);tableOpen=k(!1);hover=k(null);hasSpans=Q(()=>this.cycles().some(e=>e.spans?.length));count=Q(()=>this.cycles().length);tooMany=Q(()=>this.count()>30);graph=Q(()=>this.tooMany()?null:fk(this.cycles(),this.names()));tabStop=Q(()=>Math.min(this.current(),Math.max((this.graph()?.blocks.length??1)-1,0)));dropped=Q(()=>this.graph()?.cycles.reduce((e,t)=>e+t.droppedSpans,0)??0);label=Q(()=>`Spans in ${this.scope()} over time, nested by depth. Pick a component to show it in the tree.`);readout=Q(()=>{let e=(this.graph()?.blocks??[])[this.hover()??this.tabStop()];return e?this.describe(e):``});tableLabel=Q(()=>`Timed spans in ${this.scope()}`);fmt(e){return ak(e)}kindLabel(e){return uk[e.kind]}onToggle(e){this.tableOpen.set(e.target.open)}describe(e){let t=[e.name,uk[e.kind],`${ak(e.ms)} total`];return e.selfMs!==e.ms&&t.push(`${ak(e.selfMs)} self`),t.push(e.start<0?`cycle ${e.cycleId}, ${ak(-e.start)} before it started`:`cycle ${e.cycleId} at ${ak(e.start)}`),t.join(`, `)}choose(e){this.current.set(e.index),e.component&&this.pick.emit(e.component)}onKey(e){let t=this.graph()?.blocks??[];if(!t.length)return;let n=t[this.tabStop()],r;switch(e.key){case`ArrowRight`:r=t.find(e=>e.index>n.index&&e.depth===n.depth);break;case`ArrowLeft`:r=Hk(t,e=>e.indexe.indexe.parent===n.index)??t.find(e=>e.index>n.index&&e.depth===n.depth+1);break;case`Home`:r=t[0];break;case`End`:r=t.at(-1);break;default:return}e.preventDefault(),this.hover.set(null),r&&(this.current.set(r.index),e.currentTarget.querySelector(`button[data-index="${r.index}"]`)?.focus())}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-flame-graph`]],inputs:{cycles:[1,`cycles`],names:[1,`names`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:1,vars:1,consts:[[1,`note`],[`role`,`group`,1,`flame`,3,`keydown`],[`aria-hidden`,`true`,1,`cycles`],[3,`left`,`width`],[1,`rows`],[`type`,`button`,3,`class`,`narrow`,`left`,`width`,`top`],[`aria-hidden`,`true`,1,`readout`],[`aria-label`,`Span kinds`,1,`legend`],[1,`hint`],[1,`table`,3,`toggle`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[`type`,`button`,3,`focus`,`mouseenter`,`mouseleave`,`click`],[1,`text`],[`aria-hidden`,`true`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[1,`num`],[1,`mono`]],template:function(e,t){e&1&&M(0,Bk,4,1),e&2&&N(t.hasSpans()?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})},WA=(e,t)=>t.id,GA=(e,t)=>t.index,KA=(e,t)=>t.kind;function qA(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(2);k(),Z(` Pick `,e.max,` cycles or fewer to see their spans. `,e.count(),` are picked. `)}}function JA(e,t){if(e&1&&(B(0,`span`),J(1),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`width`,e.w,`%`),k(),X(`cycle `,e.id)}}function YA(e,t){if(e&1){let e=H();B(0,`button`,11),W(`focus`,function(){let t=T(e).$implicit;return E(G(3).current.set(t.index))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(3).hover.set(t.index))})(`mouseleave`,function(){return T(e),E(G(3).hover.set(null))})(`click`,function(){let t=T(e).$implicit;return E(G(3).choose(t))}),B(1,`span`,12),J(2),V()()}if(e&2){let e=t.$implicit,n=G(3);M_(pv(`block kind-`,e.kind)),K(`left`,e.x,`%`)(`width`,e.w,`%`)(`top`,e.depth*n.row,`px`),q(`narrow`,e.w<4),j(`tabindex`,e.index===n.tabStop()?0:-1)(`data-index`,e.index)(`aria-label`,n.describe(e))(`aria-disabled`,e.component?null:`true`),k(2),Y(e.name)}}function XA(e,t){if(e&1&&(B(0,`li`),Vg(1,`span`,13),J(2),V()),e&2){let e=t.$implicit;k(),M_(pv(`key kind-`,e.kind)),k(),Y(e.label)}}function ZA(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(3);k(),Z(` Each cycle keeps its longest spans. `,e.dropped(),` shorter `,e.dropped()===1?`span was`:`spans were`,` left out. `)}}function QA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,17),J(2),V(),B(3,`td`,18),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,17),J(8),V(),B(9,`td`,17),J(10),V(),B(11,`td`,17),J(12),V(),B(13,`td`,17),J(14),V()()),e&2){let e=t.$implicit,n=G(4);k(2),Y(e.cycleId),k(),K(`padding-left`,6+e.depth*8,`px`),k(),Y(e.name),k(2),Y(n.kindLabel(e)),k(2),Y(e.depth),k(2),Y(n.fmt(e.start)),k(2),Y(n.fmt(e.ms)),k(2),Y(n.fmt(e.selfMs))}}function $A(e,t){if(e&1&&(B(0,`div`,10)(1,`table`)(2,`caption`,14),J(3),V(),B(4,`thead`)(5,`tr`)(6,`th`,15),J(7,`Cycle`),V(),B(8,`th`,16),J(9,`Span`),V(),B(10,`th`,16),J(11,`Kind`),V(),B(12,`th`,15),J(13,`Depth`),V(),B(14,`th`,15),J(15,`Start`),V(),B(16,`th`,15),J(17,`Total`),V(),B(18,`th`,15),J(19,`Self`),V()()(),B(20,`tbody`),P(21,QA,15,9,`tr`,null,GA),V()()()),e&2){let e=G(),t=G(2);j(`aria-label`,t.tableLabel()),k(3),X(` `,t.tableLabel(),` `),k(18),F(e.blocks)}}function ej(e,t){if(e&1){let e=H();B(0,`div`,1),W(`keydown`,function(t){return T(e),E(G(2).onKey(t))}),B(1,`div`,2),P(2,JA,2,5,`span`,3,WA),V(),B(4,`div`,4),P(5,YA,3,16,`button`,5,GA),V()(),B(7,`p`,6),J(8),V(),B(9,`ul`,7),P(10,XA,3,4,`li`,null,KA),V(),B(12,`p`,8),J(13,` Arrow keys move along a row, Up goes to the enclosing span and Down to the first nested one. Enter on a component shows it in the tree. `),V(),M(14,ZA,2,2,`p`,0),B(15,`details`,9),W(`toggle`,function(t){return T(e),E(G(2).onToggle(t))}),B(16,`summary`),J(17,`Show the spans as a table`),V(),M(18,$A,23,2,`div`,10),V()}if(e&2){let e=t,n=G(2);j(`aria-label`,n.label()),k(2),F(e.cycles),k(2),K(`height`,e.depth*n.row,`px`),k(),F(e.blocks),k(3),Y(n.readout()),k(2),F(n.kinds),k(4),N(n.dropped()?14:-1),k(4),N(n.tableOpen()?18:-1)}}function tj(e,t){if(e&1&&(B(0,`h3`),J(1,`Spans in the picked cycles`),V(),M(2,qA,2,2,`p`,0)(3,ej,19,6)),e&2){let e,t=G();k(2),N(t.tooMany()?2:(e=t.graph())?3:-1,e)}}var nj=22;function rj(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return e[n]}var ij=class e{cycles=$([]);names=$([]);scope=$(`the recording`);pick=Rv();row=nj;max=30;kinds=[`c`,`h`,`r`,`o`].map(e=>({kind:e,label:iA[e]}));current=O(0);tableOpen=O(!1);hover=O(null);hasSpans=Q(()=>this.cycles().some(e=>e.spans?.length));count=Q(()=>this.cycles().length);tooMany=Q(()=>this.count()>30);graph=Q(()=>this.tooMany()?null:oA(this.cycles(),this.names()));tabStop=Q(()=>Math.min(this.current(),Math.max((this.graph()?.blocks.length??1)-1,0)));dropped=Q(()=>this.graph()?.cycles.reduce((e,t)=>e+t.droppedSpans,0)??0);label=Q(()=>`Spans in ${this.scope()} over time, nested by depth. Pick a component to show it in the tree.`);readout=Q(()=>{let e=(this.graph()?.blocks??[])[this.hover()??this.tabStop()];return e?this.describe(e):``});tableLabel=Q(()=>`Timed spans in ${this.scope()}`);fmt(e){return $k(e)}kindLabel(e){return iA[e.kind]}onToggle(e){this.tableOpen.set(e.target.open)}describe(e){let t=[e.name,iA[e.kind],`${$k(e.ms)} total`];return e.selfMs!==e.ms&&t.push(`${$k(e.selfMs)} self`),t.push(e.start<0?`cycle ${e.cycleId}, ${$k(-e.start)} before it started`:`cycle ${e.cycleId} at ${$k(e.start)}`),t.join(`, `)}choose(e){this.current.set(e.index),e.component&&this.pick.emit(e.component)}onKey(e){let t=this.graph()?.blocks??[];if(!t.length)return;let n=t[this.tabStop()],r;switch(e.key){case`ArrowRight`:r=t.find(e=>e.index>n.index&&e.depth===n.depth);break;case`ArrowLeft`:r=rj(t,e=>e.indexe.indexe.parent===n.index)??t.find(e=>e.index>n.index&&e.depth===n.depth+1);break;case`Home`:r=t[0];break;case`End`:r=t.at(-1);break;default:return}e.preventDefault(),this.hover.set(null),r&&(this.current.set(r.index),e.currentTarget.querySelector(`button[data-index="${r.index}"]`)?.focus())}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-flame-graph`]],inputs:{cycles:[1,`cycles`],names:[1,`names`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:1,vars:1,consts:[[1,`note`],[`role`,`group`,1,`flame`,3,`keydown`],[`aria-hidden`,`true`,1,`cycles`],[3,`left`,`width`],[1,`rows`],[`type`,`button`,3,`class`,`narrow`,`left`,`width`,`top`],[`aria-hidden`,`true`,1,`readout`],[`aria-label`,`Span kinds`,1,`legend`],[1,`hint`],[1,`table`,3,`toggle`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[`type`,`button`,3,`focus`,`mouseenter`,`mouseleave`,`click`],[1,`text`],[`aria-hidden`,`true`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[1,`num`],[1,`mono`]],template:function(e,t){e&1&&M(0,tj,4,1),e&2&&N(t.hasSpans()?0:-1)},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1352,7 +1431,7 @@ td.mono[_ngcontent-%COMP%] { .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; -}`]})};function Wk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit,n=G(3);A(2),Z(``,e.name,`.`,e.hook),A(2),Y(e.calls),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function Gk(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Lifecycle hooks`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Hook`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,Wk,9,5,`tr`,null,kg),V()()()),e&2){let e=G(2);A(15),F(e.hooks())}}function Kk(e,t){if(e&1&&J(0),e&2){let e=G().$implicit;X(` (`,e.listener,`) `)}}function qk(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),M(3,Kk,1,1),V(),B(4,`td`,6),J(5),V(),B(6,`td`,6),J(7),V(),B(8,`td`,6),J(9),V()()),e&2){let e=t.$implicit,n=G(3);A(2),X(` `,e.name,` `),A(),N(e.listener?3:-1),A(2),Y(e.calls),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function Jk(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Output listeners`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Listener`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,qk,10,5,`tr`,null,kg),V()()()),e&2){let e=G(2);A(15),F(e.outputs())}}function Yk(e,t){if(e&1&&(B(0,`p`,1),J(1),V()),e&2){let e=t,n=G(2);A(),iv(` afterRender callbacks ran `,e.runs,` `,e.runs===1?`time`:`times`,`, `,n.ms(e.ms),` in total, slowest `,n.ms(e.maxMs),`. `)}}function Xk(e,t){if(e&1&&(B(0,`p`,2),J(1),V()),e&2){let e=G(2);A(),Z(` `,e.dropped(),` more hook or output `,e.dropped()===1?`row is`:`rows are`,` left out. A recording lists at most 100 of each. `)}}function Zk(e,t){if(e&1&&(B(0,`div`,0),M(1,Gk,17,0,`div`),M(2,Jk,17,0,`div`),V(),M(3,Yk,2,4,`p`,1),M(4,Xk,2,2,`p`,2)),e&2){let e,t=G();A(),N(t.hooks().length?1:-1),A(),N(t.outputs().length?2:-1),A(),N((e=t.afterRender())?3:-1,e),A(),N(t.dropped()?4:-1)}}var Qk=10;function $k(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}var eA=class e{page=$(null);hooks=Q(()=>(this.page()?.hooks??[]).slice(0,Qk));outputs=Q(()=>(this.page()?.outputs??[]).slice(0,Qk));afterRender=Q(()=>{let e=this.page()?.afterRender;return e?.runs?e:null});dropped=Q(()=>this.page()?.droppedTimings??0);ms(e){return $k(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-timing`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[1,`timing`],[1,`after-render`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`mono`],[1,`num`]],template:function(e,t){e&1&&M(0,Zk,5,4),e&2&&N(t.hooks().length||t.outputs().length||t.afterRender()?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})};function aj(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit,n=G(3);k(2),Z(``,e.name,`.`,e.hook),k(2),Y(e.calls),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function oj(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Lifecycle hooks`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Hook`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,aj,9,5,`tr`,null,kg),V()()()),e&2){let e=G(2);k(15),F(e.hooks())}}function sj(e,t){if(e&1&&J(0),e&2){let e=G().$implicit;X(` (`,e.listener,`) `)}}function cj(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),M(3,sj,1,1),V(),B(4,`td`,6),J(5),V(),B(6,`td`,6),J(7),V(),B(8,`td`,6),J(9),V()()),e&2){let e=t.$implicit,n=G(3);k(2),X(` `,e.name,` `),k(),N(e.listener?3:-1),k(2),Y(e.calls),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function lj(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Output listeners`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Listener`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,cj,10,5,`tr`,null,kg),V()()()),e&2){let e=G(2);k(15),F(e.outputs())}}function uj(e,t){if(e&1&&(B(0,`p`,1),J(1),V()),e&2){let e=t,n=G(2);k(),iv(` afterRender callbacks ran `,e.runs,` `,e.runs===1?`time`:`times`,`, `,n.ms(e.ms),` in total, slowest `,n.ms(e.maxMs),`. `)}}function dj(e,t){if(e&1&&(B(0,`p`,2),J(1),V()),e&2){let e=G(2);k(),Z(` `,e.dropped(),` more hook or output `,e.dropped()===1?`row is`:`rows are`,` left out. A recording lists at most 100 of each. `)}}function fj(e,t){if(e&1&&(B(0,`div`,0),M(1,oj,17,0,`div`),M(2,lj,17,0,`div`),V(),M(3,uj,2,4,`p`,1),M(4,dj,2,2,`p`,2)),e&2){let e,t=G();k(),N(t.hooks().length?1:-1),k(),N(t.outputs().length?2:-1),k(),N((e=t.afterRender())?3:-1,e),k(),N(t.dropped()?4:-1)}}var pj=10;function mj(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}var hj=class e{page=$(null);hooks=Q(()=>(this.page()?.hooks??[]).slice(0,pj));outputs=Q(()=>(this.page()?.outputs??[]).slice(0,pj));afterRender=Q(()=>{let e=this.page()?.afterRender;return e?.runs?e:null});dropped=Q(()=>this.page()?.droppedTimings??0);ms(e){return mj(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-timing`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[1,`timing`],[1,`after-render`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`mono`],[1,`num`]],template:function(e,t){e&1&&M(0,fj,5,4),e&2&&N(t.hooks().length||t.outputs().length||t.afterRender()?0:-1)},styles:[`[_nghost-%COMP%] { display: block; } @@ -1412,7 +1491,7 @@ td.mono[_ngcontent-%COMP%] { margin: 8px 0 0; color: var(--%NS%text-2); font-size: 12px; -}`]})},tA=864e13,nA=200,rA=300,iA=100,aA=10,oA=100,sA=2e3,cA=2e3,lA=4e3,uA=1e3,dA=100,fA={component:`c`,hook:`h`,afterRender:`r`,output:`o`},pA=Object.values(fA),mA=e=>!!e&&typeof e==`object`&&!Array.isArray(e),hA=e=>typeof e==`number`&&Number.isFinite(e)&&e>=0?e:0,gA=(e,t)=>typeof e==`string`?e.slice(0,t):``,_A=e=>hA(e)>0?hA(e):void 0,vA=(e,t)=>Array.isArray(e)?e.slice(0,t):[];function yA(e){if(!mA(e))return null;let t=gA(e.name,nA);return t?{name:t,checks:hA(e.checks),ms:hA(e.ms)}:null}function bA(e,t){if(!Array.isArray(e)||e.length!==5)return null;let[n,r,i,a,o]=e;return typeof n!=`number`||!Number.isInteger(n)||n<0||n>=t||typeof r!=`number`||!Number.isFinite(r)||Math.abs(r)>1e7||typeof a!=`number`||!Number.isInteger(a)||a<0||a>uA||typeof o!=`string`||!pA.includes(o)?null:[n,r,hA(i),a,o]}function xA(e,t){if(!mA(e)||typeof e.id!=`number`)return null;let n=vA(e.components,aA).map(yA).filter(e=>!!e),r=gA(e.trigger,rA),i=vA(e.spans,40).map(e=>bA(e,t)).filter(e=>!!e),a=Array.isArray(e.spans)?e.spans.length-40:0,o=Math.floor(hA(e.droppedSpans))+Math.max(0,a),s={t:typeof e.t==`number`?hA(e.t):void 0,hookMs:_A(e.hookMs),afterRenderMs:_A(e.afterRenderMs),outputMs:_A(e.outputMs)};return{id:hA(e.id),at:hA(e.at),ms:hA(e.ms),passes:hA(e.passes),...r?{trigger:r}:{},checks:hA(e.checks),components:n,...Object.fromEntries(Object.entries(s).filter(([,e])=>e!==void 0)),...i.length?{spans:i}:{},...o?{droppedSpans:o}:{}}}function SA(e){let t=yA(e);return!t||!mA(e)?null:{...t,maxMs:hA(e.maxMs),cycles:hA(e.cycles)}}function CA(e){if(!mA(e))return null;let t=gA(e.name,nA),n=gA(e.hook,iA);if(!t||!n)return null;let{calls:r,ms:i,maxMs:a}=e;return{name:t,hook:n,calls:hA(r),ms:hA(i),maxMs:hA(a)}}function wA(e){if(!mA(e))return null;let t=gA(e.name,nA);if(!t)return null;let n=gA(e.listener,nA);return{name:t,...n?{listener:n}:{},calls:hA(e.calls),ms:hA(e.ms),maxMs:hA(e.maxMs)}}function TA(e){if(mA(e)&&hA(e.runs))return{runs:hA(e.runs),ms:hA(e.ms),maxMs:hA(e.maxMs)}}function EA(e,t){if(!mA(e))return null;let n=vA(e.spanNames,lA).map(e=>gA(e,rA)),r=Array.isArray(e.cycles)?e.cycles.slice(-Math.min(t,cA)).map(e=>xA(e,n.length)).filter(e=>!!e):[],i={},a=0;if(mA(e.hosts)){let t=Object.entries(e.hosts);a=Math.max(0,t.length-sA);for(let[e,n]of t.slice(0,sA))e.length<50&&hA(n)&&(i[e]=hA(n))}let o=Array.isArray(e.components)?e.components:[],s=Math.floor(hA(e.droppedClasses))+Math.max(0,o.length-oA),c=Math.floor(hA(e.droppedHosts))+a,l=vA(e.hooks,dA).map(CA).filter(e=>!!e),u=vA(e.outputs,dA).map(wA).filter(e=>!!e),d=Math.max(0,vA(e.hooks,1/0).length-dA)+Math.max(0,vA(e.outputs,1/0).length-dA),f=Math.floor(hA(e.droppedTimings))+d,p=TA(e.afterRender),m=r.some(e=>e.spans?.length);return{recording:e.recording===!0,startedAt:typeof e.startedAt==`number`&&e.startedAt<=tA?hA(e.startedAt):null,dropped:hA(e.dropped),cycles:r,components:o.slice(0,oA).map(SA).filter(e=>!!e),...s?{droppedClasses:s}:{},hosts:i,...c?{droppedHosts:c}:{},...l.length?{hooks:l}:{},...u.length?{outputs:u}:{},...f?{droppedTimings:f}:{},...p?{afterRender:p}:{},...m?{spanNames:n}:{}}}var DA=`pangular-inspector/change-detection`;function OA(e,t,n=Date.now()){return{format:DA,version:1,exportedAt:n,pageId:t,recording:{...EA(e,cA)??e,recording:!1,hosts:{}}}}function kA(e,t){if(e.length>2e7||e.length*3>2e7&&new TextEncoder().encode(e).byteLength>2e7)return{ok:!1,error:`The file is larger than 20 MB.`};let n;try{n=JSON.parse(e)}catch{return{ok:!1,error:`The file is not valid JSON.`}}if(!mA(n))return{ok:!1,error:`The file is not a recording.`};if(n.format!==void 0&&n.format!==`pangular-inspector/change-detection`)return{ok:!1,error:`The file is not a change detection recording.`};let r=mA(n.recording)?n.recording:n;if(!Array.isArray(r.cycles))return{ok:!1,error:`The file has no change detection cycles.`};let i=EA(r,t);if(!i)return{ok:!1,error:`The file is not a recording.`};let a=gA(n.pageId??r.pageId,49)||`imported`,o=_A(n.exportedAt);return{ok:!0,pageId:a,...o?{exportedAt:o}:{},recording:{...i,recording:!1}}}var AA=1,jA=1,MA=2,NA={c:`component`,h:`lifecycle-hook`,r:`after-render`,o:`output`},PA=e=>Math.round(e*1e6)/1e3;function FA(e,t){let n=e.spanNames??[],r=e.cycles[0]?.at??0,i=e.startedAt??r,a=[],o=0,s=0;for(let t of e.cycles){let e=t.t??Math.max(0,t.at-i),r=e+t.ms;a.push({name:`Change detection #${t.id}`,cat:`change-detection`,ph:`X`,pid:AA,tid:jA,ts:PA(e),dur:PA(t.ms),args:{checks:t.checks,passes:t.passes,...t.trigger?{trigger:t.trigger}:{},...t.hookMs?{hookMs:t.hookMs}:{},...t.afterRenderMs?{afterRenderMs:t.afterRenderMs}:{},...t.outputMs?{outputMs:t.outputMs}:{},slowest:t.components.map(e=>`${e.name} ${e.checks}x ${e.ms}ms`)}}),s+=t.droppedSpans??0;let c=[{end:r}],l=[...t.spans??[]].sort((e,t)=>e[1]-t[1]||t[2]-e[2]);for(let[r,i,s,u,d]of l){o++;let l=n[r]??`?`;if(d===fA.output){let n=e+i;a.push({name:l,cat:NA[d],ph:`X`,pid:AA,tid:MA,ts:PA(n),dur:PA(i<0?Math.max(0,Math.min(s,-i)):s),args:{cycle:t.id}});continue}let f=Math.max(e,e+i);for(;c.length>1&&c.at(-1).end<=f;)c.pop();let p=c.at(-1).end,m=Math.min(f+s,p);me.ts??0));if(c<0)for(let e of a)e.ts=PA((e.ts-c)/1e3);a.sort((e,t)=>e.ts-t.ts||t.dur-e.dur);let l=(e,t,n)=>({name:t,ph:`M`,pid:AA,tid:e,args:{name:n}});return{traceEvents:[l(0,`process_name`,`Angular change detection (page ${t})`),l(jA,`thread_name`,`Change detection`),l(MA,`thread_name`,`Outputs`),...a],displayTimeUnit:`ms`,otherData:{source:`Pangular Inspector change detection recording`,pageId:t,cycles:e.cycles.length,droppedCycles:e.dropped,spans:o,droppedSpans:s,...e.startedAt&&e.startedAt<=tA?{startedAt:new Date(e.startedAt).toISOString()}:{}}}}function IA(e,t){if(e&1&&(B(0,`p`,5),J(1),V()),e&2){let e=G();A(),Y(e.error())}}function LA(e,t){let n=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=t,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}var RA=class e{page=$(null);maxCycles=$(200);imported=Rv();error=k(``);hasCycles(){return(this.page()?.cycles.length??0)>0}exportJson(){let e=this.page();e&&LA(OA(e,e.pageId),`change-detection-${e.pageId}.json`)}exportTrace(){let e=this.page();e&&LA(FA(e,e.pageId),`change-detection-${e.pageId}.trace.json`)}async read(e){let t=e.files?.[0];if(e.value=``,!t)return;if(t.size>2e7){this.error.set(`${t.name}: The file is larger than 20 MB.`);return}let n;try{n=await t.text()}catch{this.error.set(`Could not read the file.`);return}let r=kA(n,this.maxCycles());if(!r.ok){this.error.set(`${t.name}: ${r.error}`);return}this.error.set(``),this.imported.emit({fileName:t.name,page:{...r.recording,pageId:r.pageId,supported:!0}})}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-transfer`]],inputs:{page:[1,`page`],maxCycles:[1,`maxCycles`]},outputs:{imported:`imported`},decls:10,vars:3,consts:[[`file`,``],[`role`,`group`,`aria-label`,`Export and import the recording`,1,`transfer`],[`type`,`button`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[`type`,`file`,`accept`,`.json,application/json`,`hidden`,``,3,`change`],[`role`,`alert`,1,`error`]],template:function(e,t){if(e&1){let e=H();B(0,`div`,1)(1,`button`,2),W(`click`,function(){return t.exportJson()}),J(2,`Export JSON`),V(),B(3,`button`,2),W(`click`,function(){return t.exportTrace()}),J(4,` Export trace (Perfetto) `),V(),B(5,`button`,3),W(`click`,function(){return E(e),D(d_(8).click())}),J(6,`Import`),V(),B(7,`input`,4,0),W(`change`,function(){E(e);let n=d_(8);return D(t.read(n))}),V()(),M(9,IA,2,1,`p`,5)}e&2&&(A(),qg(`disabled`,!t.hasCycles()),A(2),qg(`disabled`,!t.hasCycles()),A(6),N(t.error()?9:-1))},styles:[`[_nghost-%COMP%] { +}`]})};function gj(e,t){if(e&1&&(B(0,`p`,5),J(1),V()),e&2){let e=G();k(),Y(e.error())}}function _j(e,t){let n=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=t,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}var vj=class e{page=$(null);maxCycles=$(200);imported=Rv();error=O(``);hasCycles(){return(this.page()?.cycles.length??0)>0}exportJson(){let e=this.page();e&&_j(Uk(e,e.pageId),`change-detection-${e.pageId}.json`)}exportTrace(){let e=this.page();e&&_j(Xk(e,e.pageId),`change-detection-${e.pageId}.trace.json`)}async read(e){let t=e.files?.[0];if(e.value=``,!t)return;if(t.size>2e7){this.error.set(`${t.name}: The file is larger than 20 MB.`);return}let n;try{n=await t.text()}catch{this.error.set(`Could not read the file.`);return}let r=Wk(n,this.maxCycles());if(!r.ok){this.error.set(`${t.name}: ${r.error}`);return}this.error.set(``),this.imported.emit({fileName:t.name,page:{...r.recording,pageId:r.pageId,supported:!0}})}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-transfer`]],inputs:{page:[1,`page`],maxCycles:[1,`maxCycles`]},outputs:{imported:`imported`},decls:10,vars:3,consts:[[`file`,``],[`role`,`group`,`aria-label`,`Export and import the recording`,1,`transfer`],[`type`,`button`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[`type`,`file`,`accept`,`.json,application/json`,`hidden`,``,3,`change`],[`role`,`alert`,1,`error`]],template:function(e,t){if(e&1){let e=H();B(0,`div`,1)(1,`button`,2),W(`click`,function(){return t.exportJson()}),J(2,`Export JSON`),V(),B(3,`button`,2),W(`click`,function(){return t.exportTrace()}),J(4,` Export trace (Perfetto) `),V(),B(5,`button`,3),W(`click`,function(){return T(e),E(d_(8).click())}),J(6,`Import`),V(),B(7,`input`,4,0),W(`change`,function(){T(e);let n=d_(8);return E(t.read(n))}),V()(),M(9,gj,2,1,`p`,5)}e&2&&(k(),qg(`disabled`,!t.hasCycles()),k(2),qg(`disabled`,!t.hasCycles()),k(6),N(t.error()?9:-1))},styles:[`[_nghost-%COMP%] { display: contents; } @@ -1454,7 +1533,7 @@ button[_ngcontent-%COMP%]:disabled { margin: 0; color: var(--%NS%danger-text); font-size: 12px; -}`]})},zA=(e,t)=>t.stat.name;function BA(e,t){if(e&1&&(B(0,`span`,8),J(1),V()),e&2){let e=G(2).$implicit;A(),X(``,e.other,` more`)}}function VA(e,t){if(e&1&&(B(0,`div`,6)(1,`span`,7),J(2),V(),M(3,BA,2,1,`span`,8),V()),e&2){let e=G().$implicit;K(`--%NS%tone`,e.tone+`%`),A(2),Y(e.label),A(),N(e.roomy?3:-1)}}function HA(e,t){if(e&1&&(B(0,`span`,10),J(1),V(),B(2,`span`,11),J(3),V()),e&2){let e=G(2).$implicit,t=G(2);A(),Y(e.stat.name),A(2),Y(t.fmt(e.stat.ms))}}function UA(e,t){if(e&1){let e=H();B(0,`button`,9),W(`focus`,function(){E(e);let t=G().$index;return D(G(2).current.set(t))})(`click`,function(){E(e);let t=G().$implicit;return D(G(2).pick.emit(t.stat.name))}),M(1,HA,4,2),V()}if(e&2){let e=G(),t=e.$implicit,n=e.$index,r=G(2);K(`--%NS%tone`,t.tone+`%`),j(`tabindex`,n===r.tabStop()?0:-1)(`aria-label`,t.label)(`data-index`,n),A(),N(t.roomy?1:-1)}}function WA(e,t){if(e&1&&(B(0,`li`),M(1,VA,4,4,`div`,4)(2,UA,2,6,`button`,5),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`top`,e.y,`%`)(`width`,e.w,`%`)(`height`,e.h,`%`),A(),N(e.other?1:2)}}function GA(e,t){if(e&1){let e=H();B(0,`ul`,2),W(`keydown`,function(t){return E(e),D(G().onKey(t))}),P(1,WA,3,9,`li`,3,zA),V()}if(e&2){let e=G();j(`aria-label`,e.label()),A(),F(e.cells())}}function KA(e,t){e&1&&(B(0,`p`,1),J(1,`No component time in these cycles.`),V())}var qA=24,JA=3,YA=class e{stats=$([]);scope=$(`the recording`);pick=Rv();current=k(0);label=Q(()=>`Self time per component in ${this.scope()}, largest first. Pick one to show it in the tree.`);cells=Q(()=>{let e=this.stats().filter(e=>e.ms>0),t=e.slice(0,qA),n=e.slice(qA),r=n.reduce((e,t)=>e+t.ms,0),i=t.map(e=>({stat:e,other:0}));n.length&&i.push({stat:{name:`Other components`,checks:0,ms:r,maxMs:0,cycles:0},other:n.length});let a=e.reduce((e,t)=>e+t.ms,0),o=t[0]?.ms??1,s=lk(i,e=>e.stat.ms,JA);return s.sort((e,t)=>Number(e.item.other>0)-Number(t.item.other>0)),s.map(e=>{let{stat:t,other:n}=e.item,r=a?Math.round(t.ms/a*100):0;return{stat:t,other:n,x:e.x,y:e.y,w:e.w,h:e.h,tone:n?0:14+Math.round(26*Math.min(t.ms/o,1)),roomy:e.w>=10&&e.h>=22,label:n?`${n} more components, ${ak(t.ms)}, ${r}% of self time`:`${t.name}, ${ak(t.ms)} self time, ${r}%, ${t.checks} ${t.checks===1?`check`:`checks`}`}})});tabStop=Q(()=>Math.min(this.current(),Math.max(this.cells().filter(e=>!e.other).length-1,0)));fmt(e){return ak(e)}onKey(e){let t=this.cells().filter(e=>!e.other).length;if(!t)return;let n=this.tabStop(),r;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=Math.min(n+1,t-1);break;case`ArrowLeft`:case`ArrowUp`:r=Math.max(n-1,0);break;case`Home`:r=0;break;case`End`:r=t-1;break;default:return}e.preventDefault(),this.current.set(r),e.currentTarget.querySelector(`button[data-index="${r}"]`)?.focus()}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-treemap`]],inputs:{stats:[1,`stats`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:2,vars:1,consts:[[1,`map`],[1,`empty`],[1,`map`,3,`keydown`],[3,`left`,`top`,`width`,`height`],[1,`cell`,`other`,3,`--%NS%tone`],[`type`,`button`,1,`cell`,3,`--%NS%tone`],[1,`cell`,`other`],[1,`sr-only`],[`aria-hidden`,`true`,1,`name`],[`type`,`button`,1,`cell`,3,`focus`,`click`],[1,`name`,`mono`],[1,`ms`]],template:function(e,t){e&1&&M(0,GA,3,1,`ul`,0)(1,KA,2,0,`p`,1),e&2&&N(+!t.cells().length)},styles:[`[_nghost-%COMP%] { +}`]})},yj=(e,t)=>t.stat.name;function bj(e,t){if(e&1&&(B(0,`span`,8),J(1),V()),e&2){let e=G(2).$implicit;k(),X(``,e.other,` more`)}}function xj(e,t){if(e&1&&(B(0,`div`,6)(1,`span`,7),J(2),V(),M(3,bj,2,1,`span`,8),V()),e&2){let e=G().$implicit;K(`--%NS%tone`,e.tone+`%`),k(2),Y(e.label),k(),N(e.roomy?3:-1)}}function Sj(e,t){if(e&1&&(B(0,`span`,10),J(1),V(),B(2,`span`,11),J(3),V()),e&2){let e=G(2).$implicit,t=G(2);k(),Y(e.stat.name),k(2),Y(t.fmt(e.stat.ms))}}function Cj(e,t){if(e&1){let e=H();B(0,`button`,9),W(`focus`,function(){T(e);let t=G().$index;return E(G(2).current.set(t))})(`click`,function(){T(e);let t=G().$implicit;return E(G(2).pick.emit(t.stat.name))}),M(1,Sj,4,2),V()}if(e&2){let e=G(),t=e.$implicit,n=e.$index,r=G(2);K(`--%NS%tone`,t.tone+`%`),j(`tabindex`,n===r.tabStop()?0:-1)(`aria-label`,t.label)(`data-index`,n),k(),N(t.roomy?1:-1)}}function wj(e,t){if(e&1&&(B(0,`li`),M(1,xj,4,4,`div`,4)(2,Cj,2,6,`button`,5),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`top`,e.y,`%`)(`width`,e.w,`%`)(`height`,e.h,`%`),k(),N(e.other?1:2)}}function Tj(e,t){if(e&1){let e=H();B(0,`ul`,2),W(`keydown`,function(t){return T(e),E(G().onKey(t))}),P(1,wj,3,9,`li`,3,yj),V()}if(e&2){let e=G();j(`aria-label`,e.label()),k(),F(e.cells())}}function Ej(e,t){e&1&&(B(0,`p`,1),J(1,`No component time in these cycles.`),V())}var Dj=24,Oj=3,kj=class e{stats=$([]);scope=$(`the recording`);pick=Rv();current=O(0);label=Q(()=>`Self time per component in ${this.scope()}, largest first. Pick one to show it in the tree.`);cells=Q(()=>{let e=this.stats().filter(e=>e.ms>0),t=e.slice(0,Dj),n=e.slice(Dj),r=n.reduce((e,t)=>e+t.ms,0),i=t.map(e=>({stat:e,other:0}));n.length&&i.push({stat:{name:`Other components`,checks:0,ms:r,maxMs:0,cycles:0},other:n.length});let a=e.reduce((e,t)=>e+t.ms,0),o=t[0]?.ms??1,s=rA(i,e=>e.stat.ms,Oj);return s.sort((e,t)=>Number(e.item.other>0)-Number(t.item.other>0)),s.map(e=>{let{stat:t,other:n}=e.item,r=a?Math.round(t.ms/a*100):0;return{stat:t,other:n,x:e.x,y:e.y,w:e.w,h:e.h,tone:n?0:14+Math.round(26*Math.min(t.ms/o,1)),roomy:e.w>=10&&e.h>=22,label:n?`${n} more components, ${$k(t.ms)}, ${r}% of self time`:`${t.name}, ${$k(t.ms)} self time, ${r}%, ${t.checks} ${t.checks===1?`check`:`checks`}`}})});tabStop=Q(()=>Math.min(this.current(),Math.max(this.cells().filter(e=>!e.other).length-1,0)));fmt(e){return $k(e)}onKey(e){let t=this.cells().filter(e=>!e.other).length;if(!t)return;let n=this.tabStop(),r;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=Math.min(n+1,t-1);break;case`ArrowLeft`:case`ArrowUp`:r=Math.max(n-1,0);break;case`Home`:r=0;break;case`End`:r=t-1;break;default:return}e.preventDefault(),this.current.set(r),e.currentTarget.querySelector(`button[data-index="${r}"]`)?.focus()}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-treemap`]],inputs:{stats:[1,`stats`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:2,vars:1,consts:[[1,`map`],[1,`empty`],[1,`map`,3,`keydown`],[3,`left`,`top`,`width`,`height`],[1,`cell`,`other`,3,`--%NS%tone`],[`type`,`button`,1,`cell`,3,`--%NS%tone`],[1,`cell`,`other`],[1,`sr-only`],[`aria-hidden`,`true`,1,`name`],[`type`,`button`,1,`cell`,3,`focus`,`click`],[1,`name`,`mono`],[1,`ms`]],template:function(e,t){e&1&&M(0,Tj,3,1,`ul`,0)(1,Ej,2,0,`p`,1),e&2&&N(+!t.cells().length)},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1530,7 +1609,7 @@ button.cell[_ngcontent-%COMP%]:focus-visible { .empty[_ngcontent-%COMP%] { margin: 8px 0; color: var(--%NS%text-2); -}`]})},XA=(e,t)=>t.id;function ZA(e,t){if(e&1){let e=H();L(0,`button`,15),U(`click`,function(){return E(e),D(G(2).clear())}),J(1,`Clear`),R()}}function QA(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return E(e),D(G().toggle())}),z(1,`span`,13),J(2),R(),M(3,ZA,2,0,`button`,14)}if(e&2){let e=G();q(`on`,e.recording()),I(`disabled`,!e.pageId()),A(2),X(` `,e.recording()?`Stop recording`:`Record`,` `),A(),N(e.cycles().length?3:-1)}}function $A(e,t){if(e&1){let e=H();L(0,`p`,6)(1,`span`,16),J(2,`Imported recording`),R(),L(3,`span`,17),J(4),R(),L(5,`button`,15),U(`click`,function(){return E(e),D(G().closeImport())}),J(6,`Back to live recording`),R()()}e&2&&(A(4),Y(t.fileName))}function ej(e,t){e&1&&z(0,`app-angular-unavailable`,8),e&2&&I(`page`,G().angularPage())}function tj(e,t){e&1&&(L(0,`p`,10),J(1,`Angular profiling stays on until the page reloads.`),R())}function nj(e,t){e&1&&z(0,`app-angular-unavailable`,21),e&2&&I(`page`,G(2).angularPage())}function rj(e,t){if(e&1){let e=H();L(0,`div`,18)(1,`span`,19),J(2,`Live views`),R(),L(3,`button`,20),U(`click`,function(){E(e);let t=G();return D(t.setView(`flash`,!t.views().flash))}),z(4,`span`,13),J(5,` Flash checks `),R(),L(6,`button`,20),U(`click`,function(){E(e);let t=G();return D(t.setView(`track`,!t.views().track))}),z(7,`span`,13),J(8,` Performance track `),R(),L(9,`button`,20),U(`click`,function(){return E(e),D(G().setView(`angularProfiling`,!0))}),z(10,`span`,13),J(11,` Angular profiling `),R()(),L(12,`p`,7),J(13,` Flash checks draws a box over each component on the page as Angular checks it, with its name and how often it was checked, fading over a second. Performance track adds a Pangular track to the Chrome Performance panel with every component check, hook and output. Angular profiling turns on Angular's own track there. `),R(),M(14,tj,2,0,`p`,10)(15,nj,1,1,`app-angular-unavailable`,21)}if(e&2){let e=G();A(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().flash),A(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().track),A(3),I(`disabled`,!e.canShowViews()||e.views().angularProfiling||!e.views().angularProfilingAvailable),j(`aria-pressed`,e.views().angularProfiling),A(5),N(e.views().angularProfiling?14:e.views().angularProfilingAvailable?-1:15)}}function ij(e,t){if(e&1&&(L(0,`p`,10),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function aj(e,t){if(e&1&&(L(0,`p`,24),J(1),R()),e&2){let e=G(2);A(),X(` `,e.range()?`The picked cycles have no timed spans, so there is no flame graph for them.`:`This recording has no timed spans, so there is no flame graph. A recording from an older version, or a file saved without spans, has none.`,` `)}}function oj(e,t){e&1&&(L(0,`p`,10),J(1,` For picked cycles, totals come from the 10 slowest components each cycle lists. `),R())}function sj(e,t){if(e&1){let e=H();L(0,`h3`),J(1,`Cycles`),R(),L(2,`app-cd-cycle-chart`,22),cv(`rangeChange`,function(t){E(e);let n=G();return sv(n.range,t)||(n.range=t),D(t)}),R(),L(3,`app-cd-flame-graph`,23),U(`pick`,function(t){return E(e),D(G().showComponent.emit(t))}),R(),M(4,aj,2,1,`p`,24),L(5,`h3`),J(6,`Self time by component`),R(),M(7,oj,2,0,`p`,10),L(8,`app-cd-treemap`,25),U(`pick`,function(t){return E(e),D(G().showComponent.emit(t))}),R()}if(e&2){let e=G();A(2),I(`cycles`,e.cycles()),ov(`range`,e.range),A(),I(`cycles`,e.picked())(`names`,e.spanNames())(`scope`,e.scope()),A(),N(e.hasSpans()?-1:4),A(3),N(e.range()?7:-1),A(),I(`stats`,e.stats())(`scope`,e.scope())}}function cj(e,t){if(e&1&&(L(0,`tr`)(1,`td`,17),J(2),R(),L(3,`td`,31),J(4),R(),L(5,`td`,31),J(6),R(),L(7,`td`,31),J(8),R()()),e&2){let e=t.$implicit,n=G(2);A(2),Y(e.name),A(2),Y(e.checks),A(2),Y(n.ms(e.ms)),A(2),Y(n.ms(e.maxMs))}}function lj(e,t){e&1&&(L(0,`tr`)(1,`td`,32),J(2,`No component time in the picked cycles.`),R()())}function uj(e,t){if(e&1&&(L(0,`span`,34),J(1,`after `),L(2,`span`,17),J(3),R()()),e&2){let e=G().$implicit;A(3),Y(e.trigger)}}function dj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`hooks `,t.ms(e.hookMs))}}function fj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);A(),X(`afterRender `,t.ms(e.afterRenderMs))}}function pj(e,t){if(e&1&&(L(0,`span`,36),J(1,` slowest `),L(2,`span`,17),J(3),R(),J(4),R()),e&2){let e=t,n=G(3);A(3),Y(e.name),A(),X(` `,n.ms(e.ms),` `)}}function mj(e,t){if(e&1&&(L(0,`li`)(1,`span`,33),J(2),R(),L(3,`span`,17),J(4),R(),L(5,`span`),J(6),R(),M(7,uj,4,1,`span`,34),M(8,dj,2,1,`span`,35),M(9,fj,2,1,`span`,35),M(10,pj,5,2,`span`,36),R()),e&2){let e,n=t.$implicit,r=G(2);A(2),Y(r.clock(n.at)),A(2),Y(r.ms(n.ms)),A(2),iv(` `,n.checks,` `,n.checks===1?`check`:`checks`,`, `,n.passes,` `,n.passes===1?`pass`:`passes`,` `),A(),N(n.trigger?7:-1),A(),N(n.hookMs?8:-1),A(),N(n.afterRenderMs?9:-1),A(),N((e=n.components[0])?10:-1,e)}}function hj(e,t){if(e&1&&(L(0,`div`,26)(1,`div`)(2,`h3`),J(3),R(),L(4,`table`)(5,`thead`)(6,`tr`)(7,`th`,27),J(8,`Component`),R(),L(9,`th`,28),J(10,`Checks`),R(),L(11,`th`,28),J(12,`Self time`),R(),L(13,`th`,28),J(14,`Slowest`),R()()(),L(15,`tbody`),P(16,cj,9,4,`tr`,null,kg,!1,lj,3,0,`tr`),R()()(),L(19,`div`)(20,`h3`),J(21,`Latest cycles`),R(),L(22,`ol`,29),P(23,mj,11,10,`li`,null,XA),R()()(),z(25,`app-cd-timing`,30)),e&2){let e=G();A(3),X(` `,e.range()?`Slowest components in the picked cycles`:`Slowest components`,` `),A(13),F(e.slowest()),A(7),F(e.latest()),A(2),I(`page`,e.page())}}function gj(e,t){e&1&&(L(0,`p`,11),J(1,`Use the app. Cycles show up here as Angular runs change detection.`),R())}var _j=10,vj=class e{livePage=$(null,{alias:`page`});pageId=$(null);rpc=$(null);angularPages=lO(()=>this.rpc());angularPage=Q(()=>uO(this.angularPages(),this.pageId()));showComponent=Rv();range=k(null);imported=k(null);page=Q(()=>this.imported()?.page??this.livePage());views=Fv(()=>this.livePage()?.options??{flash:!1,track:!1,angularProfiling:!1,angularProfilingAvailable:!0});canShowViews=Q(()=>!!this.pageId()&&this.livePage()?.supported!==!1);message=k(``);announcement=k(``);recording=Q(()=>this.page()?.recording===!0);cycles=Q(()=>this.page()?.cycles??[]);maxCycles=Q(()=>tD(this.rpc()).limits.cdCycles);picked=Q(()=>ok(this.cycles(),this.range()));hasSpans=Q(()=>this.picked().some(e=>e.spans?.length));spanNames=Q(()=>this.page()?.spanNames??[]);stats=Q(()=>this.range()?sk(this.picked()):[...this.page()?.components??[]].sort((e,t)=>t.ms-e.ms));scope=Q(()=>{let e=this.range()?this.picked():[];return e.length?e.length===1?`cycle ${e[0].id}`:`cycles ${e[0].id} to ${e.at(-1).id}`:`the recording`});slowest=Q(()=>this.stats().slice(0,_j));latest=Q(()=>this.cycles().slice(-30).reverse());capNotes=Q(()=>{let e=this.page()?.droppedClasses??0,t=this.page()?.droppedHosts??0,n=[];return e>0&&n.push(`${e} more component ${e===1?`class was`:`classes were`} checked than a recording keeps, so ${e===1?`it is`:`they are`} left out of these totals.`),t>0&&n.push(`${t} component ${t===1?`instance was`:`instances were`} checked past the 2000 a recording counts, so ${t===1?`its tree row shows`:`their tree rows show`} no check count.`),n});status=Q(()=>{if(this.message())return this.message();let e=this.cycles().length;return this.imported()?`${e} ${e===1?`cycle`:`cycles`} imported.`:this.recording()?`Recording. ${e} ${e===1?`cycle`:`cycles`} so far.`:e?`${e} ${e===1?`cycle`:`cycles`} recorded.`:``});ms(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}clock(e){return ZO(e)}async toggle(){this.recording()?await this.send({on:!1},``,()=>{let e=this.cycles().length;return`Recording stopped. ${e} ${e===1?`cycle`:`cycles`} recorded.`}):await this.send({on:!0},`Starting…`,()=>`Recording started.`)}showImport(e){this.message.set(``),this.range.set(null),this.imported.set(e);let t=e.page.cycles.length;this.announce(`Imported ${e.fileName}: ${t} ${t===1?`cycle`:`cycles`}. Showing the imported recording.`)}closeImport(){this.imported.set(null),this.range.set(null),this.announce(`Showing the live recording.`)}async clear(){this.range.set(null),await this.send({clear:!0},``,()=>`Cleared the recorded cycles.`)}async setView(e,t){let n=this.views();this.views.set({...n,[e]:t});let r={flash:t?`Flash checks on.`:`Flash checks off.`,track:t?`Performance track on. Record in the Chrome Performance panel to see it.`:`Performance track off.`,angularProfiling:`Angular profiling on. It stays on until the page reloads.`}[e];await this.send({[e]:t},``,()=>r,`request-change-detection-options`)||this.views.set(n)}async send(e,t,n,r=`request-change-detection-record`){this.message.set(t);try{if(!this.rpc())throw Error(`no client`);return await BE(this.rpc(),r,{pageId:this.pageId(),...e}),this.message.set(``),this.announce(n()),!0}catch{let e=`Could not reach the page.`;return this.message.set(e),this.announce(e),!1}}announce(e){this.announcement.update(t=>t===e?`${e} `:e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-cd-recording`]],inputs:{livePage:[1,`page`,`livePage`],pageId:[1,`pageId`],rpc:[1,`rpc`]},outputs:{showComponent:`showComponent`},decls:21,vars:12,consts:[[`aria-labelledby`,`cd-heading`,1,`cd`],[1,`cd-head`],[`id`,`cd-heading`],[3,`imported`,`page`,`maxCycles`],[1,`status`],[`role`,`status`,1,`sr-only`],[1,`imported`],[1,`hint`],[`capability`,`profiler`,`missing`,``,`compact`,``,3,`page`],[`what`,`cycles`,`limit`,`cdCycles`,3,`dropped`,`max`],[1,`note`],[1,`empty`],[`type`,`button`,3,`click`,`disabled`],[`aria-hidden`,`true`,1,`dot`],[`type`,`button`],[`type`,`button`,3,`click`],[1,`badge`],[1,`mono`],[`role`,`group`,`aria-labelledby`,`cd-views-label`,1,`views`],[`id`,`cd-views-label`,1,`views-label`],[`type`,`button`,1,`view`,3,`click`,`disabled`],[`capability`,`angularProfiling`,`missing`,``,`compact`,``,3,`page`],[3,`rangeChange`,`cycles`,`range`],[3,`pick`,`cycles`,`names`,`scope`],[1,`spans-note`],[3,`pick`,`stats`,`scope`],[1,`cd-grid`],[`scope`,`col`],[`scope`,`col`,1,`num`],[`aria-label`,`Latest change detection cycles, newest first`,1,`cycles`],[3,`page`],[1,`num`],[`colspan`,`4`],[1,`when`],[1,`trigger`],[1,`timing`],[1,`top`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Change detection`),R(),M(4,QA,4,5),L(5,`app-cd-transfer`,3),U(`imported`,function(e){return t.showImport(e)}),R(),L(6,`p`,4),J(7),R(),L(8,`p`,5),J(9),R()(),M(10,$A,7,1,`p`,6),L(11,`p`,7),J(12,` Records each change detection cycle with Angular's profiler: how long it took, how many components it checked and the output that ran before it. Tree rows show how often each instance was checked. Times come from a development build. `),R(),M(13,ej,1,1,`app-angular-unavailable`,8),M(14,rj,16,7),z(15,`app-limit-note`,9),P(16,ij,2,1,`p`,10,Ag),M(18,sj,9,9),M(19,hj,26,3)(20,gj,2,0,`p`,11),R()),e&2){let e;A(4),N(t.imported()?-1:4),A(),I(`page`,t.page())(`maxCycles`,t.maxCycles()),A(2),Y(t.status()),A(2),Y(t.announcement()),A(),N((e=t.imported())?10:-1,e),A(3),N(t.page()?.supported===!1?13:-1),A(),N(t.imported()?-1:14),A(),I(`dropped`,t.page()?.dropped??0)(`max`,t.maxCycles()),A(),F(t.capNotes()),A(2),N(t.cycles().length?18:-1),A(),N(t.page()?.components?.length?19:t.recording()?20:-1)}},dependencies:[mO,nk,eA,RA,Ok,Uk,YA],styles:[`[_nghost-%COMP%] { +}`]})},Aj=(e,t)=>t.id;function jj(e,t){if(e&1){let e=H();L(0,`button`,15),U(`click`,function(){return T(e),E(G(2).clear())}),J(1,`Clear`),R()}}function Mj(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return T(e),E(G().toggle())}),z(1,`span`,13),J(2),R(),M(3,jj,2,0,`button`,14)}if(e&2){let e=G();q(`on`,e.recording()),I(`disabled`,!e.pageId()),k(2),X(` `,e.recording()?`Stop recording`:`Record`,` `),k(),N(e.cycles().length?3:-1)}}function Nj(e,t){if(e&1){let e=H();L(0,`p`,6)(1,`span`,16),J(2,`Imported recording`),R(),L(3,`span`,17),J(4),R(),L(5,`button`,15),U(`click`,function(){return T(e),E(G().closeImport())}),J(6,`Back to live recording`),R()()}e&2&&(k(4),Y(t.fileName))}function Pj(e,t){e&1&&z(0,`app-angular-unavailable`,8),e&2&&I(`page`,G().angularPage())}function Fj(e,t){e&1&&(L(0,`p`,10),J(1,`Angular profiling stays on until the page reloads.`),R())}function Ij(e,t){e&1&&z(0,`app-angular-unavailable`,21),e&2&&I(`page`,G(2).angularPage())}function Lj(e,t){if(e&1){let e=H();L(0,`div`,18)(1,`span`,19),J(2,`Live views`),R(),L(3,`button`,20),U(`click`,function(){T(e);let t=G();return E(t.setView(`flash`,!t.views().flash))}),z(4,`span`,13),J(5,` Flash checks `),R(),L(6,`button`,20),U(`click`,function(){T(e);let t=G();return E(t.setView(`track`,!t.views().track))}),z(7,`span`,13),J(8,` Performance track `),R(),L(9,`button`,20),U(`click`,function(){return T(e),E(G().setView(`angularProfiling`,!0))}),z(10,`span`,13),J(11,` Angular profiling `),R()(),L(12,`p`,7),J(13,` Flash checks draws a box over each component on the page as Angular checks it, with its name and how often it was checked, fading over a second. Performance track adds a Pangular track to the Chrome Performance panel with every component check, hook and output. Angular profiling turns on Angular's own track there. `),R(),M(14,Fj,2,0,`p`,10)(15,Ij,1,1,`app-angular-unavailable`,21)}if(e&2){let e=G();k(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().flash),k(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().track),k(3),I(`disabled`,!e.canShowViews()||e.views().angularProfiling||!e.views().angularProfilingAvailable),j(`aria-pressed`,e.views().angularProfiling),k(5),N(e.views().angularProfiling?14:e.views().angularProfilingAvailable?-1:15)}}function Rj(e,t){if(e&1&&(L(0,`p`,10),J(1),R()),e&2){let e=t.$implicit;k(),Y(e)}}function zj(e,t){if(e&1&&(L(0,`p`,24),J(1),R()),e&2){let e=G(2);k(),X(` `,e.range()?`The picked cycles have no timed spans, so there is no flame graph for them.`:`This recording has no timed spans, so there is no flame graph. A recording from an older version, or a file saved without spans, has none.`,` `)}}function Bj(e,t){e&1&&(L(0,`p`,10),J(1,` For picked cycles, totals come from the 10 slowest components each cycle lists. `),R())}function Vj(e,t){if(e&1){let e=H();L(0,`h3`),J(1,`Cycles`),R(),L(2,`app-cd-cycle-chart`,22),cv(`rangeChange`,function(t){T(e);let n=G();return sv(n.range,t)||(n.range=t),E(t)}),R(),L(3,`app-cd-flame-graph`,23),U(`pick`,function(t){return T(e),E(G().showComponent.emit(t))}),R(),M(4,zj,2,1,`p`,24),L(5,`h3`),J(6,`Self time by component`),R(),M(7,Bj,2,0,`p`,10),L(8,`app-cd-treemap`,25),U(`pick`,function(t){return T(e),E(G().showComponent.emit(t))}),R()}if(e&2){let e=G();k(2),I(`cycles`,e.cycles()),ov(`range`,e.range),k(),I(`cycles`,e.picked())(`names`,e.spanNames())(`scope`,e.scope()),k(),N(e.hasSpans()?-1:4),k(3),N(e.range()?7:-1),k(),I(`stats`,e.stats())(`scope`,e.scope())}}function Hj(e,t){if(e&1&&(L(0,`tr`)(1,`td`,17),J(2),R(),L(3,`td`,31),J(4),R(),L(5,`td`,31),J(6),R(),L(7,`td`,31),J(8),R()()),e&2){let e=t.$implicit,n=G(2);k(2),Y(e.name),k(2),Y(e.checks),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function Uj(e,t){e&1&&(L(0,`tr`)(1,`td`,32),J(2,`No component time in the picked cycles.`),R()())}function Wj(e,t){if(e&1&&(L(0,`span`,34),J(1,`from `),L(2,`span`,17),J(3),R()()),e&2){let e=G(3);k(3),Y(e.causeText(t))}}function Gj(e,t){if(e&1&&(L(0,`span`,34),J(1,`after `),L(2,`span`,17),J(3),R()()),e&2){let e=G().$implicit;k(3),Y(e.trigger)}}function Kj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit;k(),X(``,e.unchanged,` changed nothing`)}}function qj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);k(),X(`hooks `,t.ms(e.hookMs))}}function Jj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);k(),X(`afterRender `,t.ms(e.afterRenderMs))}}function Yj(e,t){if(e&1&&(L(0,`span`,36),J(1,` slowest `),L(2,`span`,17),J(3),R(),J(4),R()),e&2){let e=t,n=G(3);k(3),Y(e.name),k(),X(` `,n.ms(e.ms),` `)}}function Xj(e,t){if(e&1&&(L(0,`li`)(1,`span`,33),J(2),R(),L(3,`span`,17),J(4),R(),L(5,`span`),J(6),R(),M(7,Wj,4,1,`span`,34)(8,Gj,4,1,`span`,34),M(9,Kj,2,1,`span`,35),M(10,qj,2,1,`span`,35),M(11,Jj,2,1,`span`,35),M(12,Yj,5,2,`span`,36),R()),e&2){let e,n,r=t.$implicit,i=G(2);k(2),Y(i.clock(r.at)),k(2),Y(i.ms(r.ms)),k(2),iv(` `,r.checks,` `,r.checks===1?`check`:`checks`,`, `,r.passes,` `,r.passes===1?`pass`:`passes`,` `),k(),N((e=r.cause)?7:r.trigger?8:-1,e),k(2),N(r.unchanged?9:-1),k(),N(r.hookMs?10:-1),k(),N(r.afterRenderMs?11:-1),k(),N((n=r.components[0])?12:-1,n)}}function Zj(e,t){if(e&1&&(L(0,`div`,26)(1,`div`)(2,`h3`),J(3),R(),L(4,`table`)(5,`thead`)(6,`tr`)(7,`th`,27),J(8,`Component`),R(),L(9,`th`,28),J(10,`Checks`),R(),L(11,`th`,28),J(12,`Self time`),R(),L(13,`th`,28),J(14,`Slowest`),R()()(),L(15,`tbody`),P(16,Hj,9,4,`tr`,null,kg,!1,Uj,3,0,`tr`),R()()(),L(19,`div`)(20,`h3`),J(21,`Latest cycles`),R(),L(22,`ol`,29),P(23,Xj,13,11,`li`,null,Aj),R()()(),z(25,`app-cd-timing`,30)(26,`app-cd-diagnosis`,30)),e&2){let e=G();k(3),X(` `,e.range()?`Slowest components in the picked cycles`:`Slowest components`,` `),k(13),F(e.slowest()),k(7),F(e.latest()),k(2),I(`page`,e.page()),k(),I(`page`,e.page())}}function Qj(e,t){e&1&&(L(0,`p`,11),J(1,`Use the app. Cycles show up here as Angular runs change detection.`),R())}var $j=10,eM=class e{livePage=$(null,{alias:`page`});pageId=$(null);rpc=$(null);angularPages=uO(()=>this.rpc());angularPage=Q(()=>dO(this.angularPages(),this.pageId()));showComponent=Rv();range=O(null);imported=O(null);page=Q(()=>this.imported()?.page??this.livePage());views=Fv(()=>this.livePage()?.options??{flash:!1,track:!1,angularProfiling:!1,angularProfilingAvailable:!0});canShowViews=Q(()=>!!this.pageId()&&this.livePage()?.supported!==!1);message=O(``);announcement=O(``);recording=Q(()=>this.page()?.recording===!0);cycles=Q(()=>this.page()?.cycles??[]);maxCycles=Q(()=>nD(this.rpc()).limits.cdCycles);picked=Q(()=>eA(this.cycles(),this.range()));hasSpans=Q(()=>this.picked().some(e=>e.spans?.length));spanNames=Q(()=>this.page()?.spanNames??[]);stats=Q(()=>this.range()?tA(this.picked()):[...this.page()?.components??[]].sort((e,t)=>t.ms-e.ms));scope=Q(()=>{let e=this.range()?this.picked():[];return e.length?e.length===1?`cycle ${e[0].id}`:`cycles ${e[0].id} to ${e.at(-1).id}`:`the recording`});slowest=Q(()=>this.stats().slice(0,$j));latest=Q(()=>this.cycles().slice(-30).reverse());capNotes=Q(()=>{let e=this.page()?.droppedClasses??0,t=this.page()?.droppedHosts??0,n=[];return e>0&&n.push(`${e} more component ${e===1?`class was`:`classes were`} checked than a recording keeps, so ${e===1?`it is`:`they are`} left out of these totals.`),t>0&&n.push(`${t} component ${t===1?`instance was`:`instances were`} checked past the 2000 a recording counts, so ${t===1?`its tree row shows`:`their tree rows show`} no check count.`),n});status=Q(()=>{if(this.message())return this.message();let e=this.cycles().length;return this.imported()?`${e} ${e===1?`cycle`:`cycles`} imported.`:this.recording()?`Recording. ${e} ${e===1?`cycle`:`cycles`} so far.`:e?`${e} ${e===1?`cycle`:`cycles`} recorded.`:``});ms(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}clock(e){return QO(e)}causeText(e){return Fk(e)}async toggle(){this.recording()?await this.send({on:!1},``,()=>{let e=this.cycles().length;return`Recording stopped. ${e} ${e===1?`cycle`:`cycles`} recorded.`}):await this.send({on:!0},`Starting…`,()=>`Recording started.`)}showImport(e){this.message.set(``),this.range.set(null),this.imported.set(e);let t=e.page.cycles.length;this.announce(`Imported ${e.fileName}: ${t} ${t===1?`cycle`:`cycles`}. Showing the imported recording.`)}closeImport(){this.imported.set(null),this.range.set(null),this.announce(`Showing the live recording.`)}async clear(){this.range.set(null),await this.send({clear:!0},``,()=>`Cleared the recorded cycles.`)}async setView(e,t){let n=this.views();this.views.set({...n,[e]:t});let r={flash:t?`Flash checks on.`:`Flash checks off.`,track:t?`Performance track on. Record in the Chrome Performance panel to see it.`:`Performance track off.`,angularProfiling:`Angular profiling on. It stays on until the page reloads.`}[e];await this.send({[e]:t},``,()=>r,`request-change-detection-options`)||this.views.set(n)}async send(e,t,n,r=`request-change-detection-record`){this.message.set(t);try{if(!this.rpc())throw Error(`no client`);return await VE(this.rpc(),r,{pageId:this.pageId(),...e}),this.message.set(``),this.announce(n()),!0}catch{let e=`Could not reach the page.`;return this.message.set(e),this.announce(e),!1}}announce(e){this.announcement.update(t=>t===e?`${e} `:e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-recording`]],inputs:{livePage:[1,`page`,`livePage`],pageId:[1,`pageId`],rpc:[1,`rpc`]},outputs:{showComponent:`showComponent`},decls:21,vars:12,consts:[[`aria-labelledby`,`cd-heading`,1,`cd`],[1,`cd-head`],[`id`,`cd-heading`],[3,`imported`,`page`,`maxCycles`],[1,`status`],[`role`,`status`,1,`sr-only`],[1,`imported`],[1,`hint`],[`capability`,`profiler`,`missing`,``,`compact`,``,3,`page`],[`what`,`cycles`,`limit`,`cdCycles`,3,`dropped`,`max`],[1,`note`],[1,`empty`],[`type`,`button`,3,`click`,`disabled`],[`aria-hidden`,`true`,1,`dot`],[`type`,`button`],[`type`,`button`,3,`click`],[1,`badge`],[1,`mono`],[`role`,`group`,`aria-labelledby`,`cd-views-label`,1,`views`],[`id`,`cd-views-label`,1,`views-label`],[`type`,`button`,1,`view`,3,`click`,`disabled`],[`capability`,`angularProfiling`,`missing`,``,`compact`,``,3,`page`],[3,`rangeChange`,`cycles`,`range`],[3,`pick`,`cycles`,`names`,`scope`],[1,`spans-note`],[3,`pick`,`stats`,`scope`],[1,`cd-grid`],[`scope`,`col`],[`scope`,`col`,1,`num`],[`aria-label`,`Latest change detection cycles, newest first`,1,`cycles`],[3,`page`],[1,`num`],[`colspan`,`4`],[1,`when`],[1,`trigger`],[1,`timing`],[1,`top`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Change detection`),R(),M(4,Mj,4,5),L(5,`app-cd-transfer`,3),U(`imported`,function(e){return t.showImport(e)}),R(),L(6,`p`,4),J(7),R(),L(8,`p`,5),J(9),R()(),M(10,Nj,7,1,`p`,6),L(11,`p`,7),J(12,` Records each change detection cycle with Angular's profiler: how long it took, how many components it checked, what started it and which checks changed nothing. Tree rows show how often each instance was checked. Times come from a development build. While it records, the page also wraps Angular's scheduler, adds a signal write hook and watches DOM updates; all of it stops with the recording. `),R(),M(13,Pj,1,1,`app-angular-unavailable`,8),M(14,Lj,16,7),z(15,`app-limit-note`,9),P(16,Rj,2,1,`p`,10,Ag),M(18,Vj,9,9),M(19,Zj,27,4)(20,Qj,2,0,`p`,11),R()),e&2){let e;k(4),N(t.imported()?-1:4),k(),I(`page`,t.page())(`maxCycles`,t.maxCycles()),k(2),Y(t.status()),k(2),Y(t.announcement()),k(),N((e=t.imported())?10:-1,e),k(3),N(t.page()?.supported===!1?13:-1),k(),N(t.imported()?-1:14),k(),I(`dropped`,t.page()?.dropped??0)(`max`,t.maxCycles()),k(),F(t.capNotes()),k(2),N(t.cycles().length?18:-1),k(),N(t.page()?.components?.length?19:t.recording()?20:-1)}},dependencies:[hO,rk,hj,DA,vj,UA,ij,kj],styles:[`[_nghost-%COMP%] { display: block; margin-top: 16px; } @@ -1732,7 +1811,7 @@ td.mono[_ngcontent-%COMP%] { .trigger[_ngcontent-%COMP%] .mono[_ngcontent-%COMP%], .top[_ngcontent-%COMP%] .mono[_ngcontent-%COMP%] { overflow-wrap: anywhere; -}`]})},yj=[`*`];function bj(e,t){e&1&&J(0),e&2&&Y(G(2).label())}function xj(e,t){e&1&&s_(0,0,null,bj,1,1)}function Sj(e,t){if(e&1&&(L(0,`span`,4),J(1),R()),e&2){let e=G(2);A(),Y(e.message())}}function Cj(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){return E(e),D(G().open())}),Gg(1,3),R(),M(2,Sj,2,1,`span`,4)}if(e&2){let e=G(),t=d_(1);I(`title`,`Open `+e.label()+` in your editor`),j(`aria-label`,`Open `+e.label()+` in your editor`),A(),I(`ngTemplateOutlet`,t),A(),N(e.message()?2:-1)}}function wj(e,t){if(e&1&&(L(0,`span`,1),Gg(1,3),R()),e&2){let e=G(),t=d_(1);I(`title`,e.label()),A(),I(`ngTemplateOutlet`,t)}}var Tj=class e{source=k(k(null));client=Q(()=>this.source()());available=Q(()=>{let e=this.client();return!!e&&!HE(e)});use(e){this.source.set(e)}async open(e,t){if(!this.available())return{ok:!1,error:`No server is connected.`};try{let n=await BE(this.client(),`open-in-editor`,{file:e,...t?{line:t}:{}});return n?.ok?{ok:!0}:{ok:!1,error:n?.error??`The server did not open it.`}}catch{return{ok:!1,error:`The server did not open it.`}}}static ɵfac=function(t){return new(t||e)};static ɵprov=Ml({token:e,factory:e.ɵfac})};function Ej(e,t){return t?`${e}:${t}`:e}var Dj=class e{editor=w(Tj);file=$.required();line=$(void 0);label=Q(()=>Ej(this.file(),this.line()));message=k(``);async open(){this.message.set(``);let e=await this.editor.open(this.file(),this.line()??void 0);e.ok||this.message.set(`Not opened: ${e.error}`)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-source-link`]],inputs:{file:[1,`file`],line:[1,`line`]},ngContentSelectors:yj,decls:4,vars:1,consts:[[`text`,``],[1,`source-text`,3,`title`],[`type`,`button`,1,`source-link`,3,`click`,`title`],[3,`ngTemplateOutlet`],[`role`,`alert`,1,`message`]],template:function(e,t){e&1&&(o_(),sg(0,xj,2,0,`ng-template`,null,0,Ev),M(2,Cj,3,4)(3,wj,2,2,`span`,1)),e&2&&(A(2),N(t.editor.available()?2:3))},dependencies:[ub],styles:[`[_nghost-%COMP%] { +}`]})},tM=[`*`];function nM(e,t){e&1&&J(0),e&2&&Y(G(2).label())}function rM(e,t){e&1&&s_(0,0,null,nM,1,1)}function iM(e,t){if(e&1&&(L(0,`span`,4),J(1),R()),e&2){let e=G(2);k(),Y(e.message())}}function aM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){return T(e),E(G().open())}),Gg(1,3),R(),M(2,iM,2,1,`span`,4)}if(e&2){let e=G(),t=d_(1);I(`title`,`Open `+e.label()+` in your editor`),j(`aria-label`,`Open `+e.label()+` in your editor`),k(),I(`ngTemplateOutlet`,t),k(),N(e.message()?2:-1)}}function oM(e,t){if(e&1&&(L(0,`span`,1),Gg(1,3),R()),e&2){let e=G(),t=d_(1);I(`title`,e.label()),k(),I(`ngTemplateOutlet`,t)}}var sM=class e{source=O(O(null));client=Q(()=>this.source()());available=Q(()=>{let e=this.client();return!!e&&!UE(e)});use(e){this.source.set(e)}async open(e,t){if(!this.available())return{ok:!1,error:`No server is connected.`};try{let n=await VE(this.client(),`open-in-editor`,{file:e,...t?{line:t}:{}});return n?.ok?{ok:!0}:{ok:!1,error:n?.error??`The server did not open it.`}}catch{return{ok:!1,error:`The server did not open it.`}}}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})};function cM(e,t){return t?`${e}:${t}`:e}var lM=class e{editor=C(sM);file=$.required();line=$(void 0);label=Q(()=>cM(this.file(),this.line()));message=O(``);async open(){this.message.set(``);let e=await this.editor.open(this.file(),this.line()??void 0);e.ok||this.message.set(`Not opened: ${e.error}`)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-source-link`]],inputs:{file:[1,`file`],line:[1,`line`]},ngContentSelectors:tM,decls:4,vars:1,consts:[[`text`,``],[1,`source-text`,3,`title`],[`type`,`button`,1,`source-link`,3,`click`,`title`],[3,`ngTemplateOutlet`],[`role`,`alert`,1,`message`]],template:function(e,t){e&1&&(o_(),sg(0,rM,2,0,`ng-template`,null,0,Ev),M(2,aM,3,4)(3,oM,2,2,`span`,1)),e&2&&(k(2),N(t.editor.available()?2:3))},dependencies:[ub],styles:[`[_nghost-%COMP%] { display: inline; min-width: 0; } @@ -1767,7 +1846,7 @@ td.mono[_ngcontent-%COMP%] { color: var(--%NS%danger-text); font-family: var(--%NS%font-sans); font-size: 0.92em; -}`]})},Oj=[`field`],kj=[`editButton`],Aj=[`valueBox`];function jj(e,t){if(e&1){let e=H();B(0,`div`,5)(1,`label`,6),J(2),V(),B(3,`input`,7,0),W(`input`,function(t){return E(e),D(G().draft.set(t.target.value))})(`keydown.enter`,function(t){E(e);let n=G();return t.preventDefault(),D(n.apply())})(`keydown.escape`,function(t){E(e);let n=G();return t.preventDefault(),t.stopPropagation(),D(n.cancel())}),V(),B(5,`button`,8),W(`click`,function(){return E(e),D(G().apply())}),J(6,`Apply`),V(),B(7,`button`,9),W(`click`,function(){return E(e),D(G().cancel())}),J(8,`Cancel`),V()(),B(9,`p`,10),J(10),V()}if(e&2){let e=G();A(),qg(`htmlFor`,e.fieldId),A(),X(`New value of `,e.prop().name,`, as JSON`),A(),qg(`id`,e.fieldId)(`value`,e.draft())(`readOnly`,e.busy()),j(`aria-busy`,e.busy()?`true`:null)(`aria-invalid`,e.error()?`true`:null)(`aria-describedby`,e.hintId+(e.error()?` `+e.errorId:``)),A(2),qg(`disabled`,e.busy()),A(4),qg(`id`,e.hintId),A(),X(` JSON, such as "text", 42, true or `,e.objectSample,`. Enter applies, Escape cancels. `)}}function Mj(e,t){if(e&1&&(B(0,`pre`,null,1),J(2),xv(3,`json`),V()),e&2){let e=G(2);j(`tabindex`,e.scrollable()?0:null)(`role`,e.scrollable()?`region`:null)(`aria-label`,e.scrollable()?`Value of `+e.prop().name:null),A(2),Y(Cv(3,4,e.prop().value))}}function Nj(e,t){if(e&1){let e=H();B(0,`button`,14,2),W(`click`,function(){return E(e),D(G(2).start())}),J(2,` Edit `),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()),j(`aria-label`,`Edit `+e.prop().name)}}function Pj(e,t){if(e&1&&(B(0,`p`,13),J(1),V()),e&2){let e=G(2);A(),Y(e.prop().locked)}}function Fj(e,t){if(e&1&&(B(0,`div`,11),M(1,Mj,4,6,`pre`),M(2,Nj,3,2,`button`,12),V(),M(3,Pj,2,1,`p`,13)),e&2){let e=G();A(),N(e.bare()?-1:1),A(),N(e.editable()?2:-1),A(),N(e.writes()&&e.prop().locked?3:-1)}}function Ij(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G();qg(`id`,e.errorId),A(),Y(e.error())}}var Lj=0;function Rj(e){let t=e.trim();if(!t)return{error:`Type a JSON value, such as "text", 42, true, null or [1, 2].`};try{return{value:JSON.parse(t)}}catch{return{error:`Not valid JSON. Put text in double quotes, such as "Paris".`}}}var zj=class e{prop=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);bare=$(!1);readDraft=$(null);fieldId=`prop-edit-${++Lj}`;hintId=`${this.fieldId}-hint`;errorId=`${this.fieldId}-error`;objectSample=`{"a": 1}`;editing=k(!1);draft=k(``);busy=k(!1);error=k(``);done=k(``);editable=Q(()=>this.writes()&&!!this.prop().edit&&!!this.pageId()&&!!this.rpc());field=Jv(`field`);editButton=Jv(`editButton`);valueBox=Jv(`valueBox`);injector=w(ws);scrollable=k(!1);constructor(){dy(()=>{this.prop();let e=this.valueBox()?.nativeElement;this.scrollable.set(!!e&&e.scrollHeight>e.clientHeight+1)})}async start(){let e=this.prop().value;this.error.set(``),this.done.set(``);let t=this.readDraft();if(t){this.busy.set(!0);let n=await t();if(this.busy.set(!1),n.error!==void 0){this.error.set(n.error);return}e=n.value}this.draft.set(e===void 0?``:JSON.stringify(e)),this.editing.set(!0),Vd(()=>{let e=this.field()?.nativeElement;e?.focus(),e?.select()},{injector:this.injector})}cancel(){this.editing()&&(this.editing.set(!1),this.busy.set(!1),this.error.set(``),this.focusEdit())}async apply(){if(this.busy())return;let e=Rj(this.draft());if(`error`in e){this.error.set(e.error);return}let t=this.prop(),n=this.rpc(),r=this.pageId();if(!n||!r||!t.edit)return;this.busy.set(!0),this.error.set(``);let i;try{i=await n.scope(`pangular`).rpc.call(`request-component-edit`,{pageId:r,request:{id:this.componentId(),path:t.prop,value:e.value,kind:t.edit}})??{}}catch{i={error:`The devtools server did not answer. Try again.`}}this.busy.set(!1),this.editing()&&(i.ok?(this.editing.set(!1),this.done.set(`Set ${t.name}.`),this.focusEdit()):(this.error.set(i.error??`The page did not write it.`),this.field()?.nativeElement.focus()))}focusEdit(){Vd(()=>this.editButton()?.nativeElement.focus(),{injector:this.injector})}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-prop-value`]],viewQuery:function(e,t){e&1&&l_(t.field,Oj,5)(t.editButton,kj,5)(t.valueBox,Aj,5),e&2&&u_(3)},inputs:{prop:[1,`prop`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],bare:[1,`bare`],readDraft:[1,`readDraft`]},decls:5,vars:3,consts:[[`field`,``],[`valueBox`,``],[`editButton`,``],[`role`,`alert`,1,`error`,3,`id`],[`role`,`status`,1,`sr-only`],[1,`editor`],[1,`sr-only`,3,`for`],[`type`,`text`,`autocomplete`,`off`,`spellcheck`,`false`,1,`field`,`mono`,3,`input`,`keydown.enter`,`keydown.escape`,`id`,`value`,`readOnly`],[`type`,`button`,1,`primary`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[1,`hint`,3,`id`],[1,`view`],[`type`,`button`,1,`edit`,3,`disabled`],[1,`locked`],[`type`,`button`,1,`edit`,3,`click`,`disabled`]],template:function(e,t){e&1&&(M(0,jj,11,11)(1,Fj,4,3),M(2,Ij,2,2,`p`,3),B(3,`p`,4),J(4),V()),e&2&&(N(+!t.editing()),A(2),N(t.error()?2:-1),A(2),Y(t.done()))},dependencies:[gb],styles:[`[_nghost-%COMP%] { +}`]})},uM=[`field`],dM=[`editButton`],fM=[`valueBox`];function pM(e,t){if(e&1){let e=H();B(0,`div`,5)(1,`label`,6),J(2),V(),B(3,`input`,7,0),W(`input`,function(t){return T(e),E(G().draft.set(t.target.value))})(`keydown.enter`,function(t){T(e);let n=G();return t.preventDefault(),E(n.apply())})(`keydown.escape`,function(t){T(e);let n=G();return t.preventDefault(),t.stopPropagation(),E(n.cancel())}),V(),B(5,`button`,8),W(`click`,function(){return T(e),E(G().apply())}),J(6,`Apply`),V(),B(7,`button`,9),W(`click`,function(){return T(e),E(G().cancel())}),J(8,`Cancel`),V()(),B(9,`p`,10),J(10),V()}if(e&2){let e=G();k(),qg(`htmlFor`,e.fieldId),k(),X(`New value of `,e.prop().name,`, as JSON`),k(),qg(`id`,e.fieldId)(`value`,e.draft())(`readOnly`,e.busy()),j(`aria-busy`,e.busy()?`true`:null)(`aria-invalid`,e.error()?`true`:null)(`aria-describedby`,e.hintId+(e.error()?` `+e.errorId:``)),k(2),qg(`disabled`,e.busy()),k(4),qg(`id`,e.hintId),k(),X(` JSON, such as "text", 42, true or `,e.objectSample,`. Enter applies, Escape cancels. `)}}function mM(e,t){if(e&1&&(B(0,`pre`,null,1),J(2),xv(3,`json`),V()),e&2){let e=G(2);j(`tabindex`,e.scrollable()?0:null)(`role`,e.scrollable()?`region`:null)(`aria-label`,e.scrollable()?`Value of `+e.prop().name:null),k(2),Y(Cv(3,4,e.prop().value))}}function hM(e,t){if(e&1){let e=H();B(0,`button`,14,2),W(`click`,function(){return T(e),E(G(2).start())}),J(2,` Edit `),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()),j(`aria-label`,`Edit `+e.prop().name)}}function gM(e,t){if(e&1&&(B(0,`p`,13),J(1),V()),e&2){let e=G(2);k(),Y(e.prop().locked)}}function _M(e,t){if(e&1&&(B(0,`div`,11),M(1,mM,4,6,`pre`),M(2,hM,3,2,`button`,12),V(),M(3,gM,2,1,`p`,13)),e&2){let e=G();k(),N(e.bare()?-1:1),k(),N(e.editable()?2:-1),k(),N(e.writes()&&e.prop().locked?3:-1)}}function vM(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G();qg(`id`,e.errorId),k(),Y(e.error())}}var yM=0;function bM(e){let t=e.trim();if(!t)return{error:`Type a JSON value, such as "text", 42, true, null or [1, 2].`};try{return{value:JSON.parse(t)}}catch{return{error:`Not valid JSON. Put text in double quotes, such as "Paris".`}}}var xM=class e{prop=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);bare=$(!1);readDraft=$(null);fieldId=`prop-edit-${++yM}`;hintId=`${this.fieldId}-hint`;errorId=`${this.fieldId}-error`;objectSample=`{"a": 1}`;editing=O(!1);draft=O(``);busy=O(!1);error=O(``);done=O(``);editable=Q(()=>this.writes()&&!!this.prop().edit&&!!this.pageId()&&!!this.rpc());field=Jv(`field`);editButton=Jv(`editButton`);valueBox=Jv(`valueBox`);injector=C(Ts);scrollable=O(!1);constructor(){dy(()=>{this.prop();let e=this.valueBox()?.nativeElement;this.scrollable.set(!!e&&e.scrollHeight>e.clientHeight+1)})}async start(){let e=this.prop().value;this.error.set(``),this.done.set(``);let t=this.readDraft();if(t){this.busy.set(!0);let n=await t();if(this.busy.set(!1),n.error!==void 0){this.error.set(n.error);return}e=n.value}this.draft.set(e===void 0?``:JSON.stringify(e)),this.editing.set(!0),Hd(()=>{let e=this.field()?.nativeElement;e?.focus(),e?.select()},{injector:this.injector})}cancel(){this.editing()&&(this.editing.set(!1),this.busy.set(!1),this.error.set(``),this.focusEdit())}async apply(){if(this.busy())return;let e=bM(this.draft());if(`error`in e){this.error.set(e.error);return}let t=this.prop(),n=this.rpc(),r=this.pageId();if(!n||!r||!t.edit)return;this.busy.set(!0),this.error.set(``);let i;try{i=await n.scope(`pangular`).rpc.call(`request-component-edit`,{pageId:r,request:{id:this.componentId(),path:t.prop,value:e.value,kind:t.edit}})??{}}catch{i={error:`The devtools server did not answer. Try again.`}}this.busy.set(!1),this.editing()&&(i.ok?(this.editing.set(!1),this.done.set(`Set ${t.name}.`),this.focusEdit()):(this.error.set(i.error??`The page did not write it.`),this.field()?.nativeElement.focus()))}focusEdit(){Hd(()=>this.editButton()?.nativeElement.focus(),{injector:this.injector})}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-prop-value`]],viewQuery:function(e,t){e&1&&l_(t.field,uM,5)(t.editButton,dM,5)(t.valueBox,fM,5),e&2&&u_(3)},inputs:{prop:[1,`prop`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],bare:[1,`bare`],readDraft:[1,`readDraft`]},decls:5,vars:3,consts:[[`field`,``],[`valueBox`,``],[`editButton`,``],[`role`,`alert`,1,`error`,3,`id`],[`role`,`status`,1,`sr-only`],[1,`editor`],[1,`sr-only`,3,`for`],[`type`,`text`,`autocomplete`,`off`,`spellcheck`,`false`,1,`field`,`mono`,3,`input`,`keydown.enter`,`keydown.escape`,`id`,`value`,`readOnly`],[`type`,`button`,1,`primary`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[1,`hint`,3,`id`],[1,`view`],[`type`,`button`,1,`edit`,3,`disabled`],[1,`locked`],[`type`,`button`,1,`edit`,3,`click`,`disabled`]],template:function(e,t){e&1&&(M(0,pM,11,11)(1,_M,4,3),M(2,vM,2,2,`p`,3),B(3,`p`,4),J(4),V()),e&2&&(N(+!t.editing()),k(2),N(t.error()?2:-1),k(2),Y(t.done()))},dependencies:[gb],styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1890,7 +1969,7 @@ button.edit[_ngcontent-%COMP%] { .error[_ngcontent-%COMP%] { color: var(--%NS%danger-text); -}`]})},Bj=1e3,Vj={depth:5,limit:100},Hj=`[redacted]`;function Uj(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function Wj(e){return Uj(e)&&typeof e.$more==`number`&&Object.keys(e).length===1}function Gj(e){return Uj(e)&&typeof e.$collapsed==`string`&&typeof e.size==`number`&&Object.keys(e).length===2}function Kj(e){return e===`Array`?`array`:e===`Map`?`map`:e===`Set`?`set`:`object`}function qj(e){return e.$type===`Map`&&Array.isArray(e.entries)}function Jj(e){return e.$type===`Set`&&Array.isArray(e.values)}function Yj(e){return Object.keys(e).filter(e=>e!==`$type`&&e!==`$more`)}function Xj(e){if(!e||typeof e!=`object`)return null;if(Gj(e))return e.size<=0?null:{kind:Kj(e.$collapsed),type:e.$collapsed,size:e.size,collapsed:!0};if(Wj(e))return null;if(Array.isArray(e)){let t=e.at(-1),n=Wj(t)?t.$more:0,r=e.length-+!!n+n;return r?{kind:`array`,type:`Array`,size:r,collapsed:!1}:null}let t=e;if(qj(t)||Jj(t)){let e=typeof t.size==`number`?t.size:0,n=qj(t)?`map`:`set`;return e?{kind:n,type:n===`map`?`Map`:`Set`,size:e,collapsed:!1}:null}let n=typeof t.$more==`number`?t.$more:0,r=Yj(t).length+n,i=typeof t.$type==`string`?t.$type:`Object`;return r?{kind:`object`,type:i,size:r,collapsed:!1}:null}function Zj(e){if(typeof e==`string`)return JSON.stringify(e);let t=Xj(e);if(t)return eM(t);try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function Qj(e){let t=Xj(e);if(!t||t.collapsed)return{children:[],more:0};if(Array.isArray(e)){let n=(Wj(e.at(-1))?e.slice(0,-1):e).map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:n,more:t.size-n.length}}let n=e;if(t.kind===`map`){let e=n.entries.map((e,t)=>{let[n,r]=Array.isArray(e)?e:[void 0,e];return{key:String(t),label:Zj(n),value:r}});return{children:e,more:Math.max(0,t.size-e.length)}}if(t.kind===`set`){let e=n.values.map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:e,more:Math.max(0,t.size-e.length)}}return{children:Yj(n).map(e=>({key:e,label:e,value:n[e]})),more:typeof n.$more==`number`?n.$more:0}}function $j(e,t,n){return`${e} ${e===1?t:n}`}function eM(e){let t={array:$j(e.size,`item`,`items`),object:$j(e.size,`key`,`keys`),map:$j(e.size,`entry`,`entries`),set:$j(e.size,`value`,`values`)}[e.kind];return`${e.type} (${t})`}function tM(e,t){return JSON.stringify(t===void 0?e:[t,...e])}function nM(e,t){return e.map((e,n)=>n===0?e:(t?t[n-1]!==`object`:/^\d+$/.test(e))?`[${e}]`:`.${e}`).join(``)}function rM(e){return e.every(e=>e&&e===e.trim()&&!/[.[\]]/.test(e))?e.join(`.`):null}var iM=/^\[(Getter|Unreadable|Circular|Truncated|Function\b.*|Promise)\]$/;function aM(e){return e===null||typeof e==`boolean`?!0:typeof e==`number`?Number.isFinite(e):typeof e==`string`&&e!==Hj&&!iM.test(e)&&!e.endsWith(`…`)}function oM(e,t){return!e||t.kind===`map`||t.kind===`set`||e===`signal`&&t.kind===`object`&&t.type!==`Object`?null:e}function sM(e,t,n,r,i=500){let a=[],o=r.trim().toLowerCase();if(!o)return a;let s=new Set,c=(e,t)=>{let r=tM(e);if(!(s.has(r)||a.length>=i)){s.add(r);for(let r of Qj(t).children){let t=[...e,r.key];if(r.label.toLowerCase().includes(o)&&a.push(t),!Xj(r.value))continue;let i=n(t)??(Xj(r.value)?.collapsed?void 0:r.value);i!==void 0&&c(t,i)}}};return c(e,n(e)??t),a}var cM=(e,t)=>t.id;function lM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){E(e);let t=G().$implicit;return D(G(3).toggle(t))}),O(),L(1,`svg`,3),z(2,`path`,4),R(),gs(),L(3,`span`,14),J(4),R(),L(5,`span`,5),J(6),R()()}if(e&2){let e=G().$implicit;j(`aria-expanded`,e.open)(`aria-label`,e.label+`: `+e.text),A(4),X(``,e.label,`:`),A(2),Y(e.text)}}function uM(e,t){if(e&1&&z(0,`app-prop-value`,15),e&2){let e=G(5);I(`prop`,t)(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}function dM(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G(2).$implicit;A(),Y(e.text)}}function fM(e,t){if(e&1&&(L(0,`span`,14),J(1),R(),M(2,uM,1,5,`app-prop-value`,15)(3,dM,2,1,`span`,16)),e&2){let e,t=G().$implicit;A(),X(``,t.label,`:`),A(),N((e=t.edit)?2:3,e)}}function pM(e,t){if(e&1){let e=H();L(0,`button`,17),U(`click`,function(){E(e);let t=G().$implicit;return D(G(3).more(t))}),J(1),L(2,`span`,18),J(3),R()()}if(e&2){let e=G().$implicit,t=G(3);A(),X(` Show `,t.step(e),` more `),A(2),X(`(`,e.more,` not listed)`)}}function mM(e,t){e&1&&(L(0,`span`,12),J(1,`Reading from the page…`),R())}function hM(e,t){if(e&1&&(L(0,`span`,13),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.text)}}function gM(e,t){if(e&1&&(L(0,`li`,9),M(1,lM,7,4,`button`,10)(2,fM,4,2)(3,pM,4,2,`button`,11)(4,mM,2,0,`span`,12)(5,hM,2,1,`span`,13),R()),e&2){let e,n=t.$implicit;K(`padding-left`,n.depth*14,`px`),A(),N((e=n.kind)===`node`?1:e===`leaf`?2:e===`more`?3:e===`loading`?4:e===`error`?5:-1)}}function _M(e,t){if(e&1&&(L(0,`ul`,7),P(1,gM,6,3,`li`,8,cM),R()),e&2){let e=G(2);I(`id`,e.listId),j(`aria-label`,e.prop().name+` entries`),A(),F(e.rows())}}function vM(e,t){if(e&1){let e=H();L(0,`div`,1)(1,`button`,2),U(`click`,function(){return E(e),D(G().toggleRoot())}),O(),L(2,`svg`,3),z(3,`path`,4),R(),gs(),L(4,`span`,5),J(5),R()(),z(6,`app-prop-value`,6),R(),M(7,_M,3,2,`ul`,7)}if(e&2){let e=t,n=G();A(),j(`aria-expanded`,n.rootOpen())(`aria-controls`,n.rootOpen()?n.listId:null)(`aria-label`,n.prop().name+`: `+n.summaryOf(e)),A(4),Y(n.summaryOf(e)),A(),I(`bare`,!0)(`prop`,n.prop())(`componentId`,n.componentId())(`pageId`,n.pageId())(`rpc`,n.rpc())(`writes`,n.writes())(`readDraft`,n.readWhole),A(),N(n.rootOpen()?7:-1)}}function yM(e,t){if(e&1&&z(0,`app-prop-value`,0),e&2){let e=G();I(`prop`,e.prop())(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}var bM=0;function xM(e){if(e===void 0)return`undefined`;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function SM(e){if(Array.isArray(e))return e.every(SM);if(e&&typeof e==`object`){let t=e;return![`$collapsed`,`$more`,`$type`].some(e=>Object.hasOwn(t,e))&&Object.values(t).every(SM)}return aM(e)}var CM=class e{prop=$.required();store=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);directive=$(void 0);query=$(``);listId=`value-tree-${++bM}`;host=w(Fl);pendingMore=null;constructor(){dy(()=>{let e=this.rows(),t=this.pendingMore;if(!t)return;let n=e.findIndex(e=>(e.kind===`leaf`||e.kind===`node`)&&!t.has(e.id));if(n<0)return;this.pendingMore=null;let r=document.activeElement;r&&r!==document.body&&r.isConnected||this.focusNear(n)})}rootPath=Q(()=>[this.prop().prop]);rootValue=Q(()=>this.store().level(this.rootPath(),this.directive())??this.prop().value);root=Q(()=>Xj(this.rootValue()));needle=Q(()=>this.query().trim().toLowerCase());matches=Q(()=>{let e=this.needle(),t=this.prop();if(!e||[t.name,t.prop].some(t=>t.toLowerCase().includes(e)))return null;let n=this.store(),r=this.directive();return sM(this.rootPath(),this.rootValue(),e=>n.level(e,r),e)});rootOpen=Q(()=>!!this.matches()?.length||this.store().isOpen(this.rootPath(),this.directive()));rows=Q(()=>{let e=this.root();if(!e)return[];let t=this.store(),n=this.directive(),r=this.matches(),i=new Set,a=new Set;for(let e of r??[]){a.add(tM(e));for(let t=2;t<=e.length;t++)i.add(tM(e.slice(0,t)))}let o=this.prop(),s=this.writes()&&n===void 0,c=[],l=(e,o,d,f,p,m)=>{let{children:h,more:g}=Qj(e);for(let e of h){let h=[...o,e.key],g=tM(h);if(r&&!m&&!i.has(g))continue;let _=Xj(e.value),ee=tM(h,n);if(!_){let t=p&&aM(e.value)?rM(h):null;c.push({id:ee,kind:`leaf`,depth:f,path:h,label:e.label,text:xM(e.value),edit:s&&t&&p?{name:nM(h,[...d]),prop:t,value:e.value,edit:p}:void 0});continue}let te=!!r&&!m&&i.has(g)&&!a.has(g)||t.isOpen(h,n);if(c.push({id:ee,kind:`node`,depth:f,path:h,label:e.label,text:eM(_),container:_,open:te}),!te)continue;let ne=t.level(h,n)??(_.collapsed?void 0:e.value),re=[...d,_.kind];ne===void 0?t.errors().has(ee)?c.push({...u(h,f+1,`error`),text:t.errors().get(ee)}):c.push(u(h,f+1,`loading`)):l(ne,h,re,f+1,oM(p,_),m||a.has(g))}g>0&&(!r||m)&&c.push({...u(o,f,`more`),more:g,listed:h.length})},u=(e,t,r)=>({id:`${tM(e,n)}:${r}`,kind:r,depth:t,path:e,label:``,text:``});return l(this.rootValue(),this.rootPath(),[e.kind],0,s?oM(o.editInside??null,e):null,!r),c});readWhole=async()=>{let e=await this.store().read(this.rootPath(),Vj.depth,Vj.limit);return e.ok?SM(e.value)?{value:e.value}:{error:`Too large to edit as a whole. Open it to edit the values inside.`}:{error:e.error??`The page did not read it.`}};summaryOf(e){return eM(e)}toggleRoot(){this.pendingMore=null,this.store().toggle(this.rootPath(),this.directive(),!1)}toggle(e){this.pendingMore=null,this.store().toggle(e.path,this.directive(),!!e.container?.collapsed)}more(e){this.pendingMore=new Set(this.rows().map(e=>e.id)),this.store().more(e.path,this.directive(),e.listed??0)}focusNear(e){let t=this.host.nativeElement,n=Array.from(t.querySelectorAll(`#${this.listId} > li`)),r=e=>e?.querySelector(`button:not([disabled]), input, textarea, [tabindex="0"]`);(n.slice(e).map(r).find(Boolean)??n.slice(0,e).reverse().map(r).find(Boolean)??t.querySelector(`.root > .toggle`))?.focus()}step(e){return Math.min(100,e.more??0)}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-value-tree`]],inputs:{prop:[1,`prop`],store:[1,`store`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],directive:[1,`directive`],query:[1,`query`]},decls:2,vars:1,consts:[[3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`root`],[`type`,`button`,1,`toggle`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m9 6 6 6-6 6`],[1,`summary`,`mono`],[1,`whole`,3,`bare`,`prop`,`componentId`,`pageId`,`rpc`,`writes`,`readDraft`],[1,`entries`,3,`id`],[1,`entry`,3,`padding-left`],[1,`entry`],[`type`,`button`,1,`toggle`],[`type`,`button`,1,`more`],[`role`,`status`,1,`muted`],[`role`,`alert`,1,`error`],[1,`key`,`mono`],[1,`leaf-edit`,3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`leaf`,`mono`],[`type`,`button`,1,`more`,3,`click`],[1,`muted`]],template:function(e,t){if(e&1&&M(0,vM,8,12)(1,yM,1,5,`app-prop-value`,0),e&2){let e;N((e=t.root())?0:1,e)}},dependencies:[zj],styles:[`[_nghost-%COMP%] { +}`]})},SM=1e3,CM={depth:5,limit:100},wM=`[redacted]`;function TM(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function EM(e){return TM(e)&&typeof e.$more==`number`&&Object.keys(e).length===1}function DM(e){return TM(e)&&typeof e.$collapsed==`string`&&typeof e.size==`number`&&Object.keys(e).length===2}function OM(e){return e===`Array`?`array`:e===`Map`?`map`:e===`Set`?`set`:`object`}function kM(e){return e.$type===`Map`&&Array.isArray(e.entries)}function AM(e){return e.$type===`Set`&&Array.isArray(e.values)}function jM(e){return Object.keys(e).filter(e=>e!==`$type`&&e!==`$more`)}function MM(e){if(!e||typeof e!=`object`)return null;if(DM(e))return e.size<=0?null:{kind:OM(e.$collapsed),type:e.$collapsed,size:e.size,collapsed:!0};if(EM(e))return null;if(Array.isArray(e)){let t=e.at(-1),n=EM(t)?t.$more:0,r=e.length-+!!n+n;return r?{kind:`array`,type:`Array`,size:r,collapsed:!1}:null}let t=e;if(kM(t)||AM(t)){let e=typeof t.size==`number`?t.size:0,n=kM(t)?`map`:`set`;return e?{kind:n,type:n===`map`?`Map`:`Set`,size:e,collapsed:!1}:null}let n=typeof t.$more==`number`?t.$more:0,r=jM(t).length+n,i=typeof t.$type==`string`?t.$type:`Object`;return r?{kind:`object`,type:i,size:r,collapsed:!1}:null}function NM(e){if(typeof e==`string`)return JSON.stringify(e);let t=MM(e);if(t)return IM(t);try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function PM(e){let t=MM(e);if(!t||t.collapsed)return{children:[],more:0};if(Array.isArray(e)){let n=(EM(e.at(-1))?e.slice(0,-1):e).map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:n,more:t.size-n.length}}let n=e;if(t.kind===`map`){let e=n.entries.map((e,t)=>{let[n,r]=Array.isArray(e)?e:[void 0,e];return{key:String(t),label:NM(n),value:r}});return{children:e,more:Math.max(0,t.size-e.length)}}if(t.kind===`set`){let e=n.values.map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:e,more:Math.max(0,t.size-e.length)}}return{children:jM(n).map(e=>({key:e,label:e,value:n[e]})),more:typeof n.$more==`number`?n.$more:0}}function FM(e,t,n){return`${e} ${e===1?t:n}`}function IM(e){let t={array:FM(e.size,`item`,`items`),object:FM(e.size,`key`,`keys`),map:FM(e.size,`entry`,`entries`),set:FM(e.size,`value`,`values`)}[e.kind];return`${e.type} (${t})`}function LM(e,t){return JSON.stringify(t===void 0?e:[t,...e])}function RM(e,t){return e.map((e,n)=>n===0?e:(t?t[n-1]!==`object`:/^\d+$/.test(e))?`[${e}]`:`.${e}`).join(``)}function zM(e){return e.every(e=>e&&e===e.trim()&&!/[.[\]]/.test(e))?e.join(`.`):null}var BM=/^\[(Getter|Unreadable|Circular|Truncated|Function\b.*|Promise)\]$/;function VM(e){return e===null||typeof e==`boolean`?!0:typeof e==`number`?Number.isFinite(e):typeof e==`string`&&e!==wM&&!BM.test(e)&&!e.endsWith(`…`)}function HM(e,t){return!e||t.kind===`map`||t.kind===`set`||e===`signal`&&t.kind===`object`&&t.type!==`Object`?null:e}function UM(e,t,n,r,i=500){let a=[],o=r.trim().toLowerCase();if(!o)return a;let s=new Set,c=(e,t)=>{let r=LM(e);if(!(s.has(r)||a.length>=i)){s.add(r);for(let r of PM(t).children){let t=[...e,r.key];if(r.label.toLowerCase().includes(o)&&a.push(t),!MM(r.value))continue;let i=n(t)??(MM(r.value)?.collapsed?void 0:r.value);i!==void 0&&c(t,i)}}};return c(e,n(e)??t),a}var WM=(e,t)=>t.id;function GM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){T(e);let t=G().$implicit;return E(G(3).toggle(t))}),D(),L(1,`svg`,3),z(2,`path`,4),R(),_s(),L(3,`span`,14),J(4),R(),L(5,`span`,5),J(6),R()()}if(e&2){let e=G().$implicit;j(`aria-expanded`,e.open)(`aria-label`,e.label+`: `+e.text),k(4),X(``,e.label,`:`),k(2),Y(e.text)}}function KM(e,t){if(e&1&&z(0,`app-prop-value`,15),e&2){let e=G(5);I(`prop`,t)(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}function qM(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G(2).$implicit;k(),Y(e.text)}}function JM(e,t){if(e&1&&(L(0,`span`,14),J(1),R(),M(2,KM,1,5,`app-prop-value`,15)(3,qM,2,1,`span`,16)),e&2){let e,t=G().$implicit;k(),X(``,t.label,`:`),k(),N((e=t.edit)?2:3,e)}}function YM(e,t){if(e&1){let e=H();L(0,`button`,17),U(`click`,function(){T(e);let t=G().$implicit;return E(G(3).more(t))}),J(1),L(2,`span`,18),J(3),R()()}if(e&2){let e=G().$implicit,t=G(3);k(),X(` Show `,t.step(e),` more `),k(2),X(`(`,e.more,` not listed)`)}}function XM(e,t){e&1&&(L(0,`span`,12),J(1,`Reading from the page…`),R())}function ZM(e,t){if(e&1&&(L(0,`span`,13),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.text)}}function QM(e,t){if(e&1&&(L(0,`li`,9),M(1,GM,7,4,`button`,10)(2,JM,4,2)(3,YM,4,2,`button`,11)(4,XM,2,0,`span`,12)(5,ZM,2,1,`span`,13),R()),e&2){let e,n=t.$implicit;K(`padding-left`,n.depth*14,`px`),k(),N((e=n.kind)===`node`?1:e===`leaf`?2:e===`more`?3:e===`loading`?4:e===`error`?5:-1)}}function $M(e,t){if(e&1&&(L(0,`ul`,7),P(1,QM,6,3,`li`,8,WM),R()),e&2){let e=G(2);I(`id`,e.listId),j(`aria-label`,e.prop().name+` entries`),k(),F(e.rows())}}function eN(e,t){if(e&1){let e=H();L(0,`div`,1)(1,`button`,2),U(`click`,function(){return T(e),E(G().toggleRoot())}),D(),L(2,`svg`,3),z(3,`path`,4),R(),_s(),L(4,`span`,5),J(5),R()(),z(6,`app-prop-value`,6),R(),M(7,$M,3,2,`ul`,7)}if(e&2){let e=t,n=G();k(),j(`aria-expanded`,n.rootOpen())(`aria-controls`,n.rootOpen()?n.listId:null)(`aria-label`,n.prop().name+`: `+n.summaryOf(e)),k(4),Y(n.summaryOf(e)),k(),I(`bare`,!0)(`prop`,n.prop())(`componentId`,n.componentId())(`pageId`,n.pageId())(`rpc`,n.rpc())(`writes`,n.writes())(`readDraft`,n.readWhole),k(),N(n.rootOpen()?7:-1)}}function tN(e,t){if(e&1&&z(0,`app-prop-value`,0),e&2){let e=G();I(`prop`,e.prop())(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}var nN=0;function rN(e){if(e===void 0)return`undefined`;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function iN(e){if(Array.isArray(e))return e.every(iN);if(e&&typeof e==`object`){let t=e;return![`$collapsed`,`$more`,`$type`].some(e=>Object.hasOwn(t,e))&&Object.values(t).every(iN)}return VM(e)}var aN=class e{prop=$.required();store=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);directive=$(void 0);query=$(``);listId=`value-tree-${++nN}`;host=C(Il);pendingMore=null;constructor(){dy(()=>{let e=this.rows(),t=this.pendingMore;if(!t)return;let n=e.findIndex(e=>(e.kind===`leaf`||e.kind===`node`)&&!t.has(e.id));if(n<0)return;this.pendingMore=null;let r=document.activeElement;r&&r!==document.body&&r.isConnected||this.focusNear(n)})}rootPath=Q(()=>[this.prop().prop]);rootValue=Q(()=>this.store().level(this.rootPath(),this.directive())??this.prop().value);root=Q(()=>MM(this.rootValue()));needle=Q(()=>this.query().trim().toLowerCase());matches=Q(()=>{let e=this.needle(),t=this.prop();if(!e||[t.name,t.prop].some(t=>t.toLowerCase().includes(e)))return null;let n=this.store(),r=this.directive();return UM(this.rootPath(),this.rootValue(),e=>n.level(e,r),e)});rootOpen=Q(()=>!!this.matches()?.length||this.store().isOpen(this.rootPath(),this.directive()));rows=Q(()=>{let e=this.root();if(!e)return[];let t=this.store(),n=this.directive(),r=this.matches(),i=new Set,a=new Set;for(let e of r??[]){a.add(LM(e));for(let t=2;t<=e.length;t++)i.add(LM(e.slice(0,t)))}let o=this.prop(),s=this.writes()&&n===void 0,c=[],l=(e,o,d,f,p,m)=>{let{children:h,more:g}=PM(e);for(let e of h){let h=[...o,e.key],g=LM(h);if(r&&!m&&!i.has(g))continue;let _=MM(e.value),ee=LM(h,n);if(!_){let t=p&&VM(e.value)?zM(h):null;c.push({id:ee,kind:`leaf`,depth:f,path:h,label:e.label,text:rN(e.value),edit:s&&t&&p?{name:RM(h,[...d]),prop:t,value:e.value,edit:p}:void 0});continue}let te=!!r&&!m&&i.has(g)&&!a.has(g)||t.isOpen(h,n);if(c.push({id:ee,kind:`node`,depth:f,path:h,label:e.label,text:IM(_),container:_,open:te}),!te)continue;let ne=t.level(h,n)??(_.collapsed?void 0:e.value),re=[...d,_.kind];ne===void 0?t.errors().has(ee)?c.push({...u(h,f+1,`error`),text:t.errors().get(ee)}):c.push(u(h,f+1,`loading`)):l(ne,h,re,f+1,HM(p,_),m||a.has(g))}g>0&&(!r||m)&&c.push({...u(o,f,`more`),more:g,listed:h.length})},u=(e,t,r)=>({id:`${LM(e,n)}:${r}`,kind:r,depth:t,path:e,label:``,text:``});return l(this.rootValue(),this.rootPath(),[e.kind],0,s?HM(o.editInside??null,e):null,!r),c});readWhole=async()=>{let e=await this.store().read(this.rootPath(),CM.depth,CM.limit);return e.ok?iN(e.value)?{value:e.value}:{error:`Too large to edit as a whole. Open it to edit the values inside.`}:{error:e.error??`The page did not read it.`}};summaryOf(e){return IM(e)}toggleRoot(){this.pendingMore=null,this.store().toggle(this.rootPath(),this.directive(),!1)}toggle(e){this.pendingMore=null,this.store().toggle(e.path,this.directive(),!!e.container?.collapsed)}more(e){this.pendingMore=new Set(this.rows().map(e=>e.id)),this.store().more(e.path,this.directive(),e.listed??0)}focusNear(e){let t=this.host.nativeElement,n=Array.from(t.querySelectorAll(`#${this.listId} > li`)),r=e=>e?.querySelector(`button:not([disabled]), input, textarea, [tabindex="0"]`);(n.slice(e).map(r).find(Boolean)??n.slice(0,e).reverse().map(r).find(Boolean)??t.querySelector(`.root > .toggle`))?.focus()}step(e){return Math.min(100,e.more??0)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-value-tree`]],inputs:{prop:[1,`prop`],store:[1,`store`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],directive:[1,`directive`],query:[1,`query`]},decls:2,vars:1,consts:[[3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`root`],[`type`,`button`,1,`toggle`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m9 6 6 6-6 6`],[1,`summary`,`mono`],[1,`whole`,3,`bare`,`prop`,`componentId`,`pageId`,`rpc`,`writes`,`readDraft`],[1,`entries`,3,`id`],[1,`entry`,3,`padding-left`],[1,`entry`],[`type`,`button`,1,`toggle`],[`type`,`button`,1,`more`],[`role`,`status`,1,`muted`],[`role`,`alert`,1,`error`],[1,`key`,`mono`],[1,`leaf-edit`,3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`leaf`,`mono`],[`type`,`button`,1,`more`,3,`click`],[1,`muted`]],template:function(e,t){if(e&1&&M(0,eN,8,12)(1,tN,1,5,`app-prop-value`,0),e&2){let e;N((e=t.root())?0:1,e)}},dependencies:[xM],styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -2012,7 +2091,7 @@ button.edit[_ngcontent-%COMP%] { .more[_ngcontent-%COMP%] { transition: none; } -}`]})};function wM(e,t){return e.length>t.length&&e.startsWith(`${t.slice(0,-1)},`)}var TM=class{target={rpc:null,pageId:null,componentId:null};fetched=k(new Map);pushed=k({});open=k(new Set);loading=k(new Set);errors=k(new Map);limits=new Map;generation=0;follow(e,t){let n=e.componentId===this.target.componentId&&e.pageId===this.target.pageId;this.target=e,n||(this.generation++,this.fetched.set(new Map),this.open.set(new Set),this.loading.set(new Set),this.errors.set(new Map),this.limits.clear()),this.pushed.set(t??{})}level(e,t){let n=tM(e,t),r=this.pushed();return Object.hasOwn(r,n)?r[n]:this.fetched().get(n)}isOpen(e,t){return this.open().has(tM(e,t))}toggle(e,t,n){let r=tM(e,t),i=new Set(this.open());if(i.has(r)){for(let e of i)(e===r||wM(e,r))&&i.delete(e);this.open.set(i),this.send({path:e,directive:t,forget:!0});return}i.add(r),this.open.set(i),n&&this.load(e,t,this.limits.get(r)??30)}more(e,t,n){let r=tM(e,t),i=Math.min(Bj,Math.max(n,this.limits.get(r)??0)+100);this.limits.set(r,i),this.load(e,t,i)}async read(e,t,n){return this.send({path:e,depth:t,limit:n})}async load(e,t,n){let r=tM(e,t),i=this.generation;this.loading.update(e=>new Set(e).add(r));let a=await this.send({path:e,directive:t,limit:n,watch:!0});i===this.generation&&(this.loading.update(e=>{let t=new Set(e);return t.delete(r),t}),this.errors.update(e=>{let t=new Map(e);return a.ok?t.delete(r):t.set(r,a.error??`The page did not read it.`),t}),a.ok&&this.fetched.update(e=>new Map(e).set(r,a.value)))}async send(e){let{rpc:t,pageId:n,componentId:r}=this.target;if(!t||!n||!r)return{error:`No live page to read from.`};let{directive:i,...a}=e;try{return await t.scope(`pangular`).rpc.call(`request-component-value`,{pageId:n,request:{id:r,...a,...i===void 0?{}:{directive:i}}})??{}}catch{return{error:`The devtools server did not answer. Try again.`}}}};function EM(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(2);A(),X(`: `,e.label())}}function DM(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(3);A(),X(`: `,e.label())}}function OM(e,t){if(e&1){let e=H();B(0,`button`,4),W(`click`,function(){return E(e),D(G(2).store(`log`))}),J(1,` Log to console `),M(2,DM,2,1,`span`,1),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),A(2),N(e.label()?2:-1)}}function kM(e,t){if(e&1){let e=H();B(0,`button`,0),W(`click`,function(){return E(e),D(G().store())}),J(1,` Store as global `),M(2,EM,2,1,`span`,1),V(),M(3,OM,3,2,`button`,2),B(4,`span`,3),J(5),V()}if(e&2){let e=G();qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),A(2),N(e.label()?2:-1),A(),N(e.canLog()?3:-1),A(2),Y(e.message())}}var AM=class e{rpc=$(null);pageId=$(null);target=$.required();label=$(``);canLog=$(!1);staticReport=Q(()=>HE(this.rpc()));busy=k(!1);message=k(``);async store(e=`store`){let t=this.rpc(),n=this.pageId();if(t&&n){this.busy.set(!0),this.message.set(``);try{let r=await t.scope(`pangular`).rpc.call(`request-console-global`,{pageId:n,target:this.target(),...e===`log`?{mode:e}:{}}),i=e===`log`?r?.ok?`Logged in the page console.`:`Not logged.`:r?.ok&&r.name?`Stored as ${r.name}.`:`Not stored.`;this.message.set(r?.message||i)}catch{this.message.set(`Could not reach the page.`)}finally{this.busy.set(!1)}}}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-store-global`]],inputs:{rpc:[1,`rpc`],pageId:[1,`pageId`],target:[1,`target`],label:[1,`label`],canLog:[1,`canLog`]},decls:1,vars:1,consts:[[`type`,`button`,1,`store`,3,`click`,`disabled`],[1,`sr-only`],[`type`,`button`,1,`store`,`log`,3,`disabled`],[`role`,`status`,1,`status`],[`type`,`button`,1,`store`,`log`,3,`click`,`disabled`]],template:function(e,t){e&1&&M(0,kM,6,4),e&2&&N(t.staticReport()?-1:0)},styles:[`[_nghost-%COMP%] { +}`]})};function oN(e,t){return e.length>t.length&&e.startsWith(`${t.slice(0,-1)},`)}var sN=class{target={rpc:null,pageId:null,componentId:null};fetched=O(new Map);pushed=O({});open=O(new Set);loading=O(new Set);errors=O(new Map);limits=new Map;generation=0;follow(e,t){let n=e.componentId===this.target.componentId&&e.pageId===this.target.pageId;this.target=e,n||(this.generation++,this.fetched.set(new Map),this.open.set(new Set),this.loading.set(new Set),this.errors.set(new Map),this.limits.clear()),this.pushed.set(t??{})}level(e,t){let n=LM(e,t),r=this.pushed();return Object.hasOwn(r,n)?r[n]:this.fetched().get(n)}isOpen(e,t){return this.open().has(LM(e,t))}toggle(e,t,n){let r=LM(e,t),i=new Set(this.open());if(i.has(r)){for(let e of i)(e===r||oN(e,r))&&i.delete(e);this.open.set(i),this.send({path:e,directive:t,forget:!0});return}i.add(r),this.open.set(i),n&&this.load(e,t,this.limits.get(r)??30)}more(e,t,n){let r=LM(e,t),i=Math.min(SM,Math.max(n,this.limits.get(r)??0)+100);this.limits.set(r,i),this.load(e,t,i)}async read(e,t,n){return this.send({path:e,depth:t,limit:n})}async load(e,t,n){let r=LM(e,t),i=this.generation;this.loading.update(e=>new Set(e).add(r));let a=await this.send({path:e,directive:t,limit:n,watch:!0});i===this.generation&&(this.loading.update(e=>{let t=new Set(e);return t.delete(r),t}),this.errors.update(e=>{let t=new Map(e);return a.ok?t.delete(r):t.set(r,a.error??`The page did not read it.`),t}),a.ok&&this.fetched.update(e=>new Map(e).set(r,a.value)))}async send(e){let{rpc:t,pageId:n,componentId:r}=this.target;if(!t||!n||!r)return{error:`No live page to read from.`};let{directive:i,...a}=e;try{return await t.scope(`pangular`).rpc.call(`request-component-value`,{pageId:n,request:{id:r,...a,...i===void 0?{}:{directive:i}}})??{}}catch{return{error:`The devtools server did not answer. Try again.`}}}};function cN(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(2);k(),X(`: `,e.label())}}function lN(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(3);k(),X(`: `,e.label())}}function uN(e,t){if(e&1){let e=H();B(0,`button`,4),W(`click`,function(){return T(e),E(G(2).store(`log`))}),J(1,` Log to console `),M(2,lN,2,1,`span`,1),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),k(2),N(e.label()?2:-1)}}function dN(e,t){if(e&1){let e=H();B(0,`button`,0),W(`click`,function(){return T(e),E(G().store())}),J(1,` Store as global `),M(2,cN,2,1,`span`,1),V(),M(3,uN,3,2,`button`,2),B(4,`span`,3),J(5),V()}if(e&2){let e=G();qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),k(2),N(e.label()?2:-1),k(),N(e.canLog()?3:-1),k(2),Y(e.message())}}var fN=class e{rpc=$(null);pageId=$(null);target=$.required();label=$(``);canLog=$(!1);staticReport=Q(()=>UE(this.rpc()));busy=O(!1);message=O(``);async store(e=`store`){let t=this.rpc(),n=this.pageId();if(t&&n){this.busy.set(!0),this.message.set(``);try{let r=await t.scope(`pangular`).rpc.call(`request-console-global`,{pageId:n,target:this.target(),...e===`log`?{mode:e}:{}}),i=e===`log`?r?.ok?`Logged in the page console.`:`Not logged.`:r?.ok&&r.name?`Stored as ${r.name}.`:`Not stored.`;this.message.set(r?.message||i)}catch{this.message.set(`Could not reach the page.`)}finally{this.busy.set(!1)}}}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-store-global`]],inputs:{rpc:[1,`rpc`],pageId:[1,`pageId`],target:[1,`target`],label:[1,`label`],canLog:[1,`canLog`]},decls:1,vars:1,consts:[[`type`,`button`,1,`store`,3,`click`,`disabled`],[1,`sr-only`],[`type`,`button`,1,`store`,`log`,3,`disabled`],[`role`,`status`,1,`status`],[`type`,`button`,1,`store`,`log`,3,`click`,`disabled`]],template:function(e,t){e&1&&M(0,dN,6,4),e&2&&N(t.staticReport()?-1:0)},styles:[`[_nghost-%COMP%] { display: inline-flex; flex-wrap: wrap; align-items: center; @@ -2032,7 +2111,7 @@ button.edit[_ngcontent-%COMP%] { .status[_ngcontent-%COMP%]:empty { display: none; -}`]})},jM=(e,t)=>t.id;function MM(e,t){if(e&1&&(L(0,`p`,4),J(1),R()),e&2){let e=G(2);A(),X(`The page has more @for blocks than the `,e.length,` listed.`)}}function NM(e,t){e&1&&(L(0,`span`,9),J(1,`@empty showing`),R())}function PM(e,t){e&1&&(L(0,`span`,10),J(1,`@empty`),R())}function FM(e,t){e&1&&(L(0,`span`,10),J(1,`renders nothing`),R())}function IM(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,6),U(`click`,function(){let t=E(e).$implicit;return D(G(3).showOwner.emit(t))})(`focus`,function(){let t=E(e).$implicit,n=G(3);return D(n.highlight.emit(n.target(t)))})(`blur`,function(){return E(e),D(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=E(e).$implicit,n=G(3);return D(n.highlight.emit(n.target(t)))})(`mouseleave`,function(){return E(e),D(G(3).highlight.emit(null))}),L(2,`span`,7),J(3),R(),L(4,`span`,8),J(5),R(),M(6,NM,2,0,`span`,9)(7,PM,2,0,`span`,10)(8,FM,2,0,`span`,10),L(9,`span`,11),J(10),R()()()}if(e&2){let e=t.$implicit,n=G(3);A(),j(`aria-disabled`,e.owner?null:`true`),A(2),Y(e.owner?.name??`Unknown component`),A(2),Z(` `,e.count,` `,e.count===1?`item`:`items`,` `),A(),N(e.showingEmpty?6:e.hasEmptyBlock?7:e.count===0?8:-1),A(4),Y(n.trackLabel(e))}}function LM(e,t){if(e&1&&(L(0,`section`,1)(1,`h2`,2),J(2,` @for blocks `),L(3,`span`,3),J(4),R()(),M(5,MM,2,1,`p`,4),L(6,`ul`,5),P(7,IM,11,6,`li`,null,jM),R()()),e&2){let e=G(),t=G();A(4),Y(t.truncated()?e.length+`+`:e.length),A(),N(t.truncated()?5:-1),A(2),F(e)}}function RM(e,t){e&1&&M(0,LM,9,2,`section`,1),e&2&&N(t.length?0:-1)}function zM(e,t){e&1&&z(0,`app-angular-unavailable`,0),e&2&&I(`page`,G().angular())}var BM={$index:`track $index`,item:`track item`,function:`track expression`},VM=class e{blocks=$(void 0);truncated=$(!1);supported=$(null);angular=$(null);showOwner=Rv();highlight=Rv();target(e){return e.rootIds[0]??e.owner?.id??null}trackLabel(e){return e.track?BM[e.track]:`track unknown`}static ɵfac=function(t){return new(t||e)};static ɵcmp=Kh({type:e,selectors:[[`app-for-blocks`]],inputs:{blocks:[1,`blocks`],truncated:[1,`truncated`],supported:[1,`supported`],angular:[1,`angular`]},outputs:{showOwner:`showOwner`,highlight:`highlight`},decls:2,vars:1,consts:[[`capability`,`forBlocks`,`missing`,``,`compact`,``,1,`for`,3,`page`],[`aria-labelledby`,`ct-for-title`,1,`for`],[`id`,`ct-for-title`,1,`for-title`],[1,`pill`],[1,`note`],[1,`for-list`],[`type`,`button`,1,`for-row`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`count`],[1,`flag`,`empty`],[1,`flag`],[1,`track`,`mono`]],template:function(e,t){if(e&1&&M(0,RM,1,1)(1,zM,1,1,`app-angular-unavailable`,0),e&2){let e;N((e=t.blocks())?0:t.supported()===!1?1:-1,e)}},dependencies:[mO],styles:[`[_nghost-%COMP%] { +}`]})},pN=(e,t)=>t.id;function mN(e,t){if(e&1&&(L(0,`p`,4),J(1),R()),e&2){let e=G(2);k(),X(`The page has more @for blocks than the `,e.length,` listed.`)}}function hN(e,t){e&1&&(L(0,`span`,9),J(1,`@empty showing`),R())}function gN(e,t){e&1&&(L(0,`span`,10),J(1,`@empty`),R())}function _N(e,t){e&1&&(L(0,`span`,10),J(1,`renders nothing`),R())}function vN(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,6),U(`click`,function(){let t=T(e).$implicit;return E(G(3).showOwner.emit(t))})(`focus`,function(){let t=T(e).$implicit,n=G(3);return E(n.highlight.emit(n.target(t)))})(`blur`,function(){return T(e),E(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=T(e).$implicit,n=G(3);return E(n.highlight.emit(n.target(t)))})(`mouseleave`,function(){return T(e),E(G(3).highlight.emit(null))}),L(2,`span`,7),J(3),R(),L(4,`span`,8),J(5),R(),M(6,hN,2,0,`span`,9)(7,gN,2,0,`span`,10)(8,_N,2,0,`span`,10),L(9,`span`,11),J(10),R()()()}if(e&2){let e=t.$implicit,n=G(3);k(),j(`aria-disabled`,e.owner?null:`true`),k(2),Y(e.owner?.name??`Unknown component`),k(2),Z(` `,e.count,` `,e.count===1?`item`:`items`,` `),k(),N(e.showingEmpty?6:e.hasEmptyBlock?7:e.count===0?8:-1),k(4),Y(n.trackLabel(e))}}function yN(e,t){if(e&1&&(L(0,`section`,1)(1,`h2`,2),J(2,` @for blocks `),L(3,`span`,3),J(4),R()(),M(5,mN,2,1,`p`,4),L(6,`ul`,5),P(7,vN,11,6,`li`,null,pN),R()()),e&2){let e=G(),t=G();k(4),Y(t.truncated()?e.length+`+`:e.length),k(),N(t.truncated()?5:-1),k(2),F(e)}}function bN(e,t){e&1&&M(0,yN,9,2,`section`,1),e&2&&N(t.length?0:-1)}function xN(e,t){e&1&&z(0,`app-angular-unavailable`,0),e&2&&I(`page`,G().angular())}var SN={$index:`track $index`,item:`track item`,function:`track expression`},CN=class e{blocks=$(void 0);truncated=$(!1);supported=$(null);angular=$(null);showOwner=Rv();highlight=Rv();target(e){return e.rootIds[0]??e.owner?.id??null}trackLabel(e){return e.track?SN[e.track]:`track unknown`}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-for-blocks`]],inputs:{blocks:[1,`blocks`],truncated:[1,`truncated`],supported:[1,`supported`],angular:[1,`angular`]},outputs:{showOwner:`showOwner`,highlight:`highlight`},decls:2,vars:1,consts:[[`capability`,`forBlocks`,`missing`,``,`compact`,``,1,`for`,3,`page`],[`aria-labelledby`,`ct-for-title`,1,`for`],[`id`,`ct-for-title`,1,`for-title`],[1,`pill`],[1,`note`],[1,`for-list`],[`type`,`button`,1,`for-row`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`count`],[1,`flag`,`empty`],[1,`flag`],[1,`track`,`mono`]],template:function(e,t){if(e&1&&M(0,bN,1,1)(1,xN,1,1,`app-angular-unavailable`,0),e&2){let e;N((e=t.blocks())?0:t.supported()===!1?1:-1,e)}},dependencies:[hO],styles:[`[_nghost-%COMP%] { display: block; } @@ -2150,7 +2229,159 @@ button.edit[_ngcontent-%COMP%] { min-width: 0; text-overflow: ellipsis; white-space: nowrap; -}`]})},HM=12,UM=900;function WM(e){for(let t=e.parentElement;t;t=t.parentElement){let e=getComputedStyle(t);if(/(auto|scroll|overlay)/.test(e.overflowY))return t}return null}var GM=class{options;injector=w(ws);visibleTop=k(0);viewport=k(UM);rowHeight;host=null;scroller=null;detach=null;enabled;range;padTop;padBottom;constructor(e){this.options=e,this.rowHeight=k(e.estimate);let t=e.min??300;this.enabled=Q(()=>e.count()>t),this.range=Q(()=>{let t=e.count();if(!this.enabled())return{start:0,end:t};let n=this.rowHeight(),r=this.viewport(),i=Math.max(0,Math.min(this.visibleTop(),t*n-r)),a=Math.max(0,Math.min(t-1,Math.floor(i/n)-HM));return{start:a,end:Math.min(t,Math.max(a,Math.ceil((i+r)/n)+HM))}}),this.padTop=Q(()=>this.enabled()?this.range().start*this.rowHeight():0),this.padBottom=Q(()=>this.enabled()?(e.count()-this.range().end)*this.rowHeight():0),pc(()=>{e.count(),Vd(()=>this.update(),{injector:this.injector})}),w(Es).onDestroy(()=>this.detach?.())}get count(){return this.options.count()}rendered(e){let{start:t,end:n}=this.range();return e>=t&&ethis.update();n.addEventListener(`scroll`,r,{passive:!0}),window.addEventListener(`resize`,r),this.detach=()=>{n.removeEventListener(`scroll`,r),window.removeEventListener(`resize`,r)},this.update()}update(){let e=this.host;if(e){if(this.scroller===e)this.place(e.scrollTop,e.clientHeight);else{let t=this.scroller?this.scroller.getBoundingClientRect().top:0,n=this.scroller?this.scroller.clientHeight:window.innerHeight;this.place(t-e.getBoundingClientRect().top,n)}this.options.fixed||this.measure()}}place(e,t){this.visibleTop.set(e),this.viewport.set(t>0?t:UM)}measure(){let e=this.host?.querySelectorAll(`[data-vindex]`);if(!e||e.length<2)return;let t=e[0].getBoundingClientRect(),n=(e[e.length-1].getBoundingClientRect().bottom-t.top)/e.length;n>4&&Math.abs(n-this.rowHeight())>1&&this.rowHeight.set(n)}reveal(e,t){if(this.enabled()&&!this.rendered(e)){let t=e*this.rowHeight(),n=this.viewport(),r=Math.max(0,t-n/2);if(this.place(r,n),this.host&&this.scroller===this.host)this.host.scrollTop=r;else if(this.host){let e=this.scroller?this.scroller.getBoundingClientRect().top:0,t=this.host.getBoundingClientRect().top-e+r;this.scroller?this.scroller.scrollTop+=t:window.scrollBy(0,t)}}t&&Vd(t,{injector:this.injector})}},KM=[`filterInput`],qM=[`treeEl`],JM=[`propFilterInput`],YM=()=>[],XM=e=>({kind:`component`,id:e}),ZM=(e,t)=>t.row.node.id,QM=(e,t)=>t.outlet+t.route,$M=(e,t)=>t+e,eN=(e,t)=>t.formId,tN=(e,t)=>t.name+t.index,nN=(e,t)=>t.name,rN=(e,t)=>t.token+e,iN=(e,t)=>t.id;function aN(e,t){return this.sourceKey(t)}function oN(e,t){if(e&1){let e=H();L(0,`span`,36),J(1,`Page`),R(),L(2,`app-select`,37),U(`valueChange`,function(t){return E(e),D(G(2).selectPage(t))}),R()}if(e&2){let e=G(2);A(2),I(`options`,e.pageOptions())(`value`,e.page()?.pageId??null)}}function sN(e,t){if(e&1){let e=H();L(0,`button`,38),U(`click`,function(){return E(e),D(G(2).toggleDirectiveHosts())}),O(),L(1,`svg`,14),z(2,`path`,39)(3,`path`,40),R(),J(4,` Directive hosts `),R()}e&2&&j(`aria-pressed`,G(2).showDirectiveHosts())}function cN(e,t){if(e&1){let e=H();L(0,`button`,41),U(`click`,function(){E(e);let t=G(2);return D(t.picking()?t.cancelPick():t.pick())}),O(),L(1,`svg`,14),z(2,`path`,42),R(),J(3),R()}if(e&2){let e=G(2);q(`on`,e.picking()),A(3),X(` `,e.picking()?`Cancel pick`:`Pick component on page`,` `)}}function lN(e,t){if(e&1&&(L(0,`p`,21),J(1),R()),e&2){let e=G(2);A(),Y(e.pickMessage())}}function uN(e,t){if(e&1&&(L(0,`p`,22),J(1),R()),e&2){let e=G(2);A(),Y(e.truncationText())}}function dN(e,t){e&1&&(L(0,`p`,44),J(1,`The filter only searches the components the tree lists.`),R())}function fN(e,t){e&1&&(L(0,`p`,44),J(1,`Directive hosts are hidden, so they are not searched.`),R())}function pN(e,t){if(e&1){let e=H();L(0,`div`,25)(1,`p`,43),J(2),R(),M(3,dN,2,0,`p`,44),M(4,fN,2,0,`p`,44),L(5,`button`,45),U(`click`,function(){return E(e),D(G(2).clearFilter())}),J(6,`Clear filter`),R()()}if(e&2){let e=G(2);A(2),X(`No components match “`,e.filter().trim(),`”`),A(),N(e.page().truncated?3:-1),A(),N(!e.showDirectiveHosts()&&e.page().directiveHostCount?4:-1)}}function mN(e,t){if(e&1&&(L(0,`p`,26),J(1),R()),e&2){let e=G(2);A(),X(` `,e.rows().length,` rows. Rows render as you scroll, so the browser's find only sees the ones near view; the filter above searches them all. `)}}function hN(e,t){if(e&1){let e=H();L(0,`span`,53),U(`click`,function(t){E(e),G();let n=fv(0);return D(G(2).toggle(n.node.id,t))}),O(),L(1,`svg`,54),z(2,`path`,55),R()()}e&2&&(G(),q(`open`,fv(0).expanded))}function gN(e,t){e&1&&z(0,`span`,48)}function _N(e,t){if(e&1&&(L(0,`span`,56),J(1),R(),L(2,`span`,57),J(3),R(),L(4,`span`,24),J(5,`directive host`),R()),e&2){G();let e=fv(0),t=G(2);A(),X(`<`,e.node.tag,`>`),A(),j(`title`,e.node.directives?.join(`, `)),A(),Y(t.hostLabel(e.node))}}function vN(e,t){if(e&1&&(L(0,`span`,58),J(1),R(),L(2,`span`,59),J(3),R()),e&2){G();let e=fv(0);A(),Y(e.node.name),A(2),X(`<`,e.node.tag,`>`)}}function yN(e,t){if(e&1&&(L(0,`span`)(1,`span`,24),J(2,`Hydration: `),R(),J(3),R()),e&2){let e=t,n=G(3);M_(`hyd hyd-`+e),A(3),Y(n.hydrationText(e))}}function bN(e,t){if(e&1&&(L(0,`span`,50),J(1),R()),e&2){let e=t.$implicit;A(),Y(e.route||`/`)}}function xN(e,t){if(e&1&&(L(0,`span`,51),J(1),L(2,`span`,24),J(3),R()()),e&2){let e=t;A(),X(` `,e),A(2),X(` `,e===1?`check`:`checks`,` while recording`)}}function SN(e,t){if(e&1&&(L(0,`span`,52),J(1),L(2,`span`,24),J(3),R()()),e&2){G();let e=fv(0);j(`title`,e.node.directives.join(`, `)),A(),X(` +`,e.node.directives.length,` `),A(2),X(` `,e.node.directives.length===1?`directive`:`directives`,` `)}}function CN(e,t){if(e&1){let e=H();uv(0),L(1,`div`,46),U(`click`,function(){E(e);let t=fv(0);return D(G(2).select(t.node.id))})(`focus`,function(){E(e);let t=fv(0),n=G(2);return n.focusId.set(t.node.id),D(n.highlight(t.node.id))})(`blur`,function(){return E(e),D(G(2).highlight(null))})(`mouseenter`,function(){E(e);let t=fv(0);return D(G(2).highlight(t.node.id))})(`mouseleave`,function(){return E(e),D(G(2).highlight(null))}),M(2,hN,3,2,`span`,47)(3,gN,1,0,`span`,48),M(4,_N,6,3)(5,vN,4,2),M(6,yN,4,3,`span`,49),P(7,bN,2,1,`span`,50,QM),M(9,xN,4,2,`span`,51),M(10,SN,4,3,`span`,52),R()}if(e&2){let e,n,r=t.$implicit,i=G(2),a=dv(r.row);A(),K(`--%NS%depth`,a.depth),q(`selected`,i.selectedId()===a.node.id)(`dir-host`,a.node.kind===`directive`),j(`aria-level`,a.depth+1)(`aria-setsize`,a.setsize)(`aria-posinset`,a.posinset)(`aria-expanded`,a.hasChildren?a.expanded:null)(`aria-selected`,i.selectedId()===a.node.id)(`tabindex`,i.tabStop()===a.node.id?0:-1)(`data-vindex`,r.index)(`data-id`,a.node.id),A(),N(a.hasChildren?2:3),A(2),N(a.node.kind===`directive`?4:5),A(2),N((e=a.node.hydration)?6:-1,e),A(),F(i.routedById().get(a.node.id)??mv(20,YM)),A(2),N((n=i.cdHosts()[a.node.id])?9:-1,n),A(),N(a.node.kind!==`directive`&&a.node.directives?.length?10:-1)}}function wN(e,t){if(e&1&&(L(0,`li`,67),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function TN(e,t){if(e&1){let e=H();L(0,`div`,69)(1,`button`,45),U(`click`,function(){let t=E(e);return D(G(3).reveal(t.id,!0))}),J(2),R()()}e&2&&(A(2),X(` Show `,t.name,` `))}function EN(e,t){if(e&1&&(L(0,`section`,29)(1,`header`,60)(2,`span`,61),J(3,`directive host`),R(),L(4,`h2`,62),J(5),R(),L(6,`span`,63),J(7),R()(),L(8,`div`,64)(9,`h3`),J(10,` Directives `),L(11,`span`,65),J(12),R()(),L(13,`ul`,66),P(14,wN,2,1,`li`,67,$M),R()(),L(16,`div`,64)(17,`p`,68),J(18,` This element hosts directives but no component. Their inputs are bound in the template of the component that renders it. `),R(),M(19,TN,3,1,`div`,69),R()()),e&2){let e,n=t,r=G(2);A(5),X(`<`,n.tag,`>`),A(2),Y(r.hostLabel(n)),A(5),Y(n.directives?.length??0),A(2),F(n.directives??mv(4,YM)),A(5),N((e=r.ownerOf(n.id))?19:-1,e)}}function DN(e,t){if(e&1&&(L(0,`p`,70),z(1,`app-source-link`,74),R()),e&2){let e=t;A(),I(`file`,e.file)(`line`,e.line)}}function ON(e,t){if(e&1){let e=H();L(0,`div`,75)(1,`button`,45),U(`click`,function(){E(e);let t=G();return D(G(2).revealInElements(t))}),J(2,`Reveal in Elements`),R(),L(3,`button`,45),U(`click`,function(){E(e);let t=G();return D(G(2).openSource(t))}),J(4,`Open source`),R()(),L(5,`p`,76),J(6),R()}if(e&2){let e=G(3);A(6),Y(e.actionMessage())}}function kN(e,t){if(e&1){let e=H();L(0,`button`,78),U(`click`,function(){let t=E(e).$implicit;return D(G(5).showForm.emit(t.formId))}),J(1),R()}if(e&2){let e=t.$implicit;A(),X(` Show `,e.label,` in Forms `)}}function AN(e,t){if(e&1&&(L(0,`div`,71),P(1,kN,2,1,`button`,77,eN),R()),e&2){let e=G(),t=G(3);A(),F(t.formsIn(e.file))}}function jN(e,t){e&1&&M(0,AN,3,0,`div`,71),e&2&&N(G(3).formsIn(t.file).length?0:-1)}function MN(e,t){if(e&1){let e=H();L(0,`div`,71)(1,`button`,45),U(`click`,function(){E(e);let t=G();return D(G(2).openInjector(t))}),J(2,` Show in Injectors `),L(3,`span`,24),J(4),R()()()}if(e&2){let e=G();A(4),X(`: `,e.name)}}function NN(e,t){if(e&1&&z(0,`app-store-global`,72),e&2){let e=G(),t=G(2);I(`rpc`,t.rpc())(`pageId`,t.page()?.pageId)(`target`,hv(4,XM,e.id))(`label`,e.name)}}function PN(e,t){if(e&1&&(L(0,`dt`),J(1,`Routed`),R(),L(2,`dd`,80),J(3),R()),e&2){let e=t.$implicit;A(3),Z(``,e.route||`/`,` in outlet `,e.outlet)}}function FN(e,t){if(e&1&&(L(0,`span`,11),J(1),R()),e&2){let e=G(4);A(),Z(``,e.shownValues()?.count??0,` of `,e.valueTotal())}}function IN(e,t){if(e&1){let e=H();L(0,`div`,84)(1,`p`,43),J(2),R(),L(3,`p`,44),J(4,` The filter searches names, and the nested keys of values you opened. `),R(),L(5,`button`,45),U(`click`,function(){return E(e),D(G(5).clearPropFilter())}),J(6,`Clear filter`),R()()}if(e&2){let e=G(5);A(2),X(` No inputs, outputs or properties match “`,e.propFilter().trim(),`” `)}}function LN(e,t){if(e&1&&(L(0,`span`,88),J(1),R()),e&2){let e=G().$implicit;A(),X(`(`,e.prop,`)`)}}function RN(e,t){if(e&1&&(L(0,`li`,86)(1,`span`,87),J(2),M(3,LN,2,1,`span`,88),R(),z(4,`app-value-tree`,89),R()),e&2){let e=t.$implicit,n=G(4),r=G(3);A(2),X(` `,e.name,` `),A(),N(e.prop===e.name?-1:3),A(),I(`prop`,e)(`store`,r.values)(`query`,r.propFilter())(`componentId`,n.id)(`pageId`,r.page()?.pageId??null)(`rpc`,r.rpc())(`writes`,r.canEdit())}}function zN(e,t){if(e&1&&(L(0,`ul`,85),P(1,RN,5,9,`li`,86,nN),R()),e&2){let e=G(2);A(),F(e.inputs)}}function BN(e,t){e&1&&(L(0,`p`,68),J(1,`No inputs.`),R())}function VN(e,t){if(e&1&&(L(0,`div`,64)(1,`h3`),J(2,` Inputs `),L(3,`span`,65),J(4),R()(),M(5,zN,3,0,`ul`,85)(6,BN,2,0,`p`,68),R()),e&2){let e=G();A(4),Y(e.inputs.length),A(),N(e.inputs.length?5:6)}}function HN(e,t){if(e&1&&(L(0,`li`,91)(1,`span`,80),J(2),R(),L(3,`span`,92),J(4),R()()),e&2){let e=t.$implicit;q(`on`,e.listened),A(2),Y(e.name),A(2),Y(e.listened?`listened`:`no listener`)}}function UN(e,t){if(e&1&&(L(0,`ul`,66),P(1,HN,5,4,`li`,90,nN),R()),e&2){let e=G(2);A(),F(e.outputs)}}function WN(e,t){e&1&&(L(0,`p`,68),J(1,`No outputs.`),R())}function GN(e,t){if(e&1&&(L(0,`div`,64)(1,`h3`),J(2,` Outputs `),L(3,`span`,65),J(4),R()(),M(5,UN,3,0,`ul`,66)(6,WN,2,0,`p`,68),R()),e&2){let e=G();A(4),Y(e.outputs.length),A(),N(e.outputs.length?5:6)}}function KN(e,t){if(e&1&&(L(0,`span`,93),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.kind)}}function qN(e,t){if(e&1&&(L(0,`li`,86)(1,`span`,87),J(2),M(3,KN,2,1,`span`,93),R(),z(4,`app-value-tree`,89),R()),e&2){let e=t.$implicit,n=G(4),r=G(3);A(2),X(` `,e.name,` `),A(),N(e.kind?3:-1),A(),I(`prop`,e)(`store`,r.values)(`query`,r.propFilter())(`componentId`,n.id)(`pageId`,r.page()?.pageId??null)(`rpc`,r.rpc())(`writes`,r.canEdit())}}function JN(e,t){if(e&1&&(L(0,`ul`,85),P(1,qN,5,9,`li`,86,nN),R()),e&2){let e=G(2);A(),F(e.properties)}}function YN(e,t){e&1&&(L(0,`p`,68),J(1,`No other properties.`),R())}function XN(e,t){if(e&1&&(L(0,`div`,64)(1,`h3`),J(2,` Properties `),L(3,`span`,65),J(4),R()(),M(5,JN,3,0,`ul`,85)(6,YN,2,0,`p`,68),R()),e&2){let e=G();A(4),Y(e.properties.length),A(),N(e.properties.length?5:6)}}function ZN(e,t){if(e&1&&(L(0,`li`,67),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function QN(e,t){if(e&1&&(L(0,`div`,64)(1,`h3`),J(2,` DOM listeners `),L(3,`span`,65),J(4),R()(),L(5,`ul`,66),P(6,ZN,2,1,`li`,67,Ag),R()()),e&2){let e=G(2);A(4),Y(e.listeners.length),A(2),F(e.listeners)}}function $N(e,t){if(e&1&&(L(0,`li`,86)(1,`span`,87),J(2),R(),z(3,`app-value-tree`,94),R()),e&2){let e=t.$implicit,n=G(2).$implicit,r=G(2),i=G(3);A(2),Y(e.name),A(),I(`prop`,e)(`store`,i.values)(`query`,i.propFilter())(`directive`,n.index)(`componentId`,r.id)(`pageId`,i.page()?.pageId??null)(`rpc`,i.rpc())}}function eP(e,t){if(e&1&&(L(0,`ul`,85),P(1,$N,4,8,`li`,86,nN),R()),e&2){let e=G().$implicit;A(),F(e.inputs)}}function tP(e,t){if(e&1&&(L(0,`li`,91)(1,`span`,80),J(2),R(),L(3,`span`,92),J(4),R()()),e&2){let e=t.$implicit;q(`on`,e.listened),A(2),Y(e.name),A(2),Y(e.listened?`listened`:`no listener`)}}function nP(e,t){if(e&1&&(L(0,`ul`,66),P(1,tP,5,4,`li`,90,nN),R()),e&2){let e=G().$implicit;A(),F(e.outputs)}}function rP(e,t){e&1&&(L(0,`p`,68),J(1,`No inputs or outputs.`),R())}function iP(e,t){if(e&1&&(L(0,`div`,64)(1,`h3`)(2,`span`,80),J(3),R(),L(4,`span`,93),J(5,`directive on host`),R()(),M(6,eP,3,0,`ul`,85),M(7,nP,3,0,`ul`,66),M(8,rP,2,0,`p`,68),R()),e&2){let e=t.$implicit;A(3),Y(e.name),A(3),N(e.inputs.length?6:-1),A(),N(e.outputs.length?7:-1),A(),N(!e.inputs.length&&!e.outputs.length?8:-1)}}function aP(e,t){if(e&1&&(M(0,IN,7,1,`div`,84),M(1,VN,7,2,`div`,64),M(2,GN,7,2,`div`,64),M(3,XN,7,2,`div`,64),M(4,QN,8,1,`div`,64),P(5,iP,9,4,`div`,64,tN)),e&2){let e=t,n=G(),r=G(3);N(r.propQuery()&&!e.count?0:-1),A(),N(!r.propQuery()||e.inputs.length?1:-1),A(),N(!r.propQuery()||e.outputs.length?2:-1),A(),N(!r.propQuery()||e.properties.length?3:-1),A(),N(!r.propQuery()&&n.listeners.length?4:-1),A(),F(e.directives)}}function oP(e,t){if(e&1&&(L(0,`span`,93),J(1),R()),e&2){let e=t.$implicit;A(),Y(e)}}function sP(e,t){if(e&1&&(L(0,`span`,97),J(1,`from `),L(2,`span`,80),J(3),R()()),e&2){let e=G().$implicit;A(3),Y(e.providedByName??`an injector`)}}function cP(e,t){e&1&&(L(0,`span`,98),J(1,`not provided`),R())}function lP(e,t){if(e&1&&(L(0,`li`,95)(1,`span`,96),J(2),R(),P(3,oP,2,1,`span`,93,Ag),M(5,sP,4,1,`span`,97)(6,cP,2,0,`span`,98),R()),e&2){let e=t.$implicit;A(2),Y(e.token),A(),F(e.flags),A(2),N(e.providedBy?5:6)}}function uP(e,t){if(e&1&&(L(0,`ul`,83),P(1,lP,7,2,`li`,95,rN),R()),e&2){let e=G();A(),F(e.dependencies)}}function dP(e,t){e&1&&(L(0,`p`,68),J(1,`Nothing is injected through the constructor or inject().`),R())}function fP(e,t){if(e&1){let e=H();L(0,`dl`,79)(1,`dt`),J(2,`Change detection`),R(),L(3,`dd`),J(4),R(),L(5,`dt`),J(6,`Encapsulation`),R(),L(7,`dd`),J(8),R(),L(9,`dt`),J(10,`Host path`),R(),L(11,`dd`,80),J(12),R(),P(13,PN,4,2,null,null,QM),R(),L(15,`div`,81)(16,`div`,5),O(),L(17,`svg`,6),z(18,`circle`,7)(19,`path`,8),R(),gs(),L(20,`input`,82,2),U(`input`,function(t){return E(e),D(G(3).propFilter.set(t.target.value))})(`keydown.escape`,function(t){return E(e),D(G(3).clearPropFilter(t))}),R()(),M(22,FN,2,2,`span`,11),L(23,`p`,20),J(24),R()(),M(25,aP,7,5),L(26,`div`,64)(27,`h3`),J(28,` Injected `),L(29,`span`,65),J(30),R()(),M(31,uP,3,0,`ul`,83)(32,dP,2,0,`p`,68),R()}if(e&2){let e,n=t,r=G(),i=G(2);A(4),Y(n.changeDetection??`Unknown`),A(4),Y(n.encapsulation??`Unknown`),A(4),Y(n.path),A(),F(i.routedById().get(r.id)??mv(9,YM)),A(7),I(`value`,i.propFilter()),A(2),N(i.propQuery()?22:-1),A(2),Y(i.propFilterStatus()),A(),N((e=i.shownValues())?25:-1,e),A(5),Y(n.dependencies.length),A(),N(n.dependencies.length?31:32)}}function pP(e,t){e&1&&(L(0,`div`,73),z(1,`span`,99),L(2,`p`,44),J(3,`Reading live values from the page…`),R()())}function mP(e,t){if(e&1&&(L(0,`section`,29)(1,`header`,60)(2,`span`,61),J(3,`component`),R(),L(4,`h2`,62),J(5),R(),L(6,`span`,63),J(7),R(),M(8,DN,2,2,`p`,70),M(9,ON,7,1),M(10,jN,1,1),M(11,MN,5,1,`div`,71),M(12,NN,1,6,`app-store-global`,72),R(),M(13,fP,33,10)(14,pP,4,0,`div`,73),R()),e&2){let e,n,r,i=t,a=G(2);A(5),Y(i.name),A(2),X(`<`,i.tag,`>`),A(),N((e=a.whereOf(i))?8:-1,e),A(),N(a.devtoolsActions()?9:-1),A(),N((n=a.sourceFor(i))?10:-1,n),A(),N(a.canShowInjector()&&!a.staticReport()?11:-1),A(),N(!a.staticReport()&&!a.native()?12:-1),A(),N((r=a.detail())?13:14,r)}}function hP(e,t){e&1&&(L(0,`p`,43),J(1,`The selected component was destroyed`),R(),L(2,`p`,44)(3,`span`,80),J(4),R(),J(5,` is no longer on the page. Select another component to see its live values. `),R()),e&2&&(A(4),Y(t))}function gP(e,t){e&1&&(L(0,`p`,44),J(1,` Select a component to see its live inputs, properties, outputs, change detection and injected services. `),R())}function _P(e,t){if(e&1&&(L(0,`div`,30),M(1,hP,6,1)(2,gP,2,0,`p`,44),R()),e&2){let e,t=G(2);A(),N((e=t.destroyed())?1:2,e)}}function vP(e,t){e&1&&(L(0,`span`,93),J(1,`hydrate never`),R())}function yP(e,t){if(e&1&&(L(0,`span`,93),J(1),R()),e&2){let e=G().$implicit;A(),Y(e.hydration)}}function bP(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,102),U(`click`,function(){let t=E(e).$implicit;return D(G(3).showOwner(t))})(`focus`,function(){let t=E(e).$implicit;return D(G(3).highlightBlock(t))})(`blur`,function(){return E(e),D(G(3).highlight(null))})(`mouseenter`,function(){let t=E(e).$implicit;return D(G(3).highlightBlock(t))})(`mouseleave`,function(){return E(e),D(G(3).highlight(null))}),L(2,`span`,58),J(3),R(),L(4,`span`,103),J(5),R(),M(6,vP,2,0,`span`,93)(7,yP,2,1,`span`,93),L(8,`span`,104),J(9),R()()()}if(e&2){let e=t.$implicit;A(),j(`aria-disabled`,e.owner?null:`true`),A(2),Y(e.owner?.name??`Unknown component`),A(),M_(`defer-state-`+e.state),A(),Y(e.state),A(),N(e.hydrateNever?6:e.hydration===`not-configured`?-1:7),A(3),Y(e.triggers.join(`, `)||`no triggers`)}}function xP(e,t){if(e&1&&(L(0,`section`,31)(1,`h2`,100),J(2,` Defer blocks `),L(3,`span`,65),J(4),R()(),L(5,`ul`,101),P(6,bP,10,7,`li`,null,iN),R()()),e&2){let e=G(2);A(4),Y(e.deferCount()),A(2),F(e.deferBlocks())}}function SP(e,t){e&1&&z(0,`app-angular-unavailable`,32),e&2&&I(`page`,G(2).angularPage())}function CP(e,t){if(e&1){let e=H();L(0,`app-hydration-section`,105),U(`overlay`,function(t){return E(e),D(G(2).setHydrationOverlay(t))})(`showNode`,function(t){return E(e),D(G(2).revealNode(t))})(`highlight`,function(t){return E(e),D(G(2).highlight(t))}),R()}e&2&&I(`report`,G(2).page()?.hydration)}function wP(e,t){if(e&1){let e=H();L(0,`app-cd-recording`,106),U(`showComponent`,function(t){return E(e),D(G(2).showCdComponent(t))}),R()}if(e&2){let e=G(2);I(`page`,e.cdPage())(`pageId`,e.page().pageId)(`rpc`,e.rpc())}}function TP(e,t){if(e&1){let e=H();L(0,`p`,3),J(1,` Every component instance on the page, in the order Angular rendered them. Hover a row to highlight its host in the page, and select it to read its live inputs, properties, outputs and injected services. `),R(),L(2,`div`,4)(3,`div`,5),O(),L(4,`svg`,6),z(5,`circle`,7)(6,`path`,8),R(),gs(),L(7,`input`,9,0),U(`input`,function(t){return E(e),D(G().setFilter(t.target.value))})(`keydown.escape`,function(){return E(e),D(G().setFilter(``))}),R(),L(9,`span`,10),J(10,` Type plain text, a tag such as
    -
    -

    Depends on zone.js

    - @if (zone().length) { - - - - - - - - - - @for (z of zone(); track z.name) { + @if (hasZone()) { +
    +

    Depends on zone.js

    + @if (zone().length) { +
    ComponentZone-only ticksAfter
    + - - - + + + - } - -
    {{ z.name }}{{ z.ticks }}{{ z.tasks?.join(', ') }}ComponentZone-only ticksAfter
    - } @else if (d.triggers) { -

    {{ zoneNote() }}

    - } -
    + + + @for (z of zone(); track z.name) { + + {{ z.name }} + {{ z.ticks }} + {{ z.tasks?.join(', ') }} + + } + + + } @else if (d.triggers) { +

    {{ zoneNote() }}

    + } + + }

    Wasted checks

    @if (!d.waste) { @@ -209,11 +211,20 @@ export class CdDiagnosis { })); }); readonly zone = computed(() => (this.diagnosis()?.zone ?? []).slice(0, SHOWN)); + private readonly zoneTicks = computed(() => this.diagnosis()?.causes.zone ?? 0); + /** + * Shown when the page loads zone.js. Recordings made before `zoneJs` was + * reported fall back to whether zone.js started a tick or a component + * depends on it. + */ + readonly hasZone = computed(() => { + const zoneJs = this.diagnosis()?.zoneJs; + return zoneJs ?? (this.zone().length > 0 || this.zoneTicks() > 0); + }); readonly zoneNote = computed(() => { - const ticks = this.diagnosis()?.causes.zone ?? 0; - return ticks - ? `${ticks} ${ticks === 1 ? 'tick' : 'ticks'} came from zone.js alone, and no component changed in them.` - : 'No component changed in a tick only zone.js started.'; + const ticks = this.zoneTicks(); + if (!ticks) return 'No component changed in a tick only zone.js started.'; + return `${ticks} ${ticks === 1 ? 'tick' : 'ticks'} came from zone.js alone, and no component changed in them.`; }); readonly wasted = computed(() => (this.diagnosis()?.components ?? []).filter((c) => c.unchanged > 0).slice(0, SHOWN), diff --git a/app/src/pages/component-tree.ts b/app/src/pages/component-tree.ts index 4beed86c..3a780e54 100644 --- a/app/src/pages/component-tree.ts +++ b/app/src/pages/component-tree.ts @@ -814,7 +814,7 @@ function storedDirectiveHosts(): boolean { [pageId]="page()!.pageId" [rpc]="rpc()" [angular]="angularPage()" - (showComponent)="revealNode($event)" + (showComponent)="showLeakComponent($event)" (highlight)="highlight($event)" /> } @@ -1203,6 +1203,8 @@ function storedDirectiveHosts(): boolean { } .row { position: relative; + scroll-margin-top: var(--ct-toolbar-clearance, 72px); + scroll-margin-bottom: 8px; display: flex; align-items: center; gap: 6px; @@ -2436,6 +2438,11 @@ export class ComponentTree { if (this.index().map.has(id)) this.reveal(id); } + /** Shows a component a Leaks row names, and moves keyboard focus to its tree row. */ + showLeakComponent(id: string) { + if (this.index().map.has(id)) this.reveal(id, true); + } + /** Opens the tree to a node and selects it; `focus` also moves keyboard focus to its row. */ reveal(id: string, focus = false) { const { parents } = this.index(); @@ -2453,8 +2460,16 @@ export class ComponentTree { afterNextRender( () => { const row = document.querySelector(`.row[data-id="${CSS.escape(id)}"]`); + // Keep the row clear of the sticky toolbar, whose height changes as it wraps. + const toolbar = this.host.nativeElement.querySelector('.toolbar'); + if (toolbar) { + this.host.nativeElement.style.setProperty( + '--ct-toolbar-clearance', + `${toolbar.offsetHeight + 8}px`, + ); + } row?.scrollIntoView({ block: 'nearest' }); - if (focus) row?.focus(); + if (focus) row?.focus({ preventScroll: true }); }, { injector: this.injector }, ); diff --git a/app/src/pages/error-explain.ts b/app/src/pages/error-explain.ts index baaeb2a6..884df648 100644 --- a/app/src/pages/error-explain.ts +++ b/app/src/pages/error-explain.ts @@ -188,7 +188,7 @@ const STEP_TONE: Record = {

    {{ announcement() }}

    @@ -154,6 +157,14 @@ const plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? o >. Navigate a few times to see whether they stay.

    } + @if (devHeld().length) { +

    + Not counted: the last destroyed instance of a class with none left on the page, which + Angular's development-mode DI debug data can keep alive: + {{ names(devHeld()) }}. +

    + } @if (detached().length) {

    Off the page but not destroyed (detached views, such as a route reuse cache): @@ -285,6 +296,9 @@ const plural = (n: number, one: string, many = `${one}s`) => `${n} ${n === 1 ? o .track[aria-pressed='true'] { @include m.tint(accent); } + .track[aria-disabled='true'] { + cursor: progress; + } .track:focus-visible { @include m.focus-ring; } @@ -410,17 +424,20 @@ export class LeaksSection { const retained: LeakDestroyed[] = []; const recent: LeakDestroyed[] = []; const detached: LeakDestroyed[] = []; - if (!page) return { retained, recent, detached }; + const devHeld: LeakDestroyed[] = []; + if (!page) return { retained, recent, detached, devHeld }; for (const item of page.destroyed) { if (item.detached) detached.push(item); + else if (item.devHeld) devHeld.push(item); else if (this.isRetained(page, item)) retained.push(item); else recent.push(item); } - return { retained, recent, detached }; + return { retained, recent, detached, devHeld }; }); protected readonly retained = computed(() => this.split().retained); protected readonly recent = computed(() => this.split().recent); protected readonly detached = computed(() => this.split().detached); + protected readonly devHeld = computed(() => this.split().devHeld); private ageMs(page: LeaksPage, item: LeakDestroyed): number { return Math.max(0, this.now()() - page.reportedAt + (page.at - item.destroyedAt)); diff --git a/apps/docs/src/content/agents/tools.md b/apps/docs/src/content/agents/tools.md index 5702b4ac..39add205 100644 --- a/apps/docs/src/content/agents/tools.md +++ b/apps/docs/src/content/agents/tools.md @@ -261,11 +261,11 @@ A parent binding sets a bound input again the next time its own value changes. O Leak hints for one page, in three parts. Reads: page. -| Part | What it lists | -| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Still retained** | Component instances destroyed but still in memory after at least 2 navigations and 10 seconds: class, instance id, the route they lived on, age, navigations since and open subscriptions. Detached views are named apart. | -| **Open subscriptions after destroy** | Subscriptions still open after the component that made them went away, grouped by class, instance and call site, with why each is flagged. Only while subscription tracking is on. | -| **Live effects and subscriptions** | Components with live effects (from `ng.ɵgetSignalGraph`, Angular 20.1 and later) or tracked open subscriptions, with instance ids for `inspect-component`. | +| Part | What it lists | +| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Still retained** | Component instances destroyed but still in memory after at least 2 navigations and 10 seconds: class, instance id, the route they lived on, age, navigations since and open subscriptions. In a development build, the latest destroyed instance of a class with none left on the page is named apart and not counted, as Angular's DI debug data keeps it alive. Detached views are named apart too. | +| **Open subscriptions after destroy** | Subscriptions still open after the component that made them went away, grouped by class, instance and call site, with why each is flagged. Only while subscription tracking is on. | +| **Live effects and subscriptions** | Components with live effects (from `ng.ɵgetSignalGraph`, Angular 20.1 and later) or tracked open subscriptions, with instance ids for `inspect-component`. | | Argument | Required | Value | | ----------- | -------- | -------------------------------------------------------- | diff --git a/apps/docs/src/content/inspectors/components.md b/apps/docs/src/content/inspectors/components.md index 8409a658..df661c57 100644 --- a/apps/docs/src/content/inspectors/components.md +++ b/apps/docs/src/content/inspectors/components.md @@ -251,12 +251,14 @@ Below **Change detection**, the **Leaks** section looks for components that stay | **Open subscriptions after destroy** | RxJS subscriptions a component made that are still open after it went away, with the class, the count and the line that made them. Only while **Track subscriptions** is on. | | **Live effects and subscriptions** | Components on the page that hold live effects or tracked open subscriptions. Hover or focus a row to highlight the component in the page, and click it to select it in the tree. | -A line above the lists counts the navigations, the retained instances and the destroyed instances the browser has collected. Instances destroyed fewer than 2 navigations or 10 seconds ago are named under **Still retained**, and instances that left the page without being destroyed (detached views, such as a `RouteReuseStrategy` cache) are named apart. +A line above the lists counts the navigations, the retained instances and the destroyed instances the browser has collected. Instances destroyed fewer than 2 navigations or 10 seconds ago are left out of **Still retained** and named in a separate note, as destroyed recently and not collected yet. Instances that left the page without being destroyed (detached views, such as a `RouteReuseStrategy` cache) are named in a note of their own. The browser collects garbage when it decides, so an instance in Still retained is not proof of a leak. Take a heap snapshot in the Chrome DevTools Memory panel, search for the class name and read its Retainers to see what holds it. +In a development build, Angular's DI debug data (the records behind `ng.ɵgetInjectorProviders`) keeps the last instance of each component class alive. One destroyed instance of a class with none left on the page is therefore no sign of a leak on its own. The section and the `find-leaks` agent tool name that instance in a separate note and don't count it as retained. A second destroyed instance of the same class that stays is the stronger hint. + #### How destroyed components are found The page walks the component tree when elements come or go, and every 30 seconds otherwise. A component whose host left the page counts as destroyed when Angular has dropped its view (`ng.getInjector` gives Angular's null injector for the host). If Angular still holds the view, the component counts as detached. The page holds each instance through a `WeakRef` only, and a `FinalizationRegistry` tells it when the browser collected one, so the devtools keep nothing alive themselves. The page tracks up to 500 destroyed instances, and the section lists the oldest 100. diff --git a/apps/docs/src/content/inspectors/errors.md b/apps/docs/src/content/inspectors/errors.md index 67514277..afceaa0f 100644 --- a/apps/docs/src/content/inspectors/errors.md +++ b/apps/docs/src/content/inspectors/errors.md @@ -47,7 +47,7 @@ For `ExpressionChangedAfterItHasBeenCheckedError`, the box shows: | **Current** | The value of the second check. | | **Held by** | The fields of the component that hold the current value now, signals included. Getters and `computed` signals don't run. | -**Written by** lists the named signals written with the current value in the 2 seconds before the error. With write stacks on (see [Signals](./signals.md)), each one shows the app frames that wrote it. Without a match, the box says where to look instead. The overlay hears signal writes only while the Signals inspector is on, on Angular 17.0 or later, and only for signals with a `debugName`. +**Written by** lists the named signals written with the current value in the 2 seconds before the error. Values are compared the way Angular prints them, from the value as it was written, so dates and objects match too. When some of those signals are named like the binding or a field under **Held by**, only those are listed. With write stacks on (see [Signals](./signals.md)), each one shows the app frames that wrote it. Without a match, the box says where to look instead. The overlay hears signal writes only while the Signals inspector is on, on Angular 17.0 or later, and only for signals with a `debugName`. When the binding or a field that holds the value has a secret-looking name, both values show as `[redacted]`. @@ -55,6 +55,8 @@ When the binding or a field that holds the value has a secret-looking name, both For a hydration mismatch, the box shows Angular's first sentence and a line diff of the server HTML Angular expected (`−`) and the client DOM it found (`+`). Angular marks the node it means with `<-- AT THIS LOCATION`. The diff comes from the error message. When the message has no DOM, it comes from what Angular recorded on the component host instead, the same data as the [Hydration](./components.md#hydration) section. When Angular suspects a browser extension or a third-party script, the box says so. +Hydration errors are raised once, while the app hydrates. The page catches them only if the overlay is already running when hydration finishes. If the app imports the overlay itself after bootstrap, such as after `whenStable()`, the hydration errors of that page load are not in the list. Read them in the browser console instead, or start the overlay before the app bootstraps. See [Capture starts with the overlay](#capture-starts-with-the-overlay). + #### Missing provider (NG0201) For `NullInjectorError` and NG0201, the box shows the token, Angular's dependency path and the source injector. **Explain lookup** walks the lookup of that token from the component that asked for it: each injector Angular asks, in order, whether it provides the token, and why the lookup stops. It reads the tree the [Injectors](./injectors.md) tab shows, so it needs that tab on, and it assumes no `self`, `skipSelf`, `host` or `optional` flag. The `explain-injection` agent tool takes those flags. diff --git a/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts b/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts index 3fd2e731..3384091d 100644 --- a/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts +++ b/packages/devtools/src/__tests__/cd-diagnosis-tool.test.ts @@ -134,6 +134,16 @@ describe('change detection diagnosis data', () => { expect(clean.inputs).toHaveLength(50); expect(clean.inputs![0]).toEqual({ name: 'C0', input: 'x', inPlace: 1, sameContents: 0 }); expect(clean.zone).toEqual([{ name: 'Z', ticks: 1, tasks: ['a', 'b', 'c'] }]); + expect(clean.zoneJs).toBeUndefined(); + expect(sanitizeCdDiagnosis({ zoneJs: false })!.zoneJs).toBe(false); + expect(sanitizeCdDiagnosis({ zoneJs: 'no' })!.zoneJs).toBeUndefined(); + }); + + it('keeps whether the page loads zone.js through an export and an import', () => { + const recording = sanitizeCdRecording(report('p1'), 10)!; + const withZone = { ...recording, diagnosis: { ...recording.diagnosis!, zoneJs: false } }; + const imported = parseCdImport(JSON.stringify({ recording: withZone }), 10); + expect(imported.ok && imported.recording.diagnosis?.zoneJs).toBe(false); }); it('keeps the diagnosis through an export and an import, and names the cause in a trace', () => { @@ -166,6 +176,8 @@ describe('change detection diagnosis data', () => { expect(cdCauseText({ kind: 'tick', component: 'Poller' })).toBe( 'ApplicationRef.tick() in Poller', ); + expect(cdCauseText({ kind: 'signal', signal: '?' })).toMatch(/wrote an unnamed signal$/); + expect(cdCauseText({ kind: 'signal', signal: 'count' })).toMatch(/wrote signal count$/); }); it('suggests OnPush by version, notes classes already OnPush, and flags inputs and zone.js', () => { @@ -245,6 +257,10 @@ describe('diagnose-change-detection tool', () => { ({ pages: { p1: { ...report('p1'), reportedAt: 1, ...page } } }) as unknown as CdState; expect(cdDiagnosisText(state({ supported: false }))).toContain('needs Angular 20 or later'); expect(cdDiagnosisText(state({ diagnosis: undefined }))).toContain('reported no diagnosis'); + const zoneless = { ...diagnosis, zone: undefined, causes: { event: 1 }, zoneJs: false }; + expect(cdDiagnosisText(state({ diagnosis: zoneless }))).toContain( + 'does not load zone.js, so it runs zoneless', + ); expect( cdDiagnosisText(state({ supported: false }), {}, () => ({ version: '19.2.0', diff --git a/packages/devtools/src/__tests__/cd-diagnosis.test.ts b/packages/devtools/src/__tests__/cd-diagnosis.test.ts index 301c22e6..b2953860 100644 --- a/packages/devtools/src/__tests__/cd-diagnosis.test.ts +++ b/packages/devtools/src/__tests__/cd-diagnosis.test.ts @@ -1,6 +1,12 @@ // @vitest-environment jsdom import { afterEach, describe, expect, it, vi } from 'vitest'; -import { callerStack, createCdDiagnosis, findCdScheduler, NOTIFY } from '../cd-diagnosis.ts'; +import { + callerStack, + createCdDiagnosis, + findCdScheduler, + NOTIFY, + templateOwner, +} from '../cd-diagnosis.ts'; import { PROFILER_EVENT as E } from '../cd-recorder.ts'; import type { RawSignalNode } from '../signal-history.ts'; @@ -150,6 +156,47 @@ describe('change detection diagnosis', () => { }); }); + it('names the component, not the @for context, for a listener inside a block', () => { + const t = setup(); + t.diagnosis.start(); + class RepeaterContext {} + const listener = function HttpExample_For_3_Template_button_click_0_listener() {}; + t.scheduler.notify(NOTIFY.Listener); + t.diagnosis.onEvent(E.OutputStart, new RepeaterContext(), listener, null); + const id = t.cycle(); + expect(t.diagnosis.cycle(id).cause).toMatchObject({ + component: 'HttpExample', + listener: 'HttpExample_For_3_Template_button_click_0_listener', + }); + + // Without a compiled listener name the context gives no owner at all. + t.scheduler.notify(NOTIFY.Listener); + t.diagnosis.onEvent(E.OutputStart, new RepeaterContext(), () => {}, null); + const next = t.cycle(); + expect(t.diagnosis.cycle(next).cause?.component).toBeUndefined(); + }); + + it('reads the component from compiled template function names', () => { + expect(templateOwner('App_Template')).toBe('App'); + expect(templateOwner('App_Template_button_click_0_listener')).toBe('App'); + expect(templateOwner('App_Conditional_2_Template_a_click_1_listener')).toBe('App'); + expect(templateOwner('My_Card_ForEmpty_5_Template')).toBe('My_Card'); + expect(templateOwner('List_ng_template_2_Template_li_click_0_listener')).toBe('List'); + expect(templateOwner('_App_Template')).toBe('App'); + expect(templateOwner('onClick')).toBeUndefined(); + }); + + it('says whether the page loads zone.js', async () => { + const zoneless = setup({ global: { Zone: undefined } }); + zoneless.diagnosis.start(); + expect(zoneless.diagnosis.snapshot()?.zoneJs).toBe(false); + zoneless.diagnosis.stop(); + const zoned = setup({ global: { Zone: { current: { get: () => false } } } }); + zoned.diagnosis.start(); + expect(zoned.diagnosis.snapshot()?.zoneJs).toBe(true); + zoned.diagnosis.stop(); + }); + it('names a template listener by its DOM event, target and owner', () => { const t = setup(); t.diagnosis.start(); diff --git a/packages/devtools/src/__tests__/error-explain.test.ts b/packages/devtools/src/__tests__/error-explain.test.ts index 7754f0f8..4c19a613 100644 --- a/packages/devtools/src/__tests__/error-explain.test.ts +++ b/packages/devtools/src/__tests__/error-explain.test.ts @@ -4,6 +4,7 @@ import { elementId } from '../element-id.ts'; import { WRITE_WINDOW_MS, createRecentWrites, + enrichExplain, explainError, formatLikeAngular, membersHolding, @@ -12,6 +13,8 @@ import { parseMissingProvider, templateOf, } from '../error-explain.ts'; +import { serializeNamed } from '../serialize.ts'; +import { createSignalHistory } from '../signal-history.ts'; import { attachErrors, ownerCandidates, type ErrorsDebugNg } from '../errors-collector.ts'; import { HYDRATION_INFO_KEY } from '../hydration.ts'; import type { ErrorsReport } from '../rpc/errors-tools.ts'; @@ -175,6 +178,51 @@ describe('membersHolding', () => { }); describe('recent signal writes', () => { + it('keeps only writes to a signal the binding or a holding field names, when there are any', () => { + const writes = createRecentWrites(); + writes.add('n1', 'count', { epoch: 1, value: '3', at: 1000, source: 'write' }); + writes.add('n2', 'value', { epoch: 1, value: '3', at: 1100, source: 'write' }); + expect(writes.matching(1200, '3', ['count']).map((w) => w.signal)).toEqual(['count']); + expect(writes.matching(1200, '3', ['total']).map((w) => w.signal)).toEqual(['value', 'count']); + expect(writes.matching(1200, '3').map((w) => w.signal)).toEqual(['value', 'count']); + + const explain = enrichExplain( + { kind: 'expression-changed', binding: 'count', previous: '2', current: '3' }, + { at: 1200, writes }, + ); + expect(explain.kind === 'expression-changed' && explain.writes?.map((w) => w.signal)).toEqual([ + 'count', + ]); + }); + + it('matches a Date or an object by the value as written, not its serialized copy', async () => { + const writes = createRecentWrites(); + const history = createSignalHistory( + (value, name) => serializeNamed(name, value, { budget: 1000 }), + () => 1000, + undefined, + { onChange: (id, label, change, raw) => writes.add(id, label, change, raw) }, + ); + const when = new Date(Date.UTC(2026, 9, 13, 12)); + class Trip { + constructor(readonly to: string) {} + } + const deep = { a: { b: { c: { d: { e: { f: 'deep' } } } } } }; + history.onWrite({ debugName: 'departure', kind: 'signal', value: when, version: 1 }); + history.onWrite({ debugName: 'trip', kind: 'signal', value: new Trip('Oslo'), version: 1 }); + history.onWrite({ debugName: 'filters', kind: 'signal', value: deep, version: 1 }); + history.onWrite({ debugName: 'password', kind: 'signal', value: { p: 'hunter2' }, version: 1 }); + await Promise.resolve(); + await Promise.resolve(); + + const signals = (current: string) => writes.matching(1000, current).map((w) => w.signal); + expect(signals(formatLikeAngular(when))).toEqual(['departure']); + expect(signals(formatLikeAngular(new Trip('Oslo')))).toEqual(['trip']); + expect(signals(formatLikeAngular(deep))).toEqual(['filters']); + // A secret-named signal keeps its masked value, so it is never matched. + expect(signals('{"p":"hunter2"}')).toEqual([]); + }); + it('matches writes of the current value in the window before the error, newest first', () => { const writes = createRecentWrites(); writes.add('n1', 'title', { epoch: 1, value: 'Trips (3)', at: 1000, source: 'write' }); diff --git a/packages/devtools/src/__tests__/leaks-collector.test.ts b/packages/devtools/src/__tests__/leaks-collector.test.ts index 7bd34a43..e1310010 100644 --- a/packages/devtools/src/__tests__/leaks-collector.test.ts +++ b/packages/devtools/src/__tests__/leaks-collector.test.ts @@ -406,6 +406,30 @@ describe('attachLeaks: subscriptions', () => { expect(Object.prototype.hasOwnProperty.call(rx.Observable.prototype, 'subscribe')).toBe(true); }); + it('wraps subscribe once when tracking goes on, off and on again while RxJS loads', async () => { + const rx = fakeRxjs(); + let release!: () => void; + const loaded = new Promise((resolve) => (release = resolve)); + const h = harness(() => fakeNg(new Map()), { + loadRxjs: async () => { + await loaded; + return rx.module as never; + }, + }); + const first = h.collector.setTracking(true); + await h.collector.setTracking(false); + const second = h.collector.setTracking(true); + release(); + expect(await first).toMatchObject({ ok: false }); + expect(await second).toMatchObject({ ok: true }); + expect(rx.Observable.prototype.subscribe).not.toBe(rx.original); + + await h.collector.setTracking(false); + expect(rx.Observable.prototype.subscribe).toBe(rx.original); + h.collector.stop(); + expect(rx.Observable.prototype.subscribe).toBe(rx.original); + }); + it('leaves a wrapper someone added after it in place, and goes quiet', async () => { const rx = fakeRxjs(); page(0); @@ -599,6 +623,83 @@ describe('attachLeaks: pushes', () => { }); }); +describe('attachLeaks: development builds', () => { + it('marks only the latest destroyed instance of a class with none left as held by DI debug data', async () => { + const { root, components, cards } = page(3); + const ng = fakeNg(components); + let now = 1000; + let devMode = true; + const h = harness(() => ng, { now: () => now, devMode: () => devMode }); + await h.collector.push(); + // Two cards go, one stays: the class is still on the page, so neither is excused. + cards[0]!.remove(); + await h.collector.push(true); + now += 10; + cards[1]!.remove(); + await h.collector.push(true); + expect(h.reports.at(-1)!.destroyed.filter((d) => d.devHeld)).toEqual([]); + + // The last card goes too: only the latest destroyed card is excused. + now += 10; + cards[2]!.remove(); + await h.collector.push(true); + const held = h.reports + .at(-1)! + .destroyed.filter((d) => d.devHeld) + .map((d) => d.id); + expect(held).toEqual([elementId(cards[2]!)]); + expect(h.reports.at(-1)!.destroyed).toHaveLength(3); + + // A production build excuses nothing. + devMode = false; + await h.collector.push(true); + expect(h.reports.at(-1)!.destroyed.some((d) => d.devHeld)).toBe(false); + expect(root.isConnected).toBe(true); + }); +}); + +describe('attachLeaks: idle pages', () => { + it('keeps its bookkeeping but reads no signal graph and sends no new report while nobody looks', async () => { + let now = 1000; + let active = false; + const { components, cards } = page(2); + let graphReads = 0; + const ng = fakeNg(components, { + ɵgetSignalGraph: () => { + graphReads++; + return { nodes: [{ id: 'e1', kind: 'effect' }] }; + }, + }); + const h = harness(() => ng, { now: () => now, tickMs: () => 3000, active: () => active }); + + // The first report still goes out, so the page is listed, but without the graph. + await h.collector.push(); + expect(h.reports).toHaveLength(1); + expect(graphReads).toBe(0); + + // A component that comes and goes while idle is still seen once someone looks. + cards[1]!.remove(); + h.collector.track(); + await h.collector.push(); + expect(h.reports).toHaveLength(1); + expect(graphReads).toBe(0); + + // A keepalive re-sends the last report as it was. + now += 6000; + await h.collector.push(); + expect(h.reports).toHaveLength(2); + expect(h.reports[1]).toEqual(h.reports[0]); + expect(graphReads).toBe(0); + + active = true; + await h.collector.push(); + expect(graphReads).toBeGreaterThan(0); + const report = h.reports.at(-1)!; + expect(report.support.effects).toBe(true); + expect(report.destroyed.map((d) => d.id)).toContain(elementId(cards[1]!)); + }); +}); + describe('stackClasses', () => { it('reads constructors, methods and compiled template functions, innermost first', () => { const stack = [ diff --git a/packages/devtools/src/__tests__/leaks-tools.test.ts b/packages/devtools/src/__tests__/leaks-tools.test.ts index 2f94a302..da9b2b09 100644 --- a/packages/devtools/src/__tests__/leaks-tools.test.ts +++ b/packages/devtools/src/__tests__/leaks-tools.test.ts @@ -125,6 +125,50 @@ describe('isRetained', () => { expect(isRetained(page, page.destroyed[1]!)).toBe(false); expect(isRetained(page, { ...page.destroyed[0]!, detached: true })).toBe(false); expect(isRetained(page, { ...page.destroyed[0]!, navigations: 1 })).toBe(false); + expect(isRetained(page, { ...page.destroyed[0]!, devHeld: true })).toBe(false); + }); + + it('keeps devHeld through the sanitizer, but never on a detached view', () => { + const base = report().destroyed[0]!; + const sane = toLeaksReport( + report({ + destroyed: [ + { ...base, devHeld: true }, + { ...base, id: 'c11', detached: true, devHeld: true }, + { ...base, id: 'c12', devHeld: 'yes' as never }, + ], + }), + )!; + expect(sane.destroyed.map((item) => item.devHeld)).toEqual([true, undefined, undefined]); + }); + + it('names the instance dev-mode DI debug data may hold apart, and still lists a second one', () => { + const old = Date.now() - RETAINED_AFTER_MS - 5000; + const page = { + ...report({ + destroyed: [ + { id: 'a1', name: 'About', route: '/about', destroyedAt: old, navigations: 4 }, + { + id: 'a2', + name: 'About', + route: '/about', + destroyedAt: old + 1, + navigations: 3, + devHeld: true, + }, + { id: 'h1', name: 'Home', route: '/', destroyedAt: old, navigations: 3, devHeld: true }, + ], + subscriptions: [], + }), + reportedAt: Date.now(), + }; + const text = findLeaksText({ pages: { tab1: page } }); + expect(text).toMatch(/\| `About` \| `a1` \|/); + expect(text).not.toMatch(/\| `About` \| `a2` \|/); + expect(text).not.toMatch(/\| `Home` \|/); + expect(text).toMatch(/Not counted as retained: .*2 classes.*`About`, `Home`/); + expect(text).toMatch(/DI debug data/); + expect(text).not.toMatch(/destroyed recently/); }); }); diff --git a/packages/devtools/src/cd-data.ts b/packages/devtools/src/cd-data.ts index 28687834..06b0aad7 100644 --- a/packages/devtools/src/cd-data.ts +++ b/packages/devtools/src/cd-data.ts @@ -237,9 +237,13 @@ export function sanitizeCdDiagnosis(value: unknown): CdDiagnosis | undefined { components, ...(inputs.length ? { inputs } : {}), ...(zone.length ? { zone } : {}), + ...(typeof value['zoneJs'] === 'boolean' ? { zoneJs: value['zoneJs'] } : {}), }; } +/** What a cause holds for a signal written without a `debugName`. */ +export const UNNAMED_SIGNAL = '?'; + /** One line on what started a cycle, such as `click on button in Cart (add), wrote count`. */ export function cdCauseText(reason: CdCause): string { const parts: string[] = []; @@ -269,8 +273,13 @@ export function cdCauseText(reason: CdCause): string { default: parts.push(`${CD_CAUSE_LABEL[reason.kind]}${where}`); } - if (reason.signal) parts.push(`wrote signal ${reason.signal}`); - else if (reason.via && reason.via !== reason.kind) + if (reason.signal) { + parts.push( + reason.signal === UNNAMED_SIGNAL + ? 'wrote an unnamed signal' + : `wrote signal ${reason.signal}`, + ); + } else if (reason.via && reason.via !== reason.kind) parts.push(`via ${CD_CAUSE_LABEL[reason.via]}`); if (reason.zone && reason.kind !== 'zone') parts.push('run by zone.js'); if (reason.more) parts.push(`${reason.more} more notification${reason.more === 1 ? '' : 's'}`); diff --git a/packages/devtools/src/cd-diagnosis.ts b/packages/devtools/src/cd-diagnosis.ts index d520ea95..a4830586 100644 --- a/packages/devtools/src/cd-diagnosis.ts +++ b/packages/devtools/src/cd-diagnosis.ts @@ -1,3 +1,4 @@ +import { UNNAMED_SIGNAL } from './cd-data.ts'; import { PROFILER_EVENT } from './cd-recorder.ts'; import { listenerName } from './cd-timing.ts'; import type { @@ -174,6 +175,33 @@ const nameOf = (instance: unknown): string => { const cut = (value: string) => value.slice(0, MAX_TEXT); +/** + * The component whose compiled template function `name` is: `HttpExample` for + * `HttpExample_For_3_Template_button_click_0_listener` or `App_Template`. The + * compiler names a view `___Template`, the suffix being a + * control flow block or a lowercase tag such as `ng_template`. + */ +export function templateOwner(name: string): string | undefined { + const match = + /^(.+?)_(?:Template(?:_|$)|(?:For|ForEmpty|Conditional|Case|ProjectionFallback|Defer[A-Za-z]*|[a-z][a-z0-9_]*?)_\d+_)/.exec( + name.replace(/^_+/, ''), + ); + return match ? match[1] : undefined; +} + +/** + * Who a listener belongs to. Angular passes the view's context, which in an + * `@for`, `@if` or `` is a context object (`RepeaterContext`, + * `NgIfContext`), not a component; the listener's compiled name then gives the + * component. Undefined when neither does. + */ +function ownerName(instance: unknown, listener: string): string | undefined { + const ctor = ctorOf(instance); + const def = ctor ? read(() => ('ɵcmp' in ctor ? true : 'ɵdir' in ctor), false) : false; + if (def) return nameOf(instance); + return listener ? templateOwner(listener) : undefined; +} + function isScheduler(value: unknown): value is SchedulerLike { return ( !!value && @@ -415,7 +443,7 @@ export function createCdDiagnosis(options: CdDiagnosisOptions) { const onWrite = (node: RawSignalNode) => { if (!active || depth > 0 || !pending || pending.signal !== undefined) return; - pending.signal = cut(read(() => node.debugName, undefined) || '?'); + pending.signal = cut(read(() => node.debugName, undefined) || UNNAMED_SIGNAL); }; const causeOf = (): CdCause => { @@ -425,8 +453,8 @@ export function createCdDiagnosis(options: CdDiagnosisOptions) { const p = pending; if (p) { const base = NOTIFY_KIND[p.source] ?? 'unknown'; - const owner = p.owner !== undefined ? nameOf(p.owner) : undefined; const listener = p.listener !== undefined ? listenerName(p.listener) : ''; + const owner = p.owner !== undefined ? ownerName(p.owner, listener) : undefined; const timer = !!p.task && TIMER_TASK.test(p.task); const kind: CdCauseKind = p.http ? 'http' @@ -796,6 +824,7 @@ export function createCdDiagnosis(options: CdDiagnosisOptions) { components, ...(inputs.length ? { inputs } : {}), ...(zone.length ? { zone } : {}), + zoneJs: !!zoneApi(), }; }, /** Classes refreshed past the 1000 the diagnosis keeps totals for. */ diff --git a/packages/devtools/src/config.ts b/packages/devtools/src/config.ts index 796e8c12..75be9772 100644 --- a/packages/devtools/src/config.ts +++ b/packages/devtools/src/config.ts @@ -1384,6 +1384,8 @@ export interface CdDiagnosis { inputs?: CdInputStat[]; /** Components that changed only in zone.js ticks, at most 50. */ zone?: CdZoneStat[]; + /** Whether the page loads zone.js (a `Zone` global); missing in recordings made before it was reported. */ + zoneJs?: boolean; } /** What a {@link CdSpan} measures. */ diff --git a/packages/devtools/src/error-explain.ts b/packages/devtools/src/error-explain.ts index 9fc38878..0fa39481 100644 --- a/packages/devtools/src/error-explain.ts +++ b/packages/devtools/src/error-explain.ts @@ -241,7 +241,8 @@ export function membersHolding(component: unknown, current: string): string[] { interface RecentWrite { signal: string; at: number; - value: unknown; + /** The value as Angular prints it in NG0100, taken from the raw value written. */ + text: string; stack?: string[]; } @@ -253,13 +254,18 @@ export function createRecentWrites(max = MAX_RECENT_WRITES) { const writes: RecentWrite[] = []; let heard = false; return { - /** Pass to the signal history as (part of) `onChange`. */ - add(_id: string | undefined, label: string, change: SignalChange) { + /** + * Pass to the signal history as (part of) `onChange`. `raw` is the value as + * written; the serialized `change.value` stands in without it. A signal + * with a secret name keeps its masked value, so it is never printed or matched. + */ + add(_id: string | undefined, label: string, change: SignalChange, raw?: { value: unknown }) { if (change.source !== 'write') return; + const value = raw && !isSecretName(label) ? raw.value : change.value; writes.push({ signal: label, at: change.at, - value: change.value, + text: formatLikeAngular(value), ...(change.stack?.length ? { stack: change.stack } : {}), }); if (writes.length > max) writes.splice(0, writes.length - max); @@ -271,15 +277,18 @@ export function createRecentWrites(max = MAX_RECENT_WRITES) { get known() { return heard; }, - /** Writes whose value prints like `current`, in the window before `at`, newest first. */ - matching(at: number, current: string): ExplainWrite[] { - return writes - .filter( - (write) => - write.at <= at + 50 && - at - write.at <= WRITE_WINDOW_MS && - formatLikeAngular(write.value) === current, - ) + /** + * Writes whose value prints like `current`, in the window before `at`, newest + * first. When some were made to a signal named in `names` (the binding, the + * fields that hold the value), only those are kept: the others merely share the value. + */ + matching(at: number, current: string, names: readonly string[] = []): ExplainWrite[] { + const found = writes.filter( + (write) => + write.at <= at + 50 && at - write.at <= WRITE_WINDOW_MS && write.text === current, + ); + const named = found.filter((write) => names.includes(write.signal)); + return (named.length ? named : found) .reverse() .slice(0, 5) .map(({ signal, at: when, stack }) => ({ signal, at: when, ...(stack ? { stack } : {}) })); @@ -319,7 +328,8 @@ export function enrichExplain( if (context.writes) { out.writesKnown = context.writes.known; if (!out.masked) { - const writes = context.writes.matching(context.at, explain.current); + const names = [...(out.binding ? [out.binding] : []), ...(out.members ?? [])]; + const writes = context.writes.matching(context.at, explain.current, names); if (writes.length) out.writes = writes; } } diff --git a/packages/devtools/src/leaks-collector.ts b/packages/devtools/src/leaks-collector.ts index 99d81cd2..9f37cba1 100644 --- a/packages/devtools/src/leaks-collector.ts +++ b/packages/devtools/src/leaks-collector.ts @@ -97,11 +97,27 @@ export interface LeaksOptions { dirty?: DomDirty | null; /** Navigation events, the page's window by default. */ target?: Pick | null; + /** + * Whether a panel or an agent is looking (`page-lease.ts`). While idle the + * collector keeps its live and destroyed bookkeeping but skips the effect + * count and the report, and only re-sends the last report as a keepalive. + */ + active?: () => boolean; + /** Whether the app is a development build (`ngDevMode`), whose DI debug data holds instances. */ + devMode?: () => boolean; } export interface LeaksCollector { - /** Scans when the page changed, then pushes when the report changed or a keepalive is due. */ + /** + * Scans when the page changed, then pushes when the report changed or a + * keepalive is due. On an idle page (see `active`) only the bookkeeping runs. + */ push(force?: boolean): Promise; + /** + * Notes which components are live or destroyed when the page changed, without + * reading signal graphs or building a report; cheap enough to run on every refresh. + */ + track(): void; /** Turns subscription tracking on or off. */ setTracking(on: boolean): Promise<{ ok: boolean; message: string }>; /** Walks the page now, for tests and forced pushes. */ @@ -233,6 +249,10 @@ export function attachLeaks( ): LeaksCollector { const now = options.now ?? Date.now; const tickMs = options.tickMs ?? (() => 0); + const active = options.active ?? (() => true); + const devMode = + options.devMode ?? + (() => read(() => !!(globalThis as { ngDevMode?: unknown }).ngDevMode, false)); const hasDocument = typeof document !== 'undefined'; const tree = options.tree ?? (() => domTree()); const route = @@ -287,6 +307,8 @@ export function attachLeaks( let nullInjector: { for: unknown; value: unknown } | null = null; let effectsSupported = false; let uniqueEffects = 0; + let effectsDue = false; + let lastPayload: LeaksReport | null = null; const registry = weak.FinalizationRegistry ? new weak.FinalizationRegistry((id) => { @@ -380,7 +402,8 @@ export function attachLeaks( return out; }; - const scan = () => { + /** The cheap part of a scan: which instances are live, destroyed or detached. */ + const trackInstances = () => { const ng = getNg(); checkNavigation(); if (!ng || typeof ng.getComponent !== 'function' || !weak.WeakRef) return; @@ -436,10 +459,24 @@ export function attachLeaks( entry.navigation = navigations; lastDestroyed.set(entry.name, entry.destroyedAt); } - countEffects(ng); + effectsDue = true; pruneTracked(); }; + /** Reads the signal graph again after a walk, only when someone looks at the result. */ + const refreshEffects = () => { + if (!effectsDue) return; + const ng = getNg(); + if (!ng) return; + effectsDue = false; + countEffects(ng); + }; + + const scan = () => { + trackInstances(); + refreshEffects(); + }; + const countEffects = (ng: LeaksDebugNg) => { effectsSupported = typeof ng.ɵgetSignalGraph === 'function'; if (!effectsSupported) return; @@ -618,9 +655,14 @@ export function attachLeaks( } if (tracking === 'on') return { ok: true, message: 'Already tracking subscriptions.' }; if (starting) return starting; - const attempt = (async () => { + // Declared first, so the attempt can tell whether it is still the latest one. + let attempt!: Promise<{ ok: boolean; message: string }>; + attempt = (async () => { const rxjs = await loadRxjs().catch(() => null); - if (!starting || stopped) return { ok: false, message: 'Tracking was turned off.' }; + // A later on/off while RxJS loads replaces `starting`; only the latest attempt may wrap. + if (starting !== attempt || stopped) + return { ok: false, message: 'Tracking was turned off.' }; + if (restoreSubscribe) return { ok: true, message: 'Already tracking subscriptions.' }; const proto = read(() => rxjs?.Observable?.prototype ?? null, null); const restore = proto ? wrapSubscribe(proto) : null; if (!restore) { @@ -717,6 +759,21 @@ export function attachLeaks( ) .slice(0, MAX_LEAK_COMPONENTS); + // In a development build Angular's DI debug data (the injector profiler's records behind + // `ng.ɵgetInjectorProviders`) keeps the last instance of a class alive, so the latest + // destroyed instance of a class with none on the page proves nothing. A second one does. + const devHeld = new Set(); + if (devMode()) { + const latest = new Map(); + for (const entry of destroyed.values()) { + if (entry.detached || liveClasses.has(entry.name) || entry.ref.deref() === undefined) { + continue; + } + const held = latest.get(entry.name); + if (!held || entry.destroyedAt >= held.destroyedAt) latest.set(entry.name, entry); + } + for (const entry of latest.values()) devHeld.add(entry.id); + } const gone: LeakDestroyed[] = [...destroyed.values()] .filter((entry) => entry.ref.deref() !== undefined) .slice(0, MAX_LEAK_DESTROYED) @@ -729,6 +786,7 @@ export function attachLeaks( destroyedAt: entry.destroyedAt, navigations: navigations - entry.navigation, ...(entry.detached ? { detached: true } : {}), + ...(devHeld.has(entry.id) ? { devHeld: true } : {}), ...(subs ? { subscriptions: subs } : {}), }; }); @@ -760,24 +818,36 @@ export function attachLeaks( }; }; - let scanDue = dirty ? dirty.cached(() => scan()) : null; + let scanDue = dirty ? dirty.cached(() => trackInstances()) : null; let queue = Promise.resolve(); + const send = async (payload: LeaksReport) => { + sentAt = now(); + try { + const answer = (await my.rpc.call('push-leaks', payload)) as { known?: boolean } | undefined; + if (answer?.known === false) lastKey = ''; + } catch { + lastKey = ''; + } + }; const pushOnce = async (force: boolean) => { if (left || stopped) return; checkNavigation(); - if (force || !scanDue) scan(); + // The bookkeeping runs either way, so a component that lives only while idle is still seen. + if (force || !scanDue) trackInstances(); else scanDue(); + if (force || active()) { + refreshEffects(); + } else if (lastPayload) { + // Nobody looks: the last report keeps the page from expiring. The first one still goes out. + if (keepaliveDue(sentAt, tickMs(), now())) await send(lastPayload); + return; + } const payload = report(); const key = JSON.stringify({ ...payload, at: 0 }); if (!force && key === lastKey && !keepaliveDue(sentAt, tickMs(), now())) return; lastKey = key; - sentAt = now(); - try { - const answer = (await my.rpc.call('push-leaks', payload)) as { known?: boolean } | undefined; - if (answer?.known === false) lastKey = ''; - } catch { - lastKey = ''; - } + lastPayload = payload; + await send(payload); }; const push = (force = false) => (queue = queue.then(() => pushOnce(force))); @@ -811,6 +881,12 @@ export function attachLeaks( return { push, + track() { + if (left || stopped) return; + checkNavigation(); + if (scanDue) scanDue(); + else trackInstances(); + }, setTracking, scan, report, diff --git a/packages/devtools/src/overlay.ts b/packages/devtools/src/overlay.ts index 7954816b..3c92fbb3 100644 --- a/packages/devtools/src/overlay.ts +++ b/packages/devtools/src/overlay.ts @@ -356,9 +356,9 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) (value, name) => graphValue(name, value), { stacks: signalWatch.stacks, - onChange: (id, label, change) => { + onChange: (id, label, change, raw) => { signalWatch.onChange(id, label, change); - if (on.errors) recentWrites.add(id, label, change); + if (on.errors) recentWrites.add(id, label, change, raw); }, }, ); @@ -458,6 +458,7 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) on.injectors && pushInjectorTree(true), on.components && cd?.push(false, true), forms?.push(true), + leaks?.push(true), ]), }); own(lease.stop); @@ -493,7 +494,9 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) const errors = on.errors ? attachErrors(my, pageId, getNg, { tickMs, writes: recentWrites }) : null; - const leaks = on.components ? attachLeaks(my, pageId, getNg, { tickMs }) : null; + const leaks = on.components + ? attachLeaks(my, pageId, getNg, { tickMs, active: () => lease.active }) + : null; const angularInfo = attachAngularInfo(my, pageId, getNg, { tickMs }); const consoleGlobals = attachConsoleGlobals(my, pageId, { getNg, @@ -680,6 +683,8 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) own(run.cancel); return run; }; + // Leak bookkeeping runs on every refresh so short-lived components are seen; the report is paced. + const pushLeaks = leaks && paced(() => void leaks.push().catch(() => {})); const collectors = [ () => void angularInfo.push(), on.components && paced(() => void pushTree().catch(() => {})), @@ -692,7 +697,12 @@ async function startOverlay(options: OverlayOptions, own: (cleanup: () => void) http && (() => void http.push().catch(() => {})), cd && paced(() => void cd.push().catch(() => {})), errors && (() => void errors.push().catch(() => {})), - leaks && (() => void leaks.push().catch(() => {})), + leaks && + pushLeaks && + (() => { + leaks.track(); + pushLeaks(); + }), ].filter((collect) => typeof collect === 'function'); const pushAll = () => collectors.forEach((run) => run()); pushAll(); diff --git a/packages/devtools/src/rpc/cd-diagnosis-tools.ts b/packages/devtools/src/rpc/cd-diagnosis-tools.ts index 996ee0fa..aa9e12f1 100644 --- a/packages/devtools/src/rpc/cd-diagnosis-tools.ts +++ b/packages/devtools/src/rpc/cd-diagnosis-tools.ts @@ -66,7 +66,9 @@ export function cdDiagnosisText( const zone = diagnosis.zone ?? []; const zoneOnly = diagnosis.causes.zone ?? 0; - if (zone.length) { + if (diagnosis.zoneJs === false && !zone.length && !zoneOnly) { + parts.push('**zone.js**: the page does not load zone.js, so it runs zoneless.'); + } else if (zone.length) { parts.push( `**Components that depend on zone.js**: they changed in ticks zone.js started with no signal write, markForCheck, event listener or input before them (${zoneOnly} such tick(s))\n${zone .slice(0, limit) diff --git a/packages/devtools/src/rpc/leaks-register.ts b/packages/devtools/src/rpc/leaks-register.ts index bd7e94c5..a3a35f7e 100644 --- a/packages/devtools/src/rpc/leaks-register.ts +++ b/packages/devtools/src/rpc/leaks-register.ts @@ -124,7 +124,7 @@ export async function registerLeaks(host: LeaksHost): Promise host.agent.registerTool({ id: 'pangular:find-leaks', description: - 'Leak hints for the running page, in three parts. **Still retained**: component instances that left the page (destroyed) but are still in memory after at least 2 navigations and 10 seconds, with class, instance id, the route when destroyed, age and navigations since; the overlay holds them only through WeakRef and drops them once a FinalizationRegistry sees them collected. Garbage collection timing is up to the browser, so this is a hint to check retainers in the Chrome Memory panel, not proof of a leak. Detached views (kept on purpose, such as by a RouteReuseStrategy) are listed apart. **Open subscriptions after destroy**: RxJS subscriptions a component made that are still open after it went away, grouped by class, instance and call site, only while subscription tracking is on (pangular:track-subscriptions). **Live effects and subscriptions** per component, from the signal graph Angular keeps (20.1+). Names and routes are masked like other live values. Empty when no page is connected.', + "Leak hints for the running page, in three parts. **Still retained**: component instances that left the page (destroyed) but are still in memory after at least 2 navigations and 10 seconds, with class, instance id, the route when destroyed, age and navigations since; the overlay holds them only through WeakRef and drops them once a FinalizationRegistry sees them collected. Garbage collection timing is up to the browser, so this is a hint to check retainers in the Chrome Memory panel, not proof of a leak. In a development build Angular's DI debug data keeps the last instance of each class alive, so the latest destroyed instance of a class with none left on the page is named apart and not counted; a second one that stays is. Detached views (kept on purpose, such as by a RouteReuseStrategy) are listed apart. **Open subscriptions after destroy**: RxJS subscriptions a component made that are still open after it went away, grouped by class, instance and call site, only while subscription tracking is on (pangular:track-subscriptions). **Live effects and subscriptions** per component, from the signal graph Angular keeps (20.1+). Names and routes are masked like other live values. Empty when no page is connected.", inputSchema: { type: 'object', properties: { diff --git a/packages/devtools/src/rpc/leaks-tools.ts b/packages/devtools/src/rpc/leaks-tools.ts index d0ff2c21..d1640aa5 100644 --- a/packages/devtools/src/rpc/leaks-tools.ts +++ b/packages/devtools/src/rpc/leaks-tools.ts @@ -52,6 +52,13 @@ export interface LeakDestroyed { * as a `RouteReuseStrategy` or a portal does on purpose. */ detached?: boolean; + /** + * The latest destroyed instance of a class with none left on the page, in a + * development build: Angular's DI debug data keeps the last instance of each + * class alive, so this one alone is no sign of a leak. Never set on a + * detached view or in a production build. + */ + devHeld?: boolean; /** Subscriptions it made that are still open. */ subscriptions?: number; } @@ -160,6 +167,7 @@ function toDestroyed(value: unknown): LeakDestroyed | null { destroyedAt: num(value['destroyedAt']), navigations: count(value['navigations']), ...(value['detached'] === true ? { detached: true } : {}), + ...(value['devHeld'] === true && value['detached'] !== true ? { devHeld: true } : {}), ...(subscriptions ? { subscriptions } : {}), }; } @@ -237,6 +245,7 @@ export function destroyedAge(page: LeaksPageView, item: LeakDestroyed, now = Dat export function isRetained(page: LeaksPageView, item: LeakDestroyed, now = Date.now()): boolean { return ( !item.detached && + !item.devHeld && item.navigations >= RETAINED_AFTER_NAVIGATIONS && destroyedAge(page, item, now) >= RETAINED_AFTER_MS ); @@ -313,7 +322,10 @@ export function findLeaksText( const destroyed = page.destroyed.filter((item) => match(item.name)); const retained = destroyed.filter((item) => isRetained(page, item, now)); - const recent = destroyed.filter((item) => !item.detached && !isRetained(page, item, now)); + const recent = destroyed.filter( + (item) => !item.detached && !item.devHeld && !isRetained(page, item, now), + ); + const devHeld = destroyed.filter((item) => item.devHeld); const detached = destroyed.filter((item) => item.detached); out.push( `## Still retained\n\n${page.navigations} navigations on this page so far. ${page.totals.collected} destroyed instances were garbage collected since the overlay started. Garbage collection runs when the browser decides, so an instance listed here is not proof of a leak: it is still in memory after at least ${RETAINED_AFTER_NAVIGATIONS} navigations and ${RETAINED_AFTER_MS / 1000} seconds. Take a heap snapshot in the Chrome DevTools Memory panel, search for the class, and read its retainers to see what holds it.`, @@ -337,6 +349,16 @@ export function findLeaksText( .join(', ')}. Navigate a few times and ask again.`, ); } + if (devHeld.length) { + out.push( + `Not counted as retained: the last destroyed instance of ${plural(devHeld.length, 'class', 'classes')} with none left on the page, ${devHeld + .slice(0, 10) + .map((item) => code(item.name)) + .join( + ', ', + )}. In a development build Angular's DI debug data (the records behind \`ng.ɵgetInjectorProviders\`) keeps the last instance of each class alive, so one instance proves nothing. A second destroyed instance of the same class that stays is listed above.`, + ); + } if (detached.length) { out.push( `${plural(detached.length, 'instance is', 'instances are')} off the page but not destroyed (detached views, such as a \`RouteReuseStrategy\` cache): ${detached diff --git a/packages/devtools/src/signal-history.ts b/packages/devtools/src/signal-history.ts index 04a55f71..e05c9028 100644 --- a/packages/devtools/src/signal-history.ts +++ b/packages/devtools/src/signal-history.ts @@ -30,9 +30,15 @@ export interface SignalHistoryOptions { /** * Called with each exact write once it is serialized, and each sampled change * as it is collected. `id` is the graph node id, unknown until a snapshot - * matched the written signal to a node. + * matched the written signal to a node. `raw` holds the written value as + * the app set it (exact writes only), before serialization. */ - onChange?: (id: string | undefined, label: string, change: SignalChange) => void; + onChange?: ( + id: string | undefined, + label: string, + change: SignalChange, + raw?: { value: unknown }, + ) => void; } function append(list: SignalChange[], change: SignalChange) { @@ -72,17 +78,22 @@ export function createSignalHistory( const frames = stack ? appFrames(stack) : []; if (frames.length) change.stack = frames; append(track.changes, change); - notify(nodeOfTrack.get(track.id), track.label, change); + notify(nodeOfTrack.get(track.id), track.label, change, { value: write.value }); } track.pending = []; } dirty.clear(); } - function notify(id: string | undefined, label: string, change: SignalChange) { + function notify( + id: string | undefined, + label: string, + change: SignalChange, + raw?: { value: unknown }, + ) { if (!options.onChange) return; try { - options.onChange(id, label, change); + options.onChange(id, label, change, raw); } catch { // A listener never breaks history. } From c79e5f2e3f79d3bb99c741b5a4dea81e369c35bf Mon Sep 17 00:00:00 2001 From: erKam Date: Tue, 13 Oct 2026 04:25:25 +0000 Subject: [PATCH 4/9] build(extension): rebuild the panel bundle The panel picked up the focus, live region and leaks fixes. --- ...=> browser-agent-rpc-BXhoSh1z-DiWMXIU4.js} | 2 +- .../{index-BNWPqdBD.js => index-CwGBIRVq.js} | 112 +++++++++--------- extension/ui/index.html | 2 +- 3 files changed, 61 insertions(+), 55 deletions(-) rename extension/ui/assets/{browser-agent-rpc-BXhoSh1z-DD97nExW.js => browser-agent-rpc-BXhoSh1z-DiWMXIU4.js} (93%) rename extension/ui/assets/{index-BNWPqdBD.js => index-CwGBIRVq.js} (84%) diff --git a/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DD97nExW.js b/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DiWMXIU4.js similarity index 93% rename from extension/ui/assets/browser-agent-rpc-BXhoSh1z-DD97nExW.js rename to extension/ui/assets/browser-agent-rpc-BXhoSh1z-DiWMXIU4.js index 42015e37..7bf5c618 100644 --- a/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DD97nExW.js +++ b/extension/ui/assets/browser-agent-rpc-BXhoSh1z-DiWMXIU4.js @@ -1 +1 @@ -import{t as e}from"./index-BNWPqdBD.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge}; \ No newline at end of file +import{t as e}from"./index-CwGBIRVq.js";var t=Symbol.for(`devframe:browser-agent-registry`),{tools:n,listeners:r}=globalThis[t]??={tools:new Map,listeners:new Set};function i(){return[...n.values()]}function a(e){return r.add(e),()=>r.delete(e)}var o=`devframe:client-id`,s;function c(t=globalThis.window){try{let n=t?.sessionStorage;if(n){let t=n.getItem(o);return t||(t=e(),n.setItem(o,t)),t}}catch{}return s??=e(),s}function l(e){e.client.register({name:`devframe:agent:invoke-client-tool`,type:`action`,jsonSerializable:!0,handler:async(e,t)=>{let n=i().find(t=>t.id===e);if(!n)throw Error(`[devframe/agent] browser tool "${e}" not found`);return await n.invoke(t)}});let t=!1,n=!1,r=0,o=()=>{t||n||(t=!0,queueMicrotask(async()=>{if(t=!1,n)return;let a=i().map(({invoke:e,...t})=>t);(a.length!==0||r!==0)&&(r=a.length,await e.callOptional(`devframe:agent:sync-client-tools`,c(),a).catch(()=>{}))}))},s=a(o),l=e.events.on(`connection:status`,e=>{e===`connected`&&o()});return o(),()=>{n=!0,s(),l()}}export{l as setupBrowserAgentRpcBridge}; \ No newline at end of file diff --git a/extension/ui/assets/index-BNWPqdBD.js b/extension/ui/assets/index-CwGBIRVq.js similarity index 84% rename from extension/ui/assets/index-BNWPqdBD.js rename to extension/ui/assets/index-CwGBIRVq.js index 09e14240..234fc64f 100644 --- a/extension/ui/assets/index-BNWPqdBD.js +++ b/extension/ui/assets/index-CwGBIRVq.js @@ -5,7 +5,7 @@ `):``,this.name=`UnsubscriptionError`,this.errors=t}});function gr(e,t){if(e){var n=e.indexOf(t);0<=n&&e.splice(n,1)}}var _r=function(){function e(e){this.initialTeardown=e,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var e,t,n,r,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a){if(this._parentage=null,Array.isArray(a))try{for(var o=ur(a),s=o.next();!s.done;s=o.next())s.value.remove(this)}catch(t){e={error:t}}finally{try{s&&!s.done&&(t=o.return)&&t.call(o)}finally{if(e)throw e.error}}else a.remove(this)}var c=this.initialTeardown;if(pr(c))try{c()}catch(e){i=e instanceof hr?e.errors:[e]}var l=this._finalizers;if(l){this._finalizers=null;try{for(var u=ur(l),d=u.next();!d.done;d=u.next()){var f=d.value;try{br(f)}catch(e){i??=[],e instanceof hr?i=fr(fr([],dr(i)),dr(e.errors)):i.push(e)}}}catch(e){n={error:e}}finally{try{d&&!d.done&&(r=u.return)&&r.call(u)}finally{if(n)throw n.error}}}if(i)throw new hr(i)}},e.prototype.add=function(t){if(t&&t!==this){if(this.closed)br(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=this._finalizers??[]).push(t)}}},e.prototype._hasParent=function(e){var t=this._parentage;return t===e||Array.isArray(t)&&t.includes(e)},e.prototype._addParent=function(e){var t=this._parentage;this._parentage=Array.isArray(t)?(t.push(e),t):t?[t,e]:e},e.prototype._removeParent=function(e){var t=this._parentage;t===e?this._parentage=null:Array.isArray(t)&&gr(t,e)},e.prototype.remove=function(t){var n=this._finalizers;n&&gr(n,t),t instanceof e&&t._removeParent(this)},e.EMPTY=(function(){var t=new e;return t.closed=!0,t})(),e}(),vr=_r.EMPTY;function yr(e){return e instanceof _r||e&&`closed`in e&&pr(e.remove)&&pr(e.add)&&pr(e.unsubscribe)}function br(e){pr(e)?e():e.unsubscribe()}var xr={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1},Sr={setTimeout:function(e,t){var n=[...arguments].slice(2),r=Sr.delegate;return r?.setTimeout?r.setTimeout.apply(r,fr([e,t],dr(n))):setTimeout.apply(void 0,fr([e,t],dr(n)))},clearTimeout:function(e){return(Sr.delegate?.clearTimeout||clearTimeout)(e)},delegate:void 0};function Cr(e){Sr.setTimeout(function(){var t=xr.onUnhandledError;if(t)t(e);else throw e})}function wr(){}var Tr=(function(){return Or(`C`,void 0,void 0)})();function Er(e){return Or(`E`,void 0,e)}function Dr(e){return Or(`N`,e,void 0)}function Or(e,t,n){return{kind:e,value:t,error:n}}var kr=null;function Ar(e){if(xr.useDeprecatedSynchronousErrorHandling){var t=!kr;if(t&&(kr={errorThrown:!1,error:null}),e(),t){var n=kr,r=n.errorThrown,i=n.error;if(kr=null,r)throw i}}else e()}function jr(e){xr.useDeprecatedSynchronousErrorHandling&&kr&&(kr.errorThrown=!0,kr.error=e)}var Mr=function(e){lr(t,e);function t(t){var n=e.call(this)||this;return n.isStopped=!1,t?(n.destination=t,yr(t)&&t.add(n)):n.destination=Br,n}return t.create=function(e,t,n){return new Ir(e,t,n)},t.prototype.next=function(e){this.isStopped?zr(Dr(e),this):this._next(e)},t.prototype.error=function(e){this.isStopped?zr(Er(e),this):(this.isStopped=!0,this._error(e))},t.prototype.complete=function(){this.isStopped?zr(Tr,this):(this.isStopped=!0,this._complete())},t.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,e.prototype.unsubscribe.call(this),this.destination=null)},t.prototype._next=function(e){this.destination.next(e)},t.prototype._error=function(e){try{this.destination.error(e)}finally{this.unsubscribe()}},t.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},t}(_r),Nr=Function.prototype.bind;function Pr(e,t){return Nr.call(e,t)}var Fr=function(){function e(e){this.partialObserver=e}return e.prototype.next=function(e){var t=this.partialObserver;if(t.next)try{t.next(e)}catch(e){Lr(e)}},e.prototype.error=function(e){var t=this.partialObserver;if(t.error)try{t.error(e)}catch(e){Lr(e)}else Lr(e)},e.prototype.complete=function(){var e=this.partialObserver;if(e.complete)try{e.complete()}catch(e){Lr(e)}},e}(),Ir=function(e){lr(t,e);function t(t,n,r){var i=e.call(this)||this,a;if(pr(t)||!t)a={next:t??void 0,error:n??void 0,complete:r??void 0};else{var o;i&&xr.useDeprecatedNextContext?(o=Object.create(t),o.unsubscribe=function(){return i.unsubscribe()},a={next:t.next&&Pr(t.next,o),error:t.error&&Pr(t.error,o),complete:t.complete&&Pr(t.complete,o)}):a=t}return i.destination=new Fr(a),i}return t}(Mr);function Lr(e){xr.useDeprecatedSynchronousErrorHandling?jr(e):Cr(e)}function Rr(e){throw e}function zr(e,t){var n=xr.onStoppedNotification;n&&Sr.setTimeout(function(){return n(e,t)})}var Br={closed:!0,next:wr,error:Rr,complete:wr},Vr=(function(){return typeof Symbol==`function`&&Symbol.observable||`@@observable`})();function Hr(e){return e}function Ur(e){return e.length===0?Hr:e.length===1?e[0]:function(t){return e.reduce(function(e,t){return t(e)},t)}}var Wr=function(){function e(e){e&&(this._subscribe=e)}return e.prototype.lift=function(t){var n=new e;return n.source=this,n.operator=t,n},e.prototype.subscribe=function(e,t,n){var r=this,i=qr(e)?e:new Ir(e,t,n);return Ar(function(){var e=r,t=e.operator,n=e.source;i.add(t?t.call(i,n):n?r._subscribe(i):r._trySubscribe(i))}),i},e.prototype._trySubscribe=function(e){try{return this._subscribe(e)}catch(t){e.error(t)}},e.prototype.forEach=function(e,t){var n=this;return t=Gr(t),new t(function(t,r){var i=new Ir({next:function(t){try{e(t)}catch(e){r(e),i.unsubscribe()}},error:r,complete:t});n.subscribe(i)})},e.prototype._subscribe=function(e){return this.source?.subscribe(e)},e.prototype[Vr]=function(){return this},e.prototype.pipe=function(){return Ur([...arguments])(this)},e.prototype.toPromise=function(e){var t=this;return e=Gr(e),new e(function(e,n){var r;t.subscribe(function(e){return r=e},function(e){return n(e)},function(){return e(r)})})},e.create=function(t){return new e(t)},e}();function Gr(e){return e??xr.Promise??Promise}function Kr(e){return e&&pr(e.next)&&pr(e.error)&&pr(e.complete)}function qr(e){return e&&e instanceof Mr||Kr(e)&&yr(e)}function Jr(e){return pr(e?.lift)}function Yr(e){return function(t){if(Jr(t))return t.lift(function(t){try{return e(t,this)}catch(e){this.error(e)}});throw TypeError(`Unable to lift unknown Observable type`)}}function Xr(e,t,n,r,i){return new Zr(e,t,n,r,i)}var Zr=function(e){lr(t,e);function t(t,n,r,i,a,o){var s=e.call(this,t)||this;return s.onFinalize=a,s.shouldUnsubscribe=o,s._next=n?function(e){try{n(e)}catch(e){t.error(e)}}:e.prototype._next,s._error=i?function(e){try{i(e)}catch(e){t.error(e)}finally{this.unsubscribe()}}:e.prototype._error,s._complete=r?function(){try{r()}catch(e){t.error(e)}finally{this.unsubscribe()}}:e.prototype._complete,s}return t.prototype.unsubscribe=function(){var t;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){var n=this.closed;e.prototype.unsubscribe.call(this),!n&&((t=this.onFinalize)==null||t.call(this))}},t}(Mr),Qr=mr(function(e){return function(){e(this),this.name=`ObjectUnsubscribedError`,this.message=`object unsubscribed`}}),$r=function(e){lr(t,e);function t(){var t=e.call(this)||this;return t.closed=!1,t.currentObservers=null,t.observers=[],t.isStopped=!1,t.hasError=!1,t.thrownError=null,t}return t.prototype.lift=function(e){var t=new ei(this,this);return t.operator=e,t},t.prototype._throwIfClosed=function(){if(this.closed)throw new Qr},t.prototype.next=function(e){var t=this;Ar(function(){var n,r;if(t._throwIfClosed(),!t.isStopped){t.currentObservers||=Array.from(t.observers);try{for(var i=ur(t.currentObservers),a=i.next();!a.done;a=i.next())a.value.next(e)}catch(e){n={error:e}}finally{try{a&&!a.done&&(r=i.return)&&r.call(i)}finally{if(n)throw n.error}}}})},t.prototype.error=function(e){var t=this;Ar(function(){if(t._throwIfClosed(),!t.isStopped){t.hasError=t.isStopped=!0,t.thrownError=e;for(var n=t.observers;n.length;)n.shift().error(e)}})},t.prototype.complete=function(){var e=this;Ar(function(){if(e._throwIfClosed(),!e.isStopped){e.isStopped=!0;for(var t=e.observers;t.length;)t.shift().complete()}})},t.prototype.unsubscribe=function(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null},Object.defineProperty(t.prototype,"observed",{get:function(){return this.observers?.length>0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(t){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,t)},t.prototype._subscribe=function(e){return this._throwIfClosed(),this._checkFinalizedStatuses(e),this._innerSubscribe(e)},t.prototype._innerSubscribe=function(e){var t=this,n=this,r=n.hasError,i=n.isStopped,a=n.observers;return r||i?vr:(this.currentObservers=null,a.push(e),new _r(function(){t.currentObservers=null,gr(a,e)}))},t.prototype._checkFinalizedStatuses=function(e){var t=this,n=t.hasError,r=t.thrownError,i=t.isStopped;n?e.error(r):i&&e.complete()},t.prototype.asObservable=function(){var e=new Wr;return e.source=this,e},t.create=function(e,t){return new ei(e,t)},t}(Wr),ei=function(e){lr(t,e);function t(t,n){var r=e.call(this)||this;return r.destination=t,r.source=n,r}return t.prototype.next=function(e){var t,n;(n=(t=this.destination)?.next)==null||n.call(t,e)},t.prototype.error=function(e){var t,n;(n=(t=this.destination)?.error)==null||n.call(t,e)},t.prototype.complete=function(){var e,t;(t=(e=this.destination)?.complete)==null||t.call(e)},t.prototype._subscribe=function(e){return this.source?.subscribe(e)??vr},t}($r),ti=function(e){lr(t,e);function t(t){var n=e.call(this)||this;return n._value=t,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(t){var n=e.prototype._subscribe.call(this,t);return!n.closed&&t.next(this._value),n},t.prototype.getValue=function(){var e=this,t=e.hasError,n=e.thrownError,r=e._value;if(t)throw n;return this._throwIfClosed(),r},t.prototype.next=function(t){e.prototype.next.call(this,this._value=t)},t}($r);function ni(e,t){return Yr(function(n,r){var i=0;n.subscribe(Xr(r,function(n){r.next(e.call(t,n,i++))}))})}var ri=`https://angular.dev/best-practices/security#preventing-cross-site-scripting-xss`,ii=class extends Error{code;constructor(e,t){super(oi(e,t)),this.code=e}};function ai(e){return`NG0${Math.abs(e)}`}function oi(e,t){return`${ai(e)}${t?`: `+t:``}`}function si(e){for(let t in e)if(e[t]===si)return t;throw Error(``)}function ci(e){if(typeof e==`string`)return e;if(Array.isArray(e))return`[${e.map(ci).join(`, `)}]`;if(e==null)return``+e;let t=e.overriddenName||e.name;if(t)return`${t}`;let n=e.toString();if(n==null)return``+n;let r=n.indexOf(` `);return r>=0?n.slice(0,r):n}function li(e,t){return e?t?`${e} ${t}`:e:t||``}var ui=si({__forward_ref__:si});function di(e){return e.__forward_ref__=di,e}function fi(e){return pi(e)?e():e}function pi(e){return typeof e==`function`&&Object.hasOwn(e,ui)&&e.__forward_ref__===di}function mi(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function hi(e){return gi(e,yi)}function gi(e,t){return Object.hasOwn(e,t)&&e[t]||null}function _i(e){return(e?.[yi]??null)||null}function vi(e){return e&&Object.hasOwn(e,bi)?e[bi]:null}var yi=si({ɵprov:si}),bi=si({ɵinj:si}),xi=class{_desc;ngMetadataName=`InjectionToken`;ɵprov;constructor(e,t){this._desc=e,this.ɵprov=void 0,typeof t==`number`?this.__NG_ELEMENT_ID__=t:t!==void 0&&(this.ɵprov=mi({token:this,providedIn:t.providedIn||`root`,factory:t.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}};function Si(e){return e&&!!e.ɵproviders}var Ci=si({ɵcmp:si}),wi=si({ɵdir:si}),Ti=si({ɵpipe:si}),Ei=si({ɵfac:si}),Di=si({__NG_ELEMENT_ID__:si}),Oi=si({__NG_ENV_ID__:si});function ki(e){return Mi(e,`@Component`),e[Ci]||null}function Ai(e){return Mi(e,`@Directive`),e[wi]||null}function ji(e){return Mi(e,`@Pipe`),e[Ti]||null}function Mi(e,t){if(e==null)throw new ii(-919,!1)}function Ni(e){return typeof e==`string`?e:e==null?``:String(e)}var Pi=si({ngErrorCode:si}),Fi=si({ngErrorMessage:si}),Ii=si({ngTokenPath:si});function Li(e,t){return zi(``,-200,t)}function Ri(e,t){throw new ii(-201,!1)}function zi(e,t,n){let r=new ii(t,e);return r[Pi]=t,r[Fi]=e,n&&(r[Ii]=n),r}function Bi(e){return e[Pi]}var Vi;function Hi(){return Vi}function Ui(e){let t=Vi;return Vi=e,t}function Wi(e,t,n){let r=hi(e);if(r&&r.providedIn==`root`)return r.value===void 0?r.value=r.factory():r.value;if(n&8)return null;if(t!==void 0)return t;Ri(e,``)}var Gi=globalThis,Ki={},qi=`__NG_DI_FLAG__`,Ji=class{injector;constructor(e){this.injector=e}retrieve(e,t){let n=Zi(t)||0;try{return this.injector.get(e,n&8?null:Ki,n)}catch(e){if(nr(e))return e;throw e}}};function Yi(e,t=0){let n=$n();if(n===void 0)throw new ii(-203,!1);if(n===null)return Wi(e,void 0,t);{let r=Qi(t),i=n.retrieve(e,r);if(nr(i)){if(r.optional)return null;throw i}return i}}function Xi(e,t=0){return(Hi()||Yi)(fi(e),t)}function C(e,t){return Xi(e,Zi(t))}function Zi(e){return e===void 0||typeof e==`number`?e:0|(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function Qi(e){return{optional:!!(e&8),host:!!(e&1),self:!!(e&2),skipSelf:!!(e&4)}}function $i(e){let t=[];for(let n=0;nArray.isArray(e)?ia(e,t):t(e))}function aa(e,t,n){t>=e.length?e.push(n):e.splice(t,0,n)}function oa(e,t){return t>=e.length-1?e.pop():e.splice(t,1)[0]}function sa(e,t){let n=[];for(let r=0;rt;){let t=i-2;e[i]=e[t],i--}e[t]=n,e[t+1]=r}}function la(e,t,n){let r=da(e,t);return r>=0?e[r|1]=n:(r=~r,ca(e,r,t,n)),r}function ua(e,t){let n=da(e,t);if(n>=0)return e[n|1]}function da(e,t){return fa(e,t,1)}function fa(e,t,n){let r=0,i=e.length>>n;for(;i!==r;){let a=r+(i-r>>1),o=e[a<t?i=a:r=a+1}return~(i<{n.push(e)};return ia(t,e=>{let t=e;Sa(t,a,[],r)&&(i||=[],i.push(t))}),i!==void 0&&xa(i,a),n}function xa(e,t){for(let n=0;n{t(e,r)})}}function Sa(e,t,n,r){if(e=fi(e),!e)return!1;let i=null,a=vi(e),o=!a&&ki(e);if(!a&&!o){let t=e.ngModule;if(a=vi(t),a)i=t;else return!1}else if(o&&!o.standalone)return!1;else i=e;let s=r.has(i);if(o){if(s)return!1;if(r.add(i),o.dependencies){let e=typeof o.dependencies==`function`?o.dependencies():o.dependencies;for(let i of e)Sa(i,t,n,r)}}else if(a){if(a.imports!=null&&!s){r.add(i);let e;try{ia(a.imports,i=>{Sa(i,t,n,r)&&(e||=[],e.push(i))})}finally{}e!==void 0&&xa(e,t)}if(!s){let e=ta(i)||(()=>new i);t({provide:i,useFactory:e,deps:ma},i),t({provide:_a,useValue:i,multi:!0},i),t({provide:ha,useValue:()=>Xi(i),multi:!0},i)}let o=a.providers;if(o!=null&&!s){let n=e;Ca(o,e=>{t(e,n)})}}else return!1;return i!==e&&e.providers!==void 0}function Ca(e,t){for(let n of e)Si(n)&&(n=n.ɵproviders),Array.isArray(n)?Ca(n,t):t(n)}var wa=si({provide:String,useValue:si});function Ta(e){return typeof e==`object`&&!!e&&wa in e}function Ea(e){return!!(e&&e.useExisting)}function Da(e){return!!(e&&e.useFactory)}function Oa(e){return typeof e==`function`}var ka=new xi(``),Aa={},ja={},Ma=void 0;function Na(){return Ma===void 0&&(Ma=new va),Ma}var Pa=class{},Fa=class extends Pa{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(e,t,n,r){super(),this.parent=t,this.source=n,this.scopes=r,Ga(e,e=>this.processProvider(e)),this.records.set(ga,Va(void 0,this)),r.has(`environment`)&&this.records.set(Pa,Va(void 0,this));let i=this.records.get(ka);i!=null&&typeof i.value==`string`&&this.scopes.add(i.value),this.injectorDefTypes=new Set(this.get(_a,ma,{self:!0}))}retrieve(e,t){let n=Zi(t)||0;try{return this.get(e,Ki,n)}catch(e){if(nr(e))return e;throw e}}destroy(){Ba(this),this._destroyed=!0;let e=pn(null);try{for(let e of this._ngOnDestroyHooks)e.ngOnDestroy();let e=this._onDestroyHooks;this._onDestroyHooks=[];for(let t of e)t()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),pn(e)}}onDestroy(e){return Ba(this),this._onDestroyHooks.push(e),()=>this.removeOnDestroy(e)}runInContext(e){Ba(this);let t=er(this),n=Ui(void 0);try{return e()}finally{er(t),Ui(n)}}get(e,t=Ki,n){if(Ba(this),Object.hasOwn(e,Oi))return e[Oi](this);let r=Zi(n),i=er(this),a=Ui(void 0);try{if(!(r&4)){let t=this.records.get(e);if(t===void 0){let n=Wa(e)&&hi(e);t=n&&this.injectableDefInScope(n)?Va(Ia(e),Aa):null,this.records.set(e,t)}if(t!=null)return this.hydrate(e,t,r)}let n=r&2?Na():this.parent;return t=r&8&&t===Ki?null:t,n.get(e,t)}catch(e){let t=Bi(e);throw t===-200||t===-201?new ii(t,null):e}finally{Ui(a),er(i)}}resolveInjectorInitializers(){let e=pn(null),t=er(this),n=Ui(void 0);try{let e=this.get(ha,ma,{self:!0});for(let t of e)t()}finally{er(t),Ui(n),pn(e)}}toString(){return`R3Injector[...]`}processProvider(e){e=fi(e);let t=Oa(e)?e:fi(e&&e.provide),n=Ra(e);if(!Oa(e)&&e.multi===!0){let n=this.records.get(t);n||(n=Va(void 0,Aa,!0),n.factory=()=>$i(n.multi),this.records.set(t,n)),t=e,n.multi.push(e)}this.records.set(t,n)}hydrate(e,t,n){let r=pn(null);try{if(t.value===ja)throw Li(``);return t.value===Aa&&(t.value=ja,t.value=t.factory(void 0,n)),typeof t.value==`object`&&t.value&&Ua(t.value)&&this._ngOnDestroyHooks.add(t.value),t.value}finally{pn(r)}}injectableDefInScope(e){if(!e.providedIn)return!1;let t=fi(e.providedIn);return typeof t==`string`?t===`any`||this.scopes.has(t):this.injectorDefTypes.has(t)}removeOnDestroy(e){let t=this._onDestroyHooks.indexOf(e);t!==-1&&this._onDestroyHooks.splice(t,1)}};function Ia(e){let t=hi(e),n=t===null?ta(e):t.factory;if(n!==null)return n;if(e instanceof xi)throw new ii(-204,!1);if(e instanceof Function)return La(e);throw new ii(-204,!1)}function La(e){if(e.length>0)throw new ii(-204,!1);let t=_i(e);return t===null?()=>new e:()=>t.factory(e)}function Ra(e){return Ta(e)?Va(void 0,e.useValue):Va(za(e),Aa)}function za(e,t,n){let r;if(Oa(e)){let t=fi(e);return ta(t)||Ia(t)}if(Ta(e))r=()=>fi(e.useValue);else if(Da(e))r=()=>e.useFactory(...$i(e.deps||[]));else if(Ea(e))r=(t,n)=>Xi(fi(e.useExisting),n!==void 0&&n&8?8:void 0);else{let t=fi(e&&(e.useClass||e.provide));if(Ha(e))r=()=>new t(...$i(e.deps));else return ta(t)||Ia(t)}return r}function Ba(e){if(e.destroyed)throw new ii(-205,!1)}function Va(e,t,n=!1){return{factory:e,value:t,multi:n?[]:void 0}}function Ha(e){return!!e.deps}function Ua(e){return typeof e==`object`&&!!e&&typeof e.ngOnDestroy==`function`}function Wa(e){return typeof e==`function`||typeof e==`object`&&e.ngMetadataName===`InjectionToken`}function Ga(e,t){for(let n of e)Array.isArray(n)?Ga(n,t):n&&Si(n)?Ga(n.ɵproviders,t):t(n)}function Ka(e,t){let n;e instanceof Fa?(Ba(e),n=e):n=new Ji(e);let r=er(n),i=Ui(void 0);try{return t()}finally{er(r),Ui(i)}}function qa(){return Hi()!==void 0||$n()!=null}var Ja=1;function Ya(e){return Array.isArray(e)&&typeof e[Ja]==`object`}function Xa(e){return Array.isArray(e)&&e[Ja]===!0}function Za(e){return!!(e.flags&4)}function Qa(e){return e.componentOffset>-1}function $a(e){return(e.flags&1)==1}function eo(e){return!!e.template}function to(e){return!!(e[2]&512)}function no(e){return(e[2]&256)==256}var ro=(function(e){return e[e.NONE=0]=`NONE`,e[e.HTML=1]=`HTML`,e[e.STYLE=2]=`STYLE`,e[e.SCRIPT=3]=`SCRIPT`,e[e.URL=4]=`URL`,e[e.RESOURCE_URL=5]=`RESOURCE_URL`,e[e.ATTRIBUTE_NO_BINDING=6]=`ATTRIBUTE_NO_BINDING`,e})(ro||{}),io=`math`;function ao(e){for(;Array.isArray(e);)e=e[0];return e}function oo(e,t){return ao(t[e])}function so(e,t){return ao(t[e.index])}function co(e,t){return e.data[t]}function lo(e,t){return e[t]}function uo(e,t,n,r){n>=e.data.length&&(e.data[n]=null,e.blueprint[n]=null),t[n]=r}function fo(e,t){let n=t[e];return Ya(n)?n:n[0]}function po(e){return(e[2]&128)==128}function mo(e){return Xa(e[3])}function ho(e,t){return t==null?null:e[t]}function go(e){e[17]=0}function _o(e){e[2]&1024||(e[2]|=1024,po(e)&&xo(e))}function vo(e,t){for(;e>0;)t=t[14],e--;return t}function yo(e){return!!(e[2]&9216||e[24]?.dirty)}function bo(e){e[10].changeDetectionScheduler?.notify(8),e[2]&64&&(e[2]|=1024),yo(e)&&xo(e)}function xo(e){e[10].changeDetectionScheduler?.notify(0);let t=wo(e);for(;t!==null&&!(t[2]&8192||(t[2]|=8192,!po(t)));)t=wo(t)}function So(e,t){if(no(e))throw new ii(911,!1);e[21]===null&&(e[21]=[]),e[21].push(t)}function Co(e,t){if(e[21]===null)return;let n=e[21].indexOf(t);n!==-1&&e[21].splice(n,1)}function wo(e){let t=e[3];return Xa(t)?t[3]:t}function To(e){return e[7]??=[]}function Eo(e){return e.cleanup??=[]}function Do(e,t,n,r){let i=To(t);i.push(n),e.firstCreatePass&&Eo(e).push(r,i.length-1)}var Oo={lFrame:ls(null),bindingsEnabled:!0,skipHydrationRootTNode:null},ko=!1;function Ao(){return Oo.lFrame.elementDepthCount}function jo(){Oo.lFrame.elementDepthCount++}function Mo(){Oo.lFrame.elementDepthCount--}function No(){return Oo.bindingsEnabled}function Po(){return Oo.skipHydrationRootTNode!==null}function Fo(e){return Oo.skipHydrationRootTNode===e}function Io(){Oo.skipHydrationRootTNode=null}function w(){return Oo.lFrame.lView}function Lo(){return Oo.lFrame.tView}function T(e){return Oo.lFrame.contextLView=e,e[8]}function E(e){return Oo.lFrame.contextLView=null,e}function Ro(){let e=zo();for(;e!==null&&e.type===64;)e=e.parent;return e}function zo(){return Oo.lFrame.currentTNode}function Bo(){let e=Oo.lFrame,t=e.currentTNode;return e.isParent?t:t.parent}function Vo(e,t){let n=Oo.lFrame;n.currentTNode=e,n.isParent=t}function Ho(){return Oo.lFrame.isParent}function Uo(){Oo.lFrame.isParent=!1}function Wo(){return Oo.lFrame.contextLView}function Go(){return ko}function Ko(e){let t=ko;return ko=e,t}function qo(){let e=Oo.lFrame,t=e.bindingRootIndex;return t===-1&&(t=e.bindingRootIndex=e.tView.bindingStartIndex),t}function Jo(){return Oo.lFrame.bindingIndex}function Yo(e){return Oo.lFrame.bindingIndex=e}function Xo(){return Oo.lFrame.bindingIndex++}function Zo(e){let t=Oo.lFrame,n=t.bindingIndex;return t.bindingIndex+=e,n}function Qo(){return Oo.lFrame.inI18n}function $o(e,t){let n=Oo.lFrame;n.bindingIndex=n.bindingRootIndex=e,ts(t)}function es(){return Oo.lFrame.currentDirectiveIndex}function ts(e){Oo.lFrame.currentDirectiveIndex=e}function ns(e){let t=Oo.lFrame.currentDirectiveIndex;return t===-1?null:e[t]}function rs(){return Oo.lFrame.currentQueryIndex}function is(e){Oo.lFrame.currentQueryIndex=e}function as(e){let t=e[1];return t.type===2?t.declTNode:t.type===1?e[5]:null}function os(e,t,n){if(n&4){let r=t,i=e;for(;r=r.parent,r===null&&!(n&1)&&(r=as(i),!(r===null||(i=i[14],r.type&10))););if(r===null)return!1;t=r,e=i}let r=Oo.lFrame=cs();return r.currentTNode=t,r.lView=e,!0}function ss(e){let t=cs(),n=e[1];Oo.lFrame=t,t.currentTNode=n.firstChild,t.lView=e,t.tView=n,t.contextLView=e,t.bindingIndex=n.bindingStartIndex,t.inI18n=!1}function cs(){let e=Oo.lFrame,t=e===null?null:e.child;return t===null?ls(e):t}function ls(e){let t={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return e!==null&&(e.child=t),t}function us(){let e=Oo.lFrame;return Oo.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}var ds=us;function fs(){let e=us();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function ps(e){return(Oo.lFrame.contextLView=vo(e,Oo.lFrame.contextLView))[8]}function ms(){return Oo.lFrame.selectedIndex}function hs(e){Oo.lFrame.selectedIndex=e}function gs(){let e=Oo.lFrame;return co(e.tView,e.selectedIndex)}function D(){Oo.lFrame.currentNamespace=`svg`}function _s(){vs()}function vs(){Oo.lFrame.currentNamespace=null}function ys(){return Oo.lFrame.currentNamespace}var bs=!0;function xs(){return bs}function Ss(e){bs=e}function Cs(e,t=null,n=null,r){let i=ws(e,t,n,r);return i.resolveInjectorInitializers(),i}function ws(e,t=null,n=null,r,i=new Set){return new Fa([n||ma,ya(e)],t||Na(),null,i)}var Ts=class e{static THROW_IF_NOT_FOUND=Ki;static NULL=new va;static create(e,t){if(Array.isArray(e))return Cs({name:``},t,e,``);{let t=e.name??``;return Cs({name:t},e.parent,e.providers,t)}}static ɵprov=mi({token:e,providedIn:`any`,factory:()=>Xi(ga)});static __NG_ELEMENT_ID__=-1},Es=new xi(``),Ds=class{static __NG_ELEMENT_ID__=ks;static __NG_ENV_ID__=e=>e},Os=class extends Ds{_lView;constructor(e){super(),this._lView=e}get destroyed(){return no(this._lView)}onDestroy(e){let t=this._lView;return So(t,e),()=>Co(t,e)}};function ks(){return new Os(w())}var As=new xi(``),js=(()=>{class e{taskId=0;pendingTasks=new Set;destroyed=!1;pendingTask=new ti(!1);debugTaskTracker=C(As,{optional:!0});get hasPendingTasks(){return!this.destroyed&&this.pendingTask.value}get hasPendingTasksObservable(){return this.destroyed?new Wr(e=>{e.next(!1),e.complete()}):this.pendingTask}add(){!this.hasPendingTasks&&!this.destroyed&&this.pendingTask.next(!0);let e=this.taskId++;return this.pendingTasks.add(e),this.debugTaskTracker?.add(e),e}has(e){return this.pendingTasks.has(e)}remove(e){this.pendingTasks.delete(e),this.debugTaskTracker?.remove(e),this.pendingTasks.size===0&&this.hasPendingTasks&&this.pendingTask.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this.hasPendingTasks&&this.pendingTask.next(!1),this.destroyed=!0,this.pendingTask.unsubscribe()}static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Ms=class extends $r{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(e=!1){super(),this.__isAsync=e,qa()&&(this.destroyRef=C(Ds,{optional:!0})??void 0,this.pendingTasks=C(js,{optional:!0})??void 0)}emit(e){let t=pn(null);try{super.next(e)}finally{pn(t)}}subscribe(e,t,n){let r=e,i=t||(()=>null),a=n;if(e&&typeof e==`object`){let t=e;r=t.next?.bind(t),i=t.error?.bind(t),a=t.complete?.bind(t)}this.__isAsync&&(i=this.wrapInTimeout(i),r&&=this.wrapInTimeout(r),a&&=this.wrapInTimeout(a));let o=super.subscribe({next:r,error:i,complete:a});return e instanceof _r&&e.add(o),o}wrapInTimeout(e){return t=>{let n=this.pendingTasks?.add();setTimeout(()=>{try{e(t)}finally{n!==void 0&&this.pendingTasks?.remove(n)}})}}};function Ns(...e){}function Ps(e){let t,n;function r(){e=Ns;try{n!==void 0&&typeof cancelAnimationFrame==`function`&&cancelAnimationFrame(n),t!==void 0&&clearTimeout(t)}catch{}}return t=setTimeout(()=>{e(),r()}),typeof requestAnimationFrame==`function`&&(n=requestAnimationFrame(()=>{e(),r()})),()=>r()}function Fs(e){return queueMicrotask(()=>e()),()=>{e=Ns}}var Is=`isAngularZone`,Ls=`isAngularZone_ID`,Rs=0,zs=class e{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new Ms(!1);onMicrotaskEmpty=new Ms(!1);onStable=new Ms(!1);onError=new Ms(!1);constructor(e){let{enableLongStackTrace:t=!1,shouldCoalesceEventChangeDetection:n=!1,shouldCoalesceRunChangeDetection:r=!1,scheduleInRootZone:i=!1}=e;if(typeof Zone>`u`)throw new ii(908,!1);Zone.assertZonePatched();let a=this;a._nesting=0,a._outer=a._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(a._inner=a._inner.fork(new Zone.TaskTrackingZoneSpec)),t&&Zone.longStackTraceZoneSpec&&(a._inner=a._inner.fork(Zone.longStackTraceZoneSpec)),a.shouldCoalesceEventChangeDetection=!r&&n,a.shouldCoalesceRunChangeDetection=r,a.callbackScheduled=!1,a.scheduleInRootZone=i,Us(a)}static isInAngularZone(){return typeof Zone<`u`&&Zone.current.get(Is)===!0}static assertInAngularZone(){if(!e.isInAngularZone())throw new ii(909,!1)}static assertNotInAngularZone(){if(e.isInAngularZone())throw new ii(909,!1)}run(e,t,n){return this._inner.run(e,t,n)}runTask(e,t,n,r){let i=this._inner,a=i.scheduleEventTask(`NgZoneEvent: `+r,e,Bs,Ns,Ns);try{return i.runTask(a,t,n)}finally{i.cancelTask(a)}}runGuarded(e,t,n){return this._inner.runGuarded(e,t,n)}runOutsideAngular(e){return this._outer.run(e)}},Bs={};function Vs(e){if(e._nesting==0&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function Hs(e){if(e.isCheckStableRunning||e.callbackScheduled)return;e.callbackScheduled=!0;function t(){Ps(()=>{e.callbackScheduled=!1,Ws(e),e.isCheckStableRunning=!0,Vs(e),e.isCheckStableRunning=!1})}e.scheduleInRootZone?Zone.root.run(()=>{t()}):e._outer.run(()=>{t()}),Ws(e)}function Us(e){let t=()=>{Hs(e)},n=Rs++;e._inner=e._inner.fork({name:`angular`,properties:{[Is]:!0,[Ls]:n,[Ls+n]:!0},onInvokeTask:(n,r,i,a,o,s)=>{if(Js(s))return n.invokeTask(i,a,o,s);try{return Gs(e),n.invokeTask(i,a,o,s)}finally{(e.shouldCoalesceEventChangeDetection&&a.type===`eventTask`||e.shouldCoalesceRunChangeDetection)&&t(),Ks(e)}},onInvoke:(n,r,i,a,o,s,c)=>{try{return Gs(e),n.invoke(i,a,o,s,c)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!Ys(s)&&t(),Ks(e)}},onHasTask:(t,n,r,i)=>{t.hasTask(r,i),n===r&&(i.change==`microTask`?(e._hasPendingMicrotasks=i.microTask,Ws(e),Vs(e)):i.change==`macroTask`&&(e.hasPendingMacrotasks=i.macroTask))},onHandleError:(t,n,r,i)=>(t.handleError(r,i),e.runOutsideAngular(()=>e.onError.emit(i)),!1)})}function Ws(e){e.hasPendingMicrotasks=!!(e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&e.callbackScheduled===!0)}function Gs(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function Ks(e){e._nesting--,Vs(e)}var qs=class{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new Ms;onMicrotaskEmpty=new Ms;onStable=new Ms;onError=new Ms;run(e,t,n){return e.apply(t,n)}runGuarded(e,t,n){return e.apply(t,n)}runOutsideAngular(e){return e()}runTask(e,t,n,r){return e.apply(t,n)}};function Js(e){return Xs(e,`__ignore_ng_zone__`)}function Ys(e){return Xs(e,`__scheduler_tick__`)}function Xs(e,t){return!Array.isArray(e)||e.length!==1?!1:e[0]?.data?.[t]===!0}var Zs=class{_console=console;handleError(e){this._console.error(`ERROR`,e)}},Qs=new xi(``,{factory:()=>{let e=C(zs),t=C(Pa),n;return r=>{e.runOutsideAngular(()=>{t.destroyed&&!n?setTimeout(()=>{throw r}):(n??=t.get(Zs),n.handleError(r))})}}}),$s={provide:ha,useValue:()=>{C(Zs,{optional:!0})},multi:!0};function O(e,t){let[n,r,i]=Wn(e,t?.equal),a=n;return a[fn],a.set=r,a.update=i,a.asReadonly=ec.bind(a),a}function ec(){let e=this[fn];if(e.readonlyFn===void 0){let t=()=>this();t[fn]=e,e.readonlyFn=t}return e.readonlyFn}var tc=new xi(``,{factory:()=>nc}),nc=`ng`,rc=new xi(``),ic=new xi(``,{providedIn:`platform`,factory:()=>`unknown`}),ac=new xi(``,{factory:()=>C(Es).body?.querySelector(`[ngCspNonce]`)?.getAttribute(`ngCspNonce`)||null}),oc=(()=>{class e{view;node;constructor(e,t){this.view=e,this.node=t}static __NG_ELEMENT_ID__=sc}return e})();function sc(){return new oc(w(),Ro())}var cc=class{},lc=new xi(``,{factory:()=>!0}),uc=new xi(``),dc=(()=>{class e{static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new fc})}return e})(),fc=class{dirtyEffectCount=0;queues=new Map;add(e){this.enqueue(e),this.schedule(e)}schedule(e){e.dirty&&this.dirtyEffectCount++}remove(e){let t=e.zone,n=this.queues.get(t);n.has(e)&&(n.delete(e),e.dirty&&this.dirtyEffectCount--)}enqueue(e){let t=e.zone;this.queues.has(t)||this.queues.set(t,new Set);let n=this.queues.get(t);n.has(e)||n.add(e)}flush(){for(;this.dirtyEffectCount>0;){let e=!1;for(let[t,n]of this.queues)e||=t===null?this.flushQueue(n):t.run(()=>this.flushQueue(n));e||(this.dirtyEffectCount=0)}}flushQueue(e){let t=!1;for(let n of e)n.dirty&&(this.dirtyEffectCount--,t=!0,n.run());return t}},pc=class{[fn];constructor(e){this[fn]=e}destroy(){this[fn].destroy()}};function mc(e,t){let n=t?.injector??C(Ts),r=t?.manualCleanup===!0?null:n.get(Ds),i,a=n.get(oc,null,{optional:!0}),o=n.get(cc);return a===null?i=yc(e,n.get(dc),o):(i=vc(a.view,o,e),r instanceof Os&&r._lView===a.view&&(r=null)),i.injector=n,r!==null&&(i.onDestroyFns=[r.onDestroy(()=>i.destroy())]),new pc(i)}var hc={...Xn,cleanupFns:void 0,zone:null,onDestroyFns:null,run(){let e=Ko(!1);try{Zn(this)}finally{Ko(e)}},cleanup(){if(!this.cleanupFns?.length)return;let e=pn(null);try{for(;this.cleanupFns.length;)this.cleanupFns.pop()()}finally{this.cleanupFns=[],pn(e)}}},gc={...hc,consumerMarkedDirty(){this.scheduler.schedule(this),this.notifier.notify(12)},destroy(){if(On(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.scheduler.remove(this)}},_c={...hc,consumerMarkedDirty(){this.view[2]|=8192,xo(this.view),this.notifier.notify(13)},destroy(){if(On(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.view[23]?.delete(this)}};function vc(e,t,n){let r=Object.create(_c);return r.view=e,r.zone=typeof Zone<`u`?Zone.current:null,r.notifier=t,r.fn=bc(r,n),e[23]??=new Set,e[23].add(r),r.consumerMarkedDirty(r),r}function yc(e,t,n){let r=Object.create(gc);return r.fn=bc(r,e),r.scheduler=t,r.notifier=n,r.zone=typeof Zone<`u`?Zone.current:null,r.scheduler.add(r),r.notifier.notify(12),r}function bc(e,t){return()=>{t(t=>(e.cleanupFns??=[]).push(t))}}function xc(e){return typeof e==`function`&&e[fn]!==void 0}function Sc(e){return xc(e)&&typeof e.set==`function`}var Cc=Symbol(`InputSignalNode#UNSET`),wc={...Jn,transformFn:void 0,applyValueToInputSignal(e,t){Kn(e,t)}};function Tc(e){return{toString:e}.toString()}var Ec=(function(e){return e[e.TemplateCreateStart=0]=`TemplateCreateStart`,e[e.TemplateCreateEnd=1]=`TemplateCreateEnd`,e[e.TemplateUpdateStart=2]=`TemplateUpdateStart`,e[e.TemplateUpdateEnd=3]=`TemplateUpdateEnd`,e[e.LifecycleHookStart=4]=`LifecycleHookStart`,e[e.LifecycleHookEnd=5]=`LifecycleHookEnd`,e[e.OutputStart=6]=`OutputStart`,e[e.OutputEnd=7]=`OutputEnd`,e[e.BootstrapApplicationStart=8]=`BootstrapApplicationStart`,e[e.BootstrapApplicationEnd=9]=`BootstrapApplicationEnd`,e[e.BootstrapComponentStart=10]=`BootstrapComponentStart`,e[e.BootstrapComponentEnd=11]=`BootstrapComponentEnd`,e[e.ChangeDetectionStart=12]=`ChangeDetectionStart`,e[e.ChangeDetectionEnd=13]=`ChangeDetectionEnd`,e[e.ChangeDetectionSyncStart=14]=`ChangeDetectionSyncStart`,e[e.ChangeDetectionSyncEnd=15]=`ChangeDetectionSyncEnd`,e[e.AfterRenderHooksStart=16]=`AfterRenderHooksStart`,e[e.AfterRenderHooksEnd=17]=`AfterRenderHooksEnd`,e[e.ComponentStart=18]=`ComponentStart`,e[e.ComponentEnd=19]=`ComponentEnd`,e[e.DeferBlockStateStart=20]=`DeferBlockStateStart`,e[e.DeferBlockStateEnd=21]=`DeferBlockStateEnd`,e[e.DynamicComponentStart=22]=`DynamicComponentStart`,e[e.DynamicComponentEnd=23]=`DynamicComponentEnd`,e[e.HostBindingsUpdateStart=24]=`HostBindingsUpdateStart`,e[e.HostBindingsUpdateEnd=25]=`HostBindingsUpdateEnd`,e})(Ec||{}),Dc=class{previousValue;currentValue;firstChange;constructor(e,t,n){this.previousValue=e,this.currentValue=t,this.firstChange=n}isFirstChange(){return this.firstChange}};function Oc(e,t,n,r){t===null?e[n]=r:t.applyValueToInputSignal(t,r)}var kc=null,Ac=(()=>{kc=Mc;let e=()=>Mc;return e.ngInherit=!0,e})();function jc(){return kc}function Mc(e){return e.type.prototype.ngOnChanges&&(e.setInput=Pc),Nc}function Nc(){let e=Ic(this),t=e?.current;if(t){let n=e.previous;if(n===pa)e.previous=t;else for(let e in t)n[e]=t[e];e.current=null,this.ngOnChanges(t)}}function Pc(e,t,n,r,i){let a=this.declaredInputs[r],o=Ic(e)||Lc(e,{previous:pa,current:null}),s=o.current||={},c=o.previous,l=c[a];s[a]=new Dc(l&&l.currentValue,n,c===pa),Oc(e,t,i,n)}var Fc=`__ngSimpleChanges__`;function Ic(e){return Object.hasOwn(e,Fc)&&e[Fc]||null}function Lc(e,t){return e[Fc]=t}var Rc=[],zc=function(e,t=null,n){for(let r=0;r=r)break}else t[c]<0&&(e[17]+=65536),(s>14>16&&(e[2]&3)===t&&(e[2]+=16384,Kc(o,a)):Kc(o,a)}var Jc=-1,Yc=class{factory;name;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(e,t,n,r){this.factory=e,this.name=r,this.canSeeViewProviders=t,this.injectImpl=n}};function Xc(e){return!!(e.flags&8)}function Zc(e){return!!(e.flags&16)}function Qc(e,t,n){let r=0;for(;rt){o=a-1;break}}}for(;a>16}function ol(e,t){let n=al(e),r=t;for(;n>0;)r=r[14],n--;return r}var sl=!0;function cl(e){let t=sl;return sl=e,t}var ll=255,ul=5,dl=0,fl={};function pl(e,t,n){let r;typeof n==`string`?r=n.charCodeAt(0)||0:Object.hasOwn(n,Di)&&(r=n[Di]),r??=n[Di]=dl++;let i=r&ll,a=1<>ul)]|=a}function ml(e,t){let n=gl(e,t);if(n!==-1)return n;let r=t[1];r.firstCreatePass&&(e.injectorIndex=t.length,hl(r.data,e),hl(t,null),hl(r.blueprint,null));let i=_l(e,t),a=e.injectorIndex;if(rl(i)){let e=il(i),n=ol(i,t),r=n[1].data;for(let i=0;i<8;i++)t[a+i]=n[e+i]|r[e+i]}return t[a+8]=i,a}function hl(e,t){e.push(0,0,0,0,0,0,0,0,t)}function gl(e,t){return e.injectorIndex===-1||e.parent&&e.parent.injectorIndex===e.injectorIndex||t[e.injectorIndex+8]===null?-1:e.injectorIndex}function _l(e,t){if(e.parent&&e.parent.injectorIndex!==-1)return e.parent.injectorIndex;let n=0,r=null,i=t;for(;i!==null;){if(r=Ml(i),r===null)return Jc;if(n++,i=i[14],r.injectorIndex!==-1)return r.injectorIndex|n<<16}return Jc}function vl(e,t,n){pl(e,t,n)}function yl(e,t,n){if(n&8||e!==void 0)return e;Ri(t,`NodeInjector`)}function bl(e,t,n,r){if(n&8&&r===void 0&&(r=null),!(n&3)){let i=e[9],a=Ui(void 0);try{return i?i.get(t,r,n&8):Wi(t,r,n&8)}finally{Ui(a)}}return yl(r,t,n)}function xl(e,t,n,r=0,i){if(e!==null){if(t[2]&2048&&!(r&2)){let i=jl(e,t,n,r,fl);if(i!==fl)return i}let i=Sl(e,t,n,r,fl);if(i!==fl)return i}return bl(t,n,r,i)}function Sl(e,t,n,r,i){let a=El(n);if(typeof a==`function`){if(!os(t,e,r))return r&1?yl(i,n,r):bl(t,n,r,i);try{let e;if(e=a(r),e==null&&!(r&8))Ri(n);else return e}finally{ds()}}else if(typeof a==`number`){let i=null,o=gl(e,t),s=Jc,c=r&1?t[15][5]:null;for((o===-1||r&4)&&(s=o===-1?_l(e,t):t[o+8],s===Jc||!Ol(r,!1)?o=-1:(i=t[1],o=il(s),t=ol(s,t)));o!==-1;){let e=t[1];if(Dl(a,o,e.data)){let e=Cl(o,t,n,i,r,c);if(e!==fl)return e}s=t[o+8],s!==Jc&&Ol(r,t[1].data[o+8]===c)&&Dl(a,o,t)?(i=e,o=il(s),t=ol(s,t)):o=-1}}return i}function Cl(e,t,n,r,i,a){let o=t[1],s=o.data[e+8],c=wl(s,o,n,r==null?Qa(s)&&sl:r!=o&&!!(s.type&3),i&1&&a===s);return c===null?fl:Tl(t,o,c,s,i)}function wl(e,t,n,r,i){let a=e.providerIndexes,o=t.data,s=a&1048575,c=e.directiveStart,l=e.directiveEnd,u=a>>20,d=r?s:s+u,f=i?s+u:l;for(let e=d;e=c&&t.type===n)return e}if(i){let e=o[c];if(e&&eo(e)&&e.type===n)return c}return null}function Tl(e,t,n,r,i){let a=e[n],o=t.data;if(a instanceof Yc){let s=a;if(s.resolving)throw Li(``);let c=cl(s.canSeeViewProviders);s.resolving=!0,o[n].type||o[n];let l=s.injectImpl?Ui(s.injectImpl):null;os(e,r,0);try{a=e[n]=s.factory(void 0,i,o,e,r),t.firstCreatePass&&n>=r.directiveStart&&Bc(n,o[n],t)}finally{l!==null&&Ui(l),cl(c),s.resolving=!1,ds()}}return a}function El(e){if(typeof e==`string`)return e.charCodeAt(0)||0;let t=Object.hasOwn(e,Di)?e[Di]:void 0;return typeof t==`number`?t>=0?t&ll:Al:t}function Dl(e,t,n){let r=1<>ul)]&r)}function Ol(e,t){return!(e&2)&&!(e&1&&t)}var kl=class{_tNode;_lView;constructor(e,t){this._tNode=e,this._lView=t}get(e,t,n){return xl(this._tNode,this._lView,e,Zi(n),t)}};function Al(){return new kl(Ro(),w())}function jl(e,t,n,r,i){let a=e,o=t;for(;a!==null&&o!==null&&o[2]&2048&&!to(o);){let e=Sl(a,o,n,r|2,fl);if(e!==fl)return e;r&=-5;let t=a.parent;if(!t){let e=o[20];if(e){let t=e.get(n,fl,r);if(t!==fl)return t}t=Ml(o),o=o[14]}a=t}return i}function Ml(e){let t=e[1],n=t.type;return n===2?t.declTNode:n===1?e[5]:null}function Nl(e){return{token:e.token,providedIn:e.autoProvided===!1?null:`root`,factory:e.factory,value:void 0}}function Pl(){return Fl(Ro(),w())}function Fl(e,t){return new Il(so(e,t))}var Il=(()=>{class e{nativeElement;constructor(e){this.nativeElement=e}static __NG_ELEMENT_ID__=Pl}return e})();function Ll(e){return e instanceof Il?e.nativeElement:e}function Rl(){return this._results[Symbol.iterator]()}var zl=class{_emitDistinctChangesOnly;dirty=!0;_onDirty=void 0;_results=[];_changesDetected=!1;_changes=void 0;length=0;first=void 0;last=void 0;get changes(){return this._changes??=new $r}constructor(e=!1){this._emitDistinctChangesOnly=e}get(e){return this._results[e]}map(e){return this._results.map(e)}filter(e){return this._results.filter(e)}find(e){return this._results.find(e)}reduce(e,t){return this._results.reduce(e,t)}forEach(e){this._results.forEach(e)}some(e){return this._results.some(e)}toArray(){return this._results.slice()}toString(){return this._results.toString()}reset(e,t){this.dirty=!1;let n=ra(e);(this._changesDetected=!na(this._results,n,t))&&(this._results=n,this.length=n.length,this.last=n[this.length-1],this.first=n[0])}notifyOnChanges(){this._changes!==void 0&&(this._changesDetected||!this._emitDistinctChangesOnly)&&this._changes.next(this)}onDirty(e){this._onDirty=e}setDirty(){this.dirty=!0,this._onDirty?.()}destroy(){this._changes!==void 0&&(this._changes.complete(),this._changes.unsubscribe())}[Symbol.iterator]=Rl};function Bl(e){return(e.flags&128)==128}var Vl=(function(e){return e[e.OnPush=0]=`OnPush`,e[e.Eager=1]=`Eager`,e[e.Default=1]=`Default`,e})(Vl||{}),Hl=new Map,Ul=0;function Wl(){return Ul++}function Gl(e){Hl.set(e[19],e)}function Kl(e){Hl.delete(e[19])}var ql=`__ngContext__`;function Jl(e,t){Ya(t)?(e[ql]=t[19],Gl(t)):e[ql]=t}function Yl(e){return Zl(e[12])}function Xl(e){return Zl(e[4])}function Zl(e){for(;e!==null&&!Xa(e);)e=e[4];return e}var Ql=void 0;function $l(e){Ql=e}function eu(){if(Ql!==void 0)return Ql;if(typeof document<`u`)return document;throw new ii(210,!1)}var tu=!1,nu=new xi(``,{factory:()=>tu}),ru=new WeakMap;function iu(e,t){if(typeof e!=`object`||!e)return;let n=ru.get(e);n||(n=new WeakSet,ru.set(e,n)),n.add(t)}function au(e){return(e.flags&32)==32}var ou=()=>null;function su(e,t,n=!1){return ou(e,t,n)}function cu(e,t){let n=e.contentQueries;if(n!==null){let r=pn(null);try{for(let r=0;r|^->||--!>|)/g,bu=`​$1​`;function xu(e){return e.replace(vu,e=>e.replace(yu,bu))}function Su(e,t){return e.createText(t)}function Cu(e,t,n){e.setValue(t,n)}function wu(e,t){return e.createComment(xu(t))}function Tu(e,t,n){return e.createElement(t,n)}function Eu(e,t,n,r,i){e.insertBefore(t,n,r,i)}function Du(e,t,n){e.appendChild(t,n)}function Ou(e,t,n,r,i){r===null?Du(e,t,n):Eu(e,t,n,r,i)}function ku(e,t,n,r){e.removeChild(null,t,n,r)}function Au(e,t,n){e.setAttribute(t,`style`,n)}function ju(e,t,n){n===``?e.removeAttribute(t,`class`):e.setAttribute(t,`class`,n)}function Mu(e,t,n){let{mergedAttrs:r,classes:i,styles:a}=n;r!==null&&Qc(e,t,r),i!==null&&ju(e,t,i),a!==null&&Au(e,t,a)}function Nu(e){let t=Pu();return t?t.sanitize(ro.URL,e)||``:mu(e,`URL`)?pu(e):_u(Ni(e))}function Pu(){let e=w();return e&&e[10].sanitizer}function Fu(e){return e.ownerDocument.defaultView}function Iu(e){return e.ownerDocument}function Lu(e,t,n){let r=e.length;for(;;){let i=e.indexOf(t,n);if(i===-1)return i;if(i===0||e.charCodeAt(i-1)<=32){let n=t.length;if(i+n===r||e.charCodeAt(i+n)<=32)return i}n=i+1}}var Ru=`ng-template`;function zu(e,t,n,r){let i=0;if(r){for(;i-1){let e;for(;++ia?``:i[u+1].toLowerCase(),r&2&&l!==e){if(Uu(r))return!1;o=!0}}}}}return Uu(r)||o}function Uu(e){return!(e&1)}function Wu(e,t,n,r){if(t===null)return-1;let i=0;if(r||!n){let n=!1;for(;i-1)for(n++;n0?`="`+t+`"`:``)+`]`}else r&8?i+=`.`+o:r&4&&(i+=` `+o)}else i!==``&&!Uu(o)&&(t+=Xu(a,i),i=``),r=o,a||=!Uu(r);n++}return i!==``&&(t+=Xu(a,i)),t}function Qu(e){return e.map(Zu).join(`,`)}function $u(e){let t=[],n=[],r=1,i=2;for(;r!1});function ad(e){if(!e)return 0;let t=e.toLowerCase().indexOf(`ms`)>-1?1:1e3;return parseFloat(e)*t}function od(e,t){return e.getPropertyValue(t).split(`,`).map(e=>e.trim())}function sd(e){let t=od(e,`transition-property`),n=od(e,`transition-duration`),r=od(e,`transition-delay`),i={propertyName:``,duration:0,animationName:void 0};for(let e=0;ei.duration&&(i.propertyName=t[e],i.duration=a)}return i}function cd(e){let t=od(e,`animation-name`),n=od(e,`animation-delay`),r=od(e,`animation-duration`),i=od(e,`animation-iteration-count`),a={animationName:``,propertyName:void 0,duration:0};for(let e=0;ea.duration&&s!==`infinite`&&(a.animationName=t[e],a.duration=o)}return a}function ld(e,t){return e!==void 0&&e.duration>t.duration}function ud(e){return(e.animationName!=null||e.propertyName!=null)&&e.duration>0}function dd(e){let t=e.effect?.getTiming();if(t===void 0)return;let n=typeof t.duration==`number`?t.duration:0,r=(t.delay??0)+n,i=e.playbackRate;return i!==void 0&&i!==0&&i!==1&&(r/=Math.abs(i)),r}function fd(e,t){let n=getComputedStyle(e),r=cd(n),i=sd(n),a=r.duration>i.duration?r:i;ld(t.get(e),a)||ud(a)&&t.set(e,a)}function pd(e,t,n){if(!n)return;let r=e.getAnimations();return r.length===0?fd(e,t):md(e,t,r)}function md(e,t,n){let r={animationName:void 0,propertyName:void 0,duration:0};for(let e of n){if(e.effect?.getTiming()?.iterations===1/0)continue;let t=dd(e)??0,n,i;e.animationName?i=e.animationName:n=e.transitionProperty,t>=r.duration&&(r={animationName:i,propertyName:n,duration:t})}ld(t.get(e),r)||ud(r)&&t.set(e,r)}var hd=new Set,gd=!1,_d=1,vd=typeof document<`u`&&typeof document?.documentElement?.getAnimations==`function`;function yd(e){return e[9].get(id,gd)}function bd(e,t,n){let r=Sd.get(e);if(r){for(let e of t)r.classList.push(e);for(let e of n)r.cleanupFns.push(e)}else Sd.set(e,{classList:t,cleanupFns:n})}function xd(e){let t=Sd.get(e);if(t){for(let e of t.cleanupFns)e();Sd.delete(e)}Cd.delete(e)}var Sd=new WeakMap,Cd=new WeakMap,wd=new WeakMap;function Td(e){return e?e[14]??e:null}var Ed=new WeakSet;function Dd(e,t,n){let r=wd.get(e);if(!r||r.length===0)return;let i=t.parentNode,a=t.previousSibling,o=Td(n);for(let e=r.length-1;e>=0;e--){let{el:n,declarationView:s}=r[e],c=n.parentNode;n===t?(r.splice(e,1),Ed.add(n),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}}))):(a&&n===a||c&&i&&c!==i&&(o===null||s===null||o===s))&&(r.splice(e,1),n.dispatchEvent(new CustomEvent(`animationend`,{detail:{cancel:!0}})),n.parentNode?.removeChild(n))}}function Od(e,t,n){let r=Td(n),i=wd.get(e);i?i.some(e=>e.el===t)||i.push({el:t,declarationView:r}):wd.set(e,[{el:t,declarationView:r}])}function kd(e){let t=e[26]??={};return t.enter??=new Map}function Ad(e){let t=typeof e==`function`?e():e,n=Array.isArray(t)?t:null;return typeof t==`string`&&(n=t.trim().split(/\s+/).filter(e=>e)),n}function jd(e){return e.composedPath?e.composedPath()[0]:e.target}function Md(e,t){let n=Cd.get(t);if(n===void 0)return!0;if(t!==jd(e))return!1;let r=e.animation;if(r){let e=dd(r);if(e!==void 0&&e+_d{class e{impl=null;execute(){this.impl?.execute()}static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),zd=[0,1,2,3],Bd=(()=>{class e{ngZone=C(zs);scheduler=C(cc);errorHandler=C(Zs,{optional:!0});sequences=new Set;deferredRegistrations=new Set;executing=!1;constructor(){C(Fd,{optional:!0})}execute(){let e=this.sequences.size>0;e&&zc(Ec.AfterRenderHooksStart),this.executing=!0;for(let e of zd)for(let t of this.sequences)if(!t.erroredOrDestroyed&&t.hooks[e])try{t.pipelinedValue=this.ngZone.runOutsideAngular(()=>this.maybeTrace(()=>{let n=t.hooks[e];return n(t.pipelinedValue)},t.snapshot))}catch(e){t.erroredOrDestroyed=!0,this.errorHandler?.handleError(e)}this.executing=!1;for(let e of this.sequences)e.afterRun(),e.once&&(this.sequences.delete(e),e.destroy());for(let e of this.deferredRegistrations)this.sequences.add(e);this.deferredRegistrations.size>0&&this.scheduler.notify(7),this.deferredRegistrations.clear(),e&&zc(Ec.AfterRenderHooksEnd)}register(e){let{view:t}=e;t===void 0?this.executing?this.deferredRegistrations.add(e):this.addSequence(e):((t[25]??=[]).push(e),xo(t),t[2]|=8192)}addSequence(e){this.sequences.add(e),this.scheduler.notify(7)}unregister(e){this.executing&&this.sequences.has(e)?(e.erroredOrDestroyed=!0,e.pipelinedValue=void 0,e.once=!0):(this.sequences.delete(e),this.deferredRegistrations.delete(e))}maybeTrace(e,t){return t?t.run(Pd.AFTER_NEXT_RENDER,e):e()}static ɵprov=mi({token:e,providedIn:`root`,factory:()=>new e})}return e})(),Vd=class{impl;hooks;view;once;snapshot;erroredOrDestroyed=!1;pipelinedValue=void 0;unregisterOnDestroy;constructor(e,t,n,r,i,a=null){this.impl=e,this.hooks=t,this.view=n,this.once=r,this.snapshot=a,this.unregisterOnDestroy=i?.onDestroy(()=>this.destroy())}afterRun(){this.erroredOrDestroyed=!1,this.pipelinedValue=void 0,this.snapshot?.dispose(),this.snapshot=null}destroy(){this.impl.unregister(this),this.unregisterOnDestroy?.();let e=this.view?.[25];e&&(this.view[25]=e.filter(e=>e!==this))}};function Hd(e,t){let n=t?.injector??C(Ts);return Ld(`NgAfterNextRender`),Wd(e,n,t,!0)}function Ud(e){return e instanceof Function?[void 0,void 0,e,void 0]:[e.earlyRead,e.write,e.mixedReadWrite,e.read]}function Wd(e,t,n,r){let i=t.get(Rd);i.impl??=t.get(Bd);let a=t.get(Fd,null,{optional:!0}),o=n?.manualCleanup===!0?null:t.get(Ds),s=t.get(oc,null,{optional:!0}),c=new Vd(i.impl,Ud(e),s?.view,r,o,a?.snapshot(null));return i.impl.register(c),c}var Gd=new xi(``,{factory:()=>{let e=C(Pa),t=new Set;return e.onDestroy(()=>t.clear()),{queue:t,isScheduled:!1,scheduler:null,injector:e}}});function Kd(e,t,n){let r=e.get(Gd);if(Array.isArray(t))for(let e of t)r.queue.add(e),n?.detachedLeaveAnimationFns?.push(e);else r.queue.add(t),n?.detachedLeaveAnimationFns?.push(t);r.scheduler&&r.scheduler(e)}function qd(e,t){let n=e.get(Gd);if(Array.isArray(t))for(let e of t)n.queue.delete(e);else n.queue.delete(t)}function Jd(e,t){let n=e.get(Gd);if(t.detachedLeaveAnimationFns){for(let e of t.detachedLeaveAnimationFns)n.queue.delete(e);t.detachedLeaveAnimationFns=void 0}}function Yd(e){let t=e.get(Gd);t.isScheduled||=(Hd(()=>{t.isScheduled=!1;for(let e of t.queue)e();t.queue.clear()},{injector:t.injector}),!0)}function Xd(e){let t=e.get(Gd);t.scheduler=Yd,t.scheduler(e)}function Zd(e,t){for(let[n,r]of t)Kd(e,r.animateFns)}function Qd(e,t,n,r){let i=e?.[26]?.enter;t!==null&&i&&i.has(n.index)&&Zd(r,i)}function $d(e,t,n,r){try{n.get(ga)}catch{return r(!1)}let i=e?.[26];i?.enter?.has(t.index)&&qd(n,i.enter.get(t.index).animateFns);let a=ef(e,t,i);if(a.size===0){let n=!1;if(e){let r=[];nf(e,t,r),n=r.length>0}if(!n)return r(!1)}e&&hd.add(e[19]),Kd(n,()=>tf(e,t,i||void 0,a,r),i||void 0)}function ef(e,t,n){let r=new Map,i=n?.leave;if(i&&i.has(t.index)&&r.set(t.index,i.get(t.index)),e&&i)for(let[n,a]of i){if(r.has(n))continue;let i=e[1].data[n].parent;for(;i;){if(i===t){r.set(n,a);break}i=i.parent}}return r}function tf(e,t,n,r,i){let a=[];if(n&&n.leave)for(let[e]of r){if(!n.leave.has(e))continue;let t=n.leave.get(e);for(let e of t.animateFns){let{promise:t}=e();a.push(t)}n.detachedLeaveAnimationFns=void 0}if(e&&nf(e,t,a),a.length>0){let t=n||e?.[26];if(t){let n=t.running;n&&a.push(n),t.running=Promise.allSettled(a),af(e,t.running,i)}else Promise.allSettled(a).then(()=>{e&&hd.delete(e[19]),i(!0)})}else e&&hd.delete(e[19]),i(!1)}function nf(e,t,n){if(t.type&12){let r=e[t.index];if(Xa(r))for(let e=10;e{e[26]?.running===t&&(e[26].running=void 0,hd.delete(e[19])),n(!0)})}function of(e,t,n,r,i,a,o,s){if(i!=null){let c,l=!1;Xa(i)?c=i:Ya(i)&&(l=!0,i=i[0]);let u=ao(i);e===0&&r!==null?(Qd(s,r,a,n),o==null?Du(t,r,u):Eu(t,r,u,o||null,!0)):e===1&&r!==null?(Qd(s,r,a,n),Eu(t,r,u,o||null,!0),Dd(a,u,s)):e===2?(s?.[26]?.leave?.has(a.index)&&Od(a,u,s),Ed.delete(u),$d(s,a,n,e=>{if(Ed.has(u)){Ed.delete(u);return}ku(t,u,l,e)})):e===3&&(Ed.delete(u),$d(s,a,n,()=>{t.destroyNode(u)})),c!=null&&Af(t,e,n,c,a,r,o)}}function sf(e,t){lf(e,t),t[0]=null,t[5]=null}function cf(e,t,n,r,i,a){r[0]=i,r[5]=t,Ef(e,r,n,1,i,a)}function lf(e,t){t[10].changeDetectionScheduler?.notify(9),Ef(e,t,t[11],2,null,null)}function uf(e){let t=e[12];if(!t)return pf(e[1],e);for(;t;){let n=null;if(Ya(t))n=t[12];else{let e=t[10];e&&(n=e)}if(!n){for(;t&&!t[4]&&t!==e;)Ya(t)&&pf(t[1],t),t=t[3];t===null&&(t=e),Ya(t)&&pf(t[1],t),n=t&&t[4]}t=n}}function df(e,t){let n=e[9],r=n.indexOf(t);n.splice(r,1)}function ff(e,t){if(no(t))return;let n=t[11];n.destroyNode&&Ef(e,t,n,3,null,null),uf(t)}function pf(e,t){if(no(t))return;let n=pn(null);try{t[2]&=-129,t[2]|=256,t[24]&&On(t[24]),hf(e,t),mf(e,t),t[1].type===1&&t[11].destroy();let n=t[16];if(n!==null&&Xa(t[3])){n!==t[3]&&df(n,t);let r=t[18];r!==null&&r.detachView(e)}Kl(t)}finally{pn(n)}}function mf(e,t){let n=e.cleanup,r=t[7];if(n!==null)for(let e=0;e=0?r[t]():r[-t].unsubscribe(),e+=2}else{let t=r[n[e+1]];n[e].call(t)}r!==null&&(t[7]=null);let i=t[21];if(i!==null){t[21]=null;for(let e=0;e27&&Bf(e,t,27,!1),zc(o?Ec.TemplateUpdateStart:Ec.TemplateCreateStart,i,n),n(r,i)}finally{hs(a),zc(o?Ec.TemplateUpdateEnd:Ec.TemplateCreateEnd,i,n)}}function Wf(e,t,n){Zf(e,t,n),(n.flags&64)==64&&Qf(e,t,n)}function Gf(e,t,n=so){let r=t.localNames;if(r!==null){let i=t.index+1;for(let a=0;a{xo(e.lView)},consumerOnSignalRead(){this.lView[24]=this}};function Sp(e){let t=e[24]??Object.create(Cp);return t.lView=e,t}var Cp={...hn,consumerIsAlwaysLive:!0,kind:`template`,consumerMarkedDirty:e=>{let t=wo(e.lView);for(;t&&!wp(t[1]);)t=wo(t);t&&_o(t)},consumerOnSignalRead(){this.lView[24]=this}};function wp(e){return e.type!==2}function Tp(e){if(e[23]===null)return;let t=!0;for(;t;){let n=!1;for(let t of e[23])if(t.dirty&&(n=!0,t.zone===null||Zone.current===t.zone?t.run():t.zone.run(()=>t.run()),e[23]===null))return;t=n&&!!(e[2]&8192)}}var Ep=100;function Dp(e,t=0){let n=e[10].rendererFactory;n.begin?.();try{Op(e,t)}finally{n.end?.()}}function Op(e,t){let n=Go();try{Ko(!0),Pp(e,t);let n=0;for(;yo(e);){if(n===Ep)throw new ii(103,!1);n++,Pp(e,1)}}finally{Ko(n)}}function kp(e,t,n,r){if(no(t))return;let i=t[2];ss(t);let a=!0,o=null,s=null;wp(e)?(s=vp(t),o=Cn(s)):mn()===null?(a=!1,s=Sp(t),o=Cn(s)):t[24]&&=(On(t[24]),null);try{go(t),Yo(e.bindingStartIndex),n!==null&&Uf(e,t,n,2,r);let a=(i&3)==3;if(a){let n=e.preOrderCheckHooks;n!==null&&Hc(t,n,null)}else{let n=e.preOrderHooks;n!==null&&Uc(t,n,0,null),Wc(t,0)}if(jp(t),Tp(t),Ap(t,0),e.contentQueries!==null&&cu(e,t),a){let n=e.contentCheckHooks;n!==null&&Hc(t,n)}else{let n=e.contentHooks;n!==null&&Uc(t,n,1),Wc(t,1)}Ip(e,t);let o=e.components;o!==null&&Fp(t,o,0);let s=e.viewQuery;if(s!==null&&lu(2,s,r),a){let n=e.viewCheckHooks;n!==null&&Hc(t,n)}else{let n=e.viewHooks;n!==null&&Uc(t,n,2),Wc(t,2)}if(e.firstUpdatePass===!0&&(e.firstUpdatePass=!1),t[22]){for(let e of t[22])e();t[22]=null}gp(t),t[2]&=-73}catch(e){throw xo(t),e}finally{s!==null&&(Tn(s,o),a&&bp(s)),fs()}}function Ap(e,t){for(let n=Yl(e);n!==null;n=Xl(n))for(let e=10;e0&&(e[n-1][4]=r[4]);let a=oa(e,10+t);sf(r[1],r);let o=a[18];o!==null&&o.detachView(a[1]),r[3]=null,r[4]=null,r[2]&=-129}return r}function Up(e,t,n,r){let i=10+r,a=n.length;r>0&&(n[i-1][4]=t),r-1&&(Hp(e,n),oa(t,n))}this._attachedToViewContainer=!1}ff(this._lView[1],this._lView)}onDestroy(e){So(this._lView,e)}markForCheck(){Lp(this._cdRefInjectingView||this._lView,4)}detach(){this._lView[2]&=-129}reattach(){bo(this._lView),this._lView[2]|=128}detectChanges(){this._lView[2]|=1024,Dp(this._lView)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new ii(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;let e=to(this._lView),t=this._lView[16];t!==null&&!e&&df(t,this._lView),lf(this._lView[1],this._lView)}attachToAppRef(e){if(this._attachedToViewContainer)throw new ii(902,!1);this._appRef=e;let t=to(this._lView),n=this._lView[16];n!==null&&!t&&Wp(n,this._lView),bo(this._lView)}},Kp=(()=>{class e{_declarationLView;_declarationTContainer;elementRef;static __NG_ELEMENT_ID__=qp;constructor(e,t,n){this._declarationLView=e,this._declarationTContainer=t,this.elementRef=n}get ssrId(){return this._declarationTContainer.tView?.ssrId||null}createEmbeddedView(e,t){return this.createEmbeddedViewImpl(e,t)}createEmbeddedViewImpl(e,t,n){return new Gp(fp(this._declarationLView,this._declarationTContainer,e,{embeddedViewInjector:t,dehydratedView:n}))}}return e})();function qp(){return Jp(Ro(),w())}function Jp(e,t){return e.type&4?new Kp(t,e,Fl(e,t)):null}function Yp(e,t,n,r,i){let a=e.data[t];if(a===null)a=Xp(e,t,n,r,i),Qo()&&(a.flags|=32);else if(a.type&64){a.type=n,a.value=r,a.attrs=i;let e=Bo();a.injectorIndex=e===null?-1:e.injectorIndex}return Vo(a,!0),a}function Xp(e,t,n,r,i){let a=zo(),o=Ho(),s=o?a:a&&a.parent,c=e.data[t]=Qp(e,s,n,t,r,i);return Zp(e,c,a,o),c}function Zp(e,t,n,r){e.firstChild===null&&(e.firstChild=t),n!==null&&(r?n.child==null&&t.parent!==null&&(n.child=t):n.next===null&&(n.next=t,t.prev=n))}function Qp(e,t,n,r,i,a){let o=t?t.injectorIndex:-1,s=0;return Po()&&(s|=128),{type:n,index:r,insertBeforeIndex:null,injectorIndex:o,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,controlDirectiveIndex:-1,customControlIndex:-1,propertyBindings:null,flags:s,providerIndexes:0,value:i,namespace:ys(),attrs:a,mergedAttrs:null,localNames:null,initialInputs:null,inputs:null,hostDirectiveInputs:null,outputs:null,hostDirectiveOutputs:null,directiveToIndex:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:t,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}function $p(e){let t=e[6]??[],n=e[3][11],r=[];for(let e of t)e.data.di===void 0?em(e,n):r.push(e);e[6]=r}function em(e,t){let n=0,r=e.firstChild;if(r){let i=e.data.r;for(;nnull,nm=()=>null;function rm(e,t){return tm(e,t)}function im(e,t,n){return nm(e,t,n)}var am=class{},om=class{},sm=(()=>{class e{static ɵprov=mi({token:e,providedIn:`root`,factory:()=>null})}return e})();function cm(e){return e.debugInfo?.className||e.type.name||null}var lm={},um=class{injector;parentInjector;constructor(e,t){this.injector=e,this.parentInjector=t}get(e,t,n){let r=this.injector.get(e,lm,n);return r!==lm||t===lm?r:this.parentInjector.get(e,t,n)}};function dm(e,t,n){return e[t]=n}function fm(e,t){return e[t]}function pm(e,t,n){if(n===ed)return!1;let r=e[t];return!Object.is(r,n)&&(e[t]=n,!0)}function mm(e,t,n,r){let i=pm(e,t,n);return pm(e,t+1,r)||i}function hm(e,t,n,r,i){let a=mm(e,t,n,r);return pm(e,t+2,i)||a}function gm(e,t,n,r,i,a){let o=mm(e,t,n,r);return mm(e,t+2,i,a)||o}function _m(e,t,n){return function r(i){let a=r.__ngNativeEl__;a!==void 0&&iu(i,a),Lp(Qa(e)?fo(e.index,t):t,5);let o=t[8],s=vm(t,o,n,i),c=r.__ngNextListenerFn__;for(;c;)s=vm(t,o,c,i)&&s,c=c.__ngNextListenerFn__;return s}}function vm(e,t,n,r){let i=pn(null);try{return zc(Ec.OutputStart,t,n),n(r)!==!1}catch(t){return op(e,t),!1}finally{zc(Ec.OutputEnd,t,n),pn(i)}}function ym(e,t,n,r,i,a,o,s){let c=$a(e),l=!1,u=null;if(!r&&c&&(u=xm(t,n,a,e.index)),u!==null){let e=u.__ngLastListenerFn__||u;e.__ngNextListenerFn__=o,u.__ngLastListenerFn__=o,l=!0}else{let o=so(e,n),c=r?r(o):o;r||(s.__ngNativeEl__=o);let l=i.listen(c,a,s);bm(a)||Sm(r?t=>r(ao(t[e.index])):e.index,t,n,a,s,l,!1)}return l}function bm(e){return e.startsWith(`animation`)||e.startsWith(`transition`)}function xm(e,t,n,r){let i=e.cleanup;if(i!=null)for(let e=0;er?n[r]:null}typeof a==`string`&&(e+=2)}return null}function Sm(e,t,n,r,i,a,o){let s=t.firstCreatePass?Eo(t):null,c=To(n),l=c.length;c.push(i,a),s&&s.push(r,e,l,(l+1)*(o?-1:1))}function Cm(e,t,n,r,i,a){let o=t[n],s=t[1],c=o[s.data[n].outputs[r]].subscribe(a);Sm(e.index,s,t,i,a,c,!0)}var wm=Symbol(`BINDING`),Tm=new xi(``);function Em(e,t,n){let r=n?e.styles:null,i=n?e.classes:null,a=0;if(t!==null)for(let e=0;e0&&(n.directiveToIndex=new Map);for(let c=0;c0;){let n=e[--t];if(typeof n==`number`&&n<0)return n}return 0}function Bm(e,t,n){if(n){if(t.exportAs)for(let r=0;r{let[n,r,i]=e[t],a={propName:n,templateName:t,isSignal:(r&Vf.SignalBased)!==0};return i&&(a.transform=i),a})}function Jm(e){return Object.keys(e).map(t=>({propName:e[t],templateName:t}))}function Ym(e,t,n){let r=t instanceof Pa?t:t?.injector;return r&&e.getStandaloneInjector!==null&&(r=e.getStandaloneInjector(r)||r),r?new um(n,r):n}function Xm(e){let t=e.get(om,null);if(t===null)throw new ii(407,!1);return{rendererFactory:t,sanitizer:e.get(sm,null),changeDetectionScheduler:e.get(cc,null),ngReflect:!1,tracingService:e.get(Fd,null,{optional:!0})}}function Zm(e,t,n){let r=$m(e);return Tu(t,r,r===`svg`?`svg`:r===`math`?io:n)}function Qm(e){if((e&&`localName`in e&&typeof e.localName==`string`?e.localName:e?.tagName)?.toLowerCase()===`script`)throw new ii(905,!1)}function $m(e){return(e.selectors[0][0]||`div`).toLowerCase()}var eh=class{componentDef;ngModule;selector;componentType;ngContentSelectors;isBoundToModule;cachedInputs=null;cachedOutputs=null;get inputs(){return this.cachedInputs??=qm(this.componentDef.inputs),this.cachedInputs}get outputs(){return this.cachedOutputs??=Jm(this.componentDef.outputs),this.cachedOutputs}constructor(e,t){this.componentDef=e,this.ngModule=t,this.componentType=e.type,this.selector=Qu(e.selectors),this.ngContentSelectors=e.ngContentSelectors??[],this.isBoundToModule=!!t}create(e,t,n,r,i,a,o){zc(Ec.DynamicComponentStart);let s=pn(null);try{let s=this.componentDef,c=Ym(s,r||this.ngModule,e),l=Xm(c),u=l.tracingService;return u&&u.componentCreate?u.componentCreate(cm(s),()=>this.createComponentRef(l,c,t,n,i,a,o)):this.createComponentRef(l,c,t,n,i,a,o)}finally{pn(s)}}createComponentRef(e,t,n,r,i,a,o){let s=this.componentDef,c=th(r,s,a,i),l=e.rendererFactory.createRenderer(null,s),u=r?Kf(l,r,s.encapsulation,t):Zm(s,l,o??null);Qm(u);let d=t.get(Tm,null),f=nh(u,()=>t.get(Es,null)??eu());d&&d.addHost(f);let p=a?.some(ih)||i?.some(e=>typeof e!=`function`&&e.bindings.some(ih)),m=Ff(null,c,null,512|Lf(s),null,null,e,l,t,null,su(u,t,!0));d&&Gm&&f instanceof ShadowRoot&&So(m,()=>{d.removeHost(f)}),m[27]=u,ss(m);let h=null;try{let e=Hm(27,m,2,`#host`,()=>c.directiveRegistry,!0,0);Mu(l,u,e),Jl(u,m),Wf(c,m,e),uu(c,e,m),Um(c,e),n!==void 0&&oh(e,this.ngContentSelectors,n),h=fo(e.index,m),m[8]=h[8],up(c,m,null)}catch(e){throw h!==null&&Kl(h),Kl(m),e}finally{zc(Ec.DynamicComponentEnd),fs()}return new ah(this.componentType,m,!!p)}};function th(e,t,n,r){let i=e?[`ng-version`,`22.1.7`]:$u(t.selectors[0]),a=null,o=null,s=0;if(n)for(let e of n)s+=e[wm].requiredVars,e.create&&(e.targetIdx=0,(a??=[]).push(e)),e.update&&(e.targetIdx=0,(o??=[]).push(e));if(r)for(let e=0;e{if(n&1&&e)for(let t of e)t.create();if(n&2&&t)for(let e of t)e.update()}}function ih(e){let t=e[wm].kind;return t===`input`||t===`twoWay`}var ah=class extends am{_rootLView;_hasInputBindings;instance;hostView;changeDetectorRef;componentType;location;previousInputValues=null;_tNode;constructor(e,t,n){super(),this._rootLView=t,this._hasInputBindings=n,this._tNode=co(t[1],27),this.location=Fl(this._tNode,t),this.instance=fo(this._tNode.index,t)[8],this.hostView=this.changeDetectorRef=new Gp(t,void 0),this.componentType=e}setInput(e,t){this._hasInputBindings;let n=this._tNode;if(this.previousInputValues??=new Map,this.previousInputValues.has(e)&&Object.is(this.previousInputValues.get(e),t))return;let r=this._rootLView;sp(n,r[1],r,e,t),this.previousInputValues.set(e,t),Lp(fo(n.index,r),1)}get injector(){return new kl(this._tNode,this._rootLView)}destroy(){this.hostView.destroy()}onDestroy(e){this.hostView.onDestroy(e)}};function oh(e,t,n){let r=e.projection=[];for(let e=0;e{class e{static __NG_ELEMENT_ID__=ch}return e})();function ch(){return fh(Ro(),w())}var lh=class e extends sh{_lContainer;_hostTNode;_hostLView;constructor(e,t,n){super(),this._lContainer=e,this._hostTNode=t,this._hostLView=n}get element(){return Fl(this._hostTNode,this._hostLView)}get injector(){return new kl(this._hostTNode,this._hostLView)}get parentInjector(){let e=_l(this._hostTNode,this._hostLView);if(rl(e)){let t=ol(e,this._hostLView),n=il(e),r=t[1].data[n+8];return new kl(r,t)}return new kl(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(e){let t=uh(this._lContainer);return t!==null&&t[e]||null}get length(){return this._lContainer.length-10}createEmbeddedView(e,t,n){let r,i;typeof n==`number`?r=n:n!=null&&(r=n.index,i=n.injector);let a=rm(this._lContainer,e.ssrId),o=e.createEmbeddedViewImpl(t||{},i,a);return this.insertImpl(o,r,pp(this._hostTNode,a)),o}createComponent(e,t,n,r,i,a,o){let s,c=t||{};s=c.index,n=c.injector,r=c.projectableNodes,i=c.environmentInjector||c.ngModuleRef,a=c.directives,o=c.bindings;let l=new eh(ki(e)),u=n||this.parentInjector;if(!i&&l.ngModule==null){let e=this.parentInjector.get(Pa,null);e&&(i=e)}let d=ki(l.componentType??{}),f=rm(this._lContainer,d?.id??null),p=f?.firstChild??null,m=l.create(u,r,p,i,a,o,this._getHostElementNamespace());return this.insertImpl(m.hostView,s,pp(this._hostTNode,f)),m}_getHostElementNamespace(){if(this._hostTNode.type&2){let e=this._hostTNode.parent??this._hostLView[5];return e!==null&&e.type&2&&typeof e.value==`string`&&e.value.toLowerCase()===`foreignobject`?null:e?.namespace??null}return this._hostTNode.namespace}insert(e,t){return this.insertImpl(e,t,!0)}insertImpl(t,n,r){let i=t._lView;if(mo(i)){let n=this.indexOf(t);if(n!==-1)this.detach(n);else{let n=i[3],r=new e(n,n[5],n[3]);r.detach(r.indexOf(t))}}let a=this._adjustIndex(n),o=this._lContainer;return Bp(o,i,a,r),t.attachToViewContainerRef(),aa(dh(o),a,t),t}move(e,t){return this.insert(e,t)}indexOf(e){let t=uh(this._lContainer);return t===null?-1:t.indexOf(e)}remove(e){let t=this._adjustIndex(e,-1),n=Hp(this._lContainer,t);n&&(oa(dh(this._lContainer),t),ff(n[1],n))}detach(e){let t=this._adjustIndex(e,-1),n=Hp(this._lContainer,t);return n&&oa(dh(this._lContainer),t)!=null?new Gp(n):null}_adjustIndex(e,t=0){return e??this.length+t}};function uh(e){return e[8]}function dh(e){return e[8]||=[]}function fh(e,t){let n,r=t[e.index];return Xa(r)?n=r:(n=Rp(r,t,null,e),t[e.index]=n,zf(t,n)),mh(n,t,e,r),new lh(n,e,t)}function ph(e,t){let n=e[11],r=n.createComment(``),i=so(t,e);return Eu(n,n.parentNode(i),r,n.nextSibling(i),!1),r}var mh=_h,hh=()=>!1;function gh(e,t,n){return hh(e,t,n)}function _h(e,t,n,r){if(e[7])return;let i;i=n.type&8?ao(r):ph(t,n),e[7]=i}var vh=class e{queryList;matches=null;constructor(e){this.queryList=e}clone(){return new e(this.queryList)}setDirty(){this.queryList.setDirty()}},yh=class e{queries;constructor(e=[]){this.queries=e}createEmbeddedView(t){let n=t.queries;if(n!==null){let r=t.contentQueries===null?n.length:t.contentQueries[0],i=[];for(let e=0;e0)r.push(o[e/2]);else{let i=a[e+1],o=t[-n];for(let e=10;ee.trim())}function Nh(e,t,n){e.queries===null&&(e.queries=new xh),e.queries.track(new Sh(t,n))}function Ph(e,t){return e.queries.getByIndex(t)}function Fh(e,t){let n=e[1],r=Ph(n,t);return r.crossesNgTemplate?Oh(n,e,t,[]):Dh(n,e,r,t)}function Ih(e,t,n){let r,i=Pn(()=>{r._dirtyCounter();let n=Bh(r,e);if(t&&n===void 0)throw new ii(-951,!1);return n});return r=i[fn],r._dirtyCounter=O(0),r._flatValue=void 0,i}function Lh(e){return Ih(!0,!1,e)}function Rh(e){return Ih(!0,!0,e)}function zh(e,t){let n=e[fn];n._lView=w(),n._queryIndex=t,n._queryList=kh(n._lView,t),n._queryList.onDirty(()=>n._dirtyCounter.update(e=>e+1))}function Bh(e,t){let n=e._lView,r=e._queryIndex;if(n===void 0||r===void 0||n[2]&4)return t?void 0:ma;let i=kh(n,r),a=Fh(n,r);return i.reset(a,Ll),t?i.first:i._changesDetected||e._flatValue===void 0?e._flatValue=i.toArray():e._flatValue}function Vh(e){return!!e&&typeof e.then==`function`}function Hh(e){return!!e&&typeof e.subscribe==`function`}var Uh=class{},Wh=class extends Uh{injector;instance=null;constructor(e){super();let t=new Fa([...e.providers,{provide:Uh,useValue:this}],e.parent||Na(),e.debugName,new Set([`environment`]));this.injector=t,e.runEnvironmentInitializers&&t.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(e){this.injector.onDestroy(e)}};function Gh(e,t,n=null){return new Wh({providers:e,parent:t,debugName:n,runEnvironmentInitializers:!0}).injector}var Kh=(()=>{class e{_injector;cachedInjectors=new Map;constructor(e){this._injector=e}getOrCreateStandaloneInjector(e){if(!e.standalone)return null;if(!this.cachedInjectors.has(e)){let t=ba(!1,e.type),n=t.length>0?Gh([t],this._injector,``):null;this.cachedInjectors.set(e,n)}return this.cachedInjectors.get(e)}ngOnDestroy(){try{for(let e of this.cachedInjectors.values())e!==null&&e.destroy()}finally{this.cachedInjectors.clear()}}static ɵprov=mi({token:e,providedIn:`environment`,factory:()=>new e(Xi(Pa))})}return e})();function A(e){return Tc(()=>{let t=Qh(e),n={...t,decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection!==Vl.Eager,directiveDefs:null,pipeDefs:null,dependencies:t.standalone&&e.dependencies||null,getStandaloneInjector:t.standalone?e=>e.get(Kh).getOrCreateStandaloneInjector(n):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||du.Emulated,styles:e.styles||ma,_:null,schemas:e.schemas||null,tView:null,id:``};t.standalone&&Ld(`NgStandalone`),$h(n);let r=e.dependencies;return n.directiveDefs=eg(r,qh),n.pipeDefs=eg(r,ji),n.id=tg(n),n})}function qh(e){return ki(e)||Ai(e)}function Jh(e,t){if(e==null)return pa;let n={};for(let r in e)if(Object.hasOwn(e,r)){let i=e[r],a,o,s,c;Array.isArray(i)?(s=i[0],a=i[1],o=i[2]??a,c=i[3]||null):(a=i,o=i,s=Vf.None,c=null),n[a]=[r,s,c],t[a]=o}return n}function Yh(e){if(e==null)return pa;let t={};for(let n in e)Object.hasOwn(e,n)&&(t[e[n]]=n);return t}function Xh(e){return Tc(()=>{let t=Qh(e);return $h(t),t})}function Zh(e){return{type:e.type,name:e.name,factory:null,pure:e.pure!==!1,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function Qh(e){let t={};return{type:e.type,providersResolver:null,viewProvidersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:t,inputConfig:e.inputs||pa,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:e.signals===!0,selectors:e.selectors||ma,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,resolveHostDirectives:null,hostDirectives:null,controlDef:null,signalFormsInputPresence:null,inputs:Jh(e.inputs,t),outputs:Yh(e.outputs),debugInfo:null}}function $h(e){e.features?.forEach(t=>t(e))}function eg(e,t){return e?()=>{let n=typeof e==`function`?e():e,r=[];for(let e of n){let n=t(e);n!==null&&r.push(n)}return r}:null}function tg(e){let t=0,n=typeof e.consts==`function`?``:e.consts,r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,n,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(let e of r.join(`|`))t=Math.imul(31,t)+e.charCodeAt(0)<<0;return t+=2147483648,`c`+t}var ng=new xi(``),rg=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((e,t)=>{this.resolve=e,this.reject=t});appInits=C(ng,{optional:!0})??[];injector=C(Ts);constructor(){}runInitializers(){if(this.initialized)return;let e=[];for(let t of this.appInits){let n=Ka(this.injector,t);if(Vh(n))e.push(n);else if(Hh(n)){let t=new Promise((e,t)=>{n.subscribe({complete:e,error:t})});e.push(t)}}let t=()=>{this.done=!0,this.resolve()};Promise.all(e).then(()=>{t()}).catch(e=>{this.reject(e)}),e.length===0&&t(),this.initialized=!0}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})}return e})();function ig(e,t,n,r,i,a,o,s){if(n.firstCreatePass){e.mergedAttrs=tl(e.mergedAttrs,e.attrs);let t=e.tView=Mf(2,e,i,a,o,n.directiveRegistry,n.pipeRegistry,null,n.schemas,n.consts,null);n.queries!==null&&(n.queries.template(n,e),t.queries=n.queries.embeddedTView(e))}s&&(e.flags|=s),Vo(e,!1);let c=cg(n,t,e,r);xs()&&xf(n,t,c,e),Jl(c,t);let l=Rp(c,t,c,e);t[r+27]=l,zf(t,l),gh(l,e,t)}function ag(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;return t.firstCreatePass?(f=Yp(t,d,4,o||null,s||null),No()&&Om(t,e,f,ho(t.consts,l),ep),Vc(t,f)):f=t.data[d],ig(f,e,t,n,r,i,a,c),$a(f)&&Wf(t,e,f),l!=null&&Gf(e,f,u),f}function og(e,t,n,r,i,a,o,s,c,l,u){let d=n+27,f;if(t.firstCreatePass){if(f=Yp(t,d,4,o||null,s||null),l!=null){let e=ho(t.consts,l);f.localNames=[];for(let t=0;t{throw new ii(600,``)})}var pg=10,mg=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=C(Qs);afterRenderManager=C(Rd);zonelessEnabled=C(lc);rootEffectScheduler=C(dc);dirtyFlags=0;tracingSnapshot=null;allTestViews=new Set;autoDetectTestViews=new Set;includeAllTestViews=!1;afterTick=new $r;get allViews(){return[...(this.includeAllTestViews?this.allTestViews:this.autoDetectTestViews).keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];internalPendingTask=C(js);get isStable(){return this.internalPendingTask.hasPendingTasksObservable.pipe(ni(e=>!e))}constructor(){C(Fd,{optional:!0})}whenStable(){let e;return new Promise(t=>{e=this.isStable.subscribe({next:e=>{e&&t()}})}).finally(()=>{e.unsubscribe()})}_injector=C(Pa);_rendererFactory=null;get injector(){return this._injector}bootstrap(e,t){return this.bootstrapImpl(e,t)}bootstrapImpl(e,t,n=Ts.NULL){return this._injector.get(zs).run(()=>{if(zc(Ec.BootstrapComponentStart),!this._injector.get(rg).done)throw new ii(405,``);let r=ki(e),i=this._injector.get(Uh),a=new eh(r,i);this.componentTypes.push(e);let{hostElement:o,directives:s,bindings:c}=hg(t),l=o||a.selector,u=a.create(n,[],l,i.injector,s,c),d=u.location.nativeElement,f=u.injector.get(ug,null);return f?.registerApplication(d),u.onDestroy(()=>{this.detachView(u.hostView),gg(this.components,u),f?.unregisterApplication(d)}),this._loadComponent(u),zc(Ec.BootstrapComponentEnd,u),u})}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick(){zc(Ec.ChangeDetectionStart),this.tracingSnapshot===null?this.tickImpl():this.tracingSnapshot.run(Pd.CHANGE_DETECTION,this.tickImpl)}tickImpl=()=>{if(this._runningTick)throw zc(Ec.ChangeDetectionEnd),new ii(101,!1);let e=pn(null);try{this._runningTick=!0,this.synchronize()}finally{this._runningTick=!1,this.tracingSnapshot?.dispose(),this.tracingSnapshot=null,pn(e),this.afterTick.next(),zc(Ec.ChangeDetectionEnd)}};synchronize(){this._rendererFactory===null&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(om,null,{optional:!0}));let e=0;for(;this.dirtyFlags!==0&&e++yo(e))){this.dirtyFlags|=2;return}this.dirtyFlags&=-8}attachView(e){let t=e;this._views.push(t),t.attachToAppRef(this)}detachView(e){let t=e;gg(this._views,t),t.detachFromAppRef()}_loadComponent(e){this.attachView(e.hostView);try{this.tick()}catch(e){this.internalErrorHandler(e)}this.components.push(e),this._injector.get(dg,[]).forEach(t=>t(e))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(e=>e()),this._views.slice().forEach(e=>e.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(e){return this._destroyListeners.push(e),()=>gg(this._destroyListeners,e)}destroy(){if(this._destroyed)throw new ii(406,!1);let e=this._injector;e.destroy&&!e.destroyed&&e.destroy()}get viewCount(){return this._views.length}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})}return e})();function hg(e){return e===void 0||typeof e==`string`||e instanceof Element?{hostElement:e}:e}function gg(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}function j(e,t,n,r){let i=w();return pm(i,Xo(),t)&&(Lo(),tp(gs(),i,e,t,n,r)),j}function _g(e){if(Ld(`NgAnimateEnter`),!vd)return _g;let t=w();if(yd(t))return _g;let n=Ro(),r=t[9].get(zs);return Nd(kd(t),n,()=>vg(t,n,e,r)),Xd(t[9]),Zd(t[9],kd(t)),_g}function vg(e,t,n,r){let i=so(t,e),a=e[11],o=Ad(n),s=[],c=!1,l=e=>{if(jd(e)!==i)return;let t=e instanceof AnimationEvent?`animationend`:`transitionend`;r.runOutsideAngular(()=>{a.listen(i,t,u)})},u=e=>{jd(e)===i&&(Md(e,i)&&(c=!0),yg(e,i,a))};if(o&&o.length>0){r.runOutsideAngular(()=>{s.push(a.listen(i,`animationstart`,l)),s.push(a.listen(i,`transitionstart`,l))}),bd(i,o,s);for(let e of o)a.addClass(i,e);r.runOutsideAngular(()=>{requestAnimationFrame(()=>{if(!c&&(pd(i,Cd,vd),!Cd.has(i))){for(let e of o)a.removeClass(i,e);xd(i)}})})}}function yg(e,t,n){let r=Sd.get(t);if(jd(e)===t&&r&&Md(e,t)){e.stopPropagation();for(let e of r.classList)n.removeClass(t,e);xd(t)}}var bg=class{destroy(e){}updateValue(e,t){}swap(e,t){let n=Math.min(e,t),r=Math.max(e,t),i=this.detach(r);if(r-n>1){let e=this.detach(n);this.attach(n,i),this.attach(r,e)}else this.attach(n,i)}move(e,t){this.attach(t,this.detach(e))}};function xg(e,t,n,r,i){return e===n&&Object.is(t,r)?1:Object.is(i(e,t),i(n,r))?-1:0}function Sg(e,t,n,r){let i,a,o=0,s=e.length-1;if(Array.isArray(t)){pn(r);let c=t.length-1;for(pn(null);o<=s&&o<=c;){let r=e.at(o),l=t[o],u=xg(o,r,o,l,n);if(u!==0){u<0&&e.updateValue(o,l),o++;continue}let d=e.at(s),f=t[c],p=xg(s,d,c,f,n);if(p!==0){p<0&&e.updateValue(s,f),s--,c--;continue}let m=n(o,r),h=n(s,d),g=n(o,l);if(Object.is(g,h)){let t=n(c,f);Object.is(t,m)?(e.swap(o,s),e.updateValue(s,f),c--,s--):e.move(s,o),e.updateValue(o,l),o++;continue}if(i??=new Eg,a??=Tg(e,o,s,n),Cg(e,i,o,g))e.updateValue(o,l),o++,s++;else if(a.has(g))i.set(m,e.detach(o)),s--;else{let n=e.create(o,t[o]);e.attach(o,n),o++,s++}}for(;o<=c;)wg(e,i,n,o,t[o]),o++}else if(t!=null){pn(r);let c=t[Symbol.iterator]();pn(null);let l=c.next();for(;!l.done&&o<=s;){let t=e.at(o),r=l.value,u=xg(o,t,o,r,n);if(u!==0)u<0&&e.updateValue(o,r),o++,l=c.next();else{i??=new Eg,a??=Tg(e,o,s,n);let u=n(o,r);if(Cg(e,i,o,u))e.updateValue(o,r),o++,s++,l=c.next();else if(!a.has(u))e.attach(o,e.create(o,r)),o++,s++,l=c.next();else{let r=n(o,t);i.set(r,e.detach(o)),s--}}}for(;!l.done;)wg(e,i,n,e.length,l.value),l=c.next()}for(;o<=s;)e.destroy(e.detach(s--));i?.forEach(t=>{e.destroy(t)})}function Cg(e,t,n,r){return t!==void 0&&t.has(r)?(e.attach(n,t.get(r)),t.delete(r),!0):!1}function wg(e,t,n,r,i){if(Cg(e,t,r,n(r,i)))e.updateValue(r,i);else{let t=e.create(r,i);e.attach(r,t)}}function Tg(e,t,n,r){let i=new Set;for(let a=t;a<=n;a++)i.add(r(a,e.at(a)));return i}var Eg=class{kvMap=new Map;_vMap=void 0;has(e){return this.kvMap.has(e)}delete(e){if(!this.has(e))return!1;let t=this.kvMap.get(e);return this._vMap!==void 0&&this._vMap.has(t)?(this.kvMap.set(e,this._vMap.get(t)),this._vMap.delete(t)):this.kvMap.delete(e),!0}get(e){return this.kvMap.get(e)}set(e,t){if(this.kvMap.has(e)){let n=this.kvMap.get(e);this._vMap===void 0&&(this._vMap=new Map);let r=this._vMap;for(;r.has(n);)n=r.get(n);r.set(n,t)}else this.kvMap.set(e,t)}forEach(e){for(let[t,n]of this.kvMap)if(e(n,t),this._vMap!==void 0){let r=this._vMap;for(;r.has(n);)n=r.get(n),e(n,t)}}};function M(e,t,n,r,i,a,o,s){Ld(`NgControlFlow`);let c=w(),l=Lo();return og(c,l,e,t,n,r,i,ho(l.consts,a),256,o,s),Dg}function Dg(e,t,n,r,i,a,o,s){Ld(`NgControlFlow`);let c=w(),l=Lo();return og(c,l,e,t,n,r,i,ho(l.consts,a),512,o,s),Dg}function N(e,t){Ld(`NgControlFlow`);let n=w(),r=Xo(),i=n[r]===ed?-1:n[r],a=i===-1?void 0:Ng(n,27+i);if(pm(n,r,e)){let r=pn(null);try{if(a!==void 0&&Vp(a,0),e!==-1){let r=27+e,i=Ng(n,r),a=Rg(n[1],r),o=im(i,a,n);Bp(i,fp(n,a,t,{dehydratedView:o}),0,pp(a,o))}}finally{pn(r)}}else if(a!==void 0){let e=zp(a,0);e!==void 0&&(e[8]=t)}}var Og=class{lContainer;$implicit;$index;constructor(e,t,n){this.lContainer=e,this.$implicit=t,this.$index=n}get $count(){return this.lContainer.length-10}};function kg(e){return e}function Ag(e,t){return t}var jg=class{hasEmptyBlock;trackByFn;liveCollection;constructor(e,t,n){this.hasEmptyBlock=e,this.trackByFn=t,this.liveCollection=n}};function P(e,t,n,r,i,a,o,s,c,l,u,d,f){Ld(`NgControlFlow`);let p=w(),m=Lo(),h=c!==void 0,g=w(),_=new jg(h,s?o.bind(g[15][8]):o);g[27+e]=_,og(p,m,e+1,t,n,r,i,ho(m.consts,a),256),h&&og(p,m,e+2,c,l,u,d,ho(m.consts,f),512)}var Mg=class extends bg{lContainer;hostLView;templateTNode;operationsCounter=void 0;needsIndexUpdate=!1;constructor(e,t,n){super(),this.lContainer=e,this.hostLView=t,this.templateTNode=n}get length(){return this.lContainer.length-10}at(e){return this.getLView(e)[8].$implicit}attach(e,t){let n=t[6];this.needsIndexUpdate||=e!==this.length,Bp(this.lContainer,t,e,pp(this.templateTNode,n)),Pg(this.lContainer,e)}detach(e){return this.needsIndexUpdate||=e!==this.length-1,Fg(this.lContainer,e),Ig(this.lContainer,e)}create(e,t){let n=rm(this.lContainer,this.templateTNode.tView.ssrId);return fp(this.hostLView,this.templateTNode,new Og(this.lContainer,t,e),{dehydratedView:n})}destroy(e){ff(e[1],e)}updateValue(e,t){this.getLView(e)[8].$implicit=t}reset(){this.needsIndexUpdate=!1}updateIndexes(){if(this.needsIndexUpdate)for(let e=0;e0){let e=n[9];Jd(e,r),hd.delete(n[19]),r.detachedLeaveAnimationFns=void 0}}function Fg(e,t){if(e.length<=10)return;let n=e[10+t],r=n?n[26]:void 0;r&&r.leave&&r.leave.size>0&&(r.detachedLeaveAnimationFns=[])}function Ig(e,t){return Hp(e,t)}function Lg(e,t){return zp(e,t)}function Rg(e,t){return co(e,t)}function I(e,t,n){let r=w();return pm(r,Xo(),t)&&(Lo(),Jf(gs(),r,e,t,r[11],n)),I}function zg(e,t,n,r,i){sp(t,e,n,i?`class`:`style`,r)}function L(e,t,n,r){let i=w(),a=i[1],o=e+27,s=a.firstCreatePass?Hm(o,i,2,t,ep,No(),n,r):a.data[o];if(Qa(s)){let n=i[10].tracingService;if(n&&n.componentCreate){let o=a.data[s.directiveStart+s.componentOffset];return n.componentCreate(cm(o),()=>(Bg(e,t,i,s,r),L))}}return Bg(e,t,i,s,r),L}function Bg(e,t,n,r,i){if(ip(r,n,e,t,Hg),$a(r)){let e=n[1];Wf(e,n,r),uu(e,r,n)}i!=null&&Gf(n,r)}function R(){let e=Lo(),t=ap(Ro());return e.firstCreatePass&&Um(e,t),Fo(t)&&Io(),Mo(),t.classesWithoutHost!=null&&Xc(t)&&zg(e,t,w(),t.classesWithoutHost,!0),t.stylesWithoutHost!=null&&Zc(t)&&zg(e,t,w(),t.stylesWithoutHost,!1),R}function z(e,t,n,r){return L(e,t,n,r),R(),z}function B(e,t,n,r){let i=w(),a=i[1],o=e+27,s=a.firstCreatePass?Wm(o,a,2,t,n,r):a.data[o];return ip(s,i,e,t,Hg),r!=null&&Gf(i,s),B}function V(){return Fo(ap(Ro()))&&Io(),Mo(),V}function Vg(e,t,n,r){return B(e,t,n,r),V(),Vg}var Hg=(e,t,n,r,i)=>(Ss(!0),Tu(t[11],r,ys()));function Ug(e,t,n){let r=w(),i=r[1],a=e+27,o=i.firstCreatePass?Hm(a,r,8,`ng-container`,ep,No(),t,n):i.data[a];if(ip(o,r,e,`ng-container`,Kg),$a(o)){let e=r[1];Wf(e,r,o),uu(e,o,r)}return n!=null&&Gf(r,o),Ug}function Wg(){let e=Lo(),t=ap(Ro());return e.firstCreatePass&&Um(e,t),Wg}function Gg(e,t,n){return Ug(e,t,n),Wg(),Gg}var Kg=(e,t,n,r,i)=>(Ss(!0),wu(t[11],``));function H(){return w()}function qg(e,t,n){let r=w();return pm(r,Xo(),t)&&(Lo(),Yf(gs(),r,e,t,r[11],n)),qg}var Jg=void 0;function Yg(e){let t=Math.floor(Math.abs(e)),n=e.toString().replace(/^[^.]*\.?/,``).length;return t===1&&n===0?1:5}var Xg=[`en`,[[`a`,`p`],[`AM`,`PM`]],[[`AM`,`PM`]],[[`S`,`M`,`T`,`W`,`T`,`F`,`S`],[`Sun`,`Mon`,`Tue`,`Wed`,`Thu`,`Fri`,`Sat`],[`Sunday`,`Monday`,`Tuesday`,`Wednesday`,`Thursday`,`Friday`,`Saturday`],[`Su`,`Mo`,`Tu`,`We`,`Th`,`Fr`,`Sa`]],Jg,[[`J`,`F`,`M`,`A`,`M`,`J`,`J`,`A`,`S`,`O`,`N`,`D`],[`Jan`,`Feb`,`Mar`,`Apr`,`May`,`Jun`,`Jul`,`Aug`,`Sep`,`Oct`,`Nov`,`Dec`],[`January`,`February`,`March`,`April`,`May`,`June`,`July`,`August`,`September`,`October`,`November`,`December`]],Jg,[[`B`,`A`],[`BC`,`AD`],[`Before Christ`,`Anno Domini`]],0,[6,0],[`M/d/yy`,`MMM d, y`,`MMMM d, y`,`EEEE, MMMM d, y`],[`h:mm a`,`h:mm:ss a`,`h:mm:ss a z`,`h:mm:ss a zzzz`],[`{1}, {0}`,Jg,Jg,Jg],[`.`,`,`,`;`,`%`,`+`,`-`,`E`,`×`,`‰`,`∞`,`NaN`,`:`],[`#,##0.###`,`#,##0%`,`¤#,##0.00`,`#E0`],`USD`,`$`,`US Dollar`,{},`ltr`,Yg],Zg=Object.create(null);function Qg(e){let t=t_(e),n=$g(t);if(n)return n;let r=t.split(`-`)[0];if(n=$g(r),n)return n;if(r===`en`)return Xg;throw new ii(701,!1)}function $g(e){if(!(e in Zg)){let t=Gi.ng&&Gi.ng.common&&Gi.ng.common.locales&&Gi.ng.common.locales[e];return t!==void 0&&(Zg[e]=t),t}return Zg[e]}var e_={LocaleId:0,DayPeriodsFormat:1,DayPeriodsStandalone:2,DaysFormat:3,DaysStandalone:4,MonthsFormat:5,MonthsStandalone:6,Eras:7,FirstDayOfWeek:8,WeekendRange:9,DateFormat:10,TimeFormat:11,DateTimeFormat:12,NumberSymbols:13,NumberFormats:14,CurrencyCode:15,CurrencySymbol:16,CurrencyName:17,Currencies:18,Directionality:19,PluralCase:20,ExtraData:21};function t_(e){return e.toLowerCase().replace(/_/g,`-`)}var n_=`en-US`;function r_(e){typeof e==`string`&&e.toLowerCase().replace(/_/g,`-`)}function U(e,t,n){let r=w(),i=Lo(),a=Ro();return i_(i,r,r[11],a,e,t,n),U}function W(e,t,n){let r=w(),i=Lo(),a=Ro();return(a.type&3||n)&&ym(a,i,r,n,r[11],e,t,_m(a,r,t)),W}function i_(e,t,n,r,i,a,o){let s=!0,c=null;if((r.type&3||o)&&(c??=_m(r,t,a),ym(r,e,t,o,n,i,a,c)&&(s=!1)),s){let e=r.outputs?.[i],n=r.hostDirectiveOutputs?.[i];if(n&&n.length)for(let e=0;e>17&32767}function m_(e){return(e&2)==2}function h_(e,t){return e&131071|t<<17}function g_(e){return e|2}function __(e){return(e&131068)>>2}function v_(e,t){return e&-131069|t<<2}function y_(e){return(e&1)==1}function b_(e){return e|1}function x_(e,t,n,r,i,a){let o=a?t.classBindings:t.styleBindings,s=p_(o),c=__(o);e[r]=n;let l=!1,u;if(Array.isArray(n)){let e=n;u=e[1],(u===null||da(e,u)>0)&&(l=!0)}else u=n;if(i){if(c!==0){let t=p_(e[s+1]);e[r+1]=f_(t,s),t!==0&&(e[t+1]=v_(e[t+1],r)),e[s+1]=h_(e[s+1],r)}else e[r+1]=f_(s,0),s!==0&&(e[s+1]=v_(e[s+1],r)),s=r}else e[r+1]=f_(c,0),s===0?s=r:e[c+1]=v_(e[c+1],r),c=r;l&&(e[r+1]=g_(e[r+1])),C_(e,u,r,!0),C_(e,u,r,!1),S_(t,u,e,r,a),o=f_(s,c),a?t.classBindings=o:t.styleBindings=o}function S_(e,t,n,r,i){let a=i?e.residualClasses:e.residualStyles;a!=null&&typeof t==`string`&&da(a,t)>=0&&(n[r+1]=b_(n[r+1]))}function C_(e,t,n,r){let i=e[n+1],a=t===null,o=r?p_(i):__(i),s=!1;for(;o!==0&&(s===!1||a);){let n=e[o],i=e[o+1];w_(n,t)&&(s=!0,e[o+1]=r?b_(i):g_(i)),o=r?p_(i):__(i)}s&&(e[n+1]=r?g_(i):b_(i))}function w_(e,t){return e===null||t==null||(Array.isArray(e)?e[1]:e)===t?!0:Array.isArray(e)&&typeof t==`string`?da(e,t)>=0:!1}var T_={textEnd:0,key:0,keyEnd:0,value:0,valueEnd:0};function E_(e){return e.substring(T_.key,T_.keyEnd)}function D_(e){return k_(e),O_(e,A_(e,0,T_.textEnd))}function O_(e,t){let n=T_.textEnd;return n===t?-1:(t=T_.keyEnd=j_(e,T_.key=t,n),A_(e,t,n))}function k_(e){T_.key=0,T_.keyEnd=0,T_.value=0,T_.valueEnd=0,T_.textEnd=e.length}function A_(e,t,n){for(;t32;)t++;return t}function K(e,t,n){return P_(e,t,n,!1),K}function q(e,t){return P_(e,t,null,!0),q}function M_(e){F_(G_,N_,e,!0)}function N_(e,t){for(let n=D_(t);n>=0;n=O_(t,n))la(e,E_(t),!0)}function P_(e,t,n,r){let i=w(),a=Lo(),o=Zo(2);if(a.firstUpdatePass&&L_(a,e,o,r),t!==ed&&pm(i,o,t)){let s=a.data[ms()];q_(a,s,i,i[11],e,i[o+1]=X_(t,n),r,o)}}function F_(e,t,n,r){let i=Lo(),a=Zo(2);i.firstUpdatePass&&L_(i,null,a,r);let o=w();if(n!==ed&&pm(o,a,n)){let s=i.data[ms()];if(Z_(s,r)&&!I_(i,a)){let e=r?s.classesWithoutHost:s.stylesWithoutHost;e!==null&&(n=li(e,n||``)),zg(i,s,o,n,r)}else K_(i,s,o,o[11],o[a+1],o[a+1]=W_(e,t,n),r,a)}}function I_(e,t){return t>=e.expandoStartIndex}function L_(e,t,n,r){let i=e.data;if(i[n+1]===null){let a=i[ms()],o=I_(e,n);Z_(a,r)&&t===null&&!o&&(t=!1),t=R_(i,a,t,r),x_(i,a,t,n,o,r)}}function R_(e,t,n,r){let i=ns(e),a=r?t.residualClasses:t.residualStyles;if(i===null)(r?t.classBindings:t.styleBindings)===0&&(n=H_(null,e,t,n,r),n=U_(n,t.attrs,r),a=null);else{let o=t.directiveStylingLast;if(o===-1||e[o]!==i){if(n=H_(i,e,t,n,r),a===null){let n=z_(e,t,r);n!==void 0&&Array.isArray(n)&&(n=H_(null,e,t,n[1],r),n=U_(n,t.attrs,r),B_(e,t,r,n))}else a=V_(e,t,r)}}return a!==void 0&&(r?t.residualClasses=a:t.residualStyles=a),n}function z_(e,t,n){let r=n?t.classBindings:t.styleBindings;if(__(r)!==0)return e[p_(r)]}function B_(e,t,n,r){let i=n?t.classBindings:t.styleBindings;e[p_(i)]=r}function V_(e,t,n){let r,i=t.directiveEnd;for(let a=1+t.directiveStylingLast;a0;){let t=e[i],a=Array.isArray(t),c=a?t[1]:t,l=c===null,u=n[i+1];u===ed&&(u=l?ma:void 0);let d=l?ua(u,r):c===r?u:void 0;if(a&&!Y_(d)&&(d=ua(t,r)),Y_(d)&&(s=d,o))return s;let f=e[i+1];i=o?p_(f):__(f)}if(t!==null){let e=a?t.residualClasses:t.residualStyles;e!=null&&(s=ua(e,r))}return s}function Y_(e){return e!==void 0}function X_(e,t){return e==null||e===``||(typeof t==`string`?e=pu(e)+t:typeof e==`object`&&(e=ci(pu(e)))),e}function Z_(e,t){return!!(e.flags&(t?8:16))}function J(e,t=``){let n=w(),r=Lo(),i=e+27,a=r.firstCreatePass?Yp(r,i,1,t,null):r.data[i],o=Q_(r,n,a,t);n[i]=o,xs()&&xf(r,n,o,a),Vo(a,!1)}var Q_=(e,t,n,r)=>(Ss(!0),Su(t[11],r));function $_(e,t,n,r=``){return pm(e,Xo(),n)?t+Ni(n)+r:ed}function ev(e,t,n,r,i,a=``){let o=mm(e,Jo(),n,i);return Zo(2),o?t+Ni(n)+r+Ni(i)+a:ed}function tv(e,t,n,r,i,a,o,s=``){let c=hm(e,Jo(),n,i,o);return Zo(3),c?t+Ni(n)+r+Ni(i)+a+Ni(o)+s:ed}function nv(e,t,n,r,i,a,o,s,c,l=``){let u=gm(e,Jo(),n,i,o,c);return Zo(4),u?t+Ni(n)+r+Ni(i)+a+Ni(o)+s+Ni(c)+l:ed}function Y(e){return X(``,e),Y}function X(e,t,n){let r=w(),i=$_(r,e,t,n);return i!==ed&&av(r,ms(),i),X}function Z(e,t,n,r,i){let a=w(),o=ev(a,e,t,n,r,i);return o!==ed&&av(a,ms(),o),Z}function rv(e,t,n,r,i,a,o){let s=w(),c=tv(s,e,t,n,r,i,a,o);return c!==ed&&av(s,ms(),c),rv}function iv(e,t,n,r,i,a,o,s,c){let l=w(),u=nv(l,e,t,n,r,i,a,o,s,c);return u!==ed&&av(l,ms(),u),iv}function av(e,t,n){let r=oo(t,e);Cu(e[11],r,n)}function ov(e,t,n){Sc(t)&&(t=t());let r=w();return pm(r,Xo(),t)&&(Lo(),Jf(gs(),r,e,t,r[11],n)),ov}function sv(e,t){let n=Sc(e);return n&&e.set(t),n}function cv(e,t){let n=w(),r=Lo(),i=Ro();return i_(r,n,n[11],i,e,t),cv}var lv={};function uv(e){Ld(`NgLet`);let t=Lo(),n=w(),r=e+27;return Vo(Yp(t,r,128,null,null),!1),uo(t,n,r,lv),uv}function dv(e){return uo(Lo(),w(),ms(),e),e}function fv(e){let t=lo(Wo(),27+e);if(t===lv)throw new ii(314,!1);return t}function pv(e,t,n=``){return $_(w(),e,t,n)}function mv(e,t){let n=qo()+e,r=w();return r[n]===ed?dm(r,n,t()):fm(r,n)}function hv(e,t,n){return vv(w(),qo(),e,t,n)}function gv(e,t,n,r,i){return bv(w(),qo(),e,t,n,r,i)}function _v(e,t){let n=e[t];return n===ed?void 0:n}function vv(e,t,n,r,i,a){let o=t+n;return pm(e,o,i)?dm(e,o+1,a?r.call(a,i):r(i)):_v(e,o+1)}function yv(e,t,n,r,i,a,o){let s=t+n;return mm(e,s,i,a)?dm(e,s+2,o?r.call(o,i,a):r(i,a)):_v(e,s+2)}function bv(e,t,n,r,i,a,o,s){let c=t+n;return hm(e,c,i,a,o)?dm(e,c+3,s?r.call(s,i,a,o):r(i,a,o)):_v(e,c+3)}function xv(e,t){let n=Lo(),r,i=e+27;n.firstCreatePass?(r=Sv(t,n.pipeRegistry),n.data[i]=r,r.onDestroy&&(n.destroyHooks??=[]).push(i,r.onDestroy)):r=n.data[i];let a=r.factory||(r.factory=ta(r.type,!0)),o=Ui(Dm);try{let e=cl(!1),t=a();return cl(e),uo(n,w(),i,t),t}finally{Ui(o)}}function Sv(e,t){if(t)for(let n=t.length-1;n>=0;n--){let r=t[n];if(e===r.name)return r}}function Cv(e,t,n){let r=e+27,i=w(),a=lo(i,r);return Tv(i,r)?vv(i,qo(),t,a.transform,n,a):a.transform(n)}function wv(e,t,n,r){let i=e+27,a=w(),o=lo(a,i);return Tv(a,i)?yv(a,qo(),t,o.transform,n,r,o):o.transform(n,r)}function Tv(e,t){return e[1].data[t].pure}function Ev(e,t){return Jp(e,t)}var Dv=(()=>{class e{applicationErrorHandler=C(Qs);appRef=C(mg);taskService=C(js);ngZone=C(zs);zonelessEnabled=C(lc);tracing=C(Fd,{optional:!0});zoneIsDefined=typeof Zone<`u`&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new _r;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(Ls):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(C(uc,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{let e=this.taskService.add();if(!this.runningTick&&(this.cleanup(),!this.zonelessEnabled||this.appRef.includeAllTestViews)){this.taskService.remove(e);return}this.switchToMicrotaskScheduler(),this.taskService.remove(e)})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()}))}switchToMicrotaskScheduler(){this.ngZone.runOutsideAngular(()=>{let e=this.taskService.add();this.useMicrotaskScheduler=!0,queueMicrotask(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(e)})})}notify(e){if(!this.zonelessEnabled&&e===5)return;switch(e){case 0:case 2:this.appRef.dirtyFlags|=2;break;case 3:case 4:case 5:case 1:this.appRef.dirtyFlags|=4;break;case 6:this.appRef.dirtyFlags|=2;break;case 12:this.appRef.dirtyFlags|=16;break;case 13:this.appRef.dirtyFlags|=2;break;case 11:break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick())return;let t=this.useMicrotaskScheduler?Fs:Ps;this.pendingRenderTaskId=this.taskService.add(),this.cancelScheduledCallback=this.scheduleInRootZone?Zone.root.run(()=>t(()=>this.tick())):this.ngZone.runOutsideAngular(()=>t(()=>this.tick()))}shouldScheduleTick(){return!(this.appRef.destroyed||this.pendingRenderTaskId!==null||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(`isAngularZone_ID`+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(this.appRef.dirtyFlags===0){this.cleanup();return}!this.zonelessEnabled&&this.appRef.dirtyFlags&7&&(this.appRef.dirtyFlags|=1);let e=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(e){this.applicationErrorHandler(e)}finally{this.taskService.remove(e),this.cleanup()}}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,this.pendingRenderTaskId!==null){let e=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(e)}}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})}return e})();function Ov(){return[{provide:cc,useExisting:Dv},{provide:zs,useClass:qs},{provide:lc,useValue:!0}]}function kv(){return typeof $localize<`u`&&$localize.locale||`en-US`}var Av=new xi(``,{factory:()=>C(Av,{optional:!0,skipSelf:!0})||kv()}),jv=class{destroyed=!1;listeners=null;errorHandler=C(Zs,{optional:!0});isEmitting=!1;hasNullListeners=!1;destroyRef=C(Ds);constructor(){this.destroyRef.onDestroy(()=>{this.destroyed=!0,this.listeners=null})}subscribe(e){if(this.destroyed)throw new ii(953,!1);return(this.listeners??=[]).push(e),{unsubscribe:()=>{let t=this.listeners?this.listeners.indexOf(e):-1;t>-1&&(this.isEmitting?(this.hasNullListeners=!0,this.listeners[t]=null):this.listeners.splice(t,1))}}}emit(e){if(this.destroyed){console.warn(oi(953,!1));return}if(this.listeners===null)return;this.isEmitting=!0;let t=pn(null);try{for(let t of this.listeners)try{t!==null&&t(e)}catch(e){this.errorHandler?.handleError(e)}}finally{this.hasNullListeners&&(this.hasNullListeners=!1,this.listeners&&Mv(this.listeners)),pn(t),this.isEmitting=!1}}};function Mv(e){let t=e.length-1;for(;t>-1;)e[t]===null&&e.splice(t,1),t--}function Q(e,t){return Pn(e,t?.equal)}function Nv(e){return sr(e)}(class e extends Error{_brand;constructor(e){super(e)}static IDLE=new e(`IDLE`);static LOADING=new e(`LOADING`)});var Pv=e=>e;function Fv(e,t){return typeof e==`function`?Iv(rr(e,Pv,t?.equal),t?.debugName,t?.set):Iv(rr(e.source,e.computation,e.equal),e.debugName,e.set)}function Iv(e,t,n){let r=e[fn],i=e;if(n!==void 0){let t=e=>ir(r,e);i.set=e=>n(e,t),i.update=r=>n(r(Nv(e)),t)}else i.set=e=>ir(r,e),i.update=e=>ar(r,e);return i.asReadonly=ec.bind(e),i}function Lv(e,t){let n=Object.create(wc);n.value=e,n.transformFn=t?.transform;function r(){if(gn(n),n.value===Cc)throw new ii(-950,null);return n.value}return r[fn]=n,r}function Rv(e){return new jv}function zv(e,t){return Lv(e,t)}function Bv(e){return Lv(Cc,e)}var $=(zv.required=Bv,zv);function Vv(e,t){let n=Object.create(wc),r=new jv;n.value=e;function i(){return gn(n),Hv(n.value),n.value}return i[fn]=n,i.asReadonly=ec.bind(i),i.set=e=>{n.equal(n.value,e)||(Kn(n,e),r.emit(e))},i.update=e=>{Hv(n.value),i.set(e(n.value))},i.subscribe=r.subscribe.bind(r),i.destroyRef=r.destroyRef,i}function Hv(e){if(e===Cc)throw new ii(952,!1)}function Uv(e,t){return Vv(e,t)}function Wv(e){return Vv(Cc,e)}var Gv=(Uv.required=Wv,Uv);function Kv(e,t){return Lh(t)}function qv(e,t){return Rh(t)}var Jv=(Kv.required=qv,Kv),Yv=new xi(``),Xv=new xi(``);function Zv(e){return!e.moduleRef}function Qv(e){let t=Zv(e)?e.r3Injector:e.moduleRef.injector,n=t.get(zs);return n.run(()=>{Zv(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();let r=t.get(Qs),i;if(n.runOutsideAngular(()=>{i=n.onError.subscribe({next:r})}),Zv(e)){let n=()=>t.destroy(),r=e.platformInjector.get(Yv);r.add(n),t.onDestroy(()=>{i.unsubscribe(),r.delete(n)})}else{let t=()=>e.moduleRef.destroy(),n=e.platformInjector.get(Yv);n.add(t),e.moduleRef.onDestroy(()=>{gg(e.allPlatformModules,e.moduleRef),i.unsubscribe(),n.delete(t)})}return ey(r,n,()=>{let n=t.get(js),r=n.add(),i=t.get(rg);return i.runInitializers(),i.donePromise.then(()=>{if(r_(t.get(Av,n_)||`en-US`),!t.get(Xv,!0))return Zv(e)?t.get(mg):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if(Zv(e)){let n=t.get(mg);return e.rootComponent!==void 0&&n.bootstrap(e.rootComponent),n}return $v?.(e.moduleRef,e.allPlatformModules),e.moduleRef}).finally(()=>void n.remove(r))})})}var $v;function ey(e,t,n){try{let r=n();return Vh(r)?r.catch(n=>{throw t.runOutsideAngular(()=>e(n)),n}):r}catch(n){throw t.runOutsideAngular(()=>e(n)),n}}var ty=null;function ny(e=[],t){return Ts.create({name:t,providers:[{provide:ka,useValue:`platform`},{provide:Yv,useValue:new Set([()=>ty=null])},...e]})}function ry(e=[]){if(ty)return ty;let t=ny(e);return ty=t,fg(),iy(t),t}function iy(e){let t=e.get(rc,null);Ka(e,()=>{t?.forEach(e=>e())})}function ay(e){let{rootComponent:t,appProviders:n,platformProviders:r,platformRef:i}=e;zc(Ec.BootstrapApplicationStart);try{let e=i?.injector??ry(r);return Qv({r3Injector:new Wh({providers:[Ov(),$s,...n||[]],parent:e,debugName:``,runEnvironmentInitializers:!1}).injector,platformInjector:e,rootComponent:t})}catch(e){return Promise.reject(e)}finally{zc(Ec.BootstrapApplicationEnd)}}function oy(e){return typeof e==`boolean`?e:e!=null&&e!==`false`}var sy=Symbol(`NOT_SET`),cy=new Set,ly={...Jn,kind:`afterRenderEffectPhase`,consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,value:sy,cleanup:null,consumerMarkedDirty(){if(this.sequence.impl.executing){if(this.sequence.lastPhase===null||this.sequence.lastPhase(gn(r),r.value),r.signal[fn]=r,r.registerCleanupFn=e=>(r.cleanup??=new Set).add(e),this.nodes[e]=r,this.hooks[e]=e=>r.phaseFn(e)}}afterRun(){super.afterRun(),this.lastPhase=null}destroy(){if(this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();super.destroy();for(let e of this.nodes)if(e)try{for(let t of e.cleanup??cy)t()}finally{On(e)}}};function dy(e,t){let n=t?.injector??C(Ts),r=n.get(cc),i=n.get(Rd),a=n.get(Fd,null,{optional:!0});i.impl??=n.get(Bd);let o=e;typeof o==`function`&&(o={mixedReadWrite:e});let s=n.get(oc,null,{optional:!0}),c=new uy(i.impl,[o.earlyRead,o.write,o.mixedReadWrite,o.read],s?.view,r,n,a?.snapshot(null));return i.impl.register(c),c}var fy=null;function py(){return fy}function my(e){fy??=e}var hy=class{},gy=(function(e){return e[e.Format=0]=`Format`,e[e.Standalone=1]=`Standalone`,e})(gy||{}),_y=(function(e){return e[e.Narrow=0]=`Narrow`,e[e.Abbreviated=1]=`Abbreviated`,e[e.Wide=2]=`Wide`,e[e.Short=3]=`Short`,e})(_y||{}),vy=(function(e){return e[e.Short=0]=`Short`,e[e.Medium=1]=`Medium`,e[e.Long=2]=`Long`,e[e.Full=3]=`Full`,e})(vy||{}),yy={Decimal:0,Group:1,List:2,PercentSign:3,PlusSign:4,MinusSign:5,Exponential:6,SuperscriptingExponent:7,PerMille:8,Infinity:9,NaN:10,TimeSeparator:11,CurrencyDecimal:12,CurrencyGroup:13};function by(e){return Qg(e)[e_.LocaleId]}function xy(e,t,n){let r=Qg(e);return My(My([r[e_.DayPeriodsFormat],r[e_.DayPeriodsStandalone]],t),n)}function Sy(e,t,n){let r=Qg(e);return My(My([r[e_.DaysFormat],r[e_.DaysStandalone]],t),n)}function Cy(e,t,n){let r=Qg(e);return My(My([r[e_.MonthsFormat],r[e_.MonthsStandalone]],t),n)}function wy(e,t){let n=Qg(e)[e_.Eras];return My(n,t)}function Ty(e,t){return My(Qg(e)[e_.DateFormat],t)}function Ey(e,t){return My(Qg(e)[e_.TimeFormat],t)}function Dy(e,t){let n=Qg(e)[e_.DateTimeFormat];return My(n,t)}function Oy(e,t){let n=Qg(e),r=n[e_.NumberSymbols][t];if(r===void 0){if(t===yy.CurrencyDecimal)return n[e_.NumberSymbols][yy.Decimal];if(t===yy.CurrencyGroup)return n[e_.NumberSymbols][yy.Group]}return r}function ky(e){if(!e[e_.ExtraData])throw new ii(2303,!1)}function Ay(e){let t=Qg(e);return ky(t),(t[e_.ExtraData][2]||[]).map(e=>typeof e==`string`?Ny(e):[Ny(e[0]),Ny(e[1])])}function jy(e,t,n){let r=Qg(e);return ky(r),My(My([r[e_.ExtraData][0],r[e_.ExtraData][1]],t)||[],n)||[]}function My(e,t){for(let n=t;n>-1;n--)if(e[n]!==void 0)return e[n];throw new ii(2304,!1)}function Ny(e){let[t,n]=e.split(`:`);return{hours:+t,minutes:+n}}var Py=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,Fy=Object.create(null),Iy=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/,Ly=256;function Ry(e,t,n,r){let i=sb(e);zy(t),t=Vy(n,t)||t;let a=[],o;for(;t;)if(o=Iy.exec(t),o){a=a.concat(o.slice(1));let e=a.pop();if(!e)break;t=e}else{a.push(t);break}let s=i.getTimezoneOffset();r&&(s=ib(r,s),i=ob(i,r));let c=``;return a.forEach(e=>{let t=rb(e);c+=t?t(i,n,s):e===`''`?`'`:e.replace(/(^'|'$)/g,``).replace(/''/g,`'`)}),c}function zy(e){if(e.length>Ly)throw new ii(2300,!1)}function By(e,t,n){let r=new Date(0);return r.setFullYear(e,t,n),r.setHours(0,0,0),r}function Vy(e,t){let n=by(e);if(Fy[n]??=Object.create(null),Fy[n][t])return Fy[n][t];let r=``;switch(t){case`shortDate`:r=Ty(e,vy.Short);break;case`mediumDate`:r=Ty(e,vy.Medium);break;case`longDate`:r=Ty(e,vy.Long);break;case`fullDate`:r=Ty(e,vy.Full);break;case`shortTime`:r=Ey(e,vy.Short);break;case`mediumTime`:r=Ey(e,vy.Medium);break;case`longTime`:r=Ey(e,vy.Long);break;case`fullTime`:r=Ey(e,vy.Full);break;case`short`:let t=Vy(e,`shortTime`),n=Vy(e,`shortDate`);r=Hy(Dy(e,vy.Short),[t,n]);break;case`medium`:let i=Vy(e,`mediumTime`),a=Vy(e,`mediumDate`);r=Hy(Dy(e,vy.Medium),[i,a]);break;case`long`:let o=Vy(e,`longTime`),s=Vy(e,`longDate`);r=Hy(Dy(e,vy.Long),[o,s]);break;case`full`:let c=Vy(e,`fullTime`),l=Vy(e,`fullDate`);r=Hy(Dy(e,vy.Full),[c,l])}return r&&(Fy[n][t]=r),r}function Hy(e,t){return t&&(e=e.replace(/\{([^}]+)}/g,function(e,n){return Object.hasOwn(t,n)?t[n]:e})),e}function Uy(e,t,n=`-`,r,i){let a=``;(e<0||i&&e<=0)&&(i?e=-e+1:(e=-e,a=n));let o=String(e);for(;o.length0||s>-n)&&(s+=n),e===3)s===0&&n===-12&&(s=12);else if(e===6)return Wy(s,t);let c=Oy(o,yy.MinusSign);return Uy(s,t,c,r,i)}}function Ky(e,t){switch(e){case 0:return t.getFullYear();case 1:return t.getMonth();case 2:return t.getDate();case 3:return t.getHours();case 4:return t.getMinutes();case 5:return t.getSeconds();case 6:return t.getMilliseconds();case 7:return t.getDay();default:throw new ii(2301,!1)}}function qy(e,t,n=gy.Format,r=!1){return function(i,a){return Jy(i,a,e,t,n,r)}}function Jy(e,t,n,r,i,a){switch(n){case 2:return Cy(t,i,r)[e.getMonth()];case 1:return Sy(t,i,r)[e.getDay()];case 0:let n=e.getHours(),o=e.getMinutes();if(a){let e=Ay(t),a=jy(t,i,r),s=e.findIndex(e=>{if(Array.isArray(e)){let[t,r]=e,i=n>=t.hours&&o>=t.minutes,a=n0?Math.floor(i/60):Math.ceil(i/60);switch(e){case 0:return(i>=0?`+`:``)+Uy(o,2,a)+Uy(Math.abs(i%60),2,a);case 1:return`GMT`+(i>=0?`+`:``)+Uy(o,1,a);case 2:return`GMT`+(i>=0?`+`:``)+Uy(o,2,a)+`:`+Uy(Math.abs(i%60),2,a);case 3:return r===0?`Z`:(i>=0?`+`:``)+Uy(o,2,a)+`:`+Uy(Math.abs(i%60),2,a);default:throw new ii(2310,!1)}}}var Xy=0,Zy=4;function Qy(e){let t=By(e,Xy,1).getDay();return By(e,0,1+(t<=Zy?Zy:11)-t)}function $y(e){let t=e.getDay(),n=t===0?-3:Zy-t;return By(e.getFullYear(),e.getMonth(),e.getDate()+n)}function eb(e,t=!1){return function(n,r){let i;if(t){let e=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,t=n.getDate();i=1+Math.floor((t+e)/7)}else{let e=$y(n),t=Qy(e.getFullYear()),r=e.getTime()-t.getTime();i=1+Math.round(r/6048e5)}return Uy(i,e,Oy(r,yy.MinusSign))}}function tb(e,t=!1){return function(n,r){return Uy($y(n).getFullYear(),e,Oy(r,yy.MinusSign),t)}}var nb=Object.create(null);function rb(e){if(nb[e])return nb[e];let t;switch(e){case`G`:case`GG`:case`GGG`:t=qy(3,_y.Abbreviated);break;case`GGGG`:t=qy(3,_y.Wide);break;case`GGGGG`:t=qy(3,_y.Narrow);break;case`y`:t=Gy(0,1,0,!1,!0);break;case`yy`:t=Gy(0,2,0,!0,!0);break;case`yyy`:t=Gy(0,3,0,!1,!0);break;case`yyyy`:t=Gy(0,4,0,!1,!0);break;case`Y`:t=tb(1);break;case`YY`:t=tb(2,!0);break;case`YYY`:t=tb(3);break;case`YYYY`:t=tb(4);break;case`M`:case`L`:t=Gy(1,1,1);break;case`MM`:case`LL`:t=Gy(1,2,1);break;case`MMM`:t=qy(2,_y.Abbreviated);break;case`MMMM`:t=qy(2,_y.Wide);break;case`MMMMM`:t=qy(2,_y.Narrow);break;case`LLL`:t=qy(2,_y.Abbreviated,gy.Standalone);break;case`LLLL`:t=qy(2,_y.Wide,gy.Standalone);break;case`LLLLL`:t=qy(2,_y.Narrow,gy.Standalone);break;case`w`:t=eb(1);break;case`ww`:t=eb(2);break;case`W`:t=eb(1,!0);break;case`d`:t=Gy(2,1);break;case`dd`:t=Gy(2,2);break;case`c`:case`cc`:t=Gy(7,1);break;case`ccc`:t=qy(1,_y.Abbreviated,gy.Standalone);break;case`cccc`:t=qy(1,_y.Wide,gy.Standalone);break;case`ccccc`:t=qy(1,_y.Narrow,gy.Standalone);break;case`cccccc`:t=qy(1,_y.Short,gy.Standalone);break;case`E`:case`EE`:case`EEE`:t=qy(1,_y.Abbreviated);break;case`EEEE`:t=qy(1,_y.Wide);break;case`EEEEE`:t=qy(1,_y.Narrow);break;case`EEEEEE`:t=qy(1,_y.Short);break;case`a`:case`aa`:case`aaa`:t=qy(0,_y.Abbreviated);break;case`aaaa`:t=qy(0,_y.Wide);break;case`aaaaa`:t=qy(0,_y.Narrow);break;case`b`:case`bb`:case`bbb`:t=qy(0,_y.Abbreviated,gy.Standalone,!0);break;case`bbbb`:t=qy(0,_y.Wide,gy.Standalone,!0);break;case`bbbbb`:t=qy(0,_y.Narrow,gy.Standalone,!0);break;case`B`:case`BB`:case`BBB`:t=qy(0,_y.Abbreviated,gy.Format,!0);break;case`BBBB`:t=qy(0,_y.Wide,gy.Format,!0);break;case`BBBBB`:t=qy(0,_y.Narrow,gy.Format,!0);break;case`h`:t=Gy(3,1,-12);break;case`hh`:t=Gy(3,2,-12);break;case`H`:t=Gy(3,1);break;case`HH`:t=Gy(3,2);break;case`m`:t=Gy(4,1);break;case`mm`:t=Gy(4,2);break;case`s`:t=Gy(5,1);break;case`ss`:t=Gy(5,2);break;case`S`:t=Gy(6,1);break;case`SS`:t=Gy(6,2);break;case`SSS`:t=Gy(6,3);break;case`Z`:case`ZZ`:case`ZZZ`:t=Yy(0);break;case`ZZZZZ`:t=Yy(3);break;case`O`:case`OO`:case`OOO`:case`z`:case`zz`:case`zzz`:t=Yy(1);break;case`OOOO`:case`ZZZZ`:case`zzzz`:t=Yy(2);break;default:return null}return nb[e]=t,t}function ib(e,t){e=e.replace(/:/g,``);let n=Date.parse(`Jan 01, 1970 00:00:00 `+e)/6e4;return isNaN(n)?t:n}function ab(e,t){return e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+t),e}function ob(e,t,n){let r=e.getTimezoneOffset();return ab(e,-1*(ib(t,r)-r))}function sb(e){if(lb(e))return e;if(typeof e==`number`&&!isNaN(e))return new Date(e);if(typeof e==`string`){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){let[t,n=1,r=1]=e.split(`-`).map(e=>+e);return By(t,n-1,r)}let t=parseFloat(e);if(!isNaN(e-t))return new Date(t);let n;if(n=e.match(Py))return cb(n)}let t=new Date(e);if(!lb(t))throw new ii(2311,!1);return t}function cb(e){let t=new Date(0),n=0,r=0,i=e[8]?t.setUTCFullYear:t.setFullYear,a=e[8]?t.setUTCHours:t.setHours;e[9]&&(n=Number(e[9]+e[10]),r=Number(e[9]+e[11])),i.call(t,Number(e[1]),Number(e[2])-1,Number(e[3]));let o=Number(e[4]||0)-n,s=Number(e[5]||0)-r,c=Number(e[6]||0),l=Math.floor(parseFloat(`0.`+(e[7]||0))*1e3);return a.call(t,o,s,c,l),t}function lb(e){return e instanceof Date&&!isNaN(e.valueOf())}var ub=(()=>{class e{_viewContainerRef;_viewRef=null;ngTemplateOutletContext=null;ngTemplateOutlet=null;ngTemplateOutletInjector=null;injector=C(Ts);constructor(e){this._viewContainerRef=e}ngOnChanges(e){if(this._shouldRecreateView(e)){let e=this._viewContainerRef;if(this._viewRef&&e.remove(e.indexOf(this._viewRef)),!this.ngTemplateOutlet){this._viewRef=null;return}let t=this._createContextForwardProxy();this._viewRef=e.createEmbeddedView(this.ngTemplateOutlet,t,{injector:this._getInjector()})}}_getInjector(){return this.ngTemplateOutletInjector===`outlet`?this.injector:this.ngTemplateOutletInjector??void 0}_shouldRecreateView(e){return!!e.ngTemplateOutlet||!!e.ngTemplateOutletInjector}_createContextForwardProxy(){return new Proxy({},{set:(e,t,n)=>this.ngTemplateOutletContext?Reflect.set(this.ngTemplateOutletContext,t,n):!1,get:(e,t,n)=>{if(this.ngTemplateOutletContext)return Reflect.get(this.ngTemplateOutletContext,t,n)}})}static ɵfac=function(t){return new(t||e)(Dm(sh))};static ɵdir=Xh({type:e,selectors:[[``,`ngTemplateOutlet`,``]],inputs:{ngTemplateOutletContext:`ngTemplateOutletContext`,ngTemplateOutlet:`ngTemplateOutlet`,ngTemplateOutletInjector:`ngTemplateOutletInjector`},features:[Ac]})}return e})();function db(e,t){return new ii(2100,!1)}var fb=`mediumDate`,pb=new xi(``),mb=new xi(``),hb=(()=>{class e{locale;defaultTimezone;defaultOptions;constructor(e,t,n){this.locale=e,this.defaultTimezone=t,this.defaultOptions=n}transform(t,n,r,i){if(t==null||t===``||t!==t)return null;try{let e=n??this.defaultOptions?.dateFormat??fb,a=r??this.defaultOptions?.timezone??this.defaultTimezone??void 0;return Ry(t,e,i||this.locale,a)}catch(t){throw db(e,t.message)}}static ɵfac=function(t){return new(t||e)(Dm(Av,16),Dm(pb,24),Dm(mb,24))};static ɵpipe=Zh({name:`date`,type:e,pure:!0})}return e})(),gb=(()=>{class e{transform(e){return JSON.stringify(e,null,2)}static ɵfac=function(t){return new(t||e)};static ɵpipe=Zh({name:`json`,type:e,pure:!1})}return e})();function _b(e,t){t=encodeURIComponent(t);for(let n of e.split(`;`)){let e=n.indexOf(`=`),[r,i]=e==-1?[n,``]:[n.slice(0,e),n.slice(e+1)];if(r.trim()!==t)continue;let a=i;try{a=decodeURIComponent(i)}catch{}return a.length>1&&a[0]===`"`&&a[a.length-1]===`"`&&(a=a.slice(1,-1)),a}return null}var vb=`browser`,yb=class{_doc;constructor(e){this._doc=e}manager},bb=(()=>{class e extends yb{constructor(e){super(e)}supports(e){return!0}addEventListener(e,t,n,r){return e.addEventListener(t,n,r),()=>this.removeEventListener(e,t,n,r)}removeEventListener(e,t,n,r){return e.removeEventListener(t,n,r)}static ɵfac=function(t){return new(t||e)(Xi(Es))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),xb=new xi(``),Sb=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(e,t){this._zone=t,e.forEach(e=>{e.manager=this});let n=e.filter(e=>!(e instanceof bb));this._plugins=n.slice().reverse();let r=e.find(e=>e instanceof bb);r&&this._plugins.push(r)}addEventListener(e,t,n,r){return this._findPluginFor(t).addEventListener(e,t,n,r)}getZone(){return this._zone}_findPluginFor(e){let t=this._eventNameToPlugin.get(e);if(t)return t;if(t=this._plugins.find(t=>t.supports(e)),!t)throw new ii(-5101,!1);return this._eventNameToPlugin.set(e,t),t}static ɵfac=function(t){return new(t||e)(Xi(xb),Xi(zs))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),Cb=`ng-app-id`;function wb(e){for(let t of e)t.remove()}function Tb(e,t){let n=t.createElement(`style`);return n.textContent=e,n}function Eb(e,t,n,r){let i=e.head?.querySelectorAll(`style[${Cb}="${t}"],link[${Cb}="${t}"]`);if(!i||i.length===0)return!1;for(let e of i)e.removeAttribute(Cb),e instanceof HTMLLinkElement?r.set(e.href.slice(e.href.lastIndexOf(`/`)+1),{usage:0,elements:[e]}):e.textContent&&n.set(e.textContent,{usage:0,elements:[e]});return!0}function Db(e,t){let n=t.createElement(`link`);return n.setAttribute(`rel`,`stylesheet`),n.setAttribute(`href`,e),n}var Ob=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;constructor(e,t,n,r={}){this.doc=e,this.appId=t,this.nonce=n,Eb(e,t,this.inline,this.external)&&this.hosts.add(e.head)}addStyles(e,t){for(let t of e)this.addUsage(t,this.inline,Tb);t?.forEach(e=>this.addUsage(e,this.external,Db))}removeStyles(e,t){for(let t of e)this.removeUsage(t,this.inline);t?.forEach(e=>this.removeUsage(e,this.external))}addUsage(e,t,n){let r=t.get(e);r?r.usage++:t.set(e,{usage:1,elements:[...this.hosts].map(t=>this.addElement(t,n(e,this.doc)))})}removeUsage(e,t){let n=t.get(e);n&&(n.usage--,n.usage<=0&&(wb(n.elements),t.delete(e)))}ngOnDestroy(){for(let[,{elements:e}]of[...this.inline,...this.external])wb(e);this.hosts.clear()}addHost(e){if(!this.hosts.has(e)){this.hosts.add(e);for(let[t,{elements:n}]of this.inline)n.push(this.addElement(e,Tb(t,this.doc)));for(let[t,{elements:n}]of this.external)n.push(this.addElement(e,Db(t,this.doc)))}}removeHost(e){this.hosts.delete(e);for(let t of[...this.inline.values(),...this.external.values()]){let n=[];for(let r of t.elements)r.parentNode===e?r.remove():n.push(r);t.elements=n}}addElement(e,t){return this.nonce&&t.setAttribute(`nonce`,this.nonce),e.appendChild(t)}static ɵfac=function(t){return new(t||e)(Xi(Es),Xi(tc),Xi(ac,8),Xi(ic))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),kb={svg:`http://www.w3.org/2000/svg`,xhtml:`http://www.w3.org/1999/xhtml`,xlink:`http://www.w3.org/1999/xlink`,xml:`http://www.w3.org/XML/1998/namespace`,xmlns:`http://www.w3.org/2000/xmlns/`,math:`http://www.w3.org/1998/Math/MathML`},Ab=/%COMP%/g,jb=`%COMP%`,Mb=`_nghost-${jb}`,Nb=`_ngcontent-${jb}`,Pb=!0,Fb=new xi(``,{factory:()=>Pb}),Ib=new xi(``);function Lb(e){return Nb.replace(Ab,e)}function Rb(e){return Mb.replace(Ab,e)}function zb(e,t){return t.map(t=>t.replace(Ab,e))}var Bb=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;cssVarNamespace;constructor(e,t,n,r,i,a,o=null,s=null,c=null){this.eventManager=e,this.sharedStylesHost=t,this.appId=n,this.removeStylesOnCompDestroy=r,this.doc=i,this.ngZone=a,this.nonce=o,this.tracingService=s,this.cssVarNamespace=c??``,this.defaultRenderer=new Vb(e,i,a,this.tracingService,this.cssVarNamespace)}createRenderer(e,t){if(!e||!t)return this.defaultRenderer;let n=this.getOrCreateRenderer(e,t);return n instanceof Gb?n.applyToHost(e):n instanceof Wb&&n.applyStyles(),n}getOrCreateRenderer(e,t){let n=this.rendererByCompId,r=n.get(t.id);if(!r){let i=this.doc,a=this.ngZone,o=this.eventManager,s=this.sharedStylesHost,c=this.removeStylesOnCompDestroy,l=this.tracingService;switch(t.encapsulation){case du.Emulated:r=new Gb(o,s,t,this.appId,c,i,a,l,this.cssVarNamespace);break;case du.ShadowDom:return new Ub(o,e,t,i,a,this.nonce,l,this.cssVarNamespace,s);case du.ExperimentalIsolatedShadowDom:return new Ub(o,e,t,i,a,this.nonce,l,this.cssVarNamespace);default:r=new Wb(o,s,t,c,i,a,l,this.cssVarNamespace)}n.set(t.id,r)}return r}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(e){this.rendererByCompId.delete(e)}static ɵfac=function(t){return new(t||e)(Xi(Sb),Xi(Tm),Xi(tc),Xi(Fb),Xi(Es),Xi(zs),Xi(ac),Xi(Fd,8),Xi(Ib,8))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})(),Vb=class{eventManager;doc;ngZone;tracingService;cssVarNamespace;data=Object.create(null);throwOnSyntheticProps=!0;constructor(e,t,n,r,i=``){this.eventManager=e,this.doc=t,this.ngZone=n,this.tracingService=r,this.cssVarNamespace=i}destroy(){}destroyNode=null;createElement(e,t){return t?this.doc.createElementNS(kb[t]||t,e):this.doc.createElement(e)}createComment(e){return this.doc.createComment(e)}createText(e){return this.doc.createTextNode(e)}appendChild(e,t){(Hb(e)?e.content:e).appendChild(t)}insertBefore(e,t,n){if(e){let r=Hb(e)?e.content:e;if(n!=null&&n.parentNode!==r)throw new ii(-5106,!1);r.insertBefore(t,n)}}removeChild(e,t){t.remove()}selectRootElement(e,t){let n=typeof e==`string`?this.doc.querySelector(e):e;if(!n)throw new ii(-5104,!1);return t||(n.textContent=``),n}parentNode(e){return e.parentNode}nextSibling(e){return e.nextSibling}setAttribute(e,t,n,r){if(r){t=r+`:`+t;let i=kb[r];i?e.setAttributeNS(i,t,n):e.setAttribute(t,n)}else e.setAttribute(t,n)}removeAttribute(e,t,n){if(n){let r=kb[n];r?e.removeAttributeNS(r,t):e.removeAttribute(`${n}:${t}`)}else e.removeAttribute(t)}addClass(e,t){e.classList.add(t)}removeClass(e,t){e.classList.remove(t)}setStyle(e,t,n,r){let i=t.startsWith(`--`);i&&(t=t.replace(`%NS%`,this.cssVarNamespace)),i||r&(td.DashCase|td.Important)?e.style.setProperty(t,n,r&td.Important?`important`:``):e.style[t]=n}removeStyle(e,t,n){let r=t.startsWith(`--`);r&&(t=t.replace(`%NS%`,this.cssVarNamespace)),r||n&td.DashCase?e.style.removeProperty(t):e.style[t]=``}setProperty(e,t,n){e!=null&&(e[t]=n)}setValue(e,t){e.nodeValue=t}listen(e,t,n,r){if(typeof e==`string`&&(e=py().getGlobalEventTarget(this.doc,e),!e))throw new ii(-5102,!1);let i=this.decoratePreventDefault(n);return this.tracingService?.wrapEventListener&&(i=this.tracingService.wrapEventListener(e,t,i)),this.eventManager.addEventListener(e,t,i,r)}decoratePreventDefault(e){return t=>{if(t===`__ngUnwrap__`)return e;e(t)===!1&&t.preventDefault()}}};function Hb(e){return e.tagName===`TEMPLATE`&&e.content!==void 0}var Ub=class extends Vb{hostEl;sharedStylesHost;shadowRoot;constructor(e,t,n,r,i,a,o,s,c){super(e,r,i,o,s),this.hostEl=t,this.sharedStylesHost=c,this.shadowRoot=t.attachShadow({mode:`open`}),this.sharedStylesHost&&this.sharedStylesHost.addHost(this.shadowRoot);let l=n.styles;l=zb(n.id,l).map(e=>e.replace(/%NS%/g,s));for(let e of l){let t=document.createElement(`style`);a&&t.setAttribute(`nonce`,a),t.textContent=e,this.shadowRoot.appendChild(t)}let u=n.getExternalStyles?.();if(u)for(let e of u){let t=Db(e,r);a&&t.setAttribute(`nonce`,a),this.shadowRoot.appendChild(t)}}nodeOrShadowRoot(e){return e===this.hostEl?this.shadowRoot:e}appendChild(e,t){return super.appendChild(this.nodeOrShadowRoot(e),t)}insertBefore(e,t,n){return super.insertBefore(this.nodeOrShadowRoot(e),t,n)}removeChild(e,t){return super.removeChild(null,t)}parentNode(e){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(e)))}destroy(){this.sharedStylesHost&&this.sharedStylesHost.removeHost(this.shadowRoot)}},Wb=class extends Vb{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(e,t,n,r,i,a,o,s,c){super(e,i,a,o,s),this.sharedStylesHost=t,this.removeStylesOnCompDestroy=r;let l=n.styles,u=c?zb(c,l):l;this.styles=u.map(e=>e.replace(/%NS%/g,s)),this.styleUrls=n.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&hd.size===0&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}},Gb=class extends Wb{contentAttr;hostAttr;constructor(e,t,n,r,i,a,o,s,c){let l=r+`-`+n.id;super(e,t,n,i,a,o,s,c,l),this.contentAttr=Lb(l),this.hostAttr=Rb(l)}applyToHost(e){this.applyStyles(),this.setAttribute(e,this.hostAttr,``)}createElement(e,t){let n=super.createElement(e,t);return super.setAttribute(n,this.contentAttr,``),n}},Kb=class e extends hy{supportsDOMEvents=!0;static makeCurrent(){my(new e)}onAndCancel(e,t,n,r){return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r)}}dispatchEvent(e,t){e.dispatchEvent(t)}remove(e){e.remove()}createElement(e,t){return t||=this.getDefaultDocument(),t.createElement(e)}createHtmlDocument(){return document.implementation.createHTMLDocument(`fakeTitle`)}getDefaultDocument(){return document}isElementNode(e){return e.nodeType===Node.ELEMENT_NODE}isShadowRoot(e){return e instanceof DocumentFragment}getGlobalEventTarget(e,t){return t===`window`?window:t===`document`?e:t===`body`?e.body:null}getBaseHref(e){let t=Jb();return t==null?null:Yb(t)}resetBaseElement(){qb=null}getUserAgent(){return window.navigator.userAgent}getCookie(e){return _b(document.cookie,e)}},qb=null;function Jb(){return qb||=document.head.querySelector(`base`),qb?qb.getAttribute(`href`):null}function Yb(e){return new URL(e,document.baseURI).pathname}var Xb=[`alt`,`control`,`meta`,`shift`],Zb={"\b":`Backspace`," ":`Tab`,"":`Delete`,"\x1B":`Escape`,Del:`Delete`,Esc:`Escape`,Left:`ArrowLeft`,Right:`ArrowRight`,Up:`ArrowUp`,Down:`ArrowDown`,Menu:`ContextMenu`,Scroll:`ScrollLock`,Win:`OS`},Qb={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey},$b=(()=>{class e extends yb{constructor(e){super(e)}supports(t){return e.parseEventName(t)!=null}addEventListener(t,n,r,i){let a=e.parseEventName(n),o=e.eventCallback(a.fullKey,r,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>py().onAndCancel(t,a.domEventName,o,i))}static parseEventName(t){let n=t.toLowerCase().split(`.`),r=n.shift();if(n.length===0||r!==`keydown`&&r!==`keyup`)return null;let i=e._normalizeKey(n.pop()),a=``,o=n.indexOf(`code`);if(o>-1&&(n.splice(o,1),a=`code.`),Xb.forEach(e=>{let t=n.indexOf(e);t>-1&&(n.splice(t,1),a+=e+`.`)}),a+=i,n.length!=0||i.length===0)return null;let s={};return s.domEventName=r,s.fullKey=a,s}static matchEventFullKeyCode(e,t){let n=Zb[e.key]||e.key,r=``;return t.indexOf(`code.`)>-1&&(n=e.code,r=`code.`),n==null||!n?!1:(n=n.toLowerCase(),n===` `?n=`space`:n===`.`&&(n=`dot`),Xb.forEach(t=>{if(t!==n){let n=Qb[t];n(e)&&(r+=t+`.`)}}),r+=n,r===t)}static eventCallback(t,n,r){return i=>{e.matchEventFullKeyCode(i,t)&&r.runGuarded(()=>n(i))}}static _normalizeKey(e){return e===`esc`?`escape`:e}static ɵfac=function(t){return new(t||e)(Xi(Es))};static ɵprov=mi({token:e,factory:e.ɵfac})}return e})();async function ex(e,t,n){return ay({rootComponent:e,...tx(t,n)})}function tx(e,t){return{platformRef:t?.platformRef,appProviders:[...ox,...e?.providers??[]],platformProviders:ax}}function nx(){Kb.makeCurrent()}function rx(){return new Zs}function ix(){return $l(document),document}var ax=[{provide:ic,useValue:vb},{provide:rc,useValue:nx,multi:!0},{provide:Es,useFactory:ix}],ox=[{provide:ka,useValue:`root`},{provide:Zs,useFactory:rx},{provide:xb,useClass:bb,multi:!0},{provide:xb,useClass:$b,multi:!0},Bb,{provide:Tm,useClass:Ob},{provide:Ob,useExisting:Tm},Sb,{provide:om,useExisting:Bb},[]];function sx(e,t){let n=`\x1B[${e}m`,r=`\x1B[${t}m`;return((e,...t)=>{if(Array.isArray(e)&&`raw`in e){let i=e,a=``;for(let e=0;e{let r=new dx({code:i,why:lx(a.why,e),fix:lx(a.fix,e),docs:o,cause:e.cause,sources:e.sources,data:lx(a.data,e)},s);for(let e of t)e(r,n);return r};n[i]=s}return n}function mx(e){return t=>{let n=`${e.bold(e.red(`[${t.name}]`))} ${t.message}`,r=[];return t.fix&&r.push(`${e.dim(`fix:`)} ${t.fix}`),t.sources?.length&&r.push(`${e.dim(`sources:`)} ${t.sources.join(`, `)}`),t.docs&&r.push(`${e.dim(`see:`)} ${e.cyan(t.docs)}`),r.length===0?n:[n,...r.map((t,n)=>`${e.dim(n{e=n,t=r}),resolve:e,reject:t}}var bx=Math.random.bind(Math),xx=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`;function Sx(e=21){let t=``,n=e;for(;n--;)t+=xx[bx()*64|0];return t}var Cx=6e4,wx=e=>e,Tx=wx,{clearTimeout:Ex,setTimeout:Dx}=globalThis;function Ox(e,t){let{post:n,on:r,off:i=()=>{},eventNames:a=[],serialize:o=wx,deserialize:s=Tx,resolver:c,bind:l=`rpc`,timeout:u=Cx,proxify:d=!0}=t,f=!1,p=new Map,m,h;async function g(e,r,i,a){if(f)throw Error(`[birpc] rpc is closed, cannot call "${e}"`);let s={m:e,a:r,t:`q`};a&&(s.o=!0);let c=async e=>n(o(e));if(i){await c(s);return}if(m)try{await m}finally{m=void 0}let{promise:l,resolve:d,reject:g}=yx(),_=Sx();s.i=_;let ee;async function te(n=s){return u>=0&&(ee=Dx(()=>{try{if(t.onTimeoutError?.call(h,e,r)!==!0)throw Error(`[birpc] timeout on calling "${e}"`)}catch(e){g(e)}p.delete(_)},u),typeof ee==`object`&&(ee=ee.unref?.())),p.set(_,{resolve:d,reject:g,timeoutId:ee,method:e}),await c(n),l}try{t.onRequest?await t.onRequest.call(h,s,te,d):await te()}catch(e){if(t.onGeneralError?.call(h,e)!==!0)throw e;return}finally{Ex(ee),p.delete(_)}return l}let _={$call:(e,...t)=>g(e,t,!1),$callOptional:(e,...t)=>g(e,t,!1,!0),$callEvent:(e,...t)=>g(e,t,!0),$callRaw:e=>g(e.method,e.args,e.event,e.optional),$rejectPendingCalls:te,get $closed(){return f},get $meta(){return t.meta},$close:ee,$functions:e};h=d?new Proxy({},{get(t,n){if(Object.hasOwn(_,n))return _[n];if(n===`then`&&!a.includes(`then`)&&!(`then`in e))return;let r=(...e)=>g(n,e,!0);if(a.includes(n))return r.asEvent=r,r;let i=(...e)=>g(n,e,!1);return i.asEvent=r,i}}):_;function ee(e){f=!0,p.forEach(({reject:t,method:n})=>{let r=Error(`[birpc] rpc is closed, cannot call "${n}"`);if(e)return e.cause??=r,t(e);t(r)}),p.clear(),i(ne)}function te(e){let t=Array.from(p.values()).map(({method:t,reject:n})=>e?e({method:t,reject:n}):n(Error(`[birpc]: rejected pending call "${t}".`)));return p.clear(),t}async function ne(r,...i){let a;try{a=s(r)}catch(e){if(t.onGeneralError?.call(h,e)!==!0)throw e;return}if(a.t===`q`){let{m:r,a:s,o:u}=a,d,f,p=await(c?c.call(h,r,e[r]):e[r]);if(u&&(p||=()=>void 0),!p)f=Error(`[birpc] function "${r}" not found`);else try{d=await p.apply(l===`rpc`?h:e,s)}catch(e){f=e}if(a.i){if(f&&t.onFunctionError&&t.onFunctionError.call(h,f,r,s)===!0)return;if(!f)try{await n(o({t:`s`,i:a.i,r:d}),...i);return}catch(e){if(f=e,t.onGeneralError?.call(h,e,r,s)!==!0)throw e}try{await n(o({t:`s`,i:a.i,e:f}),...i)}catch(e){if(t.onGeneralError?.call(h,e,r,s)!==!0)throw e}}}else{let{i:e,r:t,e:n}=a,r=p.get(e);r&&(Ex(r.timeoutId),n?r.reject(n):r.resolve(t)),p.delete(e)}}return m=r(ne),h}function kx(e,t){return t.safety?t.safety:e===`static`||e===`query`||e==null?`read`:`action`}var Ax=Object.freeze({type:`object`,additionalProperties:!0});function jx(e){let t=e[`~standard`];if(t.jsonSchema)try{return t.jsonSchema.input({target:`draft-2020-12`})}catch{return Ax}return Ax}function Mx(e){if(!e||e.length===0)return{type:`object`,properties:{}};let t={},n=[];for(let r=0;rn[`arg${t}`]);if(`arg0`in n){let e=[];for(;`arg${e.length}`in n;)e.push(n[`arg${e.length}`]);return e}return Object.keys(n).length===0?[]:void 0}function Px(e,t){return Nx(e,t)??[e]}function Fx(e){return typeof e==`string`?`'${e}'`:new zx().serialize(e)}var Ix=` _-,;:!?.'"()[]{}@*/\\&#%\`^+<=>|~$0123456789abcdefghijklmnopqrstuvwxyz`,Lx=(function(){let e=new Uint8Array(128);for(let t=0;t<69;t++)e[Ix.charCodeAt(t)]=t+1;for(let t=65;t<=90;t++)e[t]=e[t+32];return e})();function Rx(e,t){if(e===t)return 0;let n=Math.min(e.length,t.length),r=0;for(let i=0;ia?-1:1)}return e.length===t.length?r:e.lengththis.compare(e[0],t[0])),r=`${e}{`;for(let e=0;ethis.compare(e,t)))}`}$Map(e){return this.serializeObjectEntries(`Map`,e.entries())}}for(let t of[`Error`,`RegExp`,`URL`])e.prototype[`$`+t]=function(e){return`${t}(${e})`};for(let t of[`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float32Array`,`Float64Array`])e.prototype[`$`+t]=function(e){return`${t}[${e.join(`,`)}]`};for(let t of[`BigInt64Array`,`BigUint64Array`])e.prototype[`$`+t]=function(e){return`${t}[${e.join(`n,`)}${e.length>0?`n`:``}]`};return e})(),Bx=[1779033703,-1150833019,1013904242,-1521486534,1359893119,-1694144372,528734635,1541459225],Vx=[1116352408,1899447441,-1245643825,-373957723,961987163,1508970993,-1841331548,-1424204075,-670586216,310598401,607225278,1426881987,1925078388,-2132889090,-1680079193,-1046744716,-459576895,-272742522,264347078,604807628,770255983,1249150122,1555081692,1996064986,-1740746414,-1473132947,-1341970488,-1084653625,-958395405,-710438585,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,-2117940946,-1838011259,-1564481375,-1474664885,-1035236496,-949202525,-778901479,-694614492,-200395387,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,-2067236844,-1933114872,-1866530822,-1538233109,-1090935817,-965641998],Hx=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_`,Ux=[],Wx=class{_data=new Gx;_hash=new Gx([...Bx]);_nDataBytes=0;_minBufferSize=0;finalize(e){e&&this._append(e);let t=this._nDataBytes*8,n=this._data.sigBytes*8;return this._data.words[n>>>5]|=128<<24-n%32,this._data.words[(n+64>>>9<<4)+14]=Math.floor(t/4294967296),this._data.words[(n+64>>>9<<4)+15]=t,this._data.sigBytes=this._data.words.length*4,this._process(),this._hash}_doProcessBlock(e,t){let n=this._hash.words,r=n[0],i=n[1],a=n[2],o=n[3],s=n[4],c=n[5],l=n[6],u=n[7];for(let n=0;n<64;n++){if(n<16)Ux[n]=e[t+n]|0;else{let e=Ux[n-15],t=(e<<25|e>>>7)^(e<<14|e>>>18)^e>>>3,r=Ux[n-2],i=(r<<15|r>>>17)^(r<<13|r>>>19)^r>>>10;Ux[n]=t+Ux[n-7]+i+Ux[n-16]}let d=s&c^~s&l,f=r&i^r&a^i&a,p=(r<<30|r>>>2)^(r<<19|r>>>13)^(r<<10|r>>>22),m=(s<<26|s>>>6)^(s<<21|s>>>11)^(s<<7|s>>>25),h=u+m+d+Vx[n]+Ux[n],g=p+f;u=l,l=c,c=s,s=o+h|0,o=a,a=i,i=r,r=h+g|0}n[0]=n[0]+r|0,n[1]=n[1]+i|0,n[2]=n[2]+a|0,n[3]=n[3]+o|0,n[4]=n[4]+s|0,n[5]=n[5]+c|0,n[6]=n[6]+l|0,n[7]=n[7]+u|0}_append(e){typeof e==`string`&&(e=Gx.fromUtf8(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes}_process(e){let t,n=this._data.sigBytes/64;n=e?Math.ceil(n):Math.max((n|0)-this._minBufferSize,0);let r=n*16,i=Math.min(r*4,this._data.sigBytes);if(r){for(let e=0;e>>2]|=(n.charCodeAt(e)&255)<<24-e%4*8;return new e(i,r)}toBase64(){let e=[];for(let t=0;t>>2]>>>24-t%4*8&255,r=this.words[t+1>>>2]>>>24-(t+1)%4*8&255,i=this.words[t+2>>>2]>>>24-(t+2)%4*8&255,a=n<<16|r<<8|i;for(let n=0;n<4&&t*8+n*6>>6*(3-n)&63))}return e.join(``)}concat(e){if(this.words[this.sigBytes>>>2]&=4294967295<<32-this.sigBytes%4*8,this.words.length=Math.ceil(this.sigBytes/4),this.sigBytes%4)for(let t=0;t>>2]>>>24-t%4*8&255;this.words[this.sigBytes+t>>>2]|=n<<24-(this.sigBytes+t)%4*8}else for(let t=0;t>>2]=e.words[t>>>2];this.sigBytes+=e.sigBytes}};function Kx(e){return new Wx().finalize(e).toBase64()}function qx(e){return Kx(Fx(e))}function Jx(e){return qx(e)}function Yx(){let e={};function t(t,...n){let r=e[t]||[];for(let e=0,t=r.length;e{e[t]=e[t]?.filter(e=>n!==e)}}function i(e,t){let n=r(e,((...e)=>(n(),t(...e))));return n}return{_listeners:e,emit:t,emitOnce:n,on:r,once:i}}var Xx=/^[\w+.-]{2,}:\/\//;function Zx(e){return e.endsWith(`/`)?e:`${e}/`}function Qx(e){return(e.endsWith(`/`)?e.slice(0,-1):e)||`/`}function $x(e,...t){let n=e;for(let e of t)e&&e!==`/`&&(n=n?Zx(n)+e.replace(/^\.?\//,``):e);return n}function eS(e,t){if(!t||t===`/`||Xx.test(e))return e;let n=Qx(t);return e.startsWith(n)?e:$x(n,e)}function tS(e,t){let n=e.match(Xx);return t+(n?e.slice(n[0].length):e)}var nS=`useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict`;function rS(e=21){let t=``,n=e;for(;n--;)t+=nS[Math.random()*64|0];return t}var iS=Symbol.for(`immer-nothing`),aS=Symbol.for(`immer-draftable`),oS=Symbol.for(`immer-state`),sS=[function(e){return`The plugin for '${e}' has not been loaded into Immer. To enable the plugin, import and call \`enable${e}()\` when initializing your application.`},function(e){return`produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${e}'`},`This object has been frozen and should not be mutated`,function(e){return`Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? `+e},`An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.`,`Immer forbids circular references`,"The first or second argument to `produce` must be a function","The third argument to `produce` must be a function or undefined","First argument to `createDraft` must be a plain object, an array, or an immerable object","First argument to `finishDraft` must be a draft returned by `createDraft`",function(e){return`'current' expects a draft, got: ${e}`},`Object.defineProperty() cannot be used on an Immer draft`,`Object.setPrototypeOf() cannot be used on an Immer draft`,`Immer only supports deleting array indices`,`Immer only supports setting array indices and the 'length' property`,function(e){return`'original' expects a draft, got: ${e}`}];function cS(e,...t){{let n=sS[e],r=MS(n)?n.apply(null,t):n;throw Error(`[Immer] ${r}`)}}var lS=Object,uS=lS.getPrototypeOf,dS=`constructor`,fS=`prototype`,pS=`configurable`,mS=`enumerable`,hS=`writable`,gS=`value`,_S=e=>!!e&&!!e[oS];function vS(e){return e?xS(e)||OS(e)||!!e[aS]||!!e[dS]?.[aS]||kS(e)||AS(e):!1}var yS=lS[fS][dS].toString(),bS=new WeakMap;function xS(e){if(!e||!jS(e))return!1;let t=uS(e);if(t===null||t===lS[fS])return!0;let n=lS.hasOwnProperty.call(t,dS)&&t[dS];if(n===Object)return!0;if(!MS(n))return!1;let r=bS.get(n);return r===void 0&&(r=Function.toString.call(n),bS.set(n,r)),r===yS}function SS(e,t,n=!0){CS(e)===0?(n?Reflect.ownKeys(e):lS.keys(e)).forEach(n=>{t(n,e[n],e)}):e.forEach((n,r)=>t(r,n,e))}function CS(e){let t=e[oS];return t?t.type_:OS(e)?1:kS(e)?2:AS(e)?3:0}var wS=(e,t,n=CS(e))=>n===2?e.has(t):lS[fS].hasOwnProperty.call(e,t),TS=(e,t,n=CS(e))=>n===2?e.get(t):e[t],ES=(e,t,n,r=CS(e))=>{r===2?e.set(t,n):r===3?e.add(n):e[t]=n};function DS(e,t){return e===t?e!==0||1/e==1/t:e!==e&&t!==t}var OS=Array.isArray,kS=e=>e instanceof Map,AS=e=>e instanceof Set,jS=e=>typeof e==`object`,MS=e=>typeof e==`function`,NS=e=>typeof e==`boolean`;function PS(e){let t=+e;return Number.isInteger(t)&&String(t)===e}var FS=e=>jS(e)?e?.[oS]:null,IS=e=>e.copy_||e.base_,LS=e=>e.modified_?e.copy_:e.base_;function RS(e,t){if(kS(e))return new Map(e);if(AS(e))return new Set(e);if(OS(e))return Array[fS].slice.call(e);let n=xS(e);if(t===!0||t===`class_only`&&!n){let t=lS.getOwnPropertyDescriptors(e);delete t[oS];let n=Reflect.ownKeys(t);for(let r=0;r1&&lS.defineProperties(e,{set:VS,add:VS,clear:VS,delete:VS}),lS.freeze(e),t&&SS(e,(e,t)=>{zS(t,!0)},!1),e)}function BS(){cS(2)}var VS={[gS]:BS};function HS(e){return e===null||!jS(e)||lS.isFrozen(e)}var US=`MapSet`,WS=`Patches`,GS=`ArrayMethods`,KS={};function qS(e){let t=KS[e];return t||cS(0,e),t}var JS=e=>!!KS[e];function YS(e,t){KS[e]||(KS[e]=t)}var XS,ZS=()=>XS,QS=(e,t)=>({drafts_:[],parent_:e,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0,handledSet_:new Set,processedForPatches_:new Set,mapSetPlugin_:JS(US)?qS(US):void 0,arrayMethodsPlugin_:JS(GS)?qS(GS):void 0});function $S(e,t){t&&(e.patchPlugin_=qS(WS),e.patches_=[],e.inversePatches_=[],e.patchListener_=t)}function eC(e){tC(e),e.drafts_.forEach(rC),e.drafts_=null}function tC(e){e===XS&&(XS=e.parent_)}var nC=e=>XS=QS(XS,e);function rC(e){let t=e[oS];t.type_===0||t.type_===1?t.revoke_():t.revoked_=!0}function iC(e,t){t.unfinalizedDrafts_=t.drafts_.length;let n=t.drafts_[0];if(e!==void 0&&e!==n){n[oS].modified_&&(eC(t),cS(4)),vS(e)&&(e=aC(t,e));let{patchPlugin_:r}=t;r&&r.generateReplacementPatches_(n[oS].base_,e,t)}else e=aC(t,n);return oC(t,e,!0),eC(t),t.patches_&&t.patchListener_(t.patches_,t.inversePatches_),e===iS?void 0:e}function aC(e,t){if(HS(t))return t;let n=t[oS];if(!n)return mC(t,e.handledSet_,e);if(!cC(n,e))return t;if(!n.modified_)return n.base_;if(!n.finalized_){let{callbacks_:t}=n;if(t)for(;t.length>0;)t.pop()(e);fC(n,e)}return n.copy_}function oC(e,t,n=!1){!e.parent_&&e.immer_.autoFreeze_&&e.canAutoFreeze_&&zS(t,n)}function sC(e){e.finalized_=!0,e.scope_.unfinalizedDrafts_--}var cC=(e,t)=>e.scope_===t,lC=[];function uC(e,t,n,r){let i=IS(e),a=e.type_;if(r!==void 0&&TS(i,r,a)===t){ES(i,r,n,a);return}if(!e.draftLocations_){let t=e.draftLocations_=new Map;SS(i,(e,n)=>{if(_S(n)){let r=t.get(n)||[];r.push(e),t.set(n,r)}})}let o=e.draftLocations_.get(t)??lC;for(let e of o)ES(i,e,n,a)}function dC(e,t,n){e.callbacks_.push(function(r){let i=t;if(!i||!cC(i,r))return;r.mapSetPlugin_?.fixSetContents(i);let a=LS(i);uC(e,i.draft_??i,a,n),fC(i,r)})}function fC(e,t){if(e.modified_&&!e.finalized_&&(e.type_===3||e.type_===1&&e.allIndicesReassigned_||(e.assigned_?.size??0)>0)){let{patchPlugin_:n}=t;if(n){let r=n.getPath(e);r&&n.generatePatches_(e,r,t)}sC(e)}}function pC(e,t,n){let{scope_:r}=e;if(_S(n)){let i=n[oS];cC(i,r)&&i.callbacks_.push(function(){CC(e),uC(e,n,LS(i),t)})}else vS(n)&&e.callbacks_.push(function(){let i=IS(e);e.type_===3?i.has(n)&&mC(n,r.handledSet_,r):TS(i,t,e.type_)===n&&r.drafts_.length>1&&(e.assigned_.get(t)??!1)===!0&&e.copy_&&mC(TS(e.copy_,t,e.type_),r.handledSet_,r)})}function mC(e,t,n){return!n.immer_.autoFreeze_&&n.unfinalizedDrafts_<1||_S(e)||t.has(e)||!vS(e)||HS(e)?e:(t.add(e),SS(e,(r,i)=>{if(_S(i)){let t=i[oS];cC(t,n)&&(ES(e,r,LS(t),e.type_),sC(t))}else vS(i)&&mC(i,t,n)}),e)}function hC(e,t){let n=OS(e),r={type_:+!!n,scope_:t?t.scope_:ZS(),modified_:!1,finalized_:!1,assigned_:void 0,parent_:t,base_:e,draft_:null,copy_:null,revoke_:null,isManual_:!1,callbacks_:void 0},i=r,a=gC;n&&(i=[r],a=_C);let{revoke:o,proxy:s}=Proxy.revocable(i,a);return r.draft_=s,r.revoke_=o,[s,r]}var gC={get(e,t){if(t===oS)return e;let n=e.scope_.arrayMethodsPlugin_,r=e.type_===1&&typeof t==`string`;if(r&&n?.isArrayOperationMethod(t))return n.createMethodInterceptor(e,t);let i=IS(e);if(!wS(i,t,e.type_))return bC(e,i,t);let a=i[t];if(e.finalized_||!vS(a)||r&&e.operationMethod&&n?.isMutatingArrayMethod(e.operationMethod)&&PS(t))return a;if(a===vC(e.base_,t)||yC(e,t,a)){CC(e);let n=e.type_===1?+t:t,r=TC(e.scope_,a,e,n);return e.copy_[n]=r}return a},has(e,t){return t in IS(e)},ownKeys(e){return Reflect.ownKeys(IS(e))},set(e,t,n){let r=xC(IS(e),t);if(r?.set)return r.set.call(e.draft_,n),!0;if(!e.modified_){let r=vC(IS(e),t),i=r?.[oS];if(i&&i.base_===n)return e.copy_[t]=n,e.assigned_.delete(t),!0;if(DS(n,r)&&(n!==void 0||wS(e.base_,t,e.type_)))return!0;CC(e),SC(e)}return e.copy_[t]===n&&(n!==void 0||wS(e.copy_,t,e.type_))||Number.isNaN(n)&&Number.isNaN(e.copy_[t])?!0:(e.copy_[t]=n,e.assigned_.set(t,!0),pC(e,t,n),!0)},deleteProperty(e,t){return CC(e),vC(e.base_,t)!==void 0||t in e.base_?(e.assigned_.set(t,!1),SC(e)):e.assigned_.delete(t),e.copy_&&delete e.copy_[t],!0},getOwnPropertyDescriptor(e,t){let n=IS(e),r=Reflect.getOwnPropertyDescriptor(n,t);return r&&{[hS]:!0,[pS]:e.type_!==1||t!==`length`,[mS]:r[mS],[gS]:n[t]}},defineProperty(){cS(11)},getPrototypeOf(e){return uS(e.base_)},setPrototypeOf(){cS(12)}},_C={};for(let e in gC){let t=gC[e];_C[e]=function(){let e=arguments;return e[0]=e[0][0],t.apply(this,e)}}_C.deleteProperty=function(e,t){return isNaN(parseInt(t))&&cS(13),_C.set.call(this,e,t,void 0)},_C.set=function(e,t,n){return t!==`length`&&isNaN(parseInt(t))&&cS(14),gC.set.call(this,e[0],t,n,e[0])};function vC(e,t){let n=e[oS];return(n?IS(n):e)[t]}function yC(e,t,n){return e.type_!==1||!e.allIndicesReassigned_||e.assigned_?.get(t)||!vS(n)||n[oS]?!1:e.baseRefs_.has(n)}function bC(e,t,n){let r=xC(t,n);return r?gS in r?r[gS]:r.get?.call(e.draft_):void 0}function xC(e,t){if(!(t in e))return;let n=uS(e);for(;n;){let e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=uS(n)}}function SC(e){e.modified_||(e.modified_=!0,e.parent_&&SC(e.parent_))}function CC(e){e.copy_||=(e.assigned_=new Map,RS(e.base_,e.scope_.immer_.useStrictShallowCopy_))}var wC=class{constructor(e){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.useStrictIteration_=!1,this.produce=(e,t,n)=>{if(MS(e)&&!MS(t)){let n=t;t=e;let r=this;return function(e=n,...i){return r.produce(e,e=>t.call(this,e,...i))}}MS(t)||cS(6),n!==void 0&&!MS(n)&&cS(7);let r;if(vS(e)){let i=nC(this),a=TC(i,e,void 0),o=!0;try{r=t(a),o=!1}finally{o?eC(i):tC(i)}return $S(i,n),iC(r,i)}if(!e||!jS(e)){if(r=t(e),r===void 0&&(r=e),r===iS&&(r=void 0),this.autoFreeze_&&zS(r,!0),n){let t=[],i=[];qS(WS).generateReplacementPatches_(e,r,{patches_:t,inversePatches_:i}),n(t,i)}return r}cS(1,e)},this.produceWithPatches=(e,t)=>{if(MS(e))return(t,...n)=>this.produceWithPatches(t,t=>e(t,...n));let n,r;return[this.produce(e,t,(e,t)=>{n=e,r=t}),n,r]},NS(e?.autoFreeze)&&this.setAutoFreeze(e.autoFreeze),NS(e?.useStrictShallowCopy)&&this.setUseStrictShallowCopy(e.useStrictShallowCopy),NS(e?.useStrictIteration)&&this.setUseStrictIteration(e.useStrictIteration)}createDraft(e){vS(e)||cS(8),_S(e)&&(e=EC(e));let t=nC(this),n=TC(t,e,void 0);return n[oS].isManual_=!0,tC(t),n}finishDraft(e,t){let n=e&&e[oS];(!n||!n.isManual_)&&cS(9);let{scope_:r}=n;return $S(r,t),iC(void 0,r)}setAutoFreeze(e){this.autoFreeze_=e}setUseStrictShallowCopy(e){this.useStrictShallowCopy_=e}setUseStrictIteration(e){this.useStrictIteration_=e}shouldUseStrictIteration(){return this.useStrictIteration_}applyPatches(e,t){let n;for(n=t.length-1;n>=0;n--){let r=t[n];if(r.path.length===0&&r.op===`replace`){e=r.value;break}}n>-1&&(t=t.slice(n+1));let r=qS(WS).applyPatches_;return _S(e)?r(e,t):this.produce(e,e=>r(e,t))}};function TC(e,t,n,r){let[i,a]=kS(t)?qS(US).proxyMap_(t,n):AS(t)?qS(US).proxySet_(t,n):hC(t,n);return(n?.scope_??ZS()).drafts_.push(i),a.callbacks_=n?.callbacks_??[],a.key_=r,n&&r!==void 0?dC(n,a,r):a.callbacks_.push(function(e){e.mapSetPlugin_?.fixSetContents(a);let{patchPlugin_:t}=e;a.modified_&&t&&t.generatePatches_(a,[],e)}),i}function EC(e){return _S(e)||cS(10,e),DC(e)}function DC(e){if(!vS(e)||HS(e))return e;let t=e[oS],n,r=!0;if(t){if(!t.modified_)return t.base_;t.finalized_=!0,n=RS(e,t.scope_.immer_.useStrictShallowCopy_),r=t.scope_.immer_.shouldUseStrictIteration()}else n=RS(e,!0);return SS(n,(e,t)=>{ES(n,e,DC(t))},r),t&&(t.finalized_=!1),n}function OC(){sS.push(`Sets cannot have "replace" patches.`,function(e){return`Unsupported patch operation: `+e},function(e){return`Cannot apply patch, path doesn't resolve: `+e},`Patching reserved attributes like __proto__, prototype and constructor is not allowed`);function e(n,r=[]){if(n.key_!==void 0){let e=n.parent_.copy_??n.parent_.base_,t=FS(TS(e,n.key_)),i=TS(e,n.key_);if(i===void 0||i!==n.draft_&&i!==n.base_&&i!==n.copy_||t!=null&&t.base_!==n.base_)return null;let a=n.parent_.type_===3,o;if(a){let e=n.parent_;o=Array.from(e.drafts_.keys()).indexOf(n.key_)}else o=n.key_;if(!(a&&e.size>o||wS(e,o)))return null;r.push(o)}if(n.parent_)return e(n.parent_,r);r.reverse();try{t(n.copy_,r)}catch{return null}return r}function t(e,t){let n=e;for(let e=0;e{let u=TS(o,e,c),f=TS(s,e,c),p=l?wS(o,e)?n:`add`:r;if(u===f&&p===n)return;let m=t.concat(e);i.push(p===r?{op:p,path:m}:{op:p,path:m,value:d(f)}),a.push(p===`add`?{op:r,path:m}:p===r?{op:`add`,path:m,value:d(u)}:{op:n,path:m,value:d(u)})})}function s(e,t,n,i){let{base_:a,copy_:o}=e,s=0;a.forEach(e=>{if(!o.has(e)){let a=t.concat([s]);n.push({op:r,path:a,value:e}),i.unshift({op:`add`,path:a,value:e})}s++}),s=0,o.forEach(e=>{if(!a.has(e)){let a=t.concat([s]);n.push({op:`add`,path:a,value:e}),i.unshift({op:r,path:a,value:e})}s++})}function c(e,t,r){let{patches_:i,inversePatches_:a}=r;i.push({op:n,path:[],value:t===iS?void 0:t}),a.push({op:n,path:[],value:e})}function l(e,t){return t.forEach(t=>{let{path:i,op:a}=t,o=e;for(let e=0;e[e,u(t)]));if(AS(e))return new Set(Array.from(e).map(u));let t=Object.create(uS(e));for(let n in e)t[n]=u(e[n]);return wS(e,aS)&&(t[aS]=e[aS]),t}function d(e){return _S(e)?u(e):e}YS(WS,{applyPatches_:l,generatePatches_:i,generateReplacementPatches_:c,getPath:e})}globalThis.Iterator?.from;var kC=new wC,AC=kC.produce,jC=kC.produceWithPatches.bind(kC),MC=kC.applyPatches.bind(kC),NC=1e3;function PC(e,t){if(e.add(t),e.size>NC){let t=e.values().next().value;t!==void 0&&e.delete(t)}}function FC(e){let{enablePatches:t=!1}=e;t&&OC();let n=Yx(),r=e.initialValue,i=new Set;return{on:n.on,value:()=>r,patch:(e,t=rS())=>{i.has(t)||(OC(),r=MC(r,e),PC(i,t),n.emit(`updated`,r,void 0,t))},mutate:(e,a=rS())=>{if(!i.has(a)){if(PC(i,a),t){let[t,i]=jC(r,e);if(t===r)return;r=t,n.emit(`updated`,r,i,a)}else{let t=AC(r,e);if(t===r)return;r=t,n.emit(`updated`,r,void 0,a)}}},syncIds:i}}var IC=typeof self==`object`?self:globalThis,LC=new Set([`Error`,`EvalError`,`RangeError`,`ReferenceError`,`SyntaxError`,`TypeError`,`URIError`,`AggregateError`]),RC=new Set([`Boolean`,`Number`,`String`,`Int8Array`,`Uint8Array`,`Uint8ClampedArray`,`Int16Array`,`Uint16Array`,`Int32Array`,`Uint32Array`,`Float16Array`,`Float32Array`,`Float64Array`,`BigInt64Array`,`BigUint64Array`]);function zC(e,t){let n=(t,n)=>(e.set(n,t),t),r=i=>{if(e.has(i))return e.get(i);let[a,o]=t[i];switch(a){case 0:case-1:return n(o,i);case 1:{let e=n([],i);for(let t of o)e.push(r(t));return e}case 2:{let e=n({},i);for(let[t,n]of o)e[r(t)]=r(n);return e}case 3:return n(new Date(o),i);case 4:{let{source:e,flags:t}=o;return n(new RegExp(e,t),i)}case 5:{let e=n(new Map,i);for(let[t,n]of o)e.set(r(t),r(n));return e}case 6:{let e=n(new Set,i);for(let t of o)e.add(r(t));return e}case 7:{let{name:e,message:t}=o,r=LC.has(e)?IC[e]:void 0;return n(new(r??IC.Error)(t),i)}case 8:return n(BigInt(o),i);case`BigInt`:return n(Object(BigInt(o)),i);case`ArrayBuffer`:return n(new Uint8Array(o).buffer,o);case`DataView`:{let{buffer:e}=new Uint8Array(o);return n(new DataView(e),o)}}if(typeof a==`string`&&RC.has(a))return n(new IC[a](o),i);throw TypeError(`unable to deserialize unsafe or unknown type: ${String(a)}`)};return r}function BC(e){return zC(new Map,e)(0)}var VC=``,{toString:HC}={},{keys:UC}=Object;function WC(e){let t=typeof e;if(t!==`object`||!e)return[0,t];let n=HC.call(e).slice(8,-1);switch(n){case`Array`:return[1,VC];case`Object`:return[2,VC];case`Date`:return[3,VC];case`RegExp`:return[4,VC];case`Map`:return[5,VC];case`Set`:return[6,VC];case`DataView`:return[1,n]}return n.includes(`Array`)?[1,n]:n.includes(`Error`)?[7,n]:[2,n]}function GC([e,t]){return e===0&&(t===`function`||t===`symbol`)}function KC(e,t,n,r){let i=(e,t)=>{let i=r.push(e)-1;return n.set(t,i),i},a=r=>{if(n.has(r))return n.get(r);let[o,s]=WC(r);switch(o){case 0:{let t=r;switch(s){case`bigint`:o=8,t=r.toString();break;case`function`:case`symbol`:if(e)throw TypeError(`unable to serialize ${s}`);t=null;break;case`undefined`:return i([-1],r)}return i([o,t],r)}case 1:{if(s){let e=r;return s===`DataView`?e=new Uint8Array(r.buffer):s===`ArrayBuffer`&&(e=new Uint8Array(r)),i([s,[...e]],r)}let e=[],t=i([o,e],r);for(let t of r)e.push(a(t));return t}case 2:{if(s)switch(s){case`BigInt`:return i([s,r.toString()],r);case`Boolean`:case`Number`:case`String`:return i([s,r.valueOf()],r)}if(t&&`toJSON`in r)return a(r.toJSON());let n=[],c=i([o,n],r);for(let t of UC(r))(e||!GC(WC(r[t])))&&n.push([a(t),a(r[t])]);return c}case 3:return i([o,r.toISOString()],r);case 4:{let{source:e,flags:t}=r;return i([o,{source:e,flags:t}],r)}case 5:{let t=[],n=i([o,t],r);for(let[n,i]of r)(e||!(GC(WC(n))||GC(WC(i))))&&t.push([a(n),a(i)]);return n}case 6:{let t=[],n=i([o,t],r);for(let n of r)(e||!GC(WC(n)))&&t.push(a(n));return n}}let{message:c}=r;return i([o,{name:s,message:c}],r)};return a}function qC(e,t={}){let n=[];return KC(!(t.json||t.lossy),!!t.json,new Map,n)(e),n}var{parse:JC,stringify:YC}=JSON,XC={json:!0,lossy:!0};function ZC(e){return BC(JC(e))}function QC(e){return YC(qC(e,XC))}function $C(e){return BC(e)}function ew(e){return QC(e)}function tw(e){return ZC(e)}var nw=256,rw=class extends Error{name=`StreamClosedError`};function iw(e={}){let t=e.id??rS(),n=Math.max(0,e.replayWindow??0),r=Yx(),i=new AbortController,a=[],o=!1,s=0;function c(e){if(o)throw new rw(`Cannot write to a closed stream "${t}"`);s+=1,n>0&&(a.push({seq:s,chunk:e}),a.length>n&&(a.length-n===1?a.shift():a.splice(0,a.length-n))),r.emit(`chunk`,s,e)}function l(e){if(o)return;o=!0;let t=ow(e);i.abort(e),r.emit(`end`,t)}function u(){o||(o=!0,i.signal.aborted||i.abort(`stream closed`),r.emit(`end`,void 0))}function d(e){o||i.signal.aborted||i.abort(e??`aborted`)}let f=new WritableStream({write(e){c(e)},close(){u()},abort(e){l(e)}});return{id:t,signal:i.signal,get closed(){return o},get lastSeq(){return s},write:c,error:l,close:u,abort:d,writable:f,events:r,buffer:a}}function aw(e={}){let t=e.id??rS(),n=Math.max(1,e.highWaterMark??nw),r=[],i=0,a=!1,o=!1,s,c,l,u;function d(){if(c){if(r.length>0){let e=r.shift(),t=c;c=void 0,t.resolve({value:e,done:!1});return}if(a){let e=c;if(c=void 0,s){let t=Error(s.message);t.name=s.name,e.reject(t)}else e.resolve({value:void 0,done:!0})}}}function f(){if(l){for(;r.length>0;){let e=r.shift();try{l.enqueue(e)}catch{break}}if(a&&l){try{if(s){let e=Error(s.message);e.name=s.name,l.error(e)}else l.close()}catch{}l=void 0}}}function p(t,s){if(!(a||o)&&!(t<=i)){if(i=t,r.push(s),r.length>n){let t=r.length-n;r.splice(0,t),e.onOverflow?.(t)}d(),u&&f()}}function m(e){a||(a=!0,s=e,d(),u&&f())}function h(){o||a||(o=!0,e.onCancel?.(),m(void 0))}function g(){return u||(u=new ReadableStream({start(e){l=e,f()},cancel(){h()}}),u)}return{id:t,get cancelled(){return o},get done(){return a},get lastSeenSeq(){return i},get readable(){return g()},cancel:h,_push:p,_end:m,[Symbol.asyncIterator](){return{next(){if(r.length>0)return Promise.resolve({value:r.shift(),done:!1});if(a){if(s){let e=Error(s.message);return e.name=s.name,Promise.reject(e)}return Promise.resolve({value:void 0,done:!0})}return new Promise((e,t)=>{c={resolve:e,reject:t}})},return(){return h(),Promise.resolve({value:void 0,done:!0})}}}}}function ow(e){if(e instanceof Error)return{name:e.name||`Error`,message:e.message};if(typeof e==`string`)return{name:`Error`,message:e};try{return{name:`Error`,message:JSON.stringify(e)}}catch{return{name:`Error`,message:String(e)}}}var sw=128;function cw(e){return e.replace(/[^\w-]+/g,`_`).slice(0,sw)}var lw=`modulepreload`,uw=function(e,t){return new URL(e,t).href},dw={},fw=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=uw(t,n),t=s(t),t in dw)return;dw[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:lw,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},pw=`__connection.json`,mw=`__DEVFRAME_CONNECTION__`,hw=`x-birpc-session`,gw=`__rpc-dump/index.json`,_w=`devframe:services`,vw=`devframe_otp`,yw=`devframe_auth_token`;hx.postMessage.remoteAssetsError;var bw=class{cacheMap=new Map;options;keySerializer;constructor(e){this.options=e,this.keySerializer=e.keySerializer||(e=>Jx(e))}updateOptions(e){this.options={...this.options,...e}}cached(e,t){let n=this.cacheMap.get(e);if(n)return n.get(this.keySerializer(t))}has(e,t){return this.cacheMap.get(e)?.has(this.keySerializer(t))??!1}apply(e,t){let n=this.cacheMap.get(e.m)||new Map;n.set(this.keySerializer(e.a),t),this.cacheMap.set(e.m,n)}validate(e){return this.options.functions.includes(e)}clear(e){e?this.cacheMap.delete(e):this.cacheMap.clear()}},xw=vx({docsBase:`https://devfra.me/errors`,codes:{DF0019:{why:e=>`RPC function "${e.name}" has \`agent\` set but \`jsonSerializable\` is \`false\`; MCP requires JSON-serializable data.`,fix:"Remove `jsonSerializable: false`, or remove `agent` to keep it RPC-only."},DF0020:{why:e=>`RPC function "${e.name}" declares \`jsonSerializable: true\` but the value at "${e.path}" is a ${e.type}.`,fix:"Either drop `jsonSerializable: true` (falls back to structured-clone) or change the value to a JSON-safe shape."},DF0021:{why:e=>`RPC function "${e.name}" is already registered`,fix:"Use the `force` parameter to overwrite an existing registration."},DF0022:{why:e=>`RPC function "${e.name}" is not registered. Use register() to add new functions.`},DF0023:{why:e=>`RPC function "${e.name}" is not registered`},DF0024:{why:e=>`Either handler or setup function must be provided for RPC function "${e.name}"`},DF0025:{why:e=>`Function "${e.name}" not found in dump store`},DF0026:{why:e=>`No dump match for "${e.name}" with args: ${e.args}`},DF0027:{why:e=>`Function "${e.name}" with type "${e.type}" cannot have dump configuration. Only "static" and "query" types support dumps.`},DF0028:{why:e=>`Function "${e.name}" with type "${e.type}" cannot use \`snapshot: true\`. Only "query" functions support this sugar; "static" functions have equivalent default behavior already.`,fix:"Remove `snapshot: true`, or change the function type to `query`."},DF0043:{why:e=>`RPC function "${e.name}" received an invalid argument at position ${e.index}: ${e.issues}`,fix:"Pass a value that satisfies the `args` schema declared for this function."},DF0044:{why:e=>`RPC function "${e.name}" returned a value that failed its \`returns\` schema: ${e.issues}`,fix:"Make the handler return a value that satisfies the `returns` schema, or relax the schema."}}});function Sw(e){if(e.agent&&e.jsonSerializable===!1)throw xw.DF0019({name:e.name});e.agent&&!e.jsonSerializable&&(e.jsonSerializable=!0)}async function Cw(e,t){let n=e[`~standard`].validate(t);return n instanceof Promise?await n:n}function ww(e){return e.map(e=>{let t=e.path?.map(e=>typeof e==`object`?e.key:e).join(`.`);return t?`${t}: ${e.message}`:e.message}).join(`; `)}async function Tw(e,t,n){let r=n.slice();if(!t||t.length===0)return r;for(let r=0;r{n.get(t)===r&&n.delete(t)}),n.set(t,r)),await r}if(!e.__promise){let n=Promise.resolve(e.setup(t));n.catch(()=>{e.__promise===n&&(e.__promise=void 0)}),e.__promise=n}return await e.__promise}async function Ow(e,t){let n=e.handler;if(!n){let r=await Dw(e,t);if(!r.handler)throw xw.DF0024({name:e.name});n=r.handler}let r=e.args,i=e.returns;if(!r&&!i)return n;let a=n;return async(...t)=>{let n=await Tw(e.name,r,t),o=await a(...n);return await Ew(e.name,i,o)}}var kw=class{context;definitions=new Map;functions;_onChanged=[];constructor(e){this.context=e;let t=this.definitions,n=this;this.functions=new Proxy({},{get(e,r){let i=t.get(r);if(i)return Ow(i,n.context)},has(e,n){return t.has(n)},getOwnPropertyDescriptor(e,n){return{value:t.get(n)?.handler,configurable:!0,enumerable:!0}},ownKeys(){return Array.from(t.keys())}})}register(e,t=!1){if(this.definitions.has(e.name)&&!t)throw xw.DF0021({name:e.name});Sw(e),this.definitions.set(e.name,e),this._onChanged.forEach(t=>t(e.name))}update(e,t=!1){if(!this.definitions.has(e.name)&&!t)throw xw.DF0022({name:e.name});Sw(e),this.definitions.set(e.name,e),this._onChanged.forEach(t=>t(e.name))}onChanged(e){return this._onChanged.push(e),()=>{let t=this._onChanged.indexOf(e);t!==-1&&this._onChanged.splice(t,1)}}async getHandler(e){return await Ow(this.definitions.get(e),this.context)}getSchema(e){let t=this.definitions.get(e);if(!t)throw xw.DF0023({name:String(e)});return{args:t.args,returns:t.returns}}has(e){return this.definitions.has(e)}get(e){return this.definitions.get(e)}list(){return Array.from(this.definitions.keys())}};function Aw(e,t=``){return JSON.stringify(e,function(e,n){let r=this,i=r==null?n:r[e];if(i===void 0){if(Array.isArray(r))throw Mw(t,`undefined`,r,e);return n}return i!==null&&jw(i,r,e,t),n})}function jw(e,t,n,r){if(typeof e==`bigint`)throw Mw(r,`BigInt`,t,n);if(typeof e!=`object`)return;if(e instanceof Map)throw Mw(r,`Map`,t,n);if(e instanceof Set)throw Mw(r,`Set`,t,n);if(e instanceof Date)throw Mw(r,`Date`,t,n);if(Array.isArray(e))return;let i=Object.getPrototypeOf(e);if(i!==null&&i!==Object.prototype)throw Mw(r,e.constructor?.name??`class instance`,t,n)}function Mw(e,t,n,r){let i=Nw(n,r);return xw.DF0020({name:e||``,type:t,path:i})}function Nw(e,t){return Array.isArray(e)?`[${t}]`:t===``?``:t}var Pw=`__DEVFRAME_CONNECTION_META__`,Fw=`__DEVFRAME_CONNECTION_AUTH_TOKEN__`;function Iw(e){let t=[()=>window?.[e],()=>globalThis?.[e],()=>parent.window?.[e]];for(let e of t)try{let t=e();if(t)return t}catch{}}function Lw(){return Iw(mw)}function Rw(){return Iw(Pw)}function zw(e){if(e)return e;try{let e=localStorage.getItem(Fw);if(e)return e}catch{}return Iw(Fw)}function Bw(e){globalThis[mw]=e,globalThis[Pw]={...e.connectionMeta,baseUrl:e.metaBaseUrl},e.authToken&&Vw(e.authToken)}function Vw(e){try{localStorage.setItem(Fw,e)}catch{}globalThis[Fw]=e;let t=Lw();t&&(globalThis[mw]={...t,authToken:e})}function Hw(e){let t=eS(pw,e);try{return new URL(t,globalThis.location?.href).href}catch{return t}}function Uw(e,t){return t&&t!==e.authToken?{...e,authToken:t}:e}function Ww(){let e=Lw();if(e)return Uw(e,zw()??e.authToken??e.connectionMeta.authToken);let t=Rw();if(t)return{connectionMeta:t,metaBaseUrl:t.baseUrl??Hw(`./`),authToken:zw(t.authToken)}}async function Gw(e={}){if(e.connection){let t=Uw(e.connection,zw(e.authToken??e.connection.authToken??e.connection.connectionMeta.authToken));return Bw(t),t}let t=Array.isArray(e.baseURL)?e.baseURL:[e.baseURL??`./`];if(e.connectionMeta){let n={connectionMeta:e.connectionMeta,metaBaseUrl:Hw(t[0]??`./`),authToken:zw(e.authToken??e.connectionMeta.authToken)};return Bw(n),n}let n=Ww();if(n){let t=Uw(n,zw(e.authToken??n.authToken??n.connectionMeta.authToken));return Bw(t),t}let r=[];for(let n of t){let t=eS(pw,n),i=Hw(n);try{let n=await fetch(t);if(!n.ok)throw Error(`Failed to fetch connection meta from ${i}: ${n.status}`);let r=await n.json(),a=n.url||i,o={connectionMeta:r,metaBaseUrl:r.baseUrl?new URL(r.baseUrl,a).href:a,authToken:zw(e.authToken??r.authToken)};return Bw(o),o}catch(e){r.push(e)}}throw Error(`Failed to get connection meta from ${t.join(`, `)}`,{cause:r})}var Kw=class extends Error{name=`DevframeConnectionError`;kind;constructor(e,t,n){super(t,n),this.kind=e}};function qw(e=vw){try{let t=globalThis.location?.hash?.replace(/^#/,``)??``;return new URLSearchParams(t).get(e)||void 0}catch{return}}function Jw(e){try{let t=new URL(globalThis.location.href),n=new URLSearchParams(t.hash.replace(/^#/,``));if(!n.has(e))return;n.delete(e),t.hash=n.toString(),globalThis.history?.replaceState(globalThis.history.state,``,t.href)}catch{}}function Yw(e=vw){let t=qw(e);return t&&Jw(e),t}async function Xw(e,t={}){let n=Yw(t.param??`devframe_otp`);return n?e.isTrusted?!0:e.requestTrustWithCode(n):!1}function Zw(e){let t={},n=new WeakMap,r,i=()=>(r??=e.sharedState.get(_w,{initialValue:{}}).then(e=>(t=e.value(),e.on(`updated`,e=>{t=e}),e)),r);return i(),{state:i,has:e=>e in t,keys:()=>Object.keys(t),get:r=>{let i=t[r];if(!i)return;let a=n.get(i);return a||(a={...i,rpc:e.scope(i.scope).rpc},n.set(i,a)),a}}}function Qw(e){let t=new Map,n=new Map,r=new Map,i=new Set,a=e.connectionMeta.backend===`static`;function o(e,t){let n=r.get(e);return n&&typeof n==`object`&&!Array.isArray(n)&&typeof t==`object`&&!Array.isArray(t)?{...n,...t}:t}e.client.register({name:hx.broadcast.clientStateUpdated,type:`event`,handler:(e,n,r)=>{let i=t.get(e);i&&!i.syncIds.has(r)&&i.mutate(()=>o(e,n),r)}}),e.client.register({name:hx.broadcast.clientStatePatch,type:`event`,handler:(e,n,r)=>{let i=t.get(e);i&&!i.syncIds.has(r)&&i.patch(n,r)}});function s(t,n){let r=[];return r.push(n.on(`updated`,(n,r,i)=>{a||(r?e.callEvent(`devframe:rpc:server-state:patch`,t,r,i):e.callEvent(`devframe:rpc:server-state:set`,t,n,i))})),()=>{for(let e of r)e()}}return{keys:()=>Array.from(t.keys()),onKeyAdded(e){return i.add(e),()=>{i.delete(e)}},delete(e){let i=n.get(e);n.delete(e);let a=t.delete(e);return r.delete(e),i?.(),a},get:async(c,l)=>{if(l?.initialValue!==void 0&&r.set(c,l.initialValue),t.has(c))return t.get(c);let u=FC({initialValue:l?.initialValue,enablePatches:!1});async function d(){if(a||e.callEvent(`devframe:rpc:server-state:subscribe`,c),l?.initialValue!==void 0){t.set(c,u);for(let e of i)e(c);return e.call(`devframe:rpc:server-state:get`,c).then(e=>{e!==void 0&&u.mutate(()=>o(c,e))}).catch(e=>{console.error(`Error getting server state`,e)}),n.set(c,s(c,u)),u}{let r=await e.call(`devframe:rpc:server-state:get`,c);u.mutate(()=>o(c,r)),t.set(c,u);for(let e of i)e(c);return n.set(c,s(c,u)),u}}return new Promise(t=>{if(e.isTrusted)d().then(t);else{t(u);let n=!1;e.events.on(hx.client.isTrustedUpdated,e=>{e&&!n&&(n=!0,d())})}})}}}var $w=new Map;function eT(e=$w){let t=new Map;return{serialize:n=>{let r;return n.t===`q`?r=n.m:(r=t.get(n.i),t.delete(n.i)),!(n.t===`s`&&`e`in n)&&r&&e.get(r)?.jsonSerializable===!0?Aw(n,r??``):`s:${ew(n)}`},deserialize:e=>{let n=e.startsWith(`s:`)?tw(e.slice(2)):JSON.parse(e);return n.t===`q`&&n.i&&n.m&&t.set(n.i,n.m),n}}}function tT(){}function nT(e){let t=e.search(/\n\n|\r\n\r\n/);if(!(t<0))return{frame:e.slice(0,t),rest:e.slice(t+(e[t]===`\r`?4:2))}}function rT(e){let t=`message`,n=[];for(let r of e.split(/\r?\n/))r.startsWith(`:`)||(r.startsWith(`event:`)?t=r.slice(6).trimStart():r.startsWith(`data:`)&&n.push(r.slice(5).replace(/^ /,``)));return{event:t,data:n}}function iT(e){let{onConnected:t=tT,onError:n=tT,onDisconnected:r=tT,definitions:i,fetch:a=globalThis.fetch.bind(globalThis)}=e,o=e.url;e.authToken&&(o=`${o}${o.includes(`?`)?`&`:`?`}${yw}=${encodeURIComponent(e.authToken)}`);let s=eT(i),c=new AbortController,l=!1,u,d,f,p,m=new Promise((e,t)=>{f=e,p=t});m.catch(()=>{});function h(e){l||(l=!0,p(e),n(e),r())}function g(){l||(l=!0,p(Error(`Devframe SSE stream closed`)),r())}function _(e,n){if(e===`session`){f(n),t();return}u?.(n)}async function ee(e){let t=e.getReader();d=t;let n=new TextDecoder,r=``;for(;;){let{done:e,value:i}=await t.read();if(e)break;for(r+=n.decode(i,{stream:!0});;){let e=nT(r);if(!e)break;r=e.rest;let{event:t,data:n}=rT(e.frame);n.length>0&&_(t,n.join(` -`))}}g()}return(async()=>{try{let e=await a(o,{headers:{accept:`text/event-stream`},signal:c.signal});if(!e.ok||!e.body)throw Error(`Devframe SSE stream request failed: ${e.status}`);await ee(e.body)}catch(e){if(c.signal.aborted){g();return}h(e instanceof Error?e:Error(String(e)))}})(),{close:()=>{l=!0,c.abort(),d?.cancel().catch(()=>{})},on:e=>{u=e},post:async e=>{let t;try{t=await m}catch{return}if(l){n(Error(`Devframe SSE channel is closed; message dropped`));return}try{let n=await a(o,{method:`POST`,headers:{"content-type":`text/plain; charset=utf-8`,[hw]:t},body:e});if(n.status===200){let e=await n.text();e&&u?.(e);return}if(!n.ok)throw Error(`Devframe SSE POST failed: ${n.status}`)}catch(e){n(e instanceof Error?e:Error(String(e)))}},serialize:s.serialize,deserialize:s.deserialize}}function aT(e,t){let{channel:n,rpcOptions:r={}}=t;return Ox(e,{...n,timeout:-1,...r,proxify:!1})}function oT(e){let{transport:t,authToken:n,connectionMeta:r,events:i,clientRpc:a,rpcOptions:o={},callTimeout:s=0}=e,c=!1,l=`connecting`,u=null,d=Promise.withResolvers();function f(e,t=null){if(t?u=t:e===`connected`&&(u=null),e===l)return;let n=l;l=e,i.emit(hx.client.connectionStatus,e,n)}let p=new Set;function m(e){for(let t of[...p])t.reject(e)}function h(){return l===`disconnected`||l===`error`?new Kw(`connection`,`[devframe] Not connected to the devframe server`,{cause:u??void 0}):l===`unauthorized`?new Kw(`auth`,`[devframe] Not authorized by the devframe server`,{cause:u??void 0}):null}function g(e,t){return new Promise((n,r)=>{let a=!1,o,c={reject(e){a||(l(),i.emit(hx.client.error,e,t),r(e))}};function l(){a=!0,p.delete(c),o&&clearTimeout(o)}p.add(c),s>0&&(o=setTimeout(()=>{c.reject(new Kw(`timeout`,`[devframe] RPC call "${t}" timed out after ${s}ms`))},s)),e.then(e=>{a||(l(),n(e))},e=>{if(a)return;l();let n=e instanceof Error?e:Error(String(e));i.emit(hx.client.error,n,t),r(n)})})}let _=new Map;for(let e of r.jsonSerializableMethods??[])_.set(e,{jsonSerializable:!0});let ee=e.createChannel({definitions:_,onError(e){f(`error`,e),i.emit(hx.client.connectionError,e),m(new Kw(`connection`,`[devframe] Connection to the devframe server failed`,{cause:e}))},onDisconnected(){l!==`error`&&f(`disconnected`),m(new Kw(`connection`,`[devframe] Disconnected from the devframe server`,{cause:u??void 0}))}}),te=aT(a.functions,{channel:ee,rpcOptions:o});a.register({name:hx.broadcast.authRevoked,type:`event`,handler:()=>{c=!1;let e=new Kw(`auth`,`[devframe] The devframe server revoked this client's trust`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e),m(e),i.emit(hx.client.isTrustedUpdated,!1)}});let ne=n;async function re(e){ne=e;let t=await te.$call(`anonymous:devframe:auth`,{authToken:e,ua:navigator.userAgent,origin:location.origin});if(c=t.isTrusted,c)d.resolve(!0),f(`connected`);else{let e=new Kw(`auth`,`[devframe] The devframe server refused this client's credentials`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e)}return i.emit(hx.client.isTrustedUpdated,c),t.isTrusted}async function ie(e){let t=(await te.$call(`anonymous:devframe:auth:exchange`,{code:e,ua:navigator.userAgent,origin:location.origin}))?.authToken??null;return t&&(ne=t,c=!0,d.resolve(!0),f(`connected`),i.emit(hx.client.isTrustedUpdated,!0)),t}async function ae(e={}){await te.$call(`anonymous:devframe:auth:request-code`,{ua:navigator.userAgent,origin:location.origin,...e.reissue?{reissue:!0}:{}})}async function oe(){return c?!0:re(ne??``)}async function se(e=6e4){if(c&&d.resolve(!0),e<=0)return d.promise;let t;try{return await Promise.race([d.promise,new Promise((n,r)=>{t=setTimeout(()=>{r(Error(`[devframe] Timeout waiting for rpc to be trusted`))},e)})]),c}finally{clearTimeout(t)}}return{transport:t,get isTrusted(){return c},get status(){return l},get connectionError(){return u},requestTrust:oe,requestTrustWithToken:re,requestTrustWithCode:ie,requestAuthCode:ae,ensureTrusted:se,call:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$call(...e),t)},callEvent:(...e)=>{let t=h();if(t){i.emit(hx.client.error,t,String(e[0]));return}return te.$callEvent(...e)},callOptional:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$callOptional(...e),t)},close:()=>{ee.close()}}}function sT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})();if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`;return new URL(e.path??`/`,`${r.protocol}//${t}`).href}return new URL(e.path??``,r).href}let i=e??``;return/^https?:\/\//i.test(i)?i:new URL(i,r).href}function cT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},sseOptions:s={},callTimeout:c=0}=e,l=sT(n.sse,r??`./`,location);return oT({transport:`sse`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>iT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(){s.onConnected?.()},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(){e.onDisconnected(),s.onDisconnected?.()}})})}function lT(e){let{name:t,message:n,cause:r,...i}=e,a=r instanceof Error?r:uT(r)?lT(r):r,o=a===void 0?Error(n):Error(n,{cause:a});return o.name=t,Object.assign(o,i),o}function uT(e){return typeof e==`object`&&!!e&&typeof e.message==`string`&&typeof e.name==`string`}function dT(e){return typeof e==`object`&&!!e&&e.type===`static`&&typeof e.path==`string`}function fT(e){return typeof e==`object`&&!!e&&e.type===`query`&&typeof e.records==`object`&&e.records!==null}function pT(e){return typeof e==`object`&&!!e&&(`output`in e||`error`in e)}function mT(e){if(e.error)throw lT(e.error);return e.output}function hT(e){return e.some(e=>e!=null)}function gT(e){return typeof e==`object`&&e&&`serialization`in e&&`data`in e?e.data:e}function _T(e,t){let n=new Map,r=new Map;function i(e,t){return t===`structured-clone`&&Array.isArray(e)?$C(e):e}function a(e,t){return i(gT(e),t)}async function o(e){n.has(e.path)||n.set(e.path,t(e.path).then(t=>a(t,e.serialization)));let r=await n.get(e.path);return pT(r)?mT(r):r}async function s(e,n){return r.has(e)||r.set(e,t(e).then(e=>a(e,n))),await r.get(e)}async function c(t,n){if(!(t in e))throw Error(`[devframe-rpc] Function "${t}" not found in dump store`);let r=e[t];if(dT(r)){if(hT(n))throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`);return await o(r)}if(fT(r)){let e=Jx(n),i=r.records[e];if(i)return mT(await s(i,r.serialization));if(r.fallback)return mT(await s(r.fallback,r.serialization));throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}if(!hT(n))return r;throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}return{call:async(e,t)=>await c(e,t),callOptional:async(t,n)=>{if(t in e)return await c(t,n)},callEvent:async(e,t)=>{}}}async function vT(e){let t=_T(await e.fetchJsonFromBases(gw),e.fetchJsonFromBases);return{transport:`static`,isTrusted:!0,status:`connected`,connectionError:null,requestTrust:async()=>!0,requestTrustWithToken:async()=>!0,requestTrustWithCode:async()=>null,requestAuthCode:async()=>{},ensureTrusted:async()=>!0,call:(...e)=>t.call(e[0],e.slice(1)),callEvent:(...e)=>t.callEvent(e[0],e.slice(1)),callOptional:(...e)=>t.callOptional(e[0],e.slice(1)),close:()=>{}}}var yT=``;function bT(e,t){return`${e}${yT}${t}`}function xT(e){let t=new Map,n=new Map;e.client.register({name:hx.broadcast.streamingChunk,type:`event`,handler(e,n,r,i){t.get(bT(e,n))?._push(r,i)}}),e.client.register({name:hx.broadcast.streamingEnd,type:`event`,handler(e,n,r){let i=bT(e,n),a=t.get(i);a&&(a._end(r),t.delete(i))}}),e.client.register({name:hx.broadcast.streamingUploadCancel,type:`event`,handler(e,t){let r=bT(e,t),i=n.get(r);i&&(i.abort(`server cancelled upload`),n.delete(r))}}),e.events.on(hx.client.isTrustedUpdated,n=>{if(n)for(let[n,r]of t){if(r.cancelled||r.done)continue;let t=n.indexOf(yT);if(t<0)continue;let i=n.slice(0,t),a=n.slice(t+1);e.callEvent(`devframe:streaming:subscribe`,i,a,{afterSeq:r.lastSeenSeq})}});function r(n,r,i={}){let a=bT(n,r),o=t.get(a);if(o)return o;let s=aw({id:r,highWaterMark:i.highWaterMark,onOverflow(e){console.warn(`[devframe] DF0029: Stream "${n}#${r}" dropped ${e} chunk(s) after exceeding the client high-water mark.`)},onCancel(){e.callEvent(`devframe:streaming:cancel`,n,r),t.delete(a)}});if(t.set(a,s),e.isTrusted)e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:0});else{let i=e.events.on(hx.client.isTrustedUpdated,o=>{o&&(i(),t.has(a)&&!s.cancelled&&!s.done&&e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:s.lastSeenSeq}))})}return s}function i(t,r){let i=bT(t,r),a=n.get(i);if(a)return a;let o=iw({id:r});return o.events.on(`chunk`,(n,i)=>{e.callEvent(`devframe:streaming:upload-chunk`,t,r,n,i)}),o.events.on(`end`,a=>{e.callEvent(`devframe:streaming:upload-end`,t,r,a),n.delete(i)}),n.set(i,o),o}return{subscribe:r,upload:i}}function ST(){}var CT=new Map;function wT(e){let t=e.url;e.authToken&&(t=`${t}?${yw}=${encodeURIComponent(e.authToken)}`);let n=new WebSocket(t),{onConnected:r=ST,onError:i=ST,onDisconnected:a=ST,definitions:o=CT}=e;n.addEventListener(`open`,e=>{r(e)}),n.addEventListener(`error`,e=>{let t=e instanceof Error?e:Error(e.type);i(t)}),n.addEventListener(`close`,e=>{a(e)});let s=eT(o);return{close:()=>{n.close()},on:e=>{n.addEventListener(`message`,t=>{e(t.data)})},post:e=>{if(n.readyState===WebSocket.OPEN){n.send(e);return}if(n.readyState===WebSocket.CONNECTING){let t=()=>{i(),n.readyState===WebSocket.OPEN&&n.send(e)},r=()=>i();function i(){n.removeEventListener(`open`,t),n.removeEventListener(`close`,r)}n.addEventListener(`open`,t),n.addEventListener(`close`,r);return}i(Error(`Devframe WebSocket is not open; message dropped`))},serialize:s.serialize,deserialize:s.deserialize}}function TT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})(),i=r.protocol===`https:`?`wss:`:`ws:`;if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`,n=new URL(e.path??`/`,`${i}//${t}`);return n.protocol=i,n.href}let t=new URL(e.path??``,r);return t.protocol=i,t.href}if(typeof e==`number`)return`${i}//${r.hostname}:${e}`;let a=e??``;if(/^wss?:\/\//i.test(a))return a;if(/^https?:\/\//i.test(a))return tS(a,/^https/i.test(a)?`wss://`:`ws://`);let o=new URL(a,r);return o.protocol=i,o.href}function ET(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},wsOptions:s={},callTimeout:c=0}=e,l=TT(n.websocket,r??`./`,location);return oT({transport:`websocket`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>wT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(e){s.onConnected?.(e)},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(t){e.onDisconnected(),s.onDisconnected?.(t)}})})}function DT(e){return e.includes(`:`)}function OT(e,t){return DT(t)?t:`${e}:${t}`}function kT(e){return{async get(t){return(await e()).value()[t]},async set(t,n){(await e()).mutate(e=>{e[t]=n})},async delete(t){(await e()).mutate(e=>{delete e[t]})},async all(){return(await e()).value()},async onChange(t){return(await e()).on(`updated`,e=>t(e))}}}function AT(e,t,n){let r=`devframe:settings:${n}:${t}`,i;function a(){return i||=e.sharedState.get(r,{initialValue:{}}),i}return kT(a)}function jT(e,t){return{global:AT(e,t,`global`),project:AT(e,t,`project`)}}function MT(e,t){return{namespace:t,base:e,rpc:{namespace:t,register(n){if(DT(n.name))throw Error(`[devframe] Scoped client RPC registration for namespace "${t}" received an already-namespaced function name "${n.name}". Pass a bare name without a ":" separator.`);e.client.register({...n,name:`${t}:${n.name}`})},call:((n,...r)=>e.call(OT(t,n),...r)),callEvent:((n,...r)=>e.callEvent(OT(t,n),...r)),callOptional:((n,...r)=>e.callOptional(OT(t,n),...r)),sharedState:((n,r)=>e.sharedState.get(OT(t,n),r)),streaming:{subscribe:(n,r,i)=>e.streaming.subscribe(OT(t,n),r,i),upload:(n,r)=>e.streaming.upload(OT(t,n),r)}},settings:jT(e,t),scope:e.scope}}function NT(){if(typeof document<`u`){let e=document.modelContext;if(e)return e}if(typeof navigator<`u`){let e=navigator.modelContext;if(e)return e}}function PT(e,t={}){let n=t.modelContext??NT();if(!n)return()=>{};let r=n,i=new Map,a=new Map;function o(t,n){let o=cw(t.name),s=a.get(o);if(s&&s!==t.name){console.warn(`[devframe] WebMCP tool name "${o}" (from "${t.name}") collides with "${s}"; keeping the first registration.`);return}let c=new AbortController,l=kx(t.type,n),u=r.registerTool({name:o,description:n.description,inputSchema:Mx(t.args),annotations:{title:n.title??t.name,readOnlyHint:l===`read`,destructiveHint:l===`destructive`},execute:n=>FT(t,e.context,n)},{signal:c.signal});u&&`then`in u&&u.then(()=>{},()=>{}),a.set(o,t.name),i.set(t.name,()=>{c.abort(),u&&`unregister`in u&&typeof u.unregister==`function`&&u.unregister(),a.delete(o)})}function s(t){let n=t?[t]:[...e.definitions.keys()];for(let t of n){i.get(t)?.(),i.delete(t);let n=e.definitions.get(t),r=n?.agent;n&&r&&o(n,r)}}s();let c=e.onChanged(e=>s(e));return()=>{c();for(let e of i.values())e();i.clear()}}async function FT(e,t,n){try{let r=Px(n,e.args?.length);return{content:[{type:`text`,text:IT(await(await Ow(e,t))(...r))}]}}catch(e){return{isError:!0,content:[{type:`text`,text:LT(e)}]}}}function IT(e){return e===void 0?`undefined`:typeof e==`string`?e:JSON.stringify(e,null,2)}function LT(e){if(!(e instanceof Error))return String(e);let t=e.cause instanceof Error?` (cause: ${e.cause.message})`:``;return`${e.name}: ${e.message}${t}`}function RT(e,t){if(t.backend===`static`)return`static`;let n=t.websocket!==void 0,r=t.sse!==void 0;if(e===`websocket`){if(!n)throw Error(`[devframe] transport: 'websocket' was requested, but this server does not advertise a WebSocket endpoint`);return`websocket`}if(e===`sse`){if(!r)throw Error(`[devframe] transport: 'sse' was requested, but this server does not advertise an SSE endpoint`);return`sse`}if(t.backend===`sse`&&r)return`sse`;if(n)return`websocket`;if(r)return`sse`;throw Error(`[devframe] This server advertises no RPC transport (backend "none"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.`)}async function zT(e={}){let{baseURL:t=`./`,rpcOptions:n={},cacheOptions:r=!1}=e,i=Yx(),a=Array.isArray(t)?t:[t],o=await Gw(e),{connectionMeta:s,metaBaseUrl:c,authToken:l}=o,u=a[0]??`./`;try{u=new URL(`.`,c).href}catch{}let d=new bw({functions:[],...typeof e.cacheOptions==`object`?e.cacheOptions:{}}),f={rpc:void 0},p=new kw(f),m=e.webmcp===!1?void 0:PT(p),h,g=!1;async function _(e){let t=[u,...a.filter(e=>e!==u)].filter(e=>e!=null),n=[];for(let r of t)try{return await fetch(eS(e,r)).then(t=>{if(!t.ok)throw Error(`Failed to fetch ${e} from ${r}: ${t.status}`);return t.json()})}catch(e){n.push(e)}throw Error(`Failed to load ${e} from ${t.join(`, `)}`,{cause:n})}let ee={authToken:l,connectionMeta:s,metaBaseUrl:c,events:i,clientRpc:p,callTimeout:e.callTimeout,rpcOptions:{...n,async onRequest(e,t,i){if(await n.onRequest?.call(this,e,t,i),r&&d?.validate(e.m)){if(d.has(e.m,e.a))return i(d.cached(e.m,e.a));let n=await t(e);d.apply(e,n)}else await t(e)}}},te=RT(e.transport??`auto`,s),ne=te===`static`?await vT({fetchJsonFromBases:_}):te===`sse`?cT({...ee,sseOptions:e.sseOptions}):ET({...ee,wsOptions:e.wsOptions}),re;try{re=new BroadcastChannel(`devframe-auth`)}catch{}let ie,ae=!1;function oe(e){return((...t)=>ae||!ie?e(...t):ie.then(()=>e(...t)))}function se(){g=!0;try{h?.(),m?.()}finally{try{re?.close()}finally{ne.close?.()}}}let ce={events:i,get isTrusted(){return ne.isTrusted},get status(){return ne.status},get connectionError(){return ne.connectionError},get transport(){return ne.transport??te},get connection(){return o},connectionMeta:s,ensureTrusted:ne.ensureTrusted,requestTrust:ne.requestTrust,requestTrustWithToken:async e=>(Vw(e),o={...o,authToken:e},ne.requestTrustWithToken(e)),requestTrustWithCode:async e=>{let t=await ne.requestTrustWithCode(e);if(!t)return!1;Vw(t),o={...o,authToken:t};try{re?.postMessage({type:`auth-update`,authToken:t})}catch{}return!0},requestAuthCode:e=>ne.requestAuthCode(e),call:oe(ne.call),callEvent:oe(ne.callEvent),callOptional:oe(ne.callOptional),client:p,sharedState:void 0,services:void 0,streaming:void 0,cacheManager:d,scope:void 0,close:se};ce.sharedState=Qw(ce),ce.streaming=xT(ce),ce.services=Zw(ce);let le=new Map;ce.scope=(e=>{if(!e)return ce;let t=le.get(e);return t||(t=MT(ce,e),le.set(e,t)),t}),f.rpc=ce;function ue(){try{return typeof window<`u`&&window.self===window.top}catch{return!1}}async function de(){if(e.simpleAuth!==!1&&ue()&&typeof globalThis.prompt==`function`)for(await ce.requestAuthCode().catch(()=>{});!ce.isTrusted;){let e=globalThis.prompt(`devframe: enter the authentication code shown in your terminal`);if(e==null)return;let t=e.trim();if(t&&await ce.requestTrustWithCode(t))return}}async function fe(){let t=await ne.requestTrust(),n=e.otpParam??`devframe_otp`,r=n?await Xw(ce,{param:n}):!1;t||r||ce.isTrusted||await de()}return ie=fe().then(()=>{ae=!0},()=>{ae=!0}),s.mcp&&fw(async()=>{let{setupBrowserAgentRpcBridge:e}=await import(`./browser-agent-rpc-BXhoSh1z-DD97nExW.js`);return{setupBrowserAgentRpcBridge:e}},[],import.meta.url).then(({setupBrowserAgentRpcBridge:e})=>{g||(h=e(ce))}).catch(()=>{}),re&&(re.onmessage=e=>{e.data?.type===`auth-update`&&e.data.authToken&&ce.requestTrustWithToken(e.data.authToken)}),ce}var BT=zT,VT=[`components`,`injectors`,`signals`,`ngrx`,`forms`,`router`,`pipes`,`http`,`analog`,`capacitor`,`errors`],HT=[`angular`,`ngrx`,`analog`,`angular-native`,`nativescript`,`capacitor`];function UT(e){return`pangular:${e}`}var WT=[`forms`,`router`,`ngrx`,`http`,`analog`,`components`],GT={refreshMs:{default:3e3,min:500,max:8e3},navigations:{default:50,min:5,max:500},formTimeline:{default:200,min:10,max:2e3},httpCalls:{default:200,min:10,max:2e3},changeLog:{default:200,min:10,max:2e3},cdCycles:{default:200,min:10,max:2e3},capacitorCalls:{default:200,min:10,max:2e3},idleAfterMs:{default:6e4,min:0,max:6e5}},KT={"opted-out":`the request sets transferCache: false`,post:`POST requests are left out unless includePostRequests is set`,method:`only GET, HEAD and POST requests are cached`,"auth-headers":`it sends an Authorization, Proxy-Authorization or Cookie header`,credentials:`it sends credentials (withCredentials or credentials: include/same-origin)`,"no-cache-request":`the request asks for no-store, no-cache or private`,"no-cache-response":`the response has Cache-Control no-store, no-cache or private`,"set-cookie":`the response sets a cookie`,error:`failed responses are not stored`,mocked:`a fault rule answered before the transfer cache ran`,"cache-off-or-filter":`the transfer cache is off, or its filter (or another withHttpTransferCacheOptions setting) left it out`},qT=[[200,`OK`],[201,`Created`],[202,`Accepted`],[203,`Non-Authoritative Information`],[204,`No Content`],[205,`Reset Content`],[206,`Partial Content`],[207,`Multi-Status`],[208,`Already Reported`],[226,`IM Used`],[300,`Multiple Choices`],[301,`Moved Permanently`],[302,`Found`],[303,`See Other`],[304,`Not Modified`],[307,`Temporary Redirect`],[308,`Permanent Redirect`],[400,`Bad Request`],[401,`Unauthorized`],[402,`Payment Required`],[403,`Forbidden`],[404,`Not Found`],[405,`Method Not Allowed`],[406,`Not Acceptable`],[407,`Proxy Authentication Required`],[408,`Request Timeout`],[409,`Conflict`],[410,`Gone`],[411,`Length Required`],[412,`Precondition Failed`],[413,`Content Too Large`],[414,`URI Too Long`],[415,`Unsupported Media Type`],[416,`Range Not Satisfiable`],[417,`Expectation Failed`],[418,`I'm a Teapot`],[421,`Misdirected Request`],[422,`Unprocessable Content`],[423,`Locked`],[424,`Failed Dependency`],[425,`Too Early`],[426,`Upgrade Required`],[428,`Precondition Required`],[429,`Too Many Requests`],[431,`Request Header Fields Too Large`],[451,`Unavailable For Legal Reasons`],[499,`Client Closed Request`],[500,`Internal Server Error`],[501,`Not Implemented`],[502,`Bad Gateway`],[503,`Service Unavailable`],[504,`Gateway Timeout`],[505,`HTTP Version Not Supported`],[506,`Variant Also Negotiates`],[507,`Insufficient Storage`],[508,`Loop Detected`],[510,`Not Extended`],[511,`Network Authentication Required`],[520,`Web Server Returned an Unknown Error`],[521,`Web Server Is Down`],[522,`Connection Timed Out`],[523,`Origin Is Unreachable`],[524,`A Timeout Occurred`]];function JT(e){return qT.some(([t])=>t===e)}var YT=`pangular`,XT={mod:`Mod`,ctrl:`Ctrl`,control:`Ctrl`,meta:`Meta`,cmd:`Meta`,command:`Meta`,alt:`Alt`,option:`Alt`,opt:`Alt`,shift:`Shift`},ZT=[`Mod`,`Ctrl`,`Meta`,`Alt`,`Shift`];function QT(e){if(typeof e!=`string`||e.length>40)return;let t=e.split(`+`).map(e=>e.trim());if(t.some(e=>!e))return;let n=new Set,r;for(let e of t){let t=XT[e.toLowerCase()];if(t){if(n.has(t))return;n.add(t);continue}if(r!==void 0)return;if(/^[a-z0-9]$/i.test(e))r=e.toUpperCase();else if(/^f([1-9]|1[0-2])$/i.test(e))r=e.toUpperCase();else return}if(r&&[...n].some(e=>e!==`Shift`)&&!(n.has(`Mod`)&&(n.has(`Ctrl`)||n.has(`Meta`))))return[...ZT.filter(e=>n.has(e)),r].join(`+`)}function $T(e,t,n){let r=t.split(`+`),i=r.pop(),a=new Set(r),o=a.has(`Ctrl`)||a.has(`Mod`)&&!n,s=a.has(`Meta`)||a.has(`Mod`)&&n;if(e.ctrlKey!==o||e.metaKey!==s||e.altKey!==a.has(`Alt`)||e.shiftKey!==a.has(`Shift`))return!1;if(/^F\d+$/.test(i))return e.key.toUpperCase()===i;let c=/^\d$/.test(i)?`Digit${i}`:`Key${i}`;return e.code?e.code===c:e.key.toUpperCase()===i}function eE(e,t){if(!t)return e.replace(/^Mod\b/,`Ctrl`);let n={Mod:`⌘`,Meta:`⌘`,Ctrl:`⌃`,Alt:`⌥`,Shift:`⇧`};return e.split(`+`).map(e=>n[e]??e).join(``)}var tE=[{id:`dashboard`,label:`Dashboard`},{id:`timeline`,label:`Timeline`},{id:`analog`,label:`Analog`,inspector:`analog`},{id:`components`,label:`Components`,inspector:`components`},{id:`routes`,label:`Routes`,inspector:`router`},{id:`signals`,label:`Signals`,inspector:`signals`},{id:`injectors`,label:`Injectors`,inspector:`injectors`},{id:`store`,label:`Store`,inspector:`ngrx`},{id:`forms`,label:`Forms`,inspector:`forms`},{id:`pipes`,label:`Pipes`,inspector:`pipes`},{id:`network`,label:`SSR & HTTP`,inspector:`http`},{id:`errors`,label:`Errors`,inspector:`errors`},{id:`capacitor`,label:`Capacitor`,inspector:`capacitor`}],nE=1e4;function rE(e){return tE.filter(t=>!(`inspector`in t)||e.inspectors[t.inspector])}var iE={components:`a component instance, by its id in the component tree`,injectors:`a component's element injector, by the component's id`,forms:`a form, by its id`},aE=200;function oE(e){let t=new URLSearchParams({tab:e.tab});return e.id&&t.set(`id`,e.id),e.page&&t.set(`page`,e.page),`#${t.toString()}`}function sE(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=e=>{let n=t.get(e)?.trim();return n&&n.length<=aE?n:void 0},r=n(`tab`);if(!r)return null;let i=n(`id`),a=n(`page`);return{tab:r,...i?{id:i}:{},...a?{page:a}:{}}}var cE=[{id:`settings`,title:`Open settings`,group:`Go to`,keywords:`preferences tabs`},{id:`pick-component`,title:`Pick component on page`,group:`Actions`,keywords:`select inspect element`,inspector:`components`},{id:`cd-record-start`,title:`Start recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-record-stop`,title:`Stop recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-clear`,title:`Clear change detection recording`,group:`Actions`,keywords:`reset recordings cycles`,inspector:`components`},{id:`theme:system`,title:`Theme: follow the system`,group:`Theme`,keywords:`auto`},{id:`theme:light`,title:`Theme: light`,group:`Theme`},{id:`theme:dark`,title:`Theme: dark`,group:`Theme`},{id:`dock:float`,title:`Popup: float`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:bottom`,title:`Popup: dock to the bottom`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:right`,title:`Popup: dock to the right`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:reset-size`,title:`Popup: reset the docked size`,group:`Popup`,keywords:`splitter resize height width`,popupOnly:!0},{id:`popout`,title:`Popup: open in its own window`,group:`Popup`,keywords:`pop out detach new window`,popupOnly:!0},{id:`popout:return`,title:`Popup: back into the page`,group:`Popup`,keywords:`pop in attach dock window`,popupOnly:!0}];function lE(e){let t=rE(e).map(e=>({id:`tab:${e.id}`,title:`Go to ${e.label}`,group:`Go to`,keywords:`tab open`})),n=cE.filter(t=>!t.inspector||e.inspectors[t.inspector]).map(({inspector:e,...t})=>t);return[...t,...n]}function uE(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function dE(e,t){return typeof e==`boolean`?e:t}var fE=100,pE=100;function mE(e){if(!Array.isArray(e))return[];let t=e.filter(e=>typeof e==`string`).map(e=>e.trim()).filter(e=>e&&e.length<=pE);return[...new Set(t)].slice(0,fE)}function hE(e,t){let{default:n,min:r,max:i}=GT[t];return typeof e!=`number`||!Number.isFinite(e)?n:Math.min(i,Math.max(r,Math.round(e)))}function gE(e,t){return Object.fromEntries(e.map(e=>[e,t(e)]))}function _E(e){let t=uE(e),n=uE(t.agent),r=uE(t.inspectors),i=uE(n.tools),a=uE(t.actions),o=dE(t.actions,!0),s=uE(t.redaction),c=uE(t.limits),l=gE(VT,e=>dE(r[e],!0));return{inspectors:l,agent:{readOnly:dE(n.readOnly,!1),tools:gE(VT,e=>l[e]&&dE(i[e],!0))},actions:gE(WT,e=>l[e]&&dE(a[e],o)),redaction:{secretNames:mE(s.secretNames),unmask:mE(s.unmask)},limits:Object.fromEntries(Object.keys(GT).map(e=>[e,hE(c[e],e)])),popup:{hotkey:vE(uE(t.popup).hotkey)}}}function vE(e){return e===!1?!1:QT(e)??`Alt+Shift+P`}function yE(e){let t=e?.configs;return _E(t?.[YT])}function bE(e){return`${{forms:`Writing to forms`,router:`Navigating and clearing navigations`,ngrx:`Restoring NgRx state and dispatching actions`,http:`Changing HTTP mock rules and clearing HTTP calls`,analog:`Calling API routes and clearing server calls`,components:`Editing component properties and signals`}[e]} is turned off in the devtools config (actions.${e}).`}var xE={components:`Components`,injectors:`Injectors`,signals:`Signals`,ngrx:`NgRx`,forms:`Forms`,router:`Router`,pipes:`Pipes`,http:`HTTP`,analog:`Analog`,capacitor:`Capacitor`,errors:`Errors`},SE={forms:`Form writes`,router:`Navigation`,ngrx:`NgRx restore and dispatch`,http:`HTTP mocking`,analog:`Analog API calls`,components:`Component edits`},CE={refreshMs:e=>`poll every ${e} ms`,navigations:e=>`${e} navigations`,formTimeline:e=>`${e} form events`,httpCalls:e=>`${e} HTTP calls`,changeLog:e=>`${e} NgRx changes`,cdCycles:e=>`${e} change detection cycles`,capacitorCalls:e=>`${e} Capacitor plugin calls`,idleAfterMs:e=>e?`idle ${e/1e3} s after the last agent call`:`never idle`};function wE(e){let t=[],n=(e,n)=>{n.length&&t.push({label:e,value:n.join(`, `)})},r=VT.filter(t=>e.inspectors[t]);return n(`Inspectors off`,VT.filter(t=>!e.inspectors[t]).map(e=>xE[e])),n(`Agent`,e.agent.readOnly?[`Read-only`]:[]),n(`Hidden from the agent`,r.filter(t=>!e.agent.tools[t]).map(e=>xE[e])),n(`Blocked actions`,WT.filter(t=>e.inspectors[t]&&!e.actions[t]).map(e=>SE[e])),n(`Extra secret names`,e.redaction.secretNames),n(`Unmasked names`,e.redaction.unmask),n(`Limits`,Object.keys(GT).filter(t=>e.limits[t]!==GT[t].default).map(t=>CE[t](e.limits[t]))),e.popup.hotkey!==`Alt+Shift+P`&&n(`Popup shortcut`,[e.popup.hotkey===!1?`Off`:e.popup.hotkey]),t}function TE(e){let t={tags:[],directives:[],text:``},n=e.toLowerCase();return n=n.replace(/<\s*([^<>\s]+)\s*>/g,(e,n)=>(t.tags.push({value:n,exact:!0}),` `)),n=n.replace(/\[\s*([^[\]\s]+)\s*\]/g,(e,n)=>(t.directives.push({value:n,exact:!0}),` `)),n=n.replace(/(^|\s)([<[])([^<>[\]\s]*)$/,(e,n,r,i)=>(i&&(r===`<`?t.tags:t.directives).push({value:i,exact:!1}),n)),t.text=n.replace(/\s+/g,` `).trim(),t}function EE(e){return!e.tags.length&&!e.directives.length&&!e.text}function DE(e,t){let n=e.tag.toLowerCase(),r=(e.directives??[]).map(e=>e.toLowerCase()),i=(e.attributes??[]).map(e=>e.toLowerCase()),a=[...r,...r.map(e=>e.replace(/directive$/,``)),...i];for(let{value:e,exact:r}of t.tags)if(r?n!==e:!n.startsWith(e))return!1;for(let{value:e,exact:n}of t.directives)if(!a.some(t=>n?t===e:t.includes(e)))return!1;if(t.text){let a=t.text;if(!(e.name.toLowerCase().includes(a)||n.includes(a)||r.some(e=>e.includes(a))||i.some(e=>e.includes(a))))return!1}return!0}var OE={debugApi:{subject:`Live data`,since:`12.0`},injectorProviders:{subject:`Reading providers and environment injectors`,since:`16.2`},injectorMetadata:{subject:`The full injector tree`,since:`17.0`},isSignal:{subject:`Telling signals apart in component values`,since:`17.1`},signalGraph:{subject:`The live signal graph`,since:`20.1`},deferBlocks:{subject:`Listing @defer blocks`,since:`19.1`},forBlocks:{subject:`Listing @for blocks`,since:`22.0`},profiler:{subject:`Recording change detection`,since:`20.0`},angularProfiling:{subject:`Angular profiling`,since:`20.0`},routerInstance:{subject:`The router debug util`,since:`20.3`}};function kE(e){let t=/^(\d+)\.(\d+)/.exec(e.trim());return t?`${t[1]}.${t[2]}`:e.trim()}function AE(e){let t=/^(\d+)(?:\.(\d+))?/.exec(e.trim());return t?[Number(t[1]),Number(t[2]??0)]:null}function jE(e,t){let n=AE(e),r=AE(t);return!n||!r?!1:n[0]===r[0]?n[1]>=r[1]:n[0]>r[0]}function ME(e,t){return e?.capabilities?.[t]===!1}function NE(e,t){let n=OE[e],r=`${n.subject} needs Angular ${n.since} or later`;if(!t)return`${r}; this page's Angular version is unknown.`;let i=kE(t);return jE(t,n.since)?`${r} in a development build; this page runs Angular ${i} without it, which usually means a production build.`:`${r}; this page runs Angular ${i}.`}var PE=`pangular-page-id`,FE=null;function IE(e){FE=e}function LE(){if(FE)return FE;try{return new URLSearchParams(location.search).get(`pageId`)||(window.top===window?null:sessionStorage.getItem(PE)||null)}catch{return null}}function RE(e,t){if(t.chosen&&e[t.chosen])return t.chosen;if(t.host)return t.host;if(t.previous&&e[t.previous])return t.previous;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n?.pageId??null}function zE(e,t){return e?t?e.pages?.[t]??null:e:null}function BE(e,t){return e?t?e.pages?.[t]??null:e.graph??null:null}function VE(e,t,n){return e?e.scope(`pangular`).rpc.call(t,...n===void 0?[]:[n]):Promise.resolve(null)}function HE(e,t,n){return VE(e,t,n).then(e=>e,()=>null)}function UE(e){return e?.connectionMeta.backend===`static`}function WE(e){let t=()=>{let t=e()?.scope(`pangular`).rpc;t&&(t.callEvent(`request-page-highlight`,null),t.callEvent(`request-form-highlight`,null))};return addEventListener(`pagehide`,t),()=>{removeEventListener(`pagehide`,t),t()}}function GE(e){return e.split(`@`)[1]??``}var KE={signal:`Signal Forms`,reactive:`Reactive`,template:`Template-driven`},qE={own:`validator`,directive:`template attribute`,tree:`cross-field rule`,async:`async`,parse:`parse`,submission:`server`,schema:`schema`,manual:`setErrors`},JE=HE,YE={key:`name looks secret`,"input-type":`password input`,autocomplete:`autocomplete is a secret kind`,marker:`marked as mask`,parent:`inside a secret group`,config:`listed in mask`};function XE(e){return YE[e]??e}var ZE=`https://pangular-inspector.dev/security/#opt-fields-in-or-out`;async function QE(e,t){return await JE(e,`request-form-action`,t)??{ok:!1,error:`The devtools server did not answer.`}}function $E(e){return`${e.ok?e.message??`Done.`:e.error??`Failed.`}${e.skipped?.length?` Skipped: ${e.skipped.map(e=>`${e.path} (${e.reason})`).join(`, `)}.`:``}${e.status?` Status: ${e.status}.`:``}`}var eD=/"(?:[^"\\\n]|\\.)*"|`([^`\n]*)`|\*\*/g;function tD(e){return(e??``).replace(/^_Labels, paths.*_\n\n/,``).replace(eD,(e,t)=>t??(e===`**`?``:e))}function nD(e){return yE(e?.connectionMeta)}function rD(e,t){return nD(e).actions[t]}var iD={components:`components`,routes:`router`,signals:`signals`,injectors:`injectors`,store:`ngrx`,forms:`forms`,pipes:`pipes`,network:`http`,analog:`analog`,capacitor:`capacitor`,errors:`errors`};function aD(e){return iD[e]}var oD=`https://pangular-inspector.dev/getting-started/configuration/#inspectors-and-agent-tools`;function sD(e,t){let n=iD[e];return!n||t.inspectors[n]}function cD(e,t){e&1&&(D(),Vg(0,`rect`,4)(1,`rect`,5)(2,`rect`,6)(3,`rect`,7))}function lD(e,t){e&1&&(D(),Vg(0,`path`,8)(1,`circle`,9)(2,`circle`,10)(3,`path`,11))}function uD(e,t){e&1&&(D(),Vg(0,`path`,12)(1,`path`,13)(2,`path`,14))}function dD(e,t){e&1&&(D(),Vg(0,`circle`,15)(1,`path`,16)(2,`circle`,17))}function fD(e,t){e&1&&(D(),Vg(0,`path`,1))}function pD(e,t){e&1&&(D(),Vg(0,`path`,18)(1,`path`,19)(2,`path`,20)(3,`path`,21))}function mD(e,t){e&1&&(D(),Vg(0,`ellipse`,22)(1,`path`,23)(2,`path`,24))}function hD(e,t){e&1&&(D(),Vg(0,`rect`,25)(1,`path`,26)(2,`path`,27)(3,`path`,28))}function gD(e,t){e&1&&(D(),Vg(0,`circle`,29)(1,`path`,8)(2,`path`,30))}function _D(e,t){e&1&&(D(),Vg(0,`path`,31)(1,`path`,32)(2,`path`,33)(3,`path`,34)(4,`circle`,35))}function vD(e,t){e&1&&(D(),Vg(0,`circle`,36)(1,`path`,37))}function yD(e,t){e&1&&(D(),Vg(0,`circle`,29)(1,`path`,38)(2,`path`,39))}function bD(e,t){e&1&&(D(),Vg(0,`path`,2))}function xD(e,t){e&1&&(D(),Vg(0,`path`,3))}var SD=class e{name=$.required();static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-tab-icon`]],inputs:{name:[1,`name`]},decls:15,vars:1,consts:[[`viewBox`,`0 0 24 24`,`width`,`16`,`height`,`16`,`fill`,`none`,`stroke`,`currentColor`,`stroke-width`,`1.8`,`stroke-linecap`,`round`,`stroke-linejoin`,`round`,`aria-hidden`,`true`],[`d`,`M22 12h-4l-3 9L9 3l-3 9H2`],[`d`,`m8 3 4 8 5-5 5 15H2L8 3z`],[`fill`,`currentColor`,`stroke`,`none`,`transform`,`translate(1.8 1.8) scale(0.85)`,`d`,`M24 3.7l-5.766 5.766 5.725 5.736-3.713 3.712L5.073 3.742 8.786.03l5.736 5.726L20.284 0 24 3.7zM.029 8.785l3.713-3.713 15.173 15.173-3.713 3.714-5.732-5.726L3.7 24 0 20.285l5.754-5.764L.029 8.785z`],[`x`,`3`,`y`,`3`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`14`,`y`,`3`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`x`,`14`,`y`,`12`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`3`,`y`,`16`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`d`,`M3 12h18`],[`cx`,`7`,`cy`,`12`,`r`,`2`],[`cx`,`14`,`cy`,`12`,`r`,`2`],[`d`,`M18 7v10`],[`d`,`M12 2 3 7l9 5 9-5-9-5Z`],[`d`,`m3 12 9 5 9-5`],[`d`,`m3 17 9 5 9-5`],[`cx`,`6`,`cy`,`19`,`r`,`3`],[`d`,`M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15`],[`cx`,`18`,`cy`,`5`,`r`,`3`],[`d`,`M12 22v-5`],[`d`,`M9 8V2`],[`d`,`M15 8V2`],[`d`,`M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z`],[`cx`,`12`,`cy`,`5`,`rx`,`9`,`ry`,`3`],[`d`,`M3 5v14a9 3 0 0 0 18 0V5`],[`d`,`M3 12a9 3 0 0 0 18 0`],[`x`,`3`,`y`,`4`,`width`,`18`,`height`,`16`,`rx`,`2`],[`d`,`M7 9h10`],[`d`,`M7 13h6`],[`d`,`M7 17h8`],[`cx`,`12`,`cy`,`12`,`r`,`9`],[`d`,`M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18Z`],[`d`,`M4 7h10`],[`d`,`M4 17h6`],[`d`,`m14 13 4 4-4 4`],[`d`,`M10 17h8`],[`cx`,`18`,`cy`,`7`,`r`,`3`],[`cx`,`12`,`cy`,`12`,`r`,`3`],[`d`,`M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z`],[`d`,`M12 7v6`],[`d`,`M12 16.5v.01`]],template:function(e,t){if(e&1&&(D(),B(0,`svg`,0),M(1,cD,4,0)(2,lD,4,0)(3,uD,3,0)(4,dD,3,0)(5,fD,1,0,`:svg:path`,1)(6,pD,4,0)(7,mD,3,0)(8,hD,4,0)(9,gD,3,0)(10,_D,5,0)(11,vD,2,0)(12,yD,3,0)(13,bD,1,0,`:svg:path`,2)(14,xD,1,0,`:svg:path`,3),V()),e&2){let e;k(),N((e=t.name())===`dashboard`?1:e===`timeline`?2:e===`components`?3:e===`routes`?4:e===`signals`?5:e===`injectors`?6:e===`store`?7:e===`forms`?8:e===`network`?9:e===`pipes`?10:e===`settings`?11:e===`errors`?12:e===`analog`?13:e===`capacitor`?14:-1)}},styles:[`[_nghost-%COMP%] { +`))}}g()}return(async()=>{try{let e=await a(o,{headers:{accept:`text/event-stream`},signal:c.signal});if(!e.ok||!e.body)throw Error(`Devframe SSE stream request failed: ${e.status}`);await ee(e.body)}catch(e){if(c.signal.aborted){g();return}h(e instanceof Error?e:Error(String(e)))}})(),{close:()=>{l=!0,c.abort(),d?.cancel().catch(()=>{})},on:e=>{u=e},post:async e=>{let t;try{t=await m}catch{return}if(l){n(Error(`Devframe SSE channel is closed; message dropped`));return}try{let n=await a(o,{method:`POST`,headers:{"content-type":`text/plain; charset=utf-8`,[hw]:t},body:e});if(n.status===200){let e=await n.text();e&&u?.(e);return}if(!n.ok)throw Error(`Devframe SSE POST failed: ${n.status}`)}catch(e){n(e instanceof Error?e:Error(String(e)))}},serialize:s.serialize,deserialize:s.deserialize}}function aT(e,t){let{channel:n,rpcOptions:r={}}=t;return Ox(e,{...n,timeout:-1,...r,proxify:!1})}function oT(e){let{transport:t,authToken:n,connectionMeta:r,events:i,clientRpc:a,rpcOptions:o={},callTimeout:s=0}=e,c=!1,l=`connecting`,u=null,d=Promise.withResolvers();function f(e,t=null){if(t?u=t:e===`connected`&&(u=null),e===l)return;let n=l;l=e,i.emit(hx.client.connectionStatus,e,n)}let p=new Set;function m(e){for(let t of[...p])t.reject(e)}function h(){return l===`disconnected`||l===`error`?new Kw(`connection`,`[devframe] Not connected to the devframe server`,{cause:u??void 0}):l===`unauthorized`?new Kw(`auth`,`[devframe] Not authorized by the devframe server`,{cause:u??void 0}):null}function g(e,t){return new Promise((n,r)=>{let a=!1,o,c={reject(e){a||(l(),i.emit(hx.client.error,e,t),r(e))}};function l(){a=!0,p.delete(c),o&&clearTimeout(o)}p.add(c),s>0&&(o=setTimeout(()=>{c.reject(new Kw(`timeout`,`[devframe] RPC call "${t}" timed out after ${s}ms`))},s)),e.then(e=>{a||(l(),n(e))},e=>{if(a)return;l();let n=e instanceof Error?e:Error(String(e));i.emit(hx.client.error,n,t),r(n)})})}let _=new Map;for(let e of r.jsonSerializableMethods??[])_.set(e,{jsonSerializable:!0});let ee=e.createChannel({definitions:_,onError(e){f(`error`,e),i.emit(hx.client.connectionError,e),m(new Kw(`connection`,`[devframe] Connection to the devframe server failed`,{cause:e}))},onDisconnected(){l!==`error`&&f(`disconnected`),m(new Kw(`connection`,`[devframe] Disconnected from the devframe server`,{cause:u??void 0}))}}),te=aT(a.functions,{channel:ee,rpcOptions:o});a.register({name:hx.broadcast.authRevoked,type:`event`,handler:()=>{c=!1;let e=new Kw(`auth`,`[devframe] The devframe server revoked this client's trust`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e),m(e),i.emit(hx.client.isTrustedUpdated,!1)}});let ne=n;async function re(e){ne=e;let t=await te.$call(`anonymous:devframe:auth`,{authToken:e,ua:navigator.userAgent,origin:location.origin});if(c=t.isTrusted,c)d.resolve(!0),f(`connected`);else{let e=new Kw(`auth`,`[devframe] The devframe server refused this client's credentials`);f(`unauthorized`,e),i.emit(hx.client.connectionError,e)}return i.emit(hx.client.isTrustedUpdated,c),t.isTrusted}async function ie(e){let t=(await te.$call(`anonymous:devframe:auth:exchange`,{code:e,ua:navigator.userAgent,origin:location.origin}))?.authToken??null;return t&&(ne=t,c=!0,d.resolve(!0),f(`connected`),i.emit(hx.client.isTrustedUpdated,!0)),t}async function ae(e={}){await te.$call(`anonymous:devframe:auth:request-code`,{ua:navigator.userAgent,origin:location.origin,...e.reissue?{reissue:!0}:{}})}async function oe(){return c?!0:re(ne??``)}async function se(e=6e4){if(c&&d.resolve(!0),e<=0)return d.promise;let t;try{return await Promise.race([d.promise,new Promise((n,r)=>{t=setTimeout(()=>{r(Error(`[devframe] Timeout waiting for rpc to be trusted`))},e)})]),c}finally{clearTimeout(t)}}return{transport:t,get isTrusted(){return c},get status(){return l},get connectionError(){return u},requestTrust:oe,requestTrustWithToken:re,requestTrustWithCode:ie,requestAuthCode:ae,ensureTrusted:se,call:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$call(...e),t)},callEvent:(...e)=>{let t=h();if(t){i.emit(hx.client.error,t,String(e[0]));return}return te.$callEvent(...e)},callOptional:(...e)=>{let t=String(e[0]),n=h();return n?(i.emit(hx.client.error,n,t),Promise.reject(n)):g(te.$callOptional(...e),t)},close:()=>{ee.close()}}}function sT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})();if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`;return new URL(e.path??`/`,`${r.protocol}//${t}`).href}return new URL(e.path??``,r).href}let i=e??``;return/^https?:\/\//i.test(i)?i:new URL(i,r).href}function cT(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},sseOptions:s={},callTimeout:c=0}=e,l=sT(n.sse,r??`./`,location);return oT({transport:`sse`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>iT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(){s.onConnected?.()},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(){e.onDisconnected(),s.onDisconnected?.()}})})}function lT(e){let{name:t,message:n,cause:r,...i}=e,a=r instanceof Error?r:uT(r)?lT(r):r,o=a===void 0?Error(n):Error(n,{cause:a});return o.name=t,Object.assign(o,i),o}function uT(e){return typeof e==`object`&&!!e&&typeof e.message==`string`&&typeof e.name==`string`}function dT(e){return typeof e==`object`&&!!e&&e.type===`static`&&typeof e.path==`string`}function fT(e){return typeof e==`object`&&!!e&&e.type===`query`&&typeof e.records==`object`&&e.records!==null}function pT(e){return typeof e==`object`&&!!e&&(`output`in e||`error`in e)}function mT(e){if(e.error)throw lT(e.error);return e.output}function hT(e){return e.some(e=>e!=null)}function gT(e){return typeof e==`object`&&e&&`serialization`in e&&`data`in e?e.data:e}function _T(e,t){let n=new Map,r=new Map;function i(e,t){return t===`structured-clone`&&Array.isArray(e)?$C(e):e}function a(e,t){return i(gT(e),t)}async function o(e){n.has(e.path)||n.set(e.path,t(e.path).then(t=>a(t,e.serialization)));let r=await n.get(e.path);return pT(r)?mT(r):r}async function s(e,n){return r.has(e)||r.set(e,t(e).then(e=>a(e,n))),await r.get(e)}async function c(t,n){if(!(t in e))throw Error(`[devframe-rpc] Function "${t}" not found in dump store`);let r=e[t];if(dT(r)){if(hT(n))throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`);return await o(r)}if(fT(r)){let e=Jx(n),i=r.records[e];if(i)return mT(await s(i,r.serialization));if(r.fallback)return mT(await s(r.fallback,r.serialization));throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}if(!hT(n))return r;throw Error(`[devframe-rpc] No dump match for "${t}" with args: ${JSON.stringify(n)}`)}return{call:async(e,t)=>await c(e,t),callOptional:async(t,n)=>{if(t in e)return await c(t,n)},callEvent:async(e,t)=>{}}}async function vT(e){let t=_T(await e.fetchJsonFromBases(gw),e.fetchJsonFromBases);return{transport:`static`,isTrusted:!0,status:`connected`,connectionError:null,requestTrust:async()=>!0,requestTrustWithToken:async()=>!0,requestTrustWithCode:async()=>null,requestAuthCode:async()=>{},ensureTrusted:async()=>!0,call:(...e)=>t.call(e[0],e.slice(1)),callEvent:(...e)=>t.callEvent(e[0],e.slice(1)),callOptional:(...e)=>t.callOptional(e[0],e.slice(1)),close:()=>{}}}var yT=``;function bT(e,t){return`${e}${yT}${t}`}function xT(e){let t=new Map,n=new Map;e.client.register({name:hx.broadcast.streamingChunk,type:`event`,handler(e,n,r,i){t.get(bT(e,n))?._push(r,i)}}),e.client.register({name:hx.broadcast.streamingEnd,type:`event`,handler(e,n,r){let i=bT(e,n),a=t.get(i);a&&(a._end(r),t.delete(i))}}),e.client.register({name:hx.broadcast.streamingUploadCancel,type:`event`,handler(e,t){let r=bT(e,t),i=n.get(r);i&&(i.abort(`server cancelled upload`),n.delete(r))}}),e.events.on(hx.client.isTrustedUpdated,n=>{if(n)for(let[n,r]of t){if(r.cancelled||r.done)continue;let t=n.indexOf(yT);if(t<0)continue;let i=n.slice(0,t),a=n.slice(t+1);e.callEvent(`devframe:streaming:subscribe`,i,a,{afterSeq:r.lastSeenSeq})}});function r(n,r,i={}){let a=bT(n,r),o=t.get(a);if(o)return o;let s=aw({id:r,highWaterMark:i.highWaterMark,onOverflow(e){console.warn(`[devframe] DF0029: Stream "${n}#${r}" dropped ${e} chunk(s) after exceeding the client high-water mark.`)},onCancel(){e.callEvent(`devframe:streaming:cancel`,n,r),t.delete(a)}});if(t.set(a,s),e.isTrusted)e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:0});else{let i=e.events.on(hx.client.isTrustedUpdated,o=>{o&&(i(),t.has(a)&&!s.cancelled&&!s.done&&e.callEvent(`devframe:streaming:subscribe`,n,r,{afterSeq:s.lastSeenSeq}))})}return s}function i(t,r){let i=bT(t,r),a=n.get(i);if(a)return a;let o=iw({id:r});return o.events.on(`chunk`,(n,i)=>{e.callEvent(`devframe:streaming:upload-chunk`,t,r,n,i)}),o.events.on(`end`,a=>{e.callEvent(`devframe:streaming:upload-end`,t,r,a),n.delete(i)}),n.set(i,o),o}return{subscribe:r,upload:i}}function ST(){}var CT=new Map;function wT(e){let t=e.url;e.authToken&&(t=`${t}?${yw}=${encodeURIComponent(e.authToken)}`);let n=new WebSocket(t),{onConnected:r=ST,onError:i=ST,onDisconnected:a=ST,definitions:o=CT}=e;n.addEventListener(`open`,e=>{r(e)}),n.addEventListener(`error`,e=>{let t=e instanceof Error?e:Error(e.type);i(t)}),n.addEventListener(`close`,e=>{a(e)});let s=eT(o);return{close:()=>{n.close()},on:e=>{n.addEventListener(`message`,t=>{e(t.data)})},post:e=>{if(n.readyState===WebSocket.OPEN){n.send(e);return}if(n.readyState===WebSocket.CONNECTING){let t=()=>{i(),n.readyState===WebSocket.OPEN&&n.send(e)},r=()=>i();function i(){n.removeEventListener(`open`,t),n.removeEventListener(`close`,r)}n.addEventListener(`open`,t),n.addEventListener(`close`,r);return}i(Error(`Devframe WebSocket is not open; message dropped`))},serialize:s.serialize,deserialize:s.deserialize}}function TT(e,t,n){let r=(()=>{try{return new URL(t,n.href)}catch{return new URL(n.href)}})(),i=r.protocol===`https:`?`wss:`:`ws:`;if(e&&typeof e==`object`){if(e.host!=null||e.port!=null){let t=e.host??`${r.hostname}:${e.port}`,n=new URL(e.path??`/`,`${i}//${t}`);return n.protocol=i,n.href}let t=new URL(e.path??``,r);return t.protocol=i,t.href}if(typeof e==`number`)return`${i}//${r.hostname}:${e}`;let a=e??``;if(/^wss?:\/\//i.test(a))return a;if(/^https?:\/\//i.test(a))return tS(a,/^https/i.test(a)?`wss://`:`ws://`);let o=new URL(a,r);return o.protocol=i,o.href}function ET(e){let{authToken:t,connectionMeta:n,metaBaseUrl:r,events:i,clientRpc:a,rpcOptions:o={},wsOptions:s={},callTimeout:c=0}=e,l=TT(n.websocket,r??`./`,location);return oT({transport:`websocket`,authToken:t,connectionMeta:n,events:i,clientRpc:a,rpcOptions:o,callTimeout:c,createChannel:e=>wT({url:l,authToken:t,definitions:e.definitions,...s,onConnected(e){s.onConnected?.(e)},onError(t){e.onError(t),s.onError?.(t)},onDisconnected(t){e.onDisconnected(),s.onDisconnected?.(t)}})})}function DT(e){return e.includes(`:`)}function OT(e,t){return DT(t)?t:`${e}:${t}`}function kT(e){return{async get(t){return(await e()).value()[t]},async set(t,n){(await e()).mutate(e=>{e[t]=n})},async delete(t){(await e()).mutate(e=>{delete e[t]})},async all(){return(await e()).value()},async onChange(t){return(await e()).on(`updated`,e=>t(e))}}}function AT(e,t,n){let r=`devframe:settings:${n}:${t}`,i;function a(){return i||=e.sharedState.get(r,{initialValue:{}}),i}return kT(a)}function jT(e,t){return{global:AT(e,t,`global`),project:AT(e,t,`project`)}}function MT(e,t){return{namespace:t,base:e,rpc:{namespace:t,register(n){if(DT(n.name))throw Error(`[devframe] Scoped client RPC registration for namespace "${t}" received an already-namespaced function name "${n.name}". Pass a bare name without a ":" separator.`);e.client.register({...n,name:`${t}:${n.name}`})},call:((n,...r)=>e.call(OT(t,n),...r)),callEvent:((n,...r)=>e.callEvent(OT(t,n),...r)),callOptional:((n,...r)=>e.callOptional(OT(t,n),...r)),sharedState:((n,r)=>e.sharedState.get(OT(t,n),r)),streaming:{subscribe:(n,r,i)=>e.streaming.subscribe(OT(t,n),r,i),upload:(n,r)=>e.streaming.upload(OT(t,n),r)}},settings:jT(e,t),scope:e.scope}}function NT(){if(typeof document<`u`){let e=document.modelContext;if(e)return e}if(typeof navigator<`u`){let e=navigator.modelContext;if(e)return e}}function PT(e,t={}){let n=t.modelContext??NT();if(!n)return()=>{};let r=n,i=new Map,a=new Map;function o(t,n){let o=cw(t.name),s=a.get(o);if(s&&s!==t.name){console.warn(`[devframe] WebMCP tool name "${o}" (from "${t.name}") collides with "${s}"; keeping the first registration.`);return}let c=new AbortController,l=kx(t.type,n),u=r.registerTool({name:o,description:n.description,inputSchema:Mx(t.args),annotations:{title:n.title??t.name,readOnlyHint:l===`read`,destructiveHint:l===`destructive`},execute:n=>FT(t,e.context,n)},{signal:c.signal});u&&`then`in u&&u.then(()=>{},()=>{}),a.set(o,t.name),i.set(t.name,()=>{c.abort(),u&&`unregister`in u&&typeof u.unregister==`function`&&u.unregister(),a.delete(o)})}function s(t){let n=t?[t]:[...e.definitions.keys()];for(let t of n){i.get(t)?.(),i.delete(t);let n=e.definitions.get(t),r=n?.agent;n&&r&&o(n,r)}}s();let c=e.onChanged(e=>s(e));return()=>{c();for(let e of i.values())e();i.clear()}}async function FT(e,t,n){try{let r=Px(n,e.args?.length);return{content:[{type:`text`,text:IT(await(await Ow(e,t))(...r))}]}}catch(e){return{isError:!0,content:[{type:`text`,text:LT(e)}]}}}function IT(e){return e===void 0?`undefined`:typeof e==`string`?e:JSON.stringify(e,null,2)}function LT(e){if(!(e instanceof Error))return String(e);let t=e.cause instanceof Error?` (cause: ${e.cause.message})`:``;return`${e.name}: ${e.message}${t}`}function RT(e,t){if(t.backend===`static`)return`static`;let n=t.websocket!==void 0,r=t.sse!==void 0;if(e===`websocket`){if(!n)throw Error(`[devframe] transport: 'websocket' was requested, but this server does not advertise a WebSocket endpoint`);return`websocket`}if(e===`sse`){if(!r)throw Error(`[devframe] transport: 'sse' was requested, but this server does not advertise an SSE endpoint`);return`sse`}if(t.backend===`sse`&&r)return`sse`;if(n)return`websocket`;if(r)return`sse`;throw Error(`[devframe] This server advertises no RPC transport (backend "none"), so there is nothing to connect to. Enable the WebSocket or SSE endpoint on the server, or use its static/MCP surfaces instead.`)}async function zT(e={}){let{baseURL:t=`./`,rpcOptions:n={},cacheOptions:r=!1}=e,i=Yx(),a=Array.isArray(t)?t:[t],o=await Gw(e),{connectionMeta:s,metaBaseUrl:c,authToken:l}=o,u=a[0]??`./`;try{u=new URL(`.`,c).href}catch{}let d=new bw({functions:[],...typeof e.cacheOptions==`object`?e.cacheOptions:{}}),f={rpc:void 0},p=new kw(f),m=e.webmcp===!1?void 0:PT(p),h,g=!1;async function _(e){let t=[u,...a.filter(e=>e!==u)].filter(e=>e!=null),n=[];for(let r of t)try{return await fetch(eS(e,r)).then(t=>{if(!t.ok)throw Error(`Failed to fetch ${e} from ${r}: ${t.status}`);return t.json()})}catch(e){n.push(e)}throw Error(`Failed to load ${e} from ${t.join(`, `)}`,{cause:n})}let ee={authToken:l,connectionMeta:s,metaBaseUrl:c,events:i,clientRpc:p,callTimeout:e.callTimeout,rpcOptions:{...n,async onRequest(e,t,i){if(await n.onRequest?.call(this,e,t,i),r&&d?.validate(e.m)){if(d.has(e.m,e.a))return i(d.cached(e.m,e.a));let n=await t(e);d.apply(e,n)}else await t(e)}}},te=RT(e.transport??`auto`,s),ne=te===`static`?await vT({fetchJsonFromBases:_}):te===`sse`?cT({...ee,sseOptions:e.sseOptions}):ET({...ee,wsOptions:e.wsOptions}),re;try{re=new BroadcastChannel(`devframe-auth`)}catch{}let ie,ae=!1;function oe(e){return((...t)=>ae||!ie?e(...t):ie.then(()=>e(...t)))}function se(){g=!0;try{h?.(),m?.()}finally{try{re?.close()}finally{ne.close?.()}}}let ce={events:i,get isTrusted(){return ne.isTrusted},get status(){return ne.status},get connectionError(){return ne.connectionError},get transport(){return ne.transport??te},get connection(){return o},connectionMeta:s,ensureTrusted:ne.ensureTrusted,requestTrust:ne.requestTrust,requestTrustWithToken:async e=>(Vw(e),o={...o,authToken:e},ne.requestTrustWithToken(e)),requestTrustWithCode:async e=>{let t=await ne.requestTrustWithCode(e);if(!t)return!1;Vw(t),o={...o,authToken:t};try{re?.postMessage({type:`auth-update`,authToken:t})}catch{}return!0},requestAuthCode:e=>ne.requestAuthCode(e),call:oe(ne.call),callEvent:oe(ne.callEvent),callOptional:oe(ne.callOptional),client:p,sharedState:void 0,services:void 0,streaming:void 0,cacheManager:d,scope:void 0,close:se};ce.sharedState=Qw(ce),ce.streaming=xT(ce),ce.services=Zw(ce);let le=new Map;ce.scope=(e=>{if(!e)return ce;let t=le.get(e);return t||(t=MT(ce,e),le.set(e,t)),t}),f.rpc=ce;function ue(){try{return typeof window<`u`&&window.self===window.top}catch{return!1}}async function de(){if(e.simpleAuth!==!1&&ue()&&typeof globalThis.prompt==`function`)for(await ce.requestAuthCode().catch(()=>{});!ce.isTrusted;){let e=globalThis.prompt(`devframe: enter the authentication code shown in your terminal`);if(e==null)return;let t=e.trim();if(t&&await ce.requestTrustWithCode(t))return}}async function fe(){let t=await ne.requestTrust(),n=e.otpParam??`devframe_otp`,r=n?await Xw(ce,{param:n}):!1;t||r||ce.isTrusted||await de()}return ie=fe().then(()=>{ae=!0},()=>{ae=!0}),s.mcp&&fw(async()=>{let{setupBrowserAgentRpcBridge:e}=await import(`./browser-agent-rpc-BXhoSh1z-DiWMXIU4.js`);return{setupBrowserAgentRpcBridge:e}},[],import.meta.url).then(({setupBrowserAgentRpcBridge:e})=>{g||(h=e(ce))}).catch(()=>{}),re&&(re.onmessage=e=>{e.data?.type===`auth-update`&&e.data.authToken&&ce.requestTrustWithToken(e.data.authToken)}),ce}var BT=zT,VT=[`components`,`injectors`,`signals`,`ngrx`,`forms`,`router`,`pipes`,`http`,`analog`,`capacitor`,`errors`],HT=[`angular`,`ngrx`,`analog`,`angular-native`,`nativescript`,`capacitor`];function UT(e){return`pangular:${e}`}var WT=[`forms`,`router`,`ngrx`,`http`,`analog`,`components`],GT={refreshMs:{default:3e3,min:500,max:8e3},navigations:{default:50,min:5,max:500},formTimeline:{default:200,min:10,max:2e3},httpCalls:{default:200,min:10,max:2e3},changeLog:{default:200,min:10,max:2e3},cdCycles:{default:200,min:10,max:2e3},capacitorCalls:{default:200,min:10,max:2e3},idleAfterMs:{default:6e4,min:0,max:6e5}},KT={"opted-out":`the request sets transferCache: false`,post:`POST requests are left out unless includePostRequests is set`,method:`only GET, HEAD and POST requests are cached`,"auth-headers":`it sends an Authorization, Proxy-Authorization or Cookie header`,credentials:`it sends credentials (withCredentials or credentials: include/same-origin)`,"no-cache-request":`the request asks for no-store, no-cache or private`,"no-cache-response":`the response has Cache-Control no-store, no-cache or private`,"set-cookie":`the response sets a cookie`,error:`failed responses are not stored`,mocked:`a fault rule answered before the transfer cache ran`,"cache-off-or-filter":`the transfer cache is off, or its filter (or another withHttpTransferCacheOptions setting) left it out`},qT=[[200,`OK`],[201,`Created`],[202,`Accepted`],[203,`Non-Authoritative Information`],[204,`No Content`],[205,`Reset Content`],[206,`Partial Content`],[207,`Multi-Status`],[208,`Already Reported`],[226,`IM Used`],[300,`Multiple Choices`],[301,`Moved Permanently`],[302,`Found`],[303,`See Other`],[304,`Not Modified`],[307,`Temporary Redirect`],[308,`Permanent Redirect`],[400,`Bad Request`],[401,`Unauthorized`],[402,`Payment Required`],[403,`Forbidden`],[404,`Not Found`],[405,`Method Not Allowed`],[406,`Not Acceptable`],[407,`Proxy Authentication Required`],[408,`Request Timeout`],[409,`Conflict`],[410,`Gone`],[411,`Length Required`],[412,`Precondition Failed`],[413,`Content Too Large`],[414,`URI Too Long`],[415,`Unsupported Media Type`],[416,`Range Not Satisfiable`],[417,`Expectation Failed`],[418,`I'm a Teapot`],[421,`Misdirected Request`],[422,`Unprocessable Content`],[423,`Locked`],[424,`Failed Dependency`],[425,`Too Early`],[426,`Upgrade Required`],[428,`Precondition Required`],[429,`Too Many Requests`],[431,`Request Header Fields Too Large`],[451,`Unavailable For Legal Reasons`],[499,`Client Closed Request`],[500,`Internal Server Error`],[501,`Not Implemented`],[502,`Bad Gateway`],[503,`Service Unavailable`],[504,`Gateway Timeout`],[505,`HTTP Version Not Supported`],[506,`Variant Also Negotiates`],[507,`Insufficient Storage`],[508,`Loop Detected`],[510,`Not Extended`],[511,`Network Authentication Required`],[520,`Web Server Returned an Unknown Error`],[521,`Web Server Is Down`],[522,`Connection Timed Out`],[523,`Origin Is Unreachable`],[524,`A Timeout Occurred`]];function JT(e){return qT.some(([t])=>t===e)}var YT=`pangular`,XT={mod:`Mod`,ctrl:`Ctrl`,control:`Ctrl`,meta:`Meta`,cmd:`Meta`,command:`Meta`,alt:`Alt`,option:`Alt`,opt:`Alt`,shift:`Shift`},ZT=[`Mod`,`Ctrl`,`Meta`,`Alt`,`Shift`];function QT(e){if(typeof e!=`string`||e.length>40)return;let t=e.split(`+`).map(e=>e.trim());if(t.some(e=>!e))return;let n=new Set,r;for(let e of t){let t=XT[e.toLowerCase()];if(t){if(n.has(t))return;n.add(t);continue}if(r!==void 0)return;if(/^[a-z0-9]$/i.test(e))r=e.toUpperCase();else if(/^f([1-9]|1[0-2])$/i.test(e))r=e.toUpperCase();else return}if(r&&[...n].some(e=>e!==`Shift`)&&!(n.has(`Mod`)&&(n.has(`Ctrl`)||n.has(`Meta`))))return[...ZT.filter(e=>n.has(e)),r].join(`+`)}function $T(e,t,n){let r=t.split(`+`),i=r.pop(),a=new Set(r),o=a.has(`Ctrl`)||a.has(`Mod`)&&!n,s=a.has(`Meta`)||a.has(`Mod`)&&n;if(e.ctrlKey!==o||e.metaKey!==s||e.altKey!==a.has(`Alt`)||e.shiftKey!==a.has(`Shift`))return!1;if(/^F\d+$/.test(i))return e.key.toUpperCase()===i;let c=/^\d$/.test(i)?`Digit${i}`:`Key${i}`;return e.code?e.code===c:e.key.toUpperCase()===i}function eE(e,t){if(!t)return e.replace(/^Mod\b/,`Ctrl`);let n={Mod:`⌘`,Meta:`⌘`,Ctrl:`⌃`,Alt:`⌥`,Shift:`⇧`};return e.split(`+`).map(e=>n[e]??e).join(``)}var tE=[{id:`dashboard`,label:`Dashboard`},{id:`timeline`,label:`Timeline`},{id:`analog`,label:`Analog`,inspector:`analog`},{id:`components`,label:`Components`,inspector:`components`},{id:`routes`,label:`Routes`,inspector:`router`},{id:`signals`,label:`Signals`,inspector:`signals`},{id:`injectors`,label:`Injectors`,inspector:`injectors`},{id:`store`,label:`Store`,inspector:`ngrx`},{id:`forms`,label:`Forms`,inspector:`forms`},{id:`pipes`,label:`Pipes`,inspector:`pipes`},{id:`network`,label:`SSR & HTTP`,inspector:`http`},{id:`errors`,label:`Errors`,inspector:`errors`},{id:`capacitor`,label:`Capacitor`,inspector:`capacitor`}],nE=1e4;function rE(e){return tE.filter(t=>!(`inspector`in t)||e.inspectors[t.inspector])}var iE={components:`a component instance, by its id in the component tree`,injectors:`a component's element injector, by the component's id`,forms:`a form, by its id`},aE=200;function oE(e){let t=new URLSearchParams({tab:e.tab});return e.id&&t.set(`id`,e.id),e.page&&t.set(`page`,e.page),`#${t.toString()}`}function sE(e){let t=new URLSearchParams(e.replace(/^#/,``)),n=e=>{let n=t.get(e)?.trim();return n&&n.length<=aE?n:void 0},r=n(`tab`);if(!r)return null;let i=n(`id`),a=n(`page`);return{tab:r,...i?{id:i}:{},...a?{page:a}:{}}}var cE=[{id:`settings`,title:`Open settings`,group:`Go to`,keywords:`preferences tabs`},{id:`pick-component`,title:`Pick component on page`,group:`Actions`,keywords:`select inspect element`,inspector:`components`},{id:`cd-record-start`,title:`Start recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-record-stop`,title:`Stop recording change detection`,group:`Actions`,keywords:`profiler cycles`,inspector:`components`},{id:`cd-clear`,title:`Clear change detection recording`,group:`Actions`,keywords:`reset recordings cycles`,inspector:`components`},{id:`theme:system`,title:`Theme: follow the system`,group:`Theme`,keywords:`auto`},{id:`theme:light`,title:`Theme: light`,group:`Theme`},{id:`theme:dark`,title:`Theme: dark`,group:`Theme`},{id:`dock:float`,title:`Popup: float`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:bottom`,title:`Popup: dock to the bottom`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:right`,title:`Popup: dock to the right`,group:`Popup`,keywords:`dock`,popupOnly:!0},{id:`dock:reset-size`,title:`Popup: reset the docked size`,group:`Popup`,keywords:`splitter resize height width`,popupOnly:!0},{id:`popout`,title:`Popup: open in its own window`,group:`Popup`,keywords:`pop out detach new window`,popupOnly:!0},{id:`popout:return`,title:`Popup: back into the page`,group:`Popup`,keywords:`pop in attach dock window`,popupOnly:!0}];function lE(e){let t=rE(e).map(e=>({id:`tab:${e.id}`,title:`Go to ${e.label}`,group:`Go to`,keywords:`tab open`})),n=cE.filter(t=>!t.inspector||e.inspectors[t.inspector]).map(({inspector:e,...t})=>t);return[...t,...n]}function uE(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function dE(e,t){return typeof e==`boolean`?e:t}var fE=100,pE=100;function mE(e){if(!Array.isArray(e))return[];let t=e.filter(e=>typeof e==`string`).map(e=>e.trim()).filter(e=>e&&e.length<=pE);return[...new Set(t)].slice(0,fE)}function hE(e,t){let{default:n,min:r,max:i}=GT[t];return typeof e!=`number`||!Number.isFinite(e)?n:Math.min(i,Math.max(r,Math.round(e)))}function gE(e,t){return Object.fromEntries(e.map(e=>[e,t(e)]))}function _E(e){let t=uE(e),n=uE(t.agent),r=uE(t.inspectors),i=uE(n.tools),a=uE(t.actions),o=dE(t.actions,!0),s=uE(t.redaction),c=uE(t.limits),l=gE(VT,e=>dE(r[e],!0));return{inspectors:l,agent:{readOnly:dE(n.readOnly,!1),tools:gE(VT,e=>l[e]&&dE(i[e],!0))},actions:gE(WT,e=>l[e]&&dE(a[e],o)),redaction:{secretNames:mE(s.secretNames),unmask:mE(s.unmask)},limits:Object.fromEntries(Object.keys(GT).map(e=>[e,hE(c[e],e)])),popup:{hotkey:vE(uE(t.popup).hotkey)}}}function vE(e){return e===!1?!1:QT(e)??`Alt+Shift+P`}function yE(e){let t=e?.configs;return _E(t?.[YT])}function bE(e){return`${{forms:`Writing to forms`,router:`Navigating and clearing navigations`,ngrx:`Restoring NgRx state and dispatching actions`,http:`Changing HTTP mock rules and clearing HTTP calls`,analog:`Calling API routes and clearing server calls`,components:`Editing component properties and signals`}[e]} is turned off in the devtools config (actions.${e}).`}var xE={components:`Components`,injectors:`Injectors`,signals:`Signals`,ngrx:`NgRx`,forms:`Forms`,router:`Router`,pipes:`Pipes`,http:`HTTP`,analog:`Analog`,capacitor:`Capacitor`,errors:`Errors`},SE={forms:`Form writes`,router:`Navigation`,ngrx:`NgRx restore and dispatch`,http:`HTTP mocking`,analog:`Analog API calls`,components:`Component edits`},CE={refreshMs:e=>`poll every ${e} ms`,navigations:e=>`${e} navigations`,formTimeline:e=>`${e} form events`,httpCalls:e=>`${e} HTTP calls`,changeLog:e=>`${e} NgRx changes`,cdCycles:e=>`${e} change detection cycles`,capacitorCalls:e=>`${e} Capacitor plugin calls`,idleAfterMs:e=>e?`idle ${e/1e3} s after the last agent call`:`never idle`};function wE(e){let t=[],n=(e,n)=>{n.length&&t.push({label:e,value:n.join(`, `)})},r=VT.filter(t=>e.inspectors[t]);return n(`Inspectors off`,VT.filter(t=>!e.inspectors[t]).map(e=>xE[e])),n(`Agent`,e.agent.readOnly?[`Read-only`]:[]),n(`Hidden from the agent`,r.filter(t=>!e.agent.tools[t]).map(e=>xE[e])),n(`Blocked actions`,WT.filter(t=>e.inspectors[t]&&!e.actions[t]).map(e=>SE[e])),n(`Extra secret names`,e.redaction.secretNames),n(`Unmasked names`,e.redaction.unmask),n(`Limits`,Object.keys(GT).filter(t=>e.limits[t]!==GT[t].default).map(t=>CE[t](e.limits[t]))),e.popup.hotkey!==`Alt+Shift+P`&&n(`Popup shortcut`,[e.popup.hotkey===!1?`Off`:e.popup.hotkey]),t}function TE(e){let t={tags:[],directives:[],text:``},n=e.toLowerCase();return n=n.replace(/<\s*([^<>\s]+)\s*>/g,(e,n)=>(t.tags.push({value:n,exact:!0}),` `)),n=n.replace(/\[\s*([^[\]\s]+)\s*\]/g,(e,n)=>(t.directives.push({value:n,exact:!0}),` `)),n=n.replace(/(^|\s)([<[])([^<>[\]\s]*)$/,(e,n,r,i)=>(i&&(r===`<`?t.tags:t.directives).push({value:i,exact:!1}),n)),t.text=n.replace(/\s+/g,` `).trim(),t}function EE(e){return!e.tags.length&&!e.directives.length&&!e.text}function DE(e,t){let n=e.tag.toLowerCase(),r=(e.directives??[]).map(e=>e.toLowerCase()),i=(e.attributes??[]).map(e=>e.toLowerCase()),a=[...r,...r.map(e=>e.replace(/directive$/,``)),...i];for(let{value:e,exact:r}of t.tags)if(r?n!==e:!n.startsWith(e))return!1;for(let{value:e,exact:n}of t.directives)if(!a.some(t=>n?t===e:t.includes(e)))return!1;if(t.text){let a=t.text;if(!(e.name.toLowerCase().includes(a)||n.includes(a)||r.some(e=>e.includes(a))||i.some(e=>e.includes(a))))return!1}return!0}var OE={debugApi:{subject:`Live data`,since:`12.0`},injectorProviders:{subject:`Reading providers and environment injectors`,since:`16.2`},injectorMetadata:{subject:`The full injector tree`,since:`17.0`},isSignal:{subject:`Telling signals apart in component values`,since:`17.1`},signalGraph:{subject:`The live signal graph`,since:`20.1`},deferBlocks:{subject:`Listing @defer blocks`,since:`19.1`},forBlocks:{subject:`Listing @for blocks`,since:`22.0`},profiler:{subject:`Recording change detection`,since:`20.0`},angularProfiling:{subject:`Angular profiling`,since:`20.0`},routerInstance:{subject:`The router debug util`,since:`20.3`}};function kE(e){let t=/^(\d+)\.(\d+)/.exec(e.trim());return t?`${t[1]}.${t[2]}`:e.trim()}function AE(e){let t=/^(\d+)(?:\.(\d+))?/.exec(e.trim());return t?[Number(t[1]),Number(t[2]??0)]:null}function jE(e,t){let n=AE(e),r=AE(t);return!n||!r?!1:n[0]===r[0]?n[1]>=r[1]:n[0]>r[0]}function ME(e,t){return e?.capabilities?.[t]===!1}function NE(e,t){let n=OE[e],r=`${n.subject} needs Angular ${n.since} or later`;if(!t)return`${r}; this page's Angular version is unknown.`;let i=kE(t);return jE(t,n.since)?`${r} in a development build; this page runs Angular ${i} without it, which usually means a production build.`:`${r}; this page runs Angular ${i}.`}var PE=`pangular-page-id`,FE=null;function IE(e){FE=e}function LE(){if(FE)return FE;try{return new URLSearchParams(location.search).get(`pageId`)||(window.top===window?null:sessionStorage.getItem(PE)||null)}catch{return null}}function RE(e,t){if(t.chosen&&e[t.chosen])return t.chosen;if(t.host)return t.host;if(t.previous&&e[t.previous])return t.previous;let n=null;for(let t of Object.values(e))(!n||t.reportedAt>n.reportedAt)&&(n=t);return n?.pageId??null}function zE(e,t){return e?t?e.pages?.[t]??null:e:null}function BE(e,t){return e?t?e.pages?.[t]??null:e.graph??null:null}function VE(e,t,n){return e?e.scope(`pangular`).rpc.call(t,...n===void 0?[]:[n]):Promise.resolve(null)}function HE(e,t,n){return VE(e,t,n).then(e=>e,()=>null)}function UE(e){return e?.connectionMeta.backend===`static`}function WE(e){let t=()=>{let t=e()?.scope(`pangular`).rpc;t&&(t.callEvent(`request-page-highlight`,null),t.callEvent(`request-form-highlight`,null))};return addEventListener(`pagehide`,t),()=>{removeEventListener(`pagehide`,t),t()}}function GE(e){return e.split(`@`)[1]??``}var KE={signal:`Signal Forms`,reactive:`Reactive`,template:`Template-driven`},qE={own:`validator`,directive:`template attribute`,tree:`cross-field rule`,async:`async`,parse:`parse`,submission:`server`,schema:`schema`,manual:`setErrors`},JE=HE,YE={key:`name looks secret`,"input-type":`password input`,autocomplete:`autocomplete is a secret kind`,marker:`marked as mask`,parent:`inside a secret group`,config:`listed in mask`};function XE(e){return YE[e]??e}var ZE=`https://pangular-inspector.dev/security/#opt-fields-in-or-out`;async function QE(e,t){return await JE(e,`request-form-action`,t)??{ok:!1,error:`The devtools server did not answer.`}}function $E(e){return`${e.ok?e.message??`Done.`:e.error??`Failed.`}${e.skipped?.length?` Skipped: ${e.skipped.map(e=>`${e.path} (${e.reason})`).join(`, `)}.`:``}${e.status?` Status: ${e.status}.`:``}`}var eD=/"(?:[^"\\\n]|\\.)*"|`([^`\n]*)`|\*\*/g;function tD(e){return(e??``).replace(/^_Labels, paths.*_\n\n/,``).replace(eD,(e,t)=>t??(e===`**`?``:e))}function nD(e){return yE(e?.connectionMeta)}function rD(e,t){return nD(e).actions[t]}var iD={components:`components`,routes:`router`,signals:`signals`,injectors:`injectors`,store:`ngrx`,forms:`forms`,pipes:`pipes`,network:`http`,analog:`analog`,capacitor:`capacitor`,errors:`errors`};function aD(e){return iD[e]}var oD=`https://pangular-inspector.dev/getting-started/configuration/#inspectors-and-agent-tools`;function sD(e,t){let n=iD[e];return!n||t.inspectors[n]}function cD(e,t){e&1&&(D(),Vg(0,`rect`,4)(1,`rect`,5)(2,`rect`,6)(3,`rect`,7))}function lD(e,t){e&1&&(D(),Vg(0,`path`,8)(1,`circle`,9)(2,`circle`,10)(3,`path`,11))}function uD(e,t){e&1&&(D(),Vg(0,`path`,12)(1,`path`,13)(2,`path`,14))}function dD(e,t){e&1&&(D(),Vg(0,`circle`,15)(1,`path`,16)(2,`circle`,17))}function fD(e,t){e&1&&(D(),Vg(0,`path`,1))}function pD(e,t){e&1&&(D(),Vg(0,`path`,18)(1,`path`,19)(2,`path`,20)(3,`path`,21))}function mD(e,t){e&1&&(D(),Vg(0,`ellipse`,22)(1,`path`,23)(2,`path`,24))}function hD(e,t){e&1&&(D(),Vg(0,`rect`,25)(1,`path`,26)(2,`path`,27)(3,`path`,28))}function gD(e,t){e&1&&(D(),Vg(0,`circle`,29)(1,`path`,8)(2,`path`,30))}function _D(e,t){e&1&&(D(),Vg(0,`path`,31)(1,`path`,32)(2,`path`,33)(3,`path`,34)(4,`circle`,35))}function vD(e,t){e&1&&(D(),Vg(0,`circle`,36)(1,`path`,37))}function yD(e,t){e&1&&(D(),Vg(0,`circle`,29)(1,`path`,38)(2,`path`,39))}function bD(e,t){e&1&&(D(),Vg(0,`path`,2))}function xD(e,t){e&1&&(D(),Vg(0,`path`,3))}var SD=class e{name=$.required();static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-tab-icon`]],inputs:{name:[1,`name`]},decls:15,vars:1,consts:[[`viewBox`,`0 0 24 24`,`width`,`16`,`height`,`16`,`fill`,`none`,`stroke`,`currentColor`,`stroke-width`,`1.8`,`stroke-linecap`,`round`,`stroke-linejoin`,`round`,`aria-hidden`,`true`],[`d`,`M22 12h-4l-3 9L9 3l-3 9H2`],[`d`,`m8 3 4 8 5-5 5 15H2L8 3z`],[`fill`,`currentColor`,`stroke`,`none`,`transform`,`translate(1.8 1.8) scale(0.85)`,`d`,`M24 3.7l-5.766 5.766 5.725 5.736-3.713 3.712L5.073 3.742 8.786.03l5.736 5.726L20.284 0 24 3.7zM.029 8.785l3.713-3.713 15.173 15.173-3.713 3.714-5.732-5.726L3.7 24 0 20.285l5.754-5.764L.029 8.785z`],[`x`,`3`,`y`,`3`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`14`,`y`,`3`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`x`,`14`,`y`,`12`,`width`,`7`,`height`,`9`,`rx`,`1.5`],[`x`,`3`,`y`,`16`,`width`,`7`,`height`,`5`,`rx`,`1.5`],[`d`,`M3 12h18`],[`cx`,`7`,`cy`,`12`,`r`,`2`],[`cx`,`14`,`cy`,`12`,`r`,`2`],[`d`,`M18 7v10`],[`d`,`M12 2 3 7l9 5 9-5-9-5Z`],[`d`,`m3 12 9 5 9-5`],[`d`,`m3 17 9 5 9-5`],[`cx`,`6`,`cy`,`19`,`r`,`3`],[`d`,`M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15`],[`cx`,`18`,`cy`,`5`,`r`,`3`],[`d`,`M12 22v-5`],[`d`,`M9 8V2`],[`d`,`M15 8V2`],[`d`,`M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z`],[`cx`,`12`,`cy`,`5`,`rx`,`9`,`ry`,`3`],[`d`,`M3 5v14a9 3 0 0 0 18 0V5`],[`d`,`M3 12a9 3 0 0 0 18 0`],[`x`,`3`,`y`,`4`,`width`,`18`,`height`,`16`,`rx`,`2`],[`d`,`M7 9h10`],[`d`,`M7 13h6`],[`d`,`M7 17h8`],[`cx`,`12`,`cy`,`12`,`r`,`9`],[`d`,`M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18Z`],[`d`,`M4 7h10`],[`d`,`M4 17h6`],[`d`,`m14 13 4 4-4 4`],[`d`,`M10 17h8`],[`cx`,`18`,`cy`,`7`,`r`,`3`],[`cx`,`12`,`cy`,`12`,`r`,`3`],[`d`,`M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z`],[`d`,`M12 7v6`],[`d`,`M12 16.5v.01`]],template:function(e,t){if(e&1&&(D(),B(0,`svg`,0),M(1,cD,4,0)(2,lD,4,0)(3,uD,3,0)(4,dD,3,0)(5,fD,1,0,`:svg:path`,1)(6,pD,4,0)(7,mD,3,0)(8,hD,4,0)(9,gD,3,0)(10,_D,5,0)(11,vD,2,0)(12,yD,3,0)(13,bD,1,0,`:svg:path`,2)(14,xD,1,0,`:svg:path`,3),V()),e&2){let e;k(),N((e=t.name())===`dashboard`?1:e===`timeline`?2:e===`components`?3:e===`routes`?4:e===`signals`?5:e===`injectors`?6:e===`store`?7:e===`forms`?8:e===`network`?9:e===`pipes`?10:e===`settings`?11:e===`errors`?12:e===`analog`?13:e===`capacitor`?14:-1)}},styles:[`[_nghost-%COMP%] { display: inline-flex; flex-shrink: 0; }`]})},CD=(e,t)=>t.tab,wD=(e,t)=>t.label;function TD(e,t){e&1&&J(0),e&2&&X(` `,G().meta()?.projectName,` `)}function ED(e,t){e&1&&J(0,` Project details unavailable `)}function DD(e,t){e&1&&J(0,` Loading… `)}function OD(e,t){e&1&&(J(0,` Run `),L(1,`code`),J(2,`pangular build`),R(),J(3,` again to rebuild the report. `))}function kD(e,t){e&1&&J(0,` Check that the dev server is running. `)}function AD(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return T(e),E(G(2).loadMeta())}),J(1,`Try again`),R()}}function jD(e,t){if(e&1&&(L(0,`p`,10),M(1,OD,4,0)(2,kD,1,0),R(),M(3,AD,2,0,`button`,11)),e&2){let e=G();k(),N(e.staticReport()?1:2),k(2),N(e.staticReport()?-1:3)}}function MD(e,t){e&1&&(L(0,`li`,5)(1,`span`),J(2,`Analog`),R(),J(3),R()),e&2&&(k(3),Y(t))}function ND(e,t){e&1&&(L(0,`li`)(1,`span`),J(2,`Change detection`),R(),J(3),R()),e&2&&(k(3),Y(t))}function PD(e,t){if(e&1&&(L(0,`span`,19),J(1),R(),L(2,`span`,20),J(3),R()),e&2){let e=G().$implicit,t=G();k(),Y(t.cards()[e.tab]?.value),k(2),Y(t.cards()[e.tab]?.sub)}}function FD(e,t){e&1&&(L(0,`span`,21),J(1,`–`),R(),L(2,`span`,20),J(3,`Count unavailable`),R())}function ID(e,t){e&1&&(z(0,`span`,22),L(1,`span`,20),J(2,`Counting…`),R())}function LD(e,t){if(e&1){let e=H();L(0,`button`,13),U(`click`,function(){let t=T(e).$implicit;return E(G().navigate.emit(t.tab))}),L(1,`span`,14)(2,`span`,15),z(3,`app-tab-icon`,16),R(),L(4,`span`,17),J(5,`→`),R()(),L(6,`span`,18),J(7),R(),M(8,PD,4,2)(9,FD,4,0)(10,ID,3,0),R()}if(e&2){let e,n=t.$implicit,r=t.$index,i=G().stateOf(n.tab);K(`animation-delay`,60*r,`ms`),j(`aria-busy`,i===`loading`),k(3),I(`name`,n.tab),k(4),Y(n.label),k(),N((e=i)===`ready`?8:e===`error`?9:10)}}function RD(e,t){e&1&&(L(0,`p`),J(1,`Loading…`),R())}function zD(e,t){if(e&1&&(L(0,`div`)(1,`dt`),J(2),R(),L(3,`dd`),J(4),R()()),e&2){let e=t.$implicit;k(2),Y(e.label),k(2),Y(e.value)}}function BD(e,t){if(e&1&&(L(0,`dl`),P(1,zD,5,2,`div`,null,wD),R()),e&2){let e=G();k(),F(e.configItems())}}function VD(e,t){e&1&&(L(0,`p`),J(1,`Defaults`),R())}var HD=[{tab:`components`,label:`Components`},{tab:`routes`,label:`Routes`},{tab:`signals`,label:`Signals`},{tab:`injectors`,label:`Injectors`},{tab:`store`,label:`NgRx declarations`},{tab:`pipes`,label:`Pipes`},{tab:`forms`,label:`Forms`},{tab:`network`,label:`SSR & HTTP`}];function UD(e){return HD.filter(t=>sD(t.tab,e))}var WD={zoneless:`Zoneless`,zone:`zone.js`,"zone-unused":`Zoneless, zone.js loaded`};function GD(e){return e&&Object.hasOwn(WD,e)?WD[e]:null}var KD=new Set([`signal`,`computed`,`linkedSignal`,`effect`]),qD={action:[`action`,`actions`],reducer:[`reducer`,`reducers`],effect:[`effect`,`effects`],selector:[`selector`,`selectors`],feature:[`feature`,`features`],"store-setup":[`setup call`,`setup calls`],"signal-store":[`signal store`,`signal stores`],"signal-state":[`signal state`,`signal states`],"signal-method":[`signal method`,`signal methods`]};function JD(e,t,n){return`${e} ${e===1?t:n}`}function YD(e,t){for(let n of e??[])t(n),YD(n.children,t)}function XD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`discovered in source`};let t=e.filter(e=>e.kind===`directive`).length;return{value:e.length-t,sub:`components · ${JD(t,`directive`,`directives`)}`}}function ZD(e){if(!e.some(e=>e.kind))return{value:e.length,sub:`route entries in source`};let t=e.filter(e=>e.kind===`redirect`).length;return{value:new Set(e.filter(e=>e.kind===`page`).map(e=>e.fullPath??e.path??``)).size,sub:`navigable paths · ${JD(t,`redirect`,`redirects`)}`}}function QD(e){let t=new Map;for(let n of e)n.kind&&t.set(n.kind,(t.get(n.kind)??0)+1);if(!t.size)return{value:e.length,sub:`declarations in source`};let n=[...t].sort((e,t)=>t[1]-e[1]).map(([e,t])=>{let[n,r]=qD[e]??[e,e];return JD(t,n,r)});return{value:e.length,sub:n.join(` · `)}}function $D(e,t){let n=e?.forms??[],r=t?n.filter(e=>GE(e.id)===t):n;if(!r.length)return{value:0,sub:`no forms on the page yet`};let i=r.filter(e=>e.root?.status===`INVALID`).length;return{value:r.length,sub:`${r.length===1?`form`:`forms`} · ${i} invalid`}}function eO(e){return e.cancelled||e.status===void 0?!1:e.status===0||e.status>=400}function tO(e,t){let n=e?.pages??[],r=t?n.find(e=>e.pageId===t)??null:n.reduce((e,t)=>!e||t.reportedAt>e.reportedAt?t:e,null),i=t&&!r?[]:e?.serverCalls??[],a=r?.initialUrl,o=[...a?i.filter(e=>!e.pageUrl||e.pageUrl===a):i,...r?.calls??[]];if(!o.length)return{value:0,sub:`no calls recorded yet`};let s=o.filter(eO).length;return{value:o.length,sub:`${o.length===1?`call`:`calls`} · ${s} failed`}}var nO=class e{rpc=$(null);navigate=Rv();staticReport=Q(()=>UE(this.rpc()));meta=O(null);config=Q(()=>nD(this.rpc()));stats=Q(()=>this.rpc()?UD(this.config()):[]);configItems=Q(()=>wE(this.config()));metaState=O(`loading`);states=O({});rows=O({});injectorTree=O(null);signalGraph=O(null);formsState=O(null);httpState=O(null);pageId=LE();destroyRef=C(Ds);stopLive=[];zone=Q(()=>GD(zE(this.injectorTree(),this.pageId)?.zone));liveInjectors=Q(()=>{let e=zE(this.injectorTree(),this.pageId);if(!e?.roots?.length)return null;let t=0,n=0,r=e=>{t++,n+=e.providers?.length??0};return YD(e.roots,r),YD(e.environment,r),{injectors:t,providers:n}});liveSignals=Q(()=>{let e=BE(this.signalGraph(),this.pageId);return e?.nodes?.length?e.nodes.filter(e=>KD.has(e.kind??``)).length:null});cards=Q(()=>{let e=this.rows(),t={};if(e.components&&(t.components=XD(e.components)),e.routes&&(t.routes=ZD(e.routes)),e.store&&(t.store=QD(e.store)),e.pipes){let n=e.pipes.filter(e=>e.builtin).length;t.pipes={value:e.pipes.length-n,sub:n?`custom pipes · ${n} built-in in use`:`custom pipes in source`}}let n=this.liveSignals();n===null?e.signals&&(t.signals={value:e.signals.length,sub:`signal declarations in source`}):t.signals={value:n,sub:e.signals?`live on the page · ${e.signals.length} declared in source`:`live on the page`};let r=this.liveInjectors();r?t.injectors={value:r.injectors,sub:`live injectors · ${JD(r.providers,`provider`,`providers`)}`}:e.injectors&&(t.injectors={value:e.injectors.filter(e=>e.type!==`injection`).length,sub:`provider declarations in source`});let i=this.formsState();i&&(t.forms=$D(i,this.pageId));let a=this.httpState();return a&&(t.network=tO(a,this.pageId)),t});loadMeta(e=this.rpc()){e&&(this.metaState.set(`loading`),e.scope(`pangular`).rpc.call(`build-meta`).then(t=>{this.rpc()===e&&(this.meta.set(t),this.metaState.set(`ready`))}).catch(()=>{this.rpc()===e&&this.metaState.set(`error`)}))}constructor(){mc(()=>{let e=this.rpc();if(!e)return;let t=e.scope(`pangular`);this.states.set({}),this.rows.set({}),this.formsState.set(null),this.httpState.set(null),this.loadMeta(e);let n=nD(e),r=e=>sD(e,n);r(`components`)&&this.load(t.rpc.call(`get-components`),`components`),r(`routes`)&&this.load(t.rpc.call(`get-routes`),`routes`),r(`signals`)&&this.load(t.rpc.call(`get-signals`),`signals`),r(`injectors`)&&this.load(t.rpc.call(`get-providers`),`injectors`),r(`store`)&&this.load(t.rpc.call(`get-ngrx-store`),`store`),r(`pipes`)&&this.load(t.rpc.call(`get-pipes`),`pipes`),this.watchLive(e,n)}),this.destroyRef.onDestroy(()=>this.unwatch())}stateOf(e){return(e===`signals`?this.liveSignals():e===`injectors`?this.liveInjectors():null)===null?this.states()[e]??`loading`:`ready`}load(e,t){let n=e=>this.states.update(n=>({...n,[t]:e}));e.then(e=>{this.rows.update(n=>({...n,[t]:Array.isArray(e)?e:[]})),n(`ready`)}).catch(()=>n(`error`))}async watchLive(e,t){this.unwatch();let n=e.scope(`pangular`).rpc,r=async(t,r,i)=>{let a=e=>i&&this.states.update(t=>({...t,[i]:e}));try{let i=await n.sharedState(t);if(this.destroyRef.destroyed||this.rpc()!==e)return;r(i.value()),a(`ready`),this.stopLive.push(i.on(`updated`,e=>r(e)))}catch{if(this.destroyRef.destroyed||this.rpc()!==e)return;r(null),a(`error`)}};await Promise.all([t.inspectors.injectors&&r(`injector-tree`,e=>this.injectorTree.set(e)),t.inspectors.signals&&r(`signal-graph`,e=>this.signalGraph.set(e)),sD(`forms`,t)&&r(`forms`,e=>this.formsState.set(e??{}),`forms`),sD(`network`,t)&&r(`http`,e=>this.httpState.set(e??{}),`network`)])}unwatch(){for(let e of this.stopLive.splice(0))e()}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-dashboard`]],inputs:{rpc:[1,`rpc`]},outputs:{navigate:`navigate`},decls:33,vars:14,consts:[[`aria-labelledby`,`project-title`,1,`project`],[1,`project-head`],[1,`eyebrow`],[`id`,`project-title`],[1,`chips`],[1,`analog`],[1,`grid`],[`type`,`button`,1,`stat`,3,`animation-delay`],[`aria-labelledby`,`config-title`,1,`config`],[`id`,`config-title`],[1,`hint`],[`type`,`button`,1,`retry`],[`type`,`button`,1,`retry`,3,`click`],[`type`,`button`,1,`stat`,3,`click`],[1,`top`],[1,`icon`],[3,`name`],[`aria-hidden`,`true`,1,`go`],[1,`label`],[1,`big`],[1,`sub`],[1,`big`,`muted`],[`aria-hidden`,`true`,1,`big`,`skeleton`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`p`,2),J(3,`Project`),R(),L(4,`h2`,3),M(5,TD,1,1)(6,ED,1,0)(7,DD,1,0),R(),M(8,jD,4,2),R(),L(9,`ul`,4)(10,`li`)(11,`span`),J(12,`Angular`),R(),J(13),R(),L(14,`li`)(15,`span`),J(16,`TypeScript`),R(),J(17),R(),L(18,`li`)(19,`span`),J(20,`SSR`),R(),J(21),R(),M(22,MD,4,1,`li`,5),M(23,ND,4,1,`li`),R()(),L(24,`div`,6),P(25,LD,11,6,`button`,7,CD),R(),L(27,`section`,8)(28,`h2`,9),J(29,`Configuration`),R(),M(30,RD,2,0,`p`)(31,BD,3,0,`dl`)(32,VD,2,0,`p`),R()),e&2){let e,n,r;j(`aria-busy`,t.metaState()===`loading`),k(4),q(`muted`,t.metaState()!==`ready`),k(),N((e=t.metaState())===`ready`?5:e===`error`?6:7),k(3),N(t.metaState()===`error`?8:-1),k(),q(`pending`,t.metaState()===`loading`),k(4),Y(t.meta()?.angularVersion??`…`),k(4),Y(t.meta()?.typescript??`…`),k(4),Y(t.meta()?t.meta()?.ssr?`On`:`Off`:`…`),k(),N((n=t.meta()?.analog)?22:-1,n),k(),N((r=t.zone())?23:-1,r),k(2),F(t.stats()),k(2),j(`aria-busy`,!t.rpc()),k(3),N(t.rpc()?t.configItems().length?31:32:30)}},dependencies:[SD],styles:[`[_nghost-%COMP%] { @@ -765,7 +765,7 @@ a[_ngcontent-%COMP%] { a[_ngcontent-%COMP%]:focus-visible { outline: 2px solid var(--%NS%accent); outline-offset: 2px; -}`]})},ik=864e13,ak=200,ok=300,sk=100,ck=10,lk=100,uk=2e3,dk=2e3,fk=4e3,pk=1e3,mk=100,hk=3,gk=50,_k={component:`c`,hook:`h`,afterRender:`r`,output:`o`},vk=Object.values(_k),yk=e=>!!e&&typeof e==`object`&&!Array.isArray(e),bk=e=>typeof e==`number`&&Number.isFinite(e)&&e>=0?e:0,xk=(e,t)=>typeof e==`string`?e.slice(0,t):``,Sk=e=>bk(e)>0?bk(e):void 0,Ck=(e,t)=>Array.isArray(e)?e.slice(0,t):[];function wk(e){if(!yk(e))return null;let t=xk(e.name,ak);return t?{name:t,checks:bk(e.checks),ms:bk(e.ms)}:null}function Tk(e,t){if(!Array.isArray(e)||e.length!==5)return null;let[n,r,i,a,o]=e;return typeof n!=`number`||!Number.isInteger(n)||n<0||n>=t||typeof r!=`number`||!Number.isFinite(r)||Math.abs(r)>1e7||typeof a!=`number`||!Number.isInteger(a)||a<0||a>pk||typeof o!=`string`||!vk.includes(o)?null:[n,r,bk(i),a,o]}function Ek(e,t){if(!yk(e)||typeof e.id!=`number`)return null;let n=Ck(e.components,ck).map(wk).filter(e=>!!e),r=xk(e.trigger,ok),i=Ck(e.spans,40).map(e=>Tk(e,t)).filter(e=>!!e),a=Array.isArray(e.spans)?e.spans.length-40:0,o=Math.floor(bk(e.droppedSpans))+Math.max(0,a),s={t:typeof e.t==`number`?bk(e.t):void 0,hookMs:Sk(e.hookMs),afterRenderMs:Sk(e.afterRenderMs),outputMs:Sk(e.outputMs)},c=Ak(e.cause),l=Sk(e.refreshed),u=Sk(e.unchanged);return{id:bk(e.id),at:bk(e.at),ms:bk(e.ms),passes:bk(e.passes),...r?{trigger:r}:{},checks:bk(e.checks),components:n,...Object.fromEntries(Object.entries(s).filter(([,e])=>e!==void 0)),...i.length?{spans:i}:{},...o?{droppedSpans:o}:{},...c?{cause:c}:{},...l?{refreshed:l}:{},...u?{unchanged:u}:{}}}var Dk=[`event`,`http`,`timer`,`signal`,`effect`,`markForCheck`,`input`,`view`,`tick`,`zone`,`unknown`],Ok={event:`Event`,http:`HTTP response`,timer:`Timer`,signal:`Signal write`,effect:`Effect`,markForCheck:`markForCheck`,input:`setInput`,view:`View change`,tick:`ApplicationRef.tick`,zone:`zone.js only`,unknown:`Unknown`},kk=e=>typeof e==`string`&&Dk.includes(e);function Ak(e){if(!yk(e)||!kk(e.kind))return;let t=[`component`,`listener`,`event`,`target`,`signal`,`task`],n={kind:e.kind};kk(e.via)&&(n.via=e.via);for(let r of t){let t=xk(e[r],ak);t&&(n[r]=t)}e.zone===!0&&(n.zone=!0);let r=Ck(e.stack,hk).map(e=>xk(e,ok)).filter(Boolean);r.length&&(n.stack=r);let i=Math.floor(bk(e.more));return i&&(n.more=i),n}function jk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=e.strategy;return{name:t,refreshed:Math.floor(bk(e.refreshed)),unchanged:Math.floor(bk(e.unchanged)),...n===`OnPush`||n===`Eager`?{strategy:n}:{}}}function Mk(e){if(!yk(e))return null;let t=xk(e.name,ak),n=xk(e.input,ak);if(!t||!n)return null;let r=xk(e.parent,ak);return{name:t,input:n,...r?{parent:r}:{},inPlace:Math.floor(bk(e.inPlace)),sameContents:Math.floor(bk(e.sameContents))}}function Nk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=Ck(e.tasks,3).map(e=>xk(e,ak)).filter(Boolean);return{name:t,ticks:Math.floor(bk(e.ticks)),...n.length?{tasks:n}:{}}}function Pk(e){if(!yk(e))return;let t={};if(yk(e.causes))for(let n of Dk){let r=Math.floor(bk(e.causes[n]));r&&(t[n]=r)}let n=Ck(e.components,lk).map(jk).filter(e=>!!e),r=Ck(e.inputs,gk).map(Mk).filter(e=>!!e),i=Ck(e.zone,gk).map(Nk).filter(e=>!!e),a=Math.floor(bk(e.major));return{triggers:e.triggers===!0,waste:e.waste===!0,...a&&a<1e3?{major:a}:{},causes:t,components:n,...r.length?{inputs:r}:{},...i.length?{zone:i}:{}}}function Fk(e){let t=[],n=e.component?` in ${e.component}${e.listener?` (${e.listener})`:``}`:``;switch(e.kind){case`event`:t.push(`${e.event??`Template listener`}${e.target?` on ${e.target}`:``}${n}`);break;case`http`:t.push(`HTTP response${n}`);break;case`timer`:t.push(`${e.task??`Timer`}${n}`);break;case`zone`:t.push(`zone.js tick with no Angular notification${e.task?` after ${e.task}`:``}`);break;case`tick`:t.push(`ApplicationRef.tick()${n}`);break;default:t.push(`${Ok[e.kind]}${n}`)}return e.signal?t.push(`wrote signal ${e.signal}`):e.via&&e.via!==e.kind&&t.push(`via ${Ok[e.via]}`),e.zone&&e.kind!==`zone`&&t.push(`run by zone.js`),e.more&&t.push(`${e.more} more notification${e.more===1?``:`s`}`),t.join(`, `)}function Ik(e){if(!e)return[];let t=[],n=(e.major??0)>=22;for(let r of e.components){if(r.refreshed<10)continue;let e=r.refreshed-r.unchanged;if(e/r.refreshed>.2)continue;let i=`refreshed ${r.refreshed} times and changed something in ${e}`;r.strategy===`Eager`?t.push({name:r.name,kind:`on-push`,text:n?`${r.name} was ${i}. It opts out of OnPush, which is the default from Angular 22: remove \`changeDetection: ChangeDetectionStrategy.Eager\` (or \`Default\`) so Angular skips it until an input, event, signal or markForCheck marks it.`:`${r.name} was ${i}. Add \`changeDetection: ChangeDetectionStrategy.OnPush\` so Angular skips it until an input, event, signal or markForCheck marks it.`}):r.strategy===`OnPush`&&t.push({name:r.name,kind:`already-on-push`,text:`${r.name} was ${i}, and it is already OnPush${n?` (the default from Angular 22)`:``}. Something keeps marking it: an input that gets a new reference each time, an event or output in it, markForCheck, or a signal it reads that is set to an equal value.`})}for(let n of e.inputs??[]){let e=n.parent?` set by ${n.parent}`:``;n.inPlace&&t.push({name:n.name,kind:`in-place`,text:`Input ${n.input} of ${n.name}${e} changed in place ${n.inPlace} time${n.inPlace===1?``:`s`}: same reference, different contents. OnPush components, computed and signal equality don't see that. Pass a new object or array instead of mutating it.`}),n.sameContents&&t.push({name:n.name,kind:`same-contents`,text:`Input ${n.input} of ${n.name}${e} got a new reference with the same contents ${n.sameContents} time${n.sameContents===1?``:`s`}, so Angular refreshed ${n.name} for nothing. Keep the reference when nothing changed, for example with a computed instead of a method call in the template.`})}for(let n of e.zone??[]){let e=n.tasks?.length?` (after ${n.tasks.join(`, `)})`:``;t.push({name:n.name,kind:`zone`,text:`${n.name} changed in ${n.ticks} tick${n.ticks===1?``:`s`} that only zone.js started${e}. Without zone.js it would not update: keep that state in a signal, or call markForCheck after changing it.`})}return t}function Lk(e){let t=wk(e);return!t||!yk(e)?null:{...t,maxMs:bk(e.maxMs),cycles:bk(e.cycles)}}function Rk(e){if(!yk(e))return null;let t=xk(e.name,ak),n=xk(e.hook,sk);if(!t||!n)return null;let{calls:r,ms:i,maxMs:a}=e;return{name:t,hook:n,calls:bk(r),ms:bk(i),maxMs:bk(a)}}function zk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=xk(e.listener,ak);return{name:t,...n?{listener:n}:{},calls:bk(e.calls),ms:bk(e.ms),maxMs:bk(e.maxMs)}}function Bk(e){if(yk(e)&&bk(e.runs))return{runs:bk(e.runs),ms:bk(e.ms),maxMs:bk(e.maxMs)}}function Vk(e,t){if(!yk(e))return null;let n=Ck(e.spanNames,fk).map(e=>xk(e,ok)),r=Array.isArray(e.cycles)?e.cycles.slice(-Math.min(t,dk)).map(e=>Ek(e,n.length)).filter(e=>!!e):[],i={},a=0;if(yk(e.hosts)){let t=Object.entries(e.hosts);a=Math.max(0,t.length-uk);for(let[e,n]of t.slice(0,uk))e.length<50&&bk(n)&&(i[e]=bk(n))}let o=Array.isArray(e.components)?e.components:[],s=Math.floor(bk(e.droppedClasses))+Math.max(0,o.length-lk),c=Math.floor(bk(e.droppedHosts))+a,l=Ck(e.hooks,mk).map(Rk).filter(e=>!!e),u=Ck(e.outputs,mk).map(zk).filter(e=>!!e),d=Math.max(0,Ck(e.hooks,1/0).length-mk)+Math.max(0,Ck(e.outputs,1/0).length-mk),f=Math.floor(bk(e.droppedTimings))+d,p=Bk(e.afterRender),m=r.some(e=>e.spans?.length),h=Pk(e.diagnosis);return{recording:e.recording===!0,startedAt:typeof e.startedAt==`number`&&e.startedAt<=ik?bk(e.startedAt):null,dropped:bk(e.dropped),cycles:r,components:o.slice(0,lk).map(Lk).filter(e=>!!e),...s?{droppedClasses:s}:{},hosts:i,...c?{droppedHosts:c}:{},...l.length?{hooks:l}:{},...u.length?{outputs:u}:{},...f?{droppedTimings:f}:{},...p?{afterRender:p}:{},...m?{spanNames:n}:{},...h?{diagnosis:h}:{}}}var Hk=`pangular-inspector/change-detection`;function Uk(e,t,n=Date.now()){return{format:Hk,version:1,exportedAt:n,pageId:t,recording:{...Vk(e,dk)??e,recording:!1,hosts:{}}}}function Wk(e,t){if(e.length>2e7||e.length*3>2e7&&new TextEncoder().encode(e).byteLength>2e7)return{ok:!1,error:`The file is larger than 20 MB.`};let n;try{n=JSON.parse(e)}catch{return{ok:!1,error:`The file is not valid JSON.`}}if(!yk(n))return{ok:!1,error:`The file is not a recording.`};if(n.format!==void 0&&n.format!==`pangular-inspector/change-detection`)return{ok:!1,error:`The file is not a change detection recording.`};let r=yk(n.recording)?n.recording:n;if(!Array.isArray(r.cycles))return{ok:!1,error:`The file has no change detection cycles.`};let i=Vk(r,t);if(!i)return{ok:!1,error:`The file is not a recording.`};let a=xk(n.pageId??r.pageId,49)||`imported`,o=Sk(n.exportedAt);return{ok:!0,pageId:a,...o?{exportedAt:o}:{},recording:{...i,recording:!1}}}var Gk=1,Kk=1,qk=2,Jk={c:`component`,h:`lifecycle-hook`,r:`after-render`,o:`output`},Yk=e=>Math.round(e*1e6)/1e3;function Xk(e,t){let n=e.spanNames??[],r=e.cycles[0]?.at??0,i=e.startedAt??r,a=[],o=0,s=0;for(let t of e.cycles){let e=t.t??Math.max(0,t.at-i),r=e+t.ms;a.push({name:`Change detection #${t.id}`,cat:`change-detection`,ph:`X`,pid:Gk,tid:Kk,ts:Yk(e),dur:Yk(t.ms),args:{checks:t.checks,passes:t.passes,...t.trigger?{trigger:t.trigger}:{},...t.hookMs?{hookMs:t.hookMs}:{},...t.afterRenderMs?{afterRenderMs:t.afterRenderMs}:{},...t.outputMs?{outputMs:t.outputMs}:{},...t.cause?{cause:Fk(t.cause)}:{},...t.unchanged?{unchanged:t.unchanged}:{},slowest:t.components.map(e=>`${e.name} ${e.checks}x ${e.ms}ms`)}}),s+=t.droppedSpans??0;let c=[{end:r}],l=[...t.spans??[]].sort((e,t)=>e[1]-t[1]||t[2]-e[2]);for(let[r,i,s,u,d]of l){o++;let l=n[r]??`?`;if(d===_k.output){let n=e+i;a.push({name:l,cat:Jk[d],ph:`X`,pid:Gk,tid:qk,ts:Yk(n),dur:Yk(i<0?Math.max(0,Math.min(s,-i)):s),args:{cycle:t.id}});continue}let f=Math.max(e,e+i);for(;c.length>1&&c.at(-1).end<=f;)c.pop();let p=c.at(-1).end,m=Math.min(f+s,p);me.ts??0));if(c<0)for(let e of a)e.ts=Yk((e.ts-c)/1e3);a.sort((e,t)=>e.ts-t.ts||t.dur-e.dur);let l=(e,t,n)=>({name:t,ph:`M`,pid:Gk,tid:e,args:{name:n}});return{traceEvents:[l(0,`process_name`,`Angular change detection (page ${t})`),l(Kk,`thread_name`,`Change detection`),l(qk,`thread_name`,`Outputs`),...a],displayTimeUnit:`ms`,otherData:{source:`Pangular Inspector change detection recording`,pageId:t,cycles:e.cycles.length,droppedCycles:e.dropped,spans:o,droppedSpans:s,...e.startedAt&&e.startedAt<=ik?{startedAt:new Date(e.startedAt).toISOString()}:{}}}}var Zk=16.6;function Qk(e){return e.ms>Zk}function $k(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}function eA(e,t){if(!t)return[...e];let n=Math.min(t.from,t.to),r=Math.max(t.from,t.to),i=e.filter(e=>e.id>=n&&e.id<=r);return i.length?i:[...e]}function tA(e){let t=new Map;for(let n of e)for(let e of n.components){let n=t.get(e.name);n?(n.checks+=e.checks,n.ms+=e.ms,n.maxMs=Math.max(n.maxMs,e.ms),n.cycles+=1):t.set(e.name,{name:e.name,checks:e.checks,ms:e.ms,maxMs:e.ms,cycles:1})}return[...t.values()].sort((e,t)=>t.ms-e.ms||e.name.localeCompare(t.name))}function nA(e){let t=e.reduce((e,t)=>Math.max(e,t.ms),0);return Math.max(t,Zk*1.25)}function rA(e,t,n=3){let r=e.map(e=>({item:e,value:t(e)})).filter(e=>e.value>0).sort((e,t)=>t.value-e.value),i=r.reduce((e,t)=>e+t.value,0);if(!i)return[];let a=n/i,o=[],s=0,c=0,l=n,u=1,d=[],f=(e,t)=>{let n=e.reduce((e,t)=>e+t,0),r=Math.max(...e),i=Math.min(...e);return Math.max(t*t*r/(n*n),n*n/(t*t*i))},p=()=>{let e=d.reduce((e,t)=>e+t.area,0);if(l>=u){let t=e/u,n=c;for(let e of d){let r=e.area/t;o.push({item:e.item,x:s,y:n,w:t,h:r}),n+=r}s+=t,l-=t}else{let t=e/l,n=s;for(let e of d){let r=e.area/t;o.push({item:e.item,x:n,y:c,w:r,h:t}),n+=r}c+=t,u-=t}d=[]};for(let e of r){let t=e.value*a,n=Math.min(l,u),r=d.map(e=>e.area);d.length&&f([...r,t],n)>f(r,n)&&p(),d.push({item:e.item,area:t})}return d.length&&p(),o.map(e=>({item:e.item,x:e.x/n*100,y:e.y*100,w:e.w/n*100,h:e.h*100}))}var iA={c:`component`,h:`hook`,r:`afterRender`,o:`output`};function aA(e,t){if(t===`c`)return e||null;if(t===`h`){let t=e.lastIndexOf(`.`);return t>0?e.slice(0,t):null}if(t===`o`){let t=e.indexOf(` (`),n=t>0?e.slice(0,t):e;return n&&n!==`?`?n:null}return null}function oA(e,t){let n=e.filter(e=>e.spans?.length);if(!n.length)return null;let r=n.map(e=>{let t=e.spans,n=Math.min(0,...t.map(e=>e[1])),r=Math.max(e.ms,...t.map(e=>e[1]+e[2]));return{cycle:e,spans:t,from:n,width:Math.max(r-n,.001)}}),i=r.reduce((e,t)=>e+t.width,0),a=[],o=[],s=0,c=0;for(let{cycle:e,spans:n,from:l,width:u}of r){o.push({id:e.id,x:s/i*100,w:u/i*100,droppedSpans:e.droppedSpans??0});let r=[...n].sort((e,t)=>e[1]-t[1]||e[3]-t[3]),d=[];for(let[n,o,u,f,p]of r){let r=t[n]??`unknown`,m=d[f-1],h=f>0&&m!==void 0&&ot.kind,cA=(e,t)=>t.name,lA=(e,t)=>t.name+`.`+t.input;function uA(e,t){e&1&&(B(0,`p`,3),J(1,` The page has no Angular change detection scheduler the overlay could find (it needs Angular 18 or later), so cycles have no cause. `),V())}function dA(e,t){if(e&1&&(B(0,`tr`)(1,`td`),J(2),V(),B(3,`td`,6),J(4),V()()),e&2){let e=t.$implicit;k(2),Y(e.label),k(2),Y(e.count)}}function fA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Trigger`),V(),B(5,`th`,5),J(6,`Cycles`),V()()(),B(7,`tbody`),P(8,dA,5,2,`tr`,null,sA),V()()),e&2){let e=G(2);k(8),F(e.causes())}}function pA(e,t){e&1&&(B(0,`p`,3),J(1,`No cycle has a cause yet.`),V())}function mA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,7),J(6),V()()),e&2){let e=t.$implicit;k(2),Y(e.name),k(2),Y(e.ticks),k(2),Y(e.tasks?.join(`, `))}}function hA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Component`),V(),B(5,`th`,5),J(6,`Zone-only ticks`),V(),B(7,`th`,4),J(8,`After`),V()()(),B(9,`tbody`),P(10,mA,7,3,`tr`,null,cA),V()()),e&2){let e=G(2);k(10),F(e.zone())}}function gA(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G(2);k(),Y(e.zoneNote())}}function _A(e,t){e&1&&(B(0,`p`,3),J(1,`The page can't watch DOM updates, so wasted checks are not counted.`),V())}function vA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`),J(8),V()()),e&2){let e=t.$implicit,n=G(3);k(2),Y(e.name),k(2),Y(e.refreshed),k(2),Z(``,e.unchanged,` (`,n.share(e.unchanged,e.refreshed),`)`),k(2),Y(e.strategy??`Unknown`)}}function yA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Component`),V(),B(5,`th`,5),J(6,`Refreshed`),V(),B(7,`th`,5),J(8,`Changed nothing`),V(),B(9,`th`,4),J(10,`Strategy`),V()()(),B(11,`tbody`),P(12,vA,9,5,`tr`,null,cA),V()()),e&2){let e=G(2);k(12),F(e.wasted())}}function bA(e,t){e&1&&(B(0,`p`,3),J(1,`Every refreshed check changed something.`),V())}function xA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,7),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit;k(2),Z(``,e.name,`.`,e.input),k(2),Y(e.parent??`Unknown`),k(2),Y(e.inPlace),k(2),Y(e.sameContents)}}function SA(e,t){if(e&1&&(B(0,`h4`),J(1,`Inputs that break OnPush`),V(),B(2,`table`)(3,`thead`)(4,`tr`)(5,`th`,4),J(6,`Input`),V(),B(7,`th`,4),J(8,`Set by`),V(),B(9,`th`,5),J(10,`Changed in place`),V(),B(11,`th`,5),J(12,`Same contents, new reference`),V()()(),B(13,`tbody`),P(14,xA,9,5,`tr`,null,lA),V()()),e&2){let e=G(2);k(14),F(e.inputs())}}function CA(e,t){if(e&1&&(B(0,`li`),J(1),V()),e&2){let e=t.$implicit;k(),Y(e.text)}}function wA(e,t){if(e&1&&(B(0,`h4`),J(1,`Hints`),V(),B(2,`ul`,8),P(3,CA,2,1,`li`,null,kg),V()),e&2){let e=G(2);k(3),F(e.hints())}}function TA(e,t){if(e&1&&(B(0,`section`,0)(1,`h3`,1),J(2,`Why it ran and what it wasted`),V(),B(3,`div`,2)(4,`div`)(5,`h4`),J(6,`What started the cycles`),V(),M(7,uA,2,0,`p`,3)(8,fA,10,0,`table`)(9,pA,2,0,`p`,3),V(),B(10,`div`)(11,`h4`),J(12,`Depends on zone.js`),V(),M(13,hA,12,0,`table`)(14,gA,2,1,`p`,3),V()(),B(15,`h4`),J(16,`Wasted checks`),V(),M(17,_A,2,0,`p`,3)(18,yA,14,0,`table`)(19,bA,2,0,`p`,3),M(20,SA,16,0),M(21,wA,5,0),V()),e&2){let e=t,n=G();k(7),N(e.triggers?n.causes().length?8:9:7),k(6),N(n.zone().length?13:e.triggers?14:-1),k(4),N(e.waste?n.wasted().length?18:19:17),k(3),N(n.inputs().length?20:-1),k(),N(n.hints().length?21:-1)}}var EA=10,DA=class e{page=$(null);diagnosis=Q(()=>this.page()?.diagnosis??null);causes=Q(()=>{let e=this.diagnosis()?.causes??{};return Dk.filter(t=>e[t]).map(t=>({kind:t,label:Ok[t],count:e[t]}))});zone=Q(()=>(this.diagnosis()?.zone??[]).slice(0,EA));zoneNote=Q(()=>{let e=this.diagnosis()?.causes.zone??0;return e?`${e} ${e===1?`tick`:`ticks`} came from zone.js alone, and no component changed in them.`:`No component changed in a tick only zone.js started.`});wasted=Q(()=>(this.diagnosis()?.components??[]).filter(e=>e.unchanged>0).slice(0,EA));inputs=Q(()=>(this.diagnosis()?.inputs??[]).slice(0,EA));hints=Q(()=>Ik(this.diagnosis()??void 0).slice(0,EA));share(e,t){return t?`${Math.round(e/t*100)}%`:`0%`}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-diagnosis`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[`aria-labelledby`,`cd-diagnosis-heading`,1,`diagnosis`],[`id`,`cd-diagnosis-heading`],[1,`grid`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`num`],[1,`mono`],[1,`hints`]],template:function(e,t){if(e&1&&M(0,TA,22,5,`section`,0),e&2){let e;N((e=t.diagnosis())?0:-1,e)}},styles:[`[_nghost-%COMP%] { +}`]})},ik=864e13,ak=200,ok=300,sk=100,ck=10,lk=100,uk=2e3,dk=2e3,fk=4e3,pk=1e3,mk=100,hk=3,gk=50,_k={component:`c`,hook:`h`,afterRender:`r`,output:`o`},vk=Object.values(_k),yk=e=>!!e&&typeof e==`object`&&!Array.isArray(e),bk=e=>typeof e==`number`&&Number.isFinite(e)&&e>=0?e:0,xk=(e,t)=>typeof e==`string`?e.slice(0,t):``,Sk=e=>bk(e)>0?bk(e):void 0,Ck=(e,t)=>Array.isArray(e)?e.slice(0,t):[];function wk(e){if(!yk(e))return null;let t=xk(e.name,ak);return t?{name:t,checks:bk(e.checks),ms:bk(e.ms)}:null}function Tk(e,t){if(!Array.isArray(e)||e.length!==5)return null;let[n,r,i,a,o]=e;return typeof n!=`number`||!Number.isInteger(n)||n<0||n>=t||typeof r!=`number`||!Number.isFinite(r)||Math.abs(r)>1e7||typeof a!=`number`||!Number.isInteger(a)||a<0||a>pk||typeof o!=`string`||!vk.includes(o)?null:[n,r,bk(i),a,o]}function Ek(e,t){if(!yk(e)||typeof e.id!=`number`)return null;let n=Ck(e.components,ck).map(wk).filter(e=>!!e),r=xk(e.trigger,ok),i=Ck(e.spans,40).map(e=>Tk(e,t)).filter(e=>!!e),a=Array.isArray(e.spans)?e.spans.length-40:0,o=Math.floor(bk(e.droppedSpans))+Math.max(0,a),s={t:typeof e.t==`number`?bk(e.t):void 0,hookMs:Sk(e.hookMs),afterRenderMs:Sk(e.afterRenderMs),outputMs:Sk(e.outputMs)},c=Ak(e.cause),l=Sk(e.refreshed),u=Sk(e.unchanged);return{id:bk(e.id),at:bk(e.at),ms:bk(e.ms),passes:bk(e.passes),...r?{trigger:r}:{},checks:bk(e.checks),components:n,...Object.fromEntries(Object.entries(s).filter(([,e])=>e!==void 0)),...i.length?{spans:i}:{},...o?{droppedSpans:o}:{},...c?{cause:c}:{},...l?{refreshed:l}:{},...u?{unchanged:u}:{}}}var Dk=[`event`,`http`,`timer`,`signal`,`effect`,`markForCheck`,`input`,`view`,`tick`,`zone`,`unknown`],Ok={event:`Event`,http:`HTTP response`,timer:`Timer`,signal:`Signal write`,effect:`Effect`,markForCheck:`markForCheck`,input:`setInput`,view:`View change`,tick:`ApplicationRef.tick`,zone:`zone.js only`,unknown:`Unknown`},kk=e=>typeof e==`string`&&Dk.includes(e);function Ak(e){if(!yk(e)||!kk(e.kind))return;let t=[`component`,`listener`,`event`,`target`,`signal`,`task`],n={kind:e.kind};kk(e.via)&&(n.via=e.via);for(let r of t){let t=xk(e[r],ak);t&&(n[r]=t)}e.zone===!0&&(n.zone=!0);let r=Ck(e.stack,hk).map(e=>xk(e,ok)).filter(Boolean);r.length&&(n.stack=r);let i=Math.floor(bk(e.more));return i&&(n.more=i),n}function jk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=e.strategy;return{name:t,refreshed:Math.floor(bk(e.refreshed)),unchanged:Math.floor(bk(e.unchanged)),...n===`OnPush`||n===`Eager`?{strategy:n}:{}}}function Mk(e){if(!yk(e))return null;let t=xk(e.name,ak),n=xk(e.input,ak);if(!t||!n)return null;let r=xk(e.parent,ak);return{name:t,input:n,...r?{parent:r}:{},inPlace:Math.floor(bk(e.inPlace)),sameContents:Math.floor(bk(e.sameContents))}}function Nk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=Ck(e.tasks,3).map(e=>xk(e,ak)).filter(Boolean);return{name:t,ticks:Math.floor(bk(e.ticks)),...n.length?{tasks:n}:{}}}function Pk(e){if(!yk(e))return;let t={};if(yk(e.causes))for(let n of Dk){let r=Math.floor(bk(e.causes[n]));r&&(t[n]=r)}let n=Ck(e.components,lk).map(jk).filter(e=>!!e),r=Ck(e.inputs,gk).map(Mk).filter(e=>!!e),i=Ck(e.zone,gk).map(Nk).filter(e=>!!e),a=Math.floor(bk(e.major));return{triggers:e.triggers===!0,waste:e.waste===!0,...a&&a<1e3?{major:a}:{},causes:t,components:n,...r.length?{inputs:r}:{},...i.length?{zone:i}:{},...typeof e.zoneJs==`boolean`?{zoneJs:e.zoneJs}:{}}}function Fk(e){let t=[],n=e.component?` in ${e.component}${e.listener?` (${e.listener})`:``}`:``;switch(e.kind){case`event`:t.push(`${e.event??`Template listener`}${e.target?` on ${e.target}`:``}${n}`);break;case`http`:t.push(`HTTP response${n}`);break;case`timer`:t.push(`${e.task??`Timer`}${n}`);break;case`zone`:t.push(`zone.js tick with no Angular notification${e.task?` after ${e.task}`:``}`);break;case`tick`:t.push(`ApplicationRef.tick()${n}`);break;default:t.push(`${Ok[e.kind]}${n}`)}return e.signal?t.push(e.signal===`?`?`wrote an unnamed signal`:`wrote signal ${e.signal}`):e.via&&e.via!==e.kind&&t.push(`via ${Ok[e.via]}`),e.zone&&e.kind!==`zone`&&t.push(`run by zone.js`),e.more&&t.push(`${e.more} more notification${e.more===1?``:`s`}`),t.join(`, `)}function Ik(e){if(!e)return[];let t=[],n=(e.major??0)>=22;for(let r of e.components){if(r.refreshed<10)continue;let e=r.refreshed-r.unchanged;if(e/r.refreshed>.2)continue;let i=`refreshed ${r.refreshed} times and changed something in ${e}`;r.strategy===`Eager`?t.push({name:r.name,kind:`on-push`,text:n?`${r.name} was ${i}. It opts out of OnPush, which is the default from Angular 22: remove \`changeDetection: ChangeDetectionStrategy.Eager\` (or \`Default\`) so Angular skips it until an input, event, signal or markForCheck marks it.`:`${r.name} was ${i}. Add \`changeDetection: ChangeDetectionStrategy.OnPush\` so Angular skips it until an input, event, signal or markForCheck marks it.`}):r.strategy===`OnPush`&&t.push({name:r.name,kind:`already-on-push`,text:`${r.name} was ${i}, and it is already OnPush${n?` (the default from Angular 22)`:``}. Something keeps marking it: an input that gets a new reference each time, an event or output in it, markForCheck, or a signal it reads that is set to an equal value.`})}for(let n of e.inputs??[]){let e=n.parent?` set by ${n.parent}`:``;n.inPlace&&t.push({name:n.name,kind:`in-place`,text:`Input ${n.input} of ${n.name}${e} changed in place ${n.inPlace} time${n.inPlace===1?``:`s`}: same reference, different contents. OnPush components, computed and signal equality don't see that. Pass a new object or array instead of mutating it.`}),n.sameContents&&t.push({name:n.name,kind:`same-contents`,text:`Input ${n.input} of ${n.name}${e} got a new reference with the same contents ${n.sameContents} time${n.sameContents===1?``:`s`}, so Angular refreshed ${n.name} for nothing. Keep the reference when nothing changed, for example with a computed instead of a method call in the template.`})}for(let n of e.zone??[]){let e=n.tasks?.length?` (after ${n.tasks.join(`, `)})`:``;t.push({name:n.name,kind:`zone`,text:`${n.name} changed in ${n.ticks} tick${n.ticks===1?``:`s`} that only zone.js started${e}. Without zone.js it would not update: keep that state in a signal, or call markForCheck after changing it.`})}return t}function Lk(e){let t=wk(e);return!t||!yk(e)?null:{...t,maxMs:bk(e.maxMs),cycles:bk(e.cycles)}}function Rk(e){if(!yk(e))return null;let t=xk(e.name,ak),n=xk(e.hook,sk);if(!t||!n)return null;let{calls:r,ms:i,maxMs:a}=e;return{name:t,hook:n,calls:bk(r),ms:bk(i),maxMs:bk(a)}}function zk(e){if(!yk(e))return null;let t=xk(e.name,ak);if(!t)return null;let n=xk(e.listener,ak);return{name:t,...n?{listener:n}:{},calls:bk(e.calls),ms:bk(e.ms),maxMs:bk(e.maxMs)}}function Bk(e){if(yk(e)&&bk(e.runs))return{runs:bk(e.runs),ms:bk(e.ms),maxMs:bk(e.maxMs)}}function Vk(e,t){if(!yk(e))return null;let n=Ck(e.spanNames,fk).map(e=>xk(e,ok)),r=Array.isArray(e.cycles)?e.cycles.slice(-Math.min(t,dk)).map(e=>Ek(e,n.length)).filter(e=>!!e):[],i={},a=0;if(yk(e.hosts)){let t=Object.entries(e.hosts);a=Math.max(0,t.length-uk);for(let[e,n]of t.slice(0,uk))e.length<50&&bk(n)&&(i[e]=bk(n))}let o=Array.isArray(e.components)?e.components:[],s=Math.floor(bk(e.droppedClasses))+Math.max(0,o.length-lk),c=Math.floor(bk(e.droppedHosts))+a,l=Ck(e.hooks,mk).map(Rk).filter(e=>!!e),u=Ck(e.outputs,mk).map(zk).filter(e=>!!e),d=Math.max(0,Ck(e.hooks,1/0).length-mk)+Math.max(0,Ck(e.outputs,1/0).length-mk),f=Math.floor(bk(e.droppedTimings))+d,p=Bk(e.afterRender),m=r.some(e=>e.spans?.length),h=Pk(e.diagnosis);return{recording:e.recording===!0,startedAt:typeof e.startedAt==`number`&&e.startedAt<=ik?bk(e.startedAt):null,dropped:bk(e.dropped),cycles:r,components:o.slice(0,lk).map(Lk).filter(e=>!!e),...s?{droppedClasses:s}:{},hosts:i,...c?{droppedHosts:c}:{},...l.length?{hooks:l}:{},...u.length?{outputs:u}:{},...f?{droppedTimings:f}:{},...p?{afterRender:p}:{},...m?{spanNames:n}:{},...h?{diagnosis:h}:{}}}var Hk=`pangular-inspector/change-detection`;function Uk(e,t,n=Date.now()){return{format:Hk,version:1,exportedAt:n,pageId:t,recording:{...Vk(e,dk)??e,recording:!1,hosts:{}}}}function Wk(e,t){if(e.length>2e7||e.length*3>2e7&&new TextEncoder().encode(e).byteLength>2e7)return{ok:!1,error:`The file is larger than 20 MB.`};let n;try{n=JSON.parse(e)}catch{return{ok:!1,error:`The file is not valid JSON.`}}if(!yk(n))return{ok:!1,error:`The file is not a recording.`};if(n.format!==void 0&&n.format!==`pangular-inspector/change-detection`)return{ok:!1,error:`The file is not a change detection recording.`};let r=yk(n.recording)?n.recording:n;if(!Array.isArray(r.cycles))return{ok:!1,error:`The file has no change detection cycles.`};let i=Vk(r,t);if(!i)return{ok:!1,error:`The file is not a recording.`};let a=xk(n.pageId??r.pageId,49)||`imported`,o=Sk(n.exportedAt);return{ok:!0,pageId:a,...o?{exportedAt:o}:{},recording:{...i,recording:!1}}}var Gk=1,Kk=1,qk=2,Jk={c:`component`,h:`lifecycle-hook`,r:`after-render`,o:`output`},Yk=e=>Math.round(e*1e6)/1e3;function Xk(e,t){let n=e.spanNames??[],r=e.cycles[0]?.at??0,i=e.startedAt??r,a=[],o=0,s=0;for(let t of e.cycles){let e=t.t??Math.max(0,t.at-i),r=e+t.ms;a.push({name:`Change detection #${t.id}`,cat:`change-detection`,ph:`X`,pid:Gk,tid:Kk,ts:Yk(e),dur:Yk(t.ms),args:{checks:t.checks,passes:t.passes,...t.trigger?{trigger:t.trigger}:{},...t.hookMs?{hookMs:t.hookMs}:{},...t.afterRenderMs?{afterRenderMs:t.afterRenderMs}:{},...t.outputMs?{outputMs:t.outputMs}:{},...t.cause?{cause:Fk(t.cause)}:{},...t.unchanged?{unchanged:t.unchanged}:{},slowest:t.components.map(e=>`${e.name} ${e.checks}x ${e.ms}ms`)}}),s+=t.droppedSpans??0;let c=[{end:r}],l=[...t.spans??[]].sort((e,t)=>e[1]-t[1]||t[2]-e[2]);for(let[r,i,s,u,d]of l){o++;let l=n[r]??`?`;if(d===_k.output){let n=e+i;a.push({name:l,cat:Jk[d],ph:`X`,pid:Gk,tid:qk,ts:Yk(n),dur:Yk(i<0?Math.max(0,Math.min(s,-i)):s),args:{cycle:t.id}});continue}let f=Math.max(e,e+i);for(;c.length>1&&c.at(-1).end<=f;)c.pop();let p=c.at(-1).end,m=Math.min(f+s,p);me.ts??0));if(c<0)for(let e of a)e.ts=Yk((e.ts-c)/1e3);a.sort((e,t)=>e.ts-t.ts||t.dur-e.dur);let l=(e,t,n)=>({name:t,ph:`M`,pid:Gk,tid:e,args:{name:n}});return{traceEvents:[l(0,`process_name`,`Angular change detection (page ${t})`),l(Kk,`thread_name`,`Change detection`),l(qk,`thread_name`,`Outputs`),...a],displayTimeUnit:`ms`,otherData:{source:`Pangular Inspector change detection recording`,pageId:t,cycles:e.cycles.length,droppedCycles:e.dropped,spans:o,droppedSpans:s,...e.startedAt&&e.startedAt<=ik?{startedAt:new Date(e.startedAt).toISOString()}:{}}}}var Zk=16.6;function Qk(e){return e.ms>Zk}function $k(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}function eA(e,t){if(!t)return[...e];let n=Math.min(t.from,t.to),r=Math.max(t.from,t.to),i=e.filter(e=>e.id>=n&&e.id<=r);return i.length?i:[...e]}function tA(e){let t=new Map;for(let n of e)for(let e of n.components){let n=t.get(e.name);n?(n.checks+=e.checks,n.ms+=e.ms,n.maxMs=Math.max(n.maxMs,e.ms),n.cycles+=1):t.set(e.name,{name:e.name,checks:e.checks,ms:e.ms,maxMs:e.ms,cycles:1})}return[...t.values()].sort((e,t)=>t.ms-e.ms||e.name.localeCompare(t.name))}function nA(e){let t=e.reduce((e,t)=>Math.max(e,t.ms),0);return Math.max(t,Zk*1.25)}function rA(e,t,n=3){let r=e.map(e=>({item:e,value:t(e)})).filter(e=>e.value>0).sort((e,t)=>t.value-e.value),i=r.reduce((e,t)=>e+t.value,0);if(!i)return[];let a=n/i,o=[],s=0,c=0,l=n,u=1,d=[],f=(e,t)=>{let n=e.reduce((e,t)=>e+t,0),r=Math.max(...e),i=Math.min(...e);return Math.max(t*t*r/(n*n),n*n/(t*t*i))},p=()=>{let e=d.reduce((e,t)=>e+t.area,0);if(l>=u){let t=e/u,n=c;for(let e of d){let r=e.area/t;o.push({item:e.item,x:s,y:n,w:t,h:r}),n+=r}s+=t,l-=t}else{let t=e/l,n=s;for(let e of d){let r=e.area/t;o.push({item:e.item,x:n,y:c,w:r,h:t}),n+=r}c+=t,u-=t}d=[]};for(let e of r){let t=e.value*a,n=Math.min(l,u),r=d.map(e=>e.area);d.length&&f([...r,t],n)>f(r,n)&&p(),d.push({item:e.item,area:t})}return d.length&&p(),o.map(e=>({item:e.item,x:e.x/n*100,y:e.y*100,w:e.w/n*100,h:e.h*100}))}var iA={c:`component`,h:`hook`,r:`afterRender`,o:`output`};function aA(e,t){if(t===`c`)return e||null;if(t===`h`){let t=e.lastIndexOf(`.`);return t>0?e.slice(0,t):null}if(t===`o`){let t=e.indexOf(` (`),n=t>0?e.slice(0,t):e;return n&&n!==`?`?n:null}return null}function oA(e,t){let n=e.filter(e=>e.spans?.length);if(!n.length)return null;let r=n.map(e=>{let t=e.spans,n=Math.min(0,...t.map(e=>e[1])),r=Math.max(e.ms,...t.map(e=>e[1]+e[2]));return{cycle:e,spans:t,from:n,width:Math.max(r-n,.001)}}),i=r.reduce((e,t)=>e+t.width,0),a=[],o=[],s=0,c=0;for(let{cycle:e,spans:n,from:l,width:u}of r){o.push({id:e.id,x:s/i*100,w:u/i*100,droppedSpans:e.droppedSpans??0});let r=[...n].sort((e,t)=>e[1]-t[1]||e[3]-t[3]),d=[];for(let[n,o,u,f,p]of r){let r=t[n]??`unknown`,m=d[f-1],h=f>0&&m!==void 0&&ot.kind,cA=(e,t)=>t.name,lA=(e,t)=>t.name+`.`+t.input;function uA(e,t){e&1&&(B(0,`p`,3),J(1,` The page has no Angular change detection scheduler the overlay could find (it needs Angular 18 or later), so cycles have no cause. `),V())}function dA(e,t){if(e&1&&(B(0,`tr`)(1,`td`),J(2),V(),B(3,`td`,6),J(4),V()()),e&2){let e=t.$implicit;k(2),Y(e.label),k(2),Y(e.count)}}function fA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Trigger`),V(),B(5,`th`,5),J(6,`Cycles`),V()()(),B(7,`tbody`),P(8,dA,5,2,`tr`,null,sA),V()()),e&2){let e=G(2);k(8),F(e.causes())}}function pA(e,t){e&1&&(B(0,`p`,3),J(1,`No cycle has a cause yet.`),V())}function mA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,7),J(6),V()()),e&2){let e=t.$implicit;k(2),Y(e.name),k(2),Y(e.ticks),k(2),Y(e.tasks?.join(`, `))}}function hA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Component`),V(),B(5,`th`,5),J(6,`Zone-only ticks`),V(),B(7,`th`,4),J(8,`After`),V()()(),B(9,`tbody`),P(10,mA,7,3,`tr`,null,cA),V()()),e&2){let e=G(3);k(10),F(e.zone())}}function gA(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G(3);k(),Y(e.zoneNote())}}function _A(e,t){if(e&1&&(B(0,`div`)(1,`h4`),J(2,`Depends on zone.js`),V(),M(3,hA,12,0,`table`)(4,gA,2,1,`p`,3),V()),e&2){let e=G(),t=G();k(3),N(t.zone().length?3:e.triggers?4:-1)}}function vA(e,t){e&1&&(B(0,`p`,3),J(1,`The page can't watch DOM updates, so wasted checks are not counted.`),V())}function yA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`),J(8),V()()),e&2){let e=t.$implicit,n=G(3);k(2),Y(e.name),k(2),Y(e.refreshed),k(2),Z(``,e.unchanged,` (`,n.share(e.unchanged,e.refreshed),`)`),k(2),Y(e.strategy??`Unknown`)}}function bA(e,t){if(e&1&&(B(0,`table`)(1,`thead`)(2,`tr`)(3,`th`,4),J(4,`Component`),V(),B(5,`th`,5),J(6,`Refreshed`),V(),B(7,`th`,5),J(8,`Changed nothing`),V(),B(9,`th`,4),J(10,`Strategy`),V()()(),B(11,`tbody`),P(12,yA,9,5,`tr`,null,cA),V()()),e&2){let e=G(2);k(12),F(e.wasted())}}function xA(e,t){e&1&&(B(0,`p`,3),J(1,`Every refreshed check changed something.`),V())}function SA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,7),J(2),V(),B(3,`td`,7),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit;k(2),Z(``,e.name,`.`,e.input),k(2),Y(e.parent??`Unknown`),k(2),Y(e.inPlace),k(2),Y(e.sameContents)}}function CA(e,t){if(e&1&&(B(0,`h4`),J(1,`Inputs that break OnPush`),V(),B(2,`table`)(3,`thead`)(4,`tr`)(5,`th`,4),J(6,`Input`),V(),B(7,`th`,4),J(8,`Set by`),V(),B(9,`th`,5),J(10,`Changed in place`),V(),B(11,`th`,5),J(12,`Same contents, new reference`),V()()(),B(13,`tbody`),P(14,SA,9,5,`tr`,null,lA),V()()),e&2){let e=G(2);k(14),F(e.inputs())}}function wA(e,t){if(e&1&&(B(0,`li`),J(1),V()),e&2){let e=t.$implicit;k(),Y(e.text)}}function TA(e,t){if(e&1&&(B(0,`h4`),J(1,`Hints`),V(),B(2,`ul`,8),P(3,wA,2,1,`li`,null,kg),V()),e&2){let e=G(2);k(3),F(e.hints())}}function EA(e,t){if(e&1&&(B(0,`section`,0)(1,`h3`,1),J(2,`Why it ran and what it wasted`),V(),B(3,`div`,2)(4,`div`)(5,`h4`),J(6,`What started the cycles`),V(),M(7,uA,2,0,`p`,3)(8,fA,10,0,`table`)(9,pA,2,0,`p`,3),V(),M(10,_A,5,1,`div`),V(),B(11,`h4`),J(12,`Wasted checks`),V(),M(13,vA,2,0,`p`,3)(14,bA,14,0,`table`)(15,xA,2,0,`p`,3),M(16,CA,16,0),M(17,TA,5,0),V()),e&2){let e=t,n=G();k(7),N(e.triggers?n.causes().length?8:9:7),k(3),N(n.hasZone()?10:-1),k(3),N(e.waste?n.wasted().length?14:15:13),k(3),N(n.inputs().length?16:-1),k(),N(n.hints().length?17:-1)}}var DA=10,OA=class e{page=$(null);diagnosis=Q(()=>this.page()?.diagnosis??null);causes=Q(()=>{let e=this.diagnosis()?.causes??{};return Dk.filter(t=>e[t]).map(t=>({kind:t,label:Ok[t],count:e[t]}))});zone=Q(()=>(this.diagnosis()?.zone??[]).slice(0,DA));zoneTicks=Q(()=>this.diagnosis()?.causes.zone??0);hasZone=Q(()=>this.diagnosis()?.zoneJs??(this.zone().length>0||this.zoneTicks()>0));zoneNote=Q(()=>{let e=this.zoneTicks();return e?`${e} ${e===1?`tick`:`ticks`} came from zone.js alone, and no component changed in them.`:`No component changed in a tick only zone.js started.`});wasted=Q(()=>(this.diagnosis()?.components??[]).filter(e=>e.unchanged>0).slice(0,DA));inputs=Q(()=>(this.diagnosis()?.inputs??[]).slice(0,DA));hints=Q(()=>Ik(this.diagnosis()??void 0).slice(0,DA));share(e,t){return t?`${Math.round(e/t*100)}%`:`0%`}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-diagnosis`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[`aria-labelledby`,`cd-diagnosis-heading`,1,`diagnosis`],[`id`,`cd-diagnosis-heading`],[1,`grid`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`num`],[1,`mono`],[1,`hints`]],template:function(e,t){if(e&1&&M(0,EA,18,5,`section`,0),e&2){let e;N((e=t.diagnosis())?0:-1,e)}},styles:[`[_nghost-%COMP%] { display: block; } @@ -844,7 +844,7 @@ td.mono[_ngcontent-%COMP%] { .hints[_ngcontent-%COMP%] li[_ngcontent-%COMP%] + li[_ngcontent-%COMP%] { margin-top: 4px; -}`]})},OA=(e,t)=>t.cycle.id,kA=(e,t)=>t.id;function AA(e,t){if(e&1){let e=H();B(0,`button`,27),W(`click`,function(){return T(e),E(G().showAll())}),J(1,`Show all cycles`),V()}}function jA(e,t){if(e&1&&Vg(0,`div`,28),e&2){let e=t;K(`left`,e.left,`%`)(`width`,e.width,`%`)}}function MA(e,t){if(e&1&&(B(0,`div`,29),Vg(1,`span`,30),V()),e&2){let e=t.$implicit,n=G();q(`over`,e.over)(`out`,!n.inRange(e.index)&&!!n.range())(`active`,n.focused()&&n.active()===e.index),qg(`id`,n.optionId(e.index)),j(`data-index`,e.index)(`aria-selected`,n.inRange(e.index))(`aria-label`,e.label),k(),K(`height`,e.height,`%`)}}function NA(e,t){e&1&&(B(0,`span`,33),J(1,`over budget`),V())}function PA(e,t){if(e&1&&(B(0,`p`),J(1,` after `),B(2,`span`,35),J(3),V()()),e&2){let e=G();k(3),Y(e.cycle.trigger)}}function FA(e,t){if(e&1&&(B(0,`p`,34)(1,`span`,36),J(2),V(),B(3,`span`),J(4),V()()),e&2){let e=t.$implicit,n=G(2);k(2),Y(e.name),k(2),Y(n.fmt(e.ms))}}function IA(e,t){if(e&1&&(B(0,`div`,31)(1,`p`,32)(2,`strong`),J(3),V(),B(4,`span`),J(5),V(),M(6,NA,2,0,`span`,33),V(),M(7,PA,4,1,`p`),B(8,`p`),J(9),V(),P(10,FA,5,2,`p`,34,kg),V()),e&2){let e=t,n=G();K(`left`,e.left)(`right`,e.right),k(3),Y(n.fmt(e.cycle.ms)),k(2),X(`cycle `,e.cycle.id),k(),N(e.over?6:-1),k(),N(e.cycle.trigger?7:-1),k(2),iv(` `,e.cycle.checks,` `,e.cycle.checks===1?`check`:`checks`,`, `,e.cycle.passes,` `,e.cycle.passes===1?`pass`:`passes`,` `),k(),F(e.top)}}function LA(e,t){if(e&1&&Vg(0,`span`),e&2){let e=t.$implicit;q(`over`,e.over)}}function RA(e,t){if(e&1&&J(0),e&2){let e=t,n=G(2);Z(` `,e.name,` (`,n.fmt(e.ms),`) `)}}function zA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,37),J(2),V(),B(3,`td`,37),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,37),J(8),V(),B(9,`td`,37),J(10),V(),B(11,`td`,35),J(12),V(),B(13,`td`,35),M(14,RA,1,2),V()()),e&2){let e,n=t.$implicit,r=G();k(2),Y(n.id),k(2),Y(r.fmt(n.ms)),k(2),Y(r.isOver(n)?`Over`:`Within`),k(2),Y(n.checks),k(2),Y(n.passes),k(2),Y(n.trigger??``),k(2),N((e=n.components[0])?14:-1,e)}}var BA=0,VA=80,HA=10,UA=class e{cycles=$([]);range=Gv(null);gapUntil=VA;budgetLabel=`${Zk} ms budget`;uid=`cd-chart-${BA++}`;hintId=`${this.uid}-hint`;active=O(null);anchor=null;dragging=!1;hover=O(null);focused=O(!1);max=Q(()=>nA(this.cycles()));budgetAt=Q(()=>Zk/this.max()*100);bars=Q(()=>{let e=this.max();return this.cycles().map((t,n)=>({cycle:t,index:n,height:t.ms/e*100,over:Qk(t),label:this.describe(t)}))});firstId=Q(()=>this.cycles()[0]?.id??0);lastId=Q(()=>this.cycles().at(-1)?.id??0);span=Q(()=>{let e=this.range();if(!e)return null;let t=this.cycles(),n=Math.min(e.from,e.to),r=Math.max(e.from,e.to),i=t.findIndex(e=>e.id>=n),a=-1;for(let e=t.length-1;e>=0;e--)if(t[e].id<=r){a=e;break}return i<0||aeA(this.cycles(),this.range()));startId=Q(()=>this.selected()[0]?.id??``);endId=Q(()=>this.selected().at(-1)?.id??``);band=Q(()=>{let e=this.span(),t=this.cycles().length;return!e||!t?null:{left:e.start/t*100,width:(e.end-e.start+1)/t*100}});summary=Q(()=>{let e=this.selected(),t=e.filter(Qk).length;return`${this.span()?e.length===1?`Cycle ${e[0].id}`:`Cycles ${e[0].id} to ${e.at(-1).id} (${e.length})`:`All ${e.length} ${e.length===1?`cycle`:`cycles`}`}. ${t} over the ${Zk} ms budget.`});tableLabel=Q(()=>this.span()?`Picked cycles, ${this.summary()}`:`All recorded cycles`);activeOptionId=Q(()=>{let e=this.active();return this.focused()&&e!==null&&e{let e=this.hover()??(this.focused()?this.active():null),t=e===null?void 0:this.cycles()[e];return!t||e===null?null:{cycle:t,over:Qk(t),top:t.components.slice(0,3),...this.tipSide(e)}});tipSide(e){let t=this.cycles().length;return e+.5=t.start&&e<=t.end}describe(e){let t=[`Cycle ${e.id}`,$k(e.ms)];Qk(e)&&t.push(`over budget`),e.trigger&&t.push(`after ${e.trigger}`),t.push(`${e.checks} ${e.checks===1?`check`:`checks`}`);let n=e.components[0];return n&&t.push(`slowest ${n.name} ${$k(n.ms)}`),t.join(`, `)}select(e,t){let n=this.cycles(),r=n[Math.min(e,t)],i=n[Math.max(e,t)];r&&i&&this.range.set({from:r.id,to:i.id})}showAll(){this.range.set(null),this.anchor=null}setEnd(e,t){if(!this.cycles().length)return;let n=t.target,r=Number.parseInt(n.value,10);if(Number.isNaN(r)){n.value=String(e===`from`?this.startId():this.endId());return}let i=Math.min(Math.max(r,this.firstId()),this.lastId()),a=this.selected(),o=e===`from`?i:a[0]?.id??this.firstId(),s=e===`to`?i:a.at(-1)?.id??this.lastId();this.range.set({from:Math.min(o,s),to:Math.max(o,s)}),n.value=String(e===`from`?Math.min(o,s):Math.max(o,s))}onFocus(){this.focused.set(!0),(this.active()===null||this.active()>=this.cycles().length)&&this.active.set(this.span()?.start??Math.max(this.cycles().length-1,0)),this.anchor??=this.active()}onKey(e){let t=this.cycles().length;if(!t)return;let n=Math.min(this.active()??t-1,t-1),r=null;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=n+1;break;case`ArrowLeft`:case`ArrowUp`:r=n-1;break;case`PageDown`:r=n+HA;break;case`PageUp`:r=n-HA;break;case`Home`:r=0;break;case`End`:r=t-1;break;case`Enter`:case` `:e.preventDefault(),this.anchor=n,this.select(n,n);return;case`Escape`:this.range()&&(e.preventDefault(),this.showAll());return;default:return}e.preventDefault(),r=Math.min(Math.max(r,0),t-1),this.active.set(r),this.hover.set(null),e.shiftKey?(this.anchor??=n,this.select(this.anchor,r)):this.anchor=r}indexAt(e){let t=e.target?.closest?.(`[data-index]`);if(t)return Number(t.getAttribute(`data-index`));let n=e.currentTarget?.getBoundingClientRect(),r=this.cycles().length;if(!n?.width||!r)return null;let i=(e.clientX-n.left)/n.width;return Math.min(Math.max(Math.floor(i*r),0),r-1)}startDrag(e){if(e.button!==0)return;let t=this.indexAt(e);t!==null&&(this.dragging=!0,this.anchor=t,this.active.set(t),this.select(t,t))}onPointerMove(e){let t=this.indexAt(e);this.hover.set(t),this.dragging&&t!==null&&this.anchor!==null&&(this.active.set(t),this.select(this.anchor,t))}endDrag(){this.dragging=!1}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-cycle-chart`]],hostBindings:function(e,t){e&1&&U(`pointerup`,function(){return t.endDrag()},Fu)(`pointercancel`,function(){return t.endDrag()},Fu)},inputs:{cycles:[1,`cycles`],range:[1,`range`]},outputs:{range:`rangeChange`},decls:69,vars:25,consts:[[1,`range`],[`type`,`number`,`inputmode`,`numeric`,3,`change`,`min`,`max`,`value`],[`type`,`button`],[1,`summary`],[1,`hint`,3,`id`],[1,`plot`],[`aria-hidden`,`true`,1,`axis`],[1,`tick`,`top`],[1,`tick`,`zero`],[1,`area`],[`aria-hidden`,`true`,1,`band`,3,`left`,`width`],[`aria-hidden`,`true`,1,`budget`],[`role`,`listbox`,`aria-multiselectable`,`true`,`aria-orientation`,`horizontal`,`tabindex`,`0`,1,`bars`,3,`keydown`,`focus`,`blur`,`pointerdown`,`pointermove`,`pointerleave`],[`role`,`option`,1,`col`,3,`id`,`over`,`out`,`active`],[`aria-hidden`,`true`,1,`tip`,3,`left`,`right`],[`aria-hidden`,`true`,1,`markers`],[3,`over`],[`aria-label`,`Chart key`,1,`legend`],[`aria-hidden`,`true`,1,`key`,`ok`],[`aria-hidden`,`true`,1,`key`,`over`],[`aria-hidden`,`true`,1,`key-marker`],[`aria-hidden`,`true`,1,`key`,`line`],[1,`table`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[`type`,`button`,3,`click`],[`aria-hidden`,`true`,1,`band`],[`role`,`option`,1,`col`,3,`id`],[1,`bar`],[`aria-hidden`,`true`,1,`tip`],[1,`tip-head`],[1,`flag`],[1,`tip-row`],[1,`mono`],[1,`mono`,`name`],[1,`num`]],template:function(e,t){if(e&1&&(B(0,`div`,0)(1,`label`)(2,`span`),J(3,`Start`),V(),B(4,`input`,1),W(`change`,function(e){return t.setEnd(`from`,e)}),V()(),B(5,`label`)(6,`span`),J(7,`End`),V(),B(8,`input`,1),W(`change`,function(e){return t.setEnd(`to`,e)}),V()(),M(9,AA,2,0,`button`,2),B(10,`p`,3),J(11),V()(),B(12,`p`,4),J(13,` Drag across the bars to pick a range of cycles. With the chart focused, the arrow keys move between cycles, Shift with an arrow key extends the range, Enter picks one cycle and Escape shows all cycles again. `),V(),B(14,`div`,5)(15,`div`,6)(16,`span`,7),J(17),V(),B(18,`span`,8),J(19,`0 ms`),V()(),B(20,`div`,9),M(21,jA,1,4,`div`,10),B(22,`div`,11)(23,`span`),J(24),V()(),B(25,`div`,12),W(`keydown`,function(e){return t.onKey(e)})(`focus`,function(){return t.onFocus()})(`blur`,function(){return t.focused.set(!1)})(`pointerdown`,function(e){return t.startDrag(e)})(`pointermove`,function(e){return t.onPointerMove(e)})(`pointerleave`,function(){return t.hover.set(null)}),P(26,MA,2,12,`div`,13,OA),V(),M(28,IA,12,12,`div`,14),V()(),B(29,`div`,15),P(30,LA,1,2,`span`,16,OA),V(),B(32,`ul`,17)(33,`li`),Vg(34,`span`,18),J(35,`Within budget`),V(),B(36,`li`),Vg(37,`span`,19)(38,`span`,20),J(39,`Over budget `),V(),B(40,`li`),Vg(41,`span`,21),J(42),V()(),B(43,`details`,22)(44,`summary`),J(45,`Show the cycles as a table`),V(),B(46,`div`,23)(47,`table`)(48,`caption`,24),J(49),V(),B(50,`thead`)(51,`tr`)(52,`th`,25),J(53,`Cycle`),V(),B(54,`th`,25),J(55,`Duration`),V(),B(56,`th`,26),J(57,`Budget`),V(),B(58,`th`,25),J(59,`Checks`),V(),B(60,`th`,25),J(61,`Passes`),V(),B(62,`th`,26),J(63,`After`),V(),B(64,`th`,26),J(65,`Slowest component`),V()()(),B(66,`tbody`),P(67,zA,15,7,`tr`,null,kA),V()()()()),e&2){let e,n;k(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.startId()),k(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.endId()),k(),N(t.range()?9:-1),k(2),Y(t.summary()),k(),qg(`id`,t.hintId),k(2),q(`flush`,t.bars().length>t.gapUntil),k(3),Y(t.fmt(t.max())),k(4),N((e=t.band())?21:-1,e),k(),K(`bottom`,t.budgetAt(),`%`),k(2),Y(t.budgetLabel),k(),j(`aria-label`,`Change detection cycles, `+t.summary())(`aria-describedby`,t.hintId)(`aria-activedescendant`,t.activeOptionId()),k(),F(t.bars()),k(2),N((n=t.tip())?28:-1,n),k(),q(`flush`,t.bars().length>t.gapUntil),k(),F(t.bars()),k(12),Y(t.budgetLabel),k(4),j(`aria-label`,t.tableLabel()),k(3),X(` `,t.tableLabel(),` `),k(18),F(t.selected())}},styles:[`[_nghost-%COMP%] { +}`]})},kA=(e,t)=>t.cycle.id,AA=(e,t)=>t.id;function jA(e,t){if(e&1){let e=H();B(0,`button`,27),W(`click`,function(){return T(e),E(G().showAll())}),J(1,`Show all cycles`),V()}}function MA(e,t){if(e&1&&Vg(0,`div`,28),e&2){let e=t;K(`left`,e.left,`%`)(`width`,e.width,`%`)}}function NA(e,t){if(e&1&&(B(0,`div`,29),Vg(1,`span`,30),V()),e&2){let e=t.$implicit,n=G();q(`over`,e.over)(`out`,!n.inRange(e.index)&&!!n.range())(`active`,n.focused()&&n.active()===e.index),qg(`id`,n.optionId(e.index)),j(`data-index`,e.index)(`aria-selected`,n.inRange(e.index))(`aria-label`,e.label),k(),K(`height`,e.height,`%`)}}function PA(e,t){e&1&&(B(0,`span`,33),J(1,`over budget`),V())}function FA(e,t){if(e&1&&(B(0,`p`),J(1,` after `),B(2,`span`,35),J(3),V()()),e&2){let e=G();k(3),Y(e.cycle.trigger)}}function IA(e,t){if(e&1&&(B(0,`p`,34)(1,`span`,36),J(2),V(),B(3,`span`),J(4),V()()),e&2){let e=t.$implicit,n=G(2);k(2),Y(e.name),k(2),Y(n.fmt(e.ms))}}function LA(e,t){if(e&1&&(B(0,`div`,31)(1,`p`,32)(2,`strong`),J(3),V(),B(4,`span`),J(5),V(),M(6,PA,2,0,`span`,33),V(),M(7,FA,4,1,`p`),B(8,`p`),J(9),V(),P(10,IA,5,2,`p`,34,kg),V()),e&2){let e=t,n=G();K(`left`,e.left)(`right`,e.right),k(3),Y(n.fmt(e.cycle.ms)),k(2),X(`cycle `,e.cycle.id),k(),N(e.over?6:-1),k(),N(e.cycle.trigger?7:-1),k(2),iv(` `,e.cycle.checks,` `,e.cycle.checks===1?`check`:`checks`,`, `,e.cycle.passes,` `,e.cycle.passes===1?`pass`:`passes`,` `),k(),F(e.top)}}function RA(e,t){if(e&1&&Vg(0,`span`),e&2){let e=t.$implicit;q(`over`,e.over)}}function zA(e,t){if(e&1&&J(0),e&2){let e=t,n=G(2);Z(` `,e.name,` (`,n.fmt(e.ms),`) `)}}function BA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,37),J(2),V(),B(3,`td`,37),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,37),J(8),V(),B(9,`td`,37),J(10),V(),B(11,`td`,35),J(12),V(),B(13,`td`,35),M(14,zA,1,2),V()()),e&2){let e,n=t.$implicit,r=G();k(2),Y(n.id),k(2),Y(r.fmt(n.ms)),k(2),Y(r.isOver(n)?`Over`:`Within`),k(2),Y(n.checks),k(2),Y(n.passes),k(2),Y(n.trigger??``),k(2),N((e=n.components[0])?14:-1,e)}}var VA=0,HA=80,UA=10,WA=class e{cycles=$([]);range=Gv(null);gapUntil=HA;budgetLabel=`${Zk} ms budget`;uid=`cd-chart-${VA++}`;hintId=`${this.uid}-hint`;active=O(null);anchor=null;dragging=!1;hover=O(null);focused=O(!1);max=Q(()=>nA(this.cycles()));budgetAt=Q(()=>Zk/this.max()*100);bars=Q(()=>{let e=this.max();return this.cycles().map((t,n)=>({cycle:t,index:n,height:t.ms/e*100,over:Qk(t),label:this.describe(t)}))});firstId=Q(()=>this.cycles()[0]?.id??0);lastId=Q(()=>this.cycles().at(-1)?.id??0);span=Q(()=>{let e=this.range();if(!e)return null;let t=this.cycles(),n=Math.min(e.from,e.to),r=Math.max(e.from,e.to),i=t.findIndex(e=>e.id>=n),a=-1;for(let e=t.length-1;e>=0;e--)if(t[e].id<=r){a=e;break}return i<0||aeA(this.cycles(),this.range()));startId=Q(()=>this.selected()[0]?.id??``);endId=Q(()=>this.selected().at(-1)?.id??``);band=Q(()=>{let e=this.span(),t=this.cycles().length;return!e||!t?null:{left:e.start/t*100,width:(e.end-e.start+1)/t*100}});summary=Q(()=>{let e=this.selected(),t=e.filter(Qk).length;return`${this.span()?e.length===1?`Cycle ${e[0].id}`:`Cycles ${e[0].id} to ${e.at(-1).id} (${e.length})`:`All ${e.length} ${e.length===1?`cycle`:`cycles`}`}. ${t} over the ${Zk} ms budget.`});tableLabel=Q(()=>this.span()?`Picked cycles, ${this.summary()}`:`All recorded cycles`);activeOptionId=Q(()=>{let e=this.active();return this.focused()&&e!==null&&e{let e=this.hover()??(this.focused()?this.active():null),t=e===null?void 0:this.cycles()[e];return!t||e===null?null:{cycle:t,over:Qk(t),top:t.components.slice(0,3),...this.tipSide(e)}});tipSide(e){let t=this.cycles().length;return e+.5=t.start&&e<=t.end}describe(e){let t=[`Cycle ${e.id}`,$k(e.ms)];Qk(e)&&t.push(`over budget`),e.trigger&&t.push(`after ${e.trigger}`),t.push(`${e.checks} ${e.checks===1?`check`:`checks`}`);let n=e.components[0];return n&&t.push(`slowest ${n.name} ${$k(n.ms)}`),t.join(`, `)}select(e,t){let n=this.cycles(),r=n[Math.min(e,t)],i=n[Math.max(e,t)];r&&i&&this.range.set({from:r.id,to:i.id})}showAll(){this.range.set(null),this.anchor=null}setEnd(e,t){if(!this.cycles().length)return;let n=t.target,r=Number.parseInt(n.value,10);if(Number.isNaN(r)){n.value=String(e===`from`?this.startId():this.endId());return}let i=Math.min(Math.max(r,this.firstId()),this.lastId()),a=this.selected(),o=e===`from`?i:a[0]?.id??this.firstId(),s=e===`to`?i:a.at(-1)?.id??this.lastId();this.range.set({from:Math.min(o,s),to:Math.max(o,s)}),n.value=String(e===`from`?Math.min(o,s):Math.max(o,s))}onFocus(){this.focused.set(!0),(this.active()===null||this.active()>=this.cycles().length)&&this.active.set(this.span()?.start??Math.max(this.cycles().length-1,0)),this.anchor??=this.active()}onKey(e){let t=this.cycles().length;if(!t)return;let n=Math.min(this.active()??t-1,t-1),r=null;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=n+1;break;case`ArrowLeft`:case`ArrowUp`:r=n-1;break;case`PageDown`:r=n+UA;break;case`PageUp`:r=n-UA;break;case`Home`:r=0;break;case`End`:r=t-1;break;case`Enter`:case` `:e.preventDefault(),this.anchor=n,this.select(n,n);return;case`Escape`:this.range()&&(e.preventDefault(),this.showAll());return;default:return}e.preventDefault(),r=Math.min(Math.max(r,0),t-1),this.active.set(r),this.hover.set(null),e.shiftKey?(this.anchor??=n,this.select(this.anchor,r)):this.anchor=r}indexAt(e){let t=e.target?.closest?.(`[data-index]`);if(t)return Number(t.getAttribute(`data-index`));let n=e.currentTarget?.getBoundingClientRect(),r=this.cycles().length;if(!n?.width||!r)return null;let i=(e.clientX-n.left)/n.width;return Math.min(Math.max(Math.floor(i*r),0),r-1)}startDrag(e){if(e.button!==0)return;let t=this.indexAt(e);t!==null&&(this.dragging=!0,this.anchor=t,this.active.set(t),this.select(t,t))}onPointerMove(e){let t=this.indexAt(e);this.hover.set(t),this.dragging&&t!==null&&this.anchor!==null&&(this.active.set(t),this.select(this.anchor,t))}endDrag(){this.dragging=!1}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-cycle-chart`]],hostBindings:function(e,t){e&1&&U(`pointerup`,function(){return t.endDrag()},Fu)(`pointercancel`,function(){return t.endDrag()},Fu)},inputs:{cycles:[1,`cycles`],range:[1,`range`]},outputs:{range:`rangeChange`},decls:69,vars:25,consts:[[1,`range`],[`type`,`number`,`inputmode`,`numeric`,3,`change`,`min`,`max`,`value`],[`type`,`button`],[1,`summary`],[1,`hint`,3,`id`],[1,`plot`],[`aria-hidden`,`true`,1,`axis`],[1,`tick`,`top`],[1,`tick`,`zero`],[1,`area`],[`aria-hidden`,`true`,1,`band`,3,`left`,`width`],[`aria-hidden`,`true`,1,`budget`],[`role`,`listbox`,`aria-multiselectable`,`true`,`aria-orientation`,`horizontal`,`tabindex`,`0`,1,`bars`,3,`keydown`,`focus`,`blur`,`pointerdown`,`pointermove`,`pointerleave`],[`role`,`option`,1,`col`,3,`id`,`over`,`out`,`active`],[`aria-hidden`,`true`,1,`tip`,3,`left`,`right`],[`aria-hidden`,`true`,1,`markers`],[3,`over`],[`aria-label`,`Chart key`,1,`legend`],[`aria-hidden`,`true`,1,`key`,`ok`],[`aria-hidden`,`true`,1,`key`,`over`],[`aria-hidden`,`true`,1,`key-marker`],[`aria-hidden`,`true`,1,`key`,`line`],[1,`table`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[`type`,`button`,3,`click`],[`aria-hidden`,`true`,1,`band`],[`role`,`option`,1,`col`,3,`id`],[1,`bar`],[`aria-hidden`,`true`,1,`tip`],[1,`tip-head`],[1,`flag`],[1,`tip-row`],[1,`mono`],[1,`mono`,`name`],[1,`num`]],template:function(e,t){if(e&1&&(B(0,`div`,0)(1,`label`)(2,`span`),J(3,`Start`),V(),B(4,`input`,1),W(`change`,function(e){return t.setEnd(`from`,e)}),V()(),B(5,`label`)(6,`span`),J(7,`End`),V(),B(8,`input`,1),W(`change`,function(e){return t.setEnd(`to`,e)}),V()(),M(9,jA,2,0,`button`,2),B(10,`p`,3),J(11),V()(),B(12,`p`,4),J(13,` Drag across the bars to pick a range of cycles. With the chart focused, the arrow keys move between cycles, Shift with an arrow key extends the range, Enter picks one cycle and Escape shows all cycles again. `),V(),B(14,`div`,5)(15,`div`,6)(16,`span`,7),J(17),V(),B(18,`span`,8),J(19,`0 ms`),V()(),B(20,`div`,9),M(21,MA,1,4,`div`,10),B(22,`div`,11)(23,`span`),J(24),V()(),B(25,`div`,12),W(`keydown`,function(e){return t.onKey(e)})(`focus`,function(){return t.onFocus()})(`blur`,function(){return t.focused.set(!1)})(`pointerdown`,function(e){return t.startDrag(e)})(`pointermove`,function(e){return t.onPointerMove(e)})(`pointerleave`,function(){return t.hover.set(null)}),P(26,NA,2,12,`div`,13,kA),V(),M(28,LA,12,12,`div`,14),V()(),B(29,`div`,15),P(30,RA,1,2,`span`,16,kA),V(),B(32,`ul`,17)(33,`li`),Vg(34,`span`,18),J(35,`Within budget`),V(),B(36,`li`),Vg(37,`span`,19)(38,`span`,20),J(39,`Over budget `),V(),B(40,`li`),Vg(41,`span`,21),J(42),V()(),B(43,`details`,22)(44,`summary`),J(45,`Show the cycles as a table`),V(),B(46,`div`,23)(47,`table`)(48,`caption`,24),J(49),V(),B(50,`thead`)(51,`tr`)(52,`th`,25),J(53,`Cycle`),V(),B(54,`th`,25),J(55,`Duration`),V(),B(56,`th`,26),J(57,`Budget`),V(),B(58,`th`,25),J(59,`Checks`),V(),B(60,`th`,25),J(61,`Passes`),V(),B(62,`th`,26),J(63,`After`),V(),B(64,`th`,26),J(65,`Slowest component`),V()()(),B(66,`tbody`),P(67,BA,15,7,`tr`,null,AA),V()()()()),e&2){let e,n;k(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.startId()),k(4),qg(`min`,t.firstId())(`max`,t.lastId())(`value`,t.endId()),k(),N(t.range()?9:-1),k(2),Y(t.summary()),k(),qg(`id`,t.hintId),k(2),q(`flush`,t.bars().length>t.gapUntil),k(3),Y(t.fmt(t.max())),k(4),N((e=t.band())?21:-1,e),k(),K(`bottom`,t.budgetAt(),`%`),k(2),Y(t.budgetLabel),k(),j(`aria-label`,`Change detection cycles, `+t.summary())(`aria-describedby`,t.hintId)(`aria-activedescendant`,t.activeOptionId()),k(),F(t.bars()),k(2),N((n=t.tip())?28:-1,n),k(),q(`flush`,t.bars().length>t.gapUntil),k(),F(t.bars()),k(12),Y(t.budgetLabel),k(4),j(`aria-label`,t.tableLabel()),k(3),X(` `,t.tableLabel(),` `),k(18),F(t.selected())}},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1224,7 +1224,7 @@ td.mono[_ngcontent-%COMP%] { .bar[_ngcontent-%COMP%] { transition: none; } -}`]})},WA=(e,t)=>t.id,GA=(e,t)=>t.index,KA=(e,t)=>t.kind;function qA(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(2);k(),Z(` Pick `,e.max,` cycles or fewer to see their spans. `,e.count(),` are picked. `)}}function JA(e,t){if(e&1&&(B(0,`span`),J(1),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`width`,e.w,`%`),k(),X(`cycle `,e.id)}}function YA(e,t){if(e&1){let e=H();B(0,`button`,11),W(`focus`,function(){let t=T(e).$implicit;return E(G(3).current.set(t.index))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(3).hover.set(t.index))})(`mouseleave`,function(){return T(e),E(G(3).hover.set(null))})(`click`,function(){let t=T(e).$implicit;return E(G(3).choose(t))}),B(1,`span`,12),J(2),V()()}if(e&2){let e=t.$implicit,n=G(3);M_(pv(`block kind-`,e.kind)),K(`left`,e.x,`%`)(`width`,e.w,`%`)(`top`,e.depth*n.row,`px`),q(`narrow`,e.w<4),j(`tabindex`,e.index===n.tabStop()?0:-1)(`data-index`,e.index)(`aria-label`,n.describe(e))(`aria-disabled`,e.component?null:`true`),k(2),Y(e.name)}}function XA(e,t){if(e&1&&(B(0,`li`),Vg(1,`span`,13),J(2),V()),e&2){let e=t.$implicit;k(),M_(pv(`key kind-`,e.kind)),k(),Y(e.label)}}function ZA(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(3);k(),Z(` Each cycle keeps its longest spans. `,e.dropped(),` shorter `,e.dropped()===1?`span was`:`spans were`,` left out. `)}}function QA(e,t){if(e&1&&(B(0,`tr`)(1,`td`,17),J(2),V(),B(3,`td`,18),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,17),J(8),V(),B(9,`td`,17),J(10),V(),B(11,`td`,17),J(12),V(),B(13,`td`,17),J(14),V()()),e&2){let e=t.$implicit,n=G(4);k(2),Y(e.cycleId),k(),K(`padding-left`,6+e.depth*8,`px`),k(),Y(e.name),k(2),Y(n.kindLabel(e)),k(2),Y(e.depth),k(2),Y(n.fmt(e.start)),k(2),Y(n.fmt(e.ms)),k(2),Y(n.fmt(e.selfMs))}}function $A(e,t){if(e&1&&(B(0,`div`,10)(1,`table`)(2,`caption`,14),J(3),V(),B(4,`thead`)(5,`tr`)(6,`th`,15),J(7,`Cycle`),V(),B(8,`th`,16),J(9,`Span`),V(),B(10,`th`,16),J(11,`Kind`),V(),B(12,`th`,15),J(13,`Depth`),V(),B(14,`th`,15),J(15,`Start`),V(),B(16,`th`,15),J(17,`Total`),V(),B(18,`th`,15),J(19,`Self`),V()()(),B(20,`tbody`),P(21,QA,15,9,`tr`,null,GA),V()()()),e&2){let e=G(),t=G(2);j(`aria-label`,t.tableLabel()),k(3),X(` `,t.tableLabel(),` `),k(18),F(e.blocks)}}function ej(e,t){if(e&1){let e=H();B(0,`div`,1),W(`keydown`,function(t){return T(e),E(G(2).onKey(t))}),B(1,`div`,2),P(2,JA,2,5,`span`,3,WA),V(),B(4,`div`,4),P(5,YA,3,16,`button`,5,GA),V()(),B(7,`p`,6),J(8),V(),B(9,`ul`,7),P(10,XA,3,4,`li`,null,KA),V(),B(12,`p`,8),J(13,` Arrow keys move along a row, Up goes to the enclosing span and Down to the first nested one. Enter on a component shows it in the tree. `),V(),M(14,ZA,2,2,`p`,0),B(15,`details`,9),W(`toggle`,function(t){return T(e),E(G(2).onToggle(t))}),B(16,`summary`),J(17,`Show the spans as a table`),V(),M(18,$A,23,2,`div`,10),V()}if(e&2){let e=t,n=G(2);j(`aria-label`,n.label()),k(2),F(e.cycles),k(2),K(`height`,e.depth*n.row,`px`),k(),F(e.blocks),k(3),Y(n.readout()),k(2),F(n.kinds),k(4),N(n.dropped()?14:-1),k(4),N(n.tableOpen()?18:-1)}}function tj(e,t){if(e&1&&(B(0,`h3`),J(1,`Spans in the picked cycles`),V(),M(2,qA,2,2,`p`,0)(3,ej,19,6)),e&2){let e,t=G();k(2),N(t.tooMany()?2:(e=t.graph())?3:-1,e)}}var nj=22;function rj(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return e[n]}var ij=class e{cycles=$([]);names=$([]);scope=$(`the recording`);pick=Rv();row=nj;max=30;kinds=[`c`,`h`,`r`,`o`].map(e=>({kind:e,label:iA[e]}));current=O(0);tableOpen=O(!1);hover=O(null);hasSpans=Q(()=>this.cycles().some(e=>e.spans?.length));count=Q(()=>this.cycles().length);tooMany=Q(()=>this.count()>30);graph=Q(()=>this.tooMany()?null:oA(this.cycles(),this.names()));tabStop=Q(()=>Math.min(this.current(),Math.max((this.graph()?.blocks.length??1)-1,0)));dropped=Q(()=>this.graph()?.cycles.reduce((e,t)=>e+t.droppedSpans,0)??0);label=Q(()=>`Spans in ${this.scope()} over time, nested by depth. Pick a component to show it in the tree.`);readout=Q(()=>{let e=(this.graph()?.blocks??[])[this.hover()??this.tabStop()];return e?this.describe(e):``});tableLabel=Q(()=>`Timed spans in ${this.scope()}`);fmt(e){return $k(e)}kindLabel(e){return iA[e.kind]}onToggle(e){this.tableOpen.set(e.target.open)}describe(e){let t=[e.name,iA[e.kind],`${$k(e.ms)} total`];return e.selfMs!==e.ms&&t.push(`${$k(e.selfMs)} self`),t.push(e.start<0?`cycle ${e.cycleId}, ${$k(-e.start)} before it started`:`cycle ${e.cycleId} at ${$k(e.start)}`),t.join(`, `)}choose(e){this.current.set(e.index),e.component&&this.pick.emit(e.component)}onKey(e){let t=this.graph()?.blocks??[];if(!t.length)return;let n=t[this.tabStop()],r;switch(e.key){case`ArrowRight`:r=t.find(e=>e.index>n.index&&e.depth===n.depth);break;case`ArrowLeft`:r=rj(t,e=>e.indexe.indexe.parent===n.index)??t.find(e=>e.index>n.index&&e.depth===n.depth+1);break;case`Home`:r=t[0];break;case`End`:r=t.at(-1);break;default:return}e.preventDefault(),this.hover.set(null),r&&(this.current.set(r.index),e.currentTarget.querySelector(`button[data-index="${r.index}"]`)?.focus())}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-flame-graph`]],inputs:{cycles:[1,`cycles`],names:[1,`names`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:1,vars:1,consts:[[1,`note`],[`role`,`group`,1,`flame`,3,`keydown`],[`aria-hidden`,`true`,1,`cycles`],[3,`left`,`width`],[1,`rows`],[`type`,`button`,3,`class`,`narrow`,`left`,`width`,`top`],[`aria-hidden`,`true`,1,`readout`],[`aria-label`,`Span kinds`,1,`legend`],[1,`hint`],[1,`table`,3,`toggle`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[`type`,`button`,3,`focus`,`mouseenter`,`mouseleave`,`click`],[1,`text`],[`aria-hidden`,`true`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[1,`num`],[1,`mono`]],template:function(e,t){e&1&&M(0,tj,4,1),e&2&&N(t.hasSpans()?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})},GA=(e,t)=>t.id,KA=(e,t)=>t.index,qA=(e,t)=>t.kind;function JA(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(2);k(),Z(` Pick `,e.max,` cycles or fewer to see their spans. `,e.count(),` are picked. `)}}function YA(e,t){if(e&1&&(B(0,`span`),J(1),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`width`,e.w,`%`),k(),X(`cycle `,e.id)}}function XA(e,t){if(e&1){let e=H();B(0,`button`,11),W(`focus`,function(){let t=T(e).$implicit;return E(G(3).current.set(t.index))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(3).hover.set(t.index))})(`mouseleave`,function(){return T(e),E(G(3).hover.set(null))})(`click`,function(){let t=T(e).$implicit;return E(G(3).choose(t))}),B(1,`span`,12),J(2),V()()}if(e&2){let e=t.$implicit,n=G(3);M_(pv(`block kind-`,e.kind)),K(`left`,e.x,`%`)(`width`,e.w,`%`)(`top`,e.depth*n.row,`px`),q(`narrow`,e.w<4),j(`tabindex`,e.index===n.tabStop()?0:-1)(`data-index`,e.index)(`aria-label`,n.describe(e))(`aria-disabled`,e.component?null:`true`),k(2),Y(e.name)}}function ZA(e,t){if(e&1&&(B(0,`li`),Vg(1,`span`,13),J(2),V()),e&2){let e=t.$implicit;k(),M_(pv(`key kind-`,e.kind)),k(),Y(e.label)}}function QA(e,t){if(e&1&&(B(0,`p`,0),J(1),V()),e&2){let e=G(3);k(),Z(` Each cycle keeps its longest spans. `,e.dropped(),` shorter `,e.dropped()===1?`span was`:`spans were`,` left out. `)}}function $A(e,t){if(e&1&&(B(0,`tr`)(1,`td`,17),J(2),V(),B(3,`td`,18),J(4),V(),B(5,`td`),J(6),V(),B(7,`td`,17),J(8),V(),B(9,`td`,17),J(10),V(),B(11,`td`,17),J(12),V(),B(13,`td`,17),J(14),V()()),e&2){let e=t.$implicit,n=G(4);k(2),Y(e.cycleId),k(),K(`padding-left`,6+e.depth*8,`px`),k(),Y(e.name),k(2),Y(n.kindLabel(e)),k(2),Y(e.depth),k(2),Y(n.fmt(e.start)),k(2),Y(n.fmt(e.ms)),k(2),Y(n.fmt(e.selfMs))}}function ej(e,t){if(e&1&&(B(0,`div`,10)(1,`table`)(2,`caption`,14),J(3),V(),B(4,`thead`)(5,`tr`)(6,`th`,15),J(7,`Cycle`),V(),B(8,`th`,16),J(9,`Span`),V(),B(10,`th`,16),J(11,`Kind`),V(),B(12,`th`,15),J(13,`Depth`),V(),B(14,`th`,15),J(15,`Start`),V(),B(16,`th`,15),J(17,`Total`),V(),B(18,`th`,15),J(19,`Self`),V()()(),B(20,`tbody`),P(21,$A,15,9,`tr`,null,KA),V()()()),e&2){let e=G(),t=G(2);j(`aria-label`,t.tableLabel()),k(3),X(` `,t.tableLabel(),` `),k(18),F(e.blocks)}}function tj(e,t){if(e&1){let e=H();B(0,`div`,1),W(`keydown`,function(t){return T(e),E(G(2).onKey(t))}),B(1,`div`,2),P(2,YA,2,5,`span`,3,GA),V(),B(4,`div`,4),P(5,XA,3,16,`button`,5,KA),V()(),B(7,`p`,6),J(8),V(),B(9,`ul`,7),P(10,ZA,3,4,`li`,null,qA),V(),B(12,`p`,8),J(13,` Arrow keys move along a row, Up goes to the enclosing span and Down to the first nested one. Enter on a component shows it in the tree. `),V(),M(14,QA,2,2,`p`,0),B(15,`details`,9),W(`toggle`,function(t){return T(e),E(G(2).onToggle(t))}),B(16,`summary`),J(17,`Show the spans as a table`),V(),M(18,ej,23,2,`div`,10),V()}if(e&2){let e=t,n=G(2);j(`aria-label`,n.label()),k(2),F(e.cycles),k(2),K(`height`,e.depth*n.row,`px`),k(),F(e.blocks),k(3),Y(n.readout()),k(2),F(n.kinds),k(4),N(n.dropped()?14:-1),k(4),N(n.tableOpen()?18:-1)}}function nj(e,t){if(e&1&&(B(0,`h3`),J(1,`Spans in the picked cycles`),V(),M(2,JA,2,2,`p`,0)(3,tj,19,6)),e&2){let e,t=G();k(2),N(t.tooMany()?2:(e=t.graph())?3:-1,e)}}var rj=22;function ij(e,t){for(let n=e.length-1;n>=0;n--)if(t(e[n]))return e[n]}var aj=class e{cycles=$([]);names=$([]);scope=$(`the recording`);pick=Rv();row=rj;max=30;kinds=[`c`,`h`,`r`,`o`].map(e=>({kind:e,label:iA[e]}));current=O(0);tableOpen=O(!1);hover=O(null);hasSpans=Q(()=>this.cycles().some(e=>e.spans?.length));count=Q(()=>this.cycles().length);tooMany=Q(()=>this.count()>30);graph=Q(()=>this.tooMany()?null:oA(this.cycles(),this.names()));tabStop=Q(()=>Math.min(this.current(),Math.max((this.graph()?.blocks.length??1)-1,0)));dropped=Q(()=>this.graph()?.cycles.reduce((e,t)=>e+t.droppedSpans,0)??0);label=Q(()=>`Spans in ${this.scope()} over time, nested by depth. Pick a component to show it in the tree.`);readout=Q(()=>{let e=(this.graph()?.blocks??[])[this.hover()??this.tabStop()];return e?this.describe(e):``});tableLabel=Q(()=>`Timed spans in ${this.scope()}`);fmt(e){return $k(e)}kindLabel(e){return iA[e.kind]}onToggle(e){this.tableOpen.set(e.target.open)}describe(e){let t=[e.name,iA[e.kind],`${$k(e.ms)} total`];return e.selfMs!==e.ms&&t.push(`${$k(e.selfMs)} self`),t.push(e.start<0?`cycle ${e.cycleId}, ${$k(-e.start)} before it started`:`cycle ${e.cycleId} at ${$k(e.start)}`),t.join(`, `)}choose(e){this.current.set(e.index),e.component&&this.pick.emit(e.component)}onKey(e){let t=this.graph()?.blocks??[];if(!t.length)return;let n=t[this.tabStop()],r;switch(e.key){case`ArrowRight`:r=t.find(e=>e.index>n.index&&e.depth===n.depth);break;case`ArrowLeft`:r=ij(t,e=>e.indexe.indexe.parent===n.index)??t.find(e=>e.index>n.index&&e.depth===n.depth+1);break;case`Home`:r=t[0];break;case`End`:r=t.at(-1);break;default:return}e.preventDefault(),this.hover.set(null),r&&(this.current.set(r.index),e.currentTarget.querySelector(`button[data-index="${r.index}"]`)?.focus())}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-flame-graph`]],inputs:{cycles:[1,`cycles`],names:[1,`names`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:1,vars:1,consts:[[1,`note`],[`role`,`group`,1,`flame`,3,`keydown`],[`aria-hidden`,`true`,1,`cycles`],[3,`left`,`width`],[1,`rows`],[`type`,`button`,3,`class`,`narrow`,`left`,`width`,`top`],[`aria-hidden`,`true`,1,`readout`],[`aria-label`,`Span kinds`,1,`legend`],[1,`hint`],[1,`table`,3,`toggle`],[`tabindex`,`0`,`role`,`region`,1,`table-wrap`],[`type`,`button`,3,`focus`,`mouseenter`,`mouseleave`,`click`],[1,`text`],[`aria-hidden`,`true`],[1,`sr-only`],[`scope`,`col`,1,`num`],[`scope`,`col`],[1,`num`],[1,`mono`]],template:function(e,t){e&1&&M(0,nj,4,1),e&2&&N(t.hasSpans()?0:-1)},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1431,7 +1431,7 @@ td.mono[_ngcontent-%COMP%] { .num[_ngcontent-%COMP%] { text-align: right; font-variant-numeric: tabular-nums; -}`]})};function aj(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit,n=G(3);k(2),Z(``,e.name,`.`,e.hook),k(2),Y(e.calls),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function oj(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Lifecycle hooks`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Hook`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,aj,9,5,`tr`,null,kg),V()()()),e&2){let e=G(2);k(15),F(e.hooks())}}function sj(e,t){if(e&1&&J(0),e&2){let e=G().$implicit;X(` (`,e.listener,`) `)}}function cj(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),M(3,sj,1,1),V(),B(4,`td`,6),J(5),V(),B(6,`td`,6),J(7),V(),B(8,`td`,6),J(9),V()()),e&2){let e=t.$implicit,n=G(3);k(2),X(` `,e.name,` `),k(),N(e.listener?3:-1),k(2),Y(e.calls),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function lj(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Output listeners`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Listener`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,cj,10,5,`tr`,null,kg),V()()()),e&2){let e=G(2);k(15),F(e.outputs())}}function uj(e,t){if(e&1&&(B(0,`p`,1),J(1),V()),e&2){let e=t,n=G(2);k(),iv(` afterRender callbacks ran `,e.runs,` `,e.runs===1?`time`:`times`,`, `,n.ms(e.ms),` in total, slowest `,n.ms(e.maxMs),`. `)}}function dj(e,t){if(e&1&&(B(0,`p`,2),J(1),V()),e&2){let e=G(2);k(),Z(` `,e.dropped(),` more hook or output `,e.dropped()===1?`row is`:`rows are`,` left out. A recording lists at most 100 of each. `)}}function fj(e,t){if(e&1&&(B(0,`div`,0),M(1,oj,17,0,`div`),M(2,lj,17,0,`div`),V(),M(3,uj,2,4,`p`,1),M(4,dj,2,2,`p`,2)),e&2){let e,t=G();k(),N(t.hooks().length?1:-1),k(),N(t.outputs().length?2:-1),k(),N((e=t.afterRender())?3:-1,e),k(),N(t.dropped()?4:-1)}}var pj=10;function mj(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}var hj=class e{page=$(null);hooks=Q(()=>(this.page()?.hooks??[]).slice(0,pj));outputs=Q(()=>(this.page()?.outputs??[]).slice(0,pj));afterRender=Q(()=>{let e=this.page()?.afterRender;return e?.runs?e:null});dropped=Q(()=>this.page()?.droppedTimings??0);ms(e){return mj(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-timing`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[1,`timing`],[1,`after-render`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`mono`],[1,`num`]],template:function(e,t){e&1&&M(0,fj,5,4),e&2&&N(t.hooks().length||t.outputs().length||t.afterRender()?0:-1)},styles:[`[_nghost-%COMP%] { +}`]})};function oj(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),V(),B(3,`td`,6),J(4),V(),B(5,`td`,6),J(6),V(),B(7,`td`,6),J(8),V()()),e&2){let e=t.$implicit,n=G(3);k(2),Z(``,e.name,`.`,e.hook),k(2),Y(e.calls),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function sj(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Lifecycle hooks`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Hook`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,oj,9,5,`tr`,null,kg),V()()()),e&2){let e=G(2);k(15),F(e.hooks())}}function cj(e,t){if(e&1&&J(0),e&2){let e=G().$implicit;X(` (`,e.listener,`) `)}}function lj(e,t){if(e&1&&(B(0,`tr`)(1,`td`,5),J(2),M(3,cj,1,1),V(),B(4,`td`,6),J(5),V(),B(6,`td`,6),J(7),V(),B(8,`td`,6),J(9),V()()),e&2){let e=t.$implicit,n=G(3);k(2),X(` `,e.name,` `),k(),N(e.listener?3:-1),k(2),Y(e.calls),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function uj(e,t){if(e&1&&(B(0,`div`)(1,`h3`),J(2,`Output listeners`),V(),B(3,`table`)(4,`thead`)(5,`tr`)(6,`th`,3),J(7,`Listener`),V(),B(8,`th`,4),J(9,`Calls`),V(),B(10,`th`,4),J(11,`Time`),V(),B(12,`th`,4),J(13,`Slowest`),V()()(),B(14,`tbody`),P(15,lj,10,5,`tr`,null,kg),V()()()),e&2){let e=G(2);k(15),F(e.outputs())}}function dj(e,t){if(e&1&&(B(0,`p`,1),J(1),V()),e&2){let e=t,n=G(2);k(),iv(` afterRender callbacks ran `,e.runs,` `,e.runs===1?`time`:`times`,`, `,n.ms(e.ms),` in total, slowest `,n.ms(e.maxMs),`. `)}}function fj(e,t){if(e&1&&(B(0,`p`,2),J(1),V()),e&2){let e=G(2);k(),Z(` `,e.dropped(),` more hook or output `,e.dropped()===1?`row is`:`rows are`,` left out. A recording lists at most 100 of each. `)}}function pj(e,t){if(e&1&&(B(0,`div`,0),M(1,sj,17,0,`div`),M(2,uj,17,0,`div`),V(),M(3,dj,2,4,`p`,1),M(4,fj,2,2,`p`,2)),e&2){let e,t=G();k(),N(t.hooks().length?1:-1),k(),N(t.outputs().length?2:-1),k(),N((e=t.afterRender())?3:-1,e),k(),N(t.dropped()?4:-1)}}var mj=10;function hj(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}var gj=class e{page=$(null);hooks=Q(()=>(this.page()?.hooks??[]).slice(0,mj));outputs=Q(()=>(this.page()?.outputs??[]).slice(0,mj));afterRender=Q(()=>{let e=this.page()?.afterRender;return e?.runs?e:null});dropped=Q(()=>this.page()?.droppedTimings??0);ms(e){return hj(e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-timing`]],inputs:{page:[1,`page`]},decls:1,vars:1,consts:[[1,`timing`],[1,`after-render`],[1,`note`],[`scope`,`col`],[`scope`,`col`,1,`num`],[1,`mono`],[1,`num`]],template:function(e,t){e&1&&M(0,pj,5,4),e&2&&N(t.hooks().length||t.outputs().length||t.afterRender()?0:-1)},styles:[`[_nghost-%COMP%] { display: block; } @@ -1491,7 +1491,7 @@ td.mono[_ngcontent-%COMP%] { margin: 8px 0 0; color: var(--%NS%text-2); font-size: 12px; -}`]})};function gj(e,t){if(e&1&&(B(0,`p`,5),J(1),V()),e&2){let e=G();k(),Y(e.error())}}function _j(e,t){let n=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=t,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}var vj=class e{page=$(null);maxCycles=$(200);imported=Rv();error=O(``);hasCycles(){return(this.page()?.cycles.length??0)>0}exportJson(){let e=this.page();e&&_j(Uk(e,e.pageId),`change-detection-${e.pageId}.json`)}exportTrace(){let e=this.page();e&&_j(Xk(e,e.pageId),`change-detection-${e.pageId}.trace.json`)}async read(e){let t=e.files?.[0];if(e.value=``,!t)return;if(t.size>2e7){this.error.set(`${t.name}: The file is larger than 20 MB.`);return}let n;try{n=await t.text()}catch{this.error.set(`Could not read the file.`);return}let r=Wk(n,this.maxCycles());if(!r.ok){this.error.set(`${t.name}: ${r.error}`);return}this.error.set(``),this.imported.emit({fileName:t.name,page:{...r.recording,pageId:r.pageId,supported:!0}})}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-transfer`]],inputs:{page:[1,`page`],maxCycles:[1,`maxCycles`]},outputs:{imported:`imported`},decls:10,vars:3,consts:[[`file`,``],[`role`,`group`,`aria-label`,`Export and import the recording`,1,`transfer`],[`type`,`button`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[`type`,`file`,`accept`,`.json,application/json`,`hidden`,``,3,`change`],[`role`,`alert`,1,`error`]],template:function(e,t){if(e&1){let e=H();B(0,`div`,1)(1,`button`,2),W(`click`,function(){return t.exportJson()}),J(2,`Export JSON`),V(),B(3,`button`,2),W(`click`,function(){return t.exportTrace()}),J(4,` Export trace (Perfetto) `),V(),B(5,`button`,3),W(`click`,function(){return T(e),E(d_(8).click())}),J(6,`Import`),V(),B(7,`input`,4,0),W(`change`,function(){T(e);let n=d_(8);return E(t.read(n))}),V()(),M(9,gj,2,1,`p`,5)}e&2&&(k(),qg(`disabled`,!t.hasCycles()),k(2),qg(`disabled`,!t.hasCycles()),k(6),N(t.error()?9:-1))},styles:[`[_nghost-%COMP%] { +}`]})};function _j(e,t){if(e&1&&(B(0,`p`,5),J(1),V()),e&2){let e=G();k(),Y(e.error())}}function vj(e,t){let n=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=t,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),0)}var yj=class e{page=$(null);maxCycles=$(200);imported=Rv();error=O(``);hasCycles(){return(this.page()?.cycles.length??0)>0}exportJson(){let e=this.page();e&&vj(Uk(e,e.pageId),`change-detection-${e.pageId}.json`)}exportTrace(){let e=this.page();e&&vj(Xk(e,e.pageId),`change-detection-${e.pageId}.trace.json`)}async read(e){let t=e.files?.[0];if(e.value=``,!t)return;if(t.size>2e7){this.error.set(`${t.name}: The file is larger than 20 MB.`);return}let n;try{n=await t.text()}catch{this.error.set(`Could not read the file.`);return}let r=Wk(n,this.maxCycles());if(!r.ok){this.error.set(`${t.name}: ${r.error}`);return}this.error.set(``),this.imported.emit({fileName:t.name,page:{...r.recording,pageId:r.pageId,supported:!0}})}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-transfer`]],inputs:{page:[1,`page`],maxCycles:[1,`maxCycles`]},outputs:{imported:`imported`},decls:10,vars:3,consts:[[`file`,``],[`role`,`group`,`aria-label`,`Export and import the recording`,1,`transfer`],[`type`,`button`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[`type`,`file`,`accept`,`.json,application/json`,`hidden`,``,3,`change`],[`role`,`alert`,1,`error`]],template:function(e,t){if(e&1){let e=H();B(0,`div`,1)(1,`button`,2),W(`click`,function(){return t.exportJson()}),J(2,`Export JSON`),V(),B(3,`button`,2),W(`click`,function(){return t.exportTrace()}),J(4,` Export trace (Perfetto) `),V(),B(5,`button`,3),W(`click`,function(){return T(e),E(d_(8).click())}),J(6,`Import`),V(),B(7,`input`,4,0),W(`change`,function(){T(e);let n=d_(8);return E(t.read(n))}),V()(),M(9,_j,2,1,`p`,5)}e&2&&(k(),qg(`disabled`,!t.hasCycles()),k(2),qg(`disabled`,!t.hasCycles()),k(6),N(t.error()?9:-1))},styles:[`[_nghost-%COMP%] { display: contents; } @@ -1533,7 +1533,7 @@ button[_ngcontent-%COMP%]:disabled { margin: 0; color: var(--%NS%danger-text); font-size: 12px; -}`]})},yj=(e,t)=>t.stat.name;function bj(e,t){if(e&1&&(B(0,`span`,8),J(1),V()),e&2){let e=G(2).$implicit;k(),X(``,e.other,` more`)}}function xj(e,t){if(e&1&&(B(0,`div`,6)(1,`span`,7),J(2),V(),M(3,bj,2,1,`span`,8),V()),e&2){let e=G().$implicit;K(`--%NS%tone`,e.tone+`%`),k(2),Y(e.label),k(),N(e.roomy?3:-1)}}function Sj(e,t){if(e&1&&(B(0,`span`,10),J(1),V(),B(2,`span`,11),J(3),V()),e&2){let e=G(2).$implicit,t=G(2);k(),Y(e.stat.name),k(2),Y(t.fmt(e.stat.ms))}}function Cj(e,t){if(e&1){let e=H();B(0,`button`,9),W(`focus`,function(){T(e);let t=G().$index;return E(G(2).current.set(t))})(`click`,function(){T(e);let t=G().$implicit;return E(G(2).pick.emit(t.stat.name))}),M(1,Sj,4,2),V()}if(e&2){let e=G(),t=e.$implicit,n=e.$index,r=G(2);K(`--%NS%tone`,t.tone+`%`),j(`tabindex`,n===r.tabStop()?0:-1)(`aria-label`,t.label)(`data-index`,n),k(),N(t.roomy?1:-1)}}function wj(e,t){if(e&1&&(B(0,`li`),M(1,xj,4,4,`div`,4)(2,Cj,2,6,`button`,5),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`top`,e.y,`%`)(`width`,e.w,`%`)(`height`,e.h,`%`),k(),N(e.other?1:2)}}function Tj(e,t){if(e&1){let e=H();B(0,`ul`,2),W(`keydown`,function(t){return T(e),E(G().onKey(t))}),P(1,wj,3,9,`li`,3,yj),V()}if(e&2){let e=G();j(`aria-label`,e.label()),k(),F(e.cells())}}function Ej(e,t){e&1&&(B(0,`p`,1),J(1,`No component time in these cycles.`),V())}var Dj=24,Oj=3,kj=class e{stats=$([]);scope=$(`the recording`);pick=Rv();current=O(0);label=Q(()=>`Self time per component in ${this.scope()}, largest first. Pick one to show it in the tree.`);cells=Q(()=>{let e=this.stats().filter(e=>e.ms>0),t=e.slice(0,Dj),n=e.slice(Dj),r=n.reduce((e,t)=>e+t.ms,0),i=t.map(e=>({stat:e,other:0}));n.length&&i.push({stat:{name:`Other components`,checks:0,ms:r,maxMs:0,cycles:0},other:n.length});let a=e.reduce((e,t)=>e+t.ms,0),o=t[0]?.ms??1,s=rA(i,e=>e.stat.ms,Oj);return s.sort((e,t)=>Number(e.item.other>0)-Number(t.item.other>0)),s.map(e=>{let{stat:t,other:n}=e.item,r=a?Math.round(t.ms/a*100):0;return{stat:t,other:n,x:e.x,y:e.y,w:e.w,h:e.h,tone:n?0:14+Math.round(26*Math.min(t.ms/o,1)),roomy:e.w>=10&&e.h>=22,label:n?`${n} more components, ${$k(t.ms)}, ${r}% of self time`:`${t.name}, ${$k(t.ms)} self time, ${r}%, ${t.checks} ${t.checks===1?`check`:`checks`}`}})});tabStop=Q(()=>Math.min(this.current(),Math.max(this.cells().filter(e=>!e.other).length-1,0)));fmt(e){return $k(e)}onKey(e){let t=this.cells().filter(e=>!e.other).length;if(!t)return;let n=this.tabStop(),r;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=Math.min(n+1,t-1);break;case`ArrowLeft`:case`ArrowUp`:r=Math.max(n-1,0);break;case`Home`:r=0;break;case`End`:r=t-1;break;default:return}e.preventDefault(),this.current.set(r),e.currentTarget.querySelector(`button[data-index="${r}"]`)?.focus()}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-treemap`]],inputs:{stats:[1,`stats`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:2,vars:1,consts:[[1,`map`],[1,`empty`],[1,`map`,3,`keydown`],[3,`left`,`top`,`width`,`height`],[1,`cell`,`other`,3,`--%NS%tone`],[`type`,`button`,1,`cell`,3,`--%NS%tone`],[1,`cell`,`other`],[1,`sr-only`],[`aria-hidden`,`true`,1,`name`],[`type`,`button`,1,`cell`,3,`focus`,`click`],[1,`name`,`mono`],[1,`ms`]],template:function(e,t){e&1&&M(0,Tj,3,1,`ul`,0)(1,Ej,2,0,`p`,1),e&2&&N(+!t.cells().length)},styles:[`[_nghost-%COMP%] { +}`]})},bj=(e,t)=>t.stat.name;function xj(e,t){if(e&1&&(B(0,`span`,8),J(1),V()),e&2){let e=G(2).$implicit;k(),X(``,e.other,` more`)}}function Sj(e,t){if(e&1&&(B(0,`div`,6)(1,`span`,7),J(2),V(),M(3,xj,2,1,`span`,8),V()),e&2){let e=G().$implicit;K(`--%NS%tone`,e.tone+`%`),k(2),Y(e.label),k(),N(e.roomy?3:-1)}}function Cj(e,t){if(e&1&&(B(0,`span`,10),J(1),V(),B(2,`span`,11),J(3),V()),e&2){let e=G(2).$implicit,t=G(2);k(),Y(e.stat.name),k(2),Y(t.fmt(e.stat.ms))}}function wj(e,t){if(e&1){let e=H();B(0,`button`,9),W(`focus`,function(){T(e);let t=G().$index;return E(G(2).current.set(t))})(`click`,function(){T(e);let t=G().$implicit;return E(G(2).pick.emit(t.stat.name))}),M(1,Cj,4,2),V()}if(e&2){let e=G(),t=e.$implicit,n=e.$index,r=G(2);K(`--%NS%tone`,t.tone+`%`),j(`tabindex`,n===r.tabStop()?0:-1)(`aria-label`,t.label)(`data-index`,n),k(),N(t.roomy?1:-1)}}function Tj(e,t){if(e&1&&(B(0,`li`),M(1,Sj,4,4,`div`,4)(2,wj,2,6,`button`,5),V()),e&2){let e=t.$implicit;K(`left`,e.x,`%`)(`top`,e.y,`%`)(`width`,e.w,`%`)(`height`,e.h,`%`),k(),N(e.other?1:2)}}function Ej(e,t){if(e&1){let e=H();B(0,`ul`,2),W(`keydown`,function(t){return T(e),E(G().onKey(t))}),P(1,Tj,3,9,`li`,3,bj),V()}if(e&2){let e=G();j(`aria-label`,e.label()),k(),F(e.cells())}}function Dj(e,t){e&1&&(B(0,`p`,1),J(1,`No component time in these cycles.`),V())}var Oj=24,kj=3,Aj=class e{stats=$([]);scope=$(`the recording`);pick=Rv();current=O(0);label=Q(()=>`Self time per component in ${this.scope()}, largest first. Pick one to show it in the tree.`);cells=Q(()=>{let e=this.stats().filter(e=>e.ms>0),t=e.slice(0,Oj),n=e.slice(Oj),r=n.reduce((e,t)=>e+t.ms,0),i=t.map(e=>({stat:e,other:0}));n.length&&i.push({stat:{name:`Other components`,checks:0,ms:r,maxMs:0,cycles:0},other:n.length});let a=e.reduce((e,t)=>e+t.ms,0),o=t[0]?.ms??1,s=rA(i,e=>e.stat.ms,kj);return s.sort((e,t)=>Number(e.item.other>0)-Number(t.item.other>0)),s.map(e=>{let{stat:t,other:n}=e.item,r=a?Math.round(t.ms/a*100):0;return{stat:t,other:n,x:e.x,y:e.y,w:e.w,h:e.h,tone:n?0:14+Math.round(26*Math.min(t.ms/o,1)),roomy:e.w>=10&&e.h>=22,label:n?`${n} more components, ${$k(t.ms)}, ${r}% of self time`:`${t.name}, ${$k(t.ms)} self time, ${r}%, ${t.checks} ${t.checks===1?`check`:`checks`}`}})});tabStop=Q(()=>Math.min(this.current(),Math.max(this.cells().filter(e=>!e.other).length-1,0)));fmt(e){return $k(e)}onKey(e){let t=this.cells().filter(e=>!e.other).length;if(!t)return;let n=this.tabStop(),r;switch(e.key){case`ArrowRight`:case`ArrowDown`:r=Math.min(n+1,t-1);break;case`ArrowLeft`:case`ArrowUp`:r=Math.max(n-1,0);break;case`Home`:r=0;break;case`End`:r=t-1;break;default:return}e.preventDefault(),this.current.set(r),e.currentTarget.querySelector(`button[data-index="${r}"]`)?.focus()}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-treemap`]],inputs:{stats:[1,`stats`],scope:[1,`scope`]},outputs:{pick:`pick`},decls:2,vars:1,consts:[[1,`map`],[1,`empty`],[1,`map`,3,`keydown`],[3,`left`,`top`,`width`,`height`],[1,`cell`,`other`,3,`--%NS%tone`],[`type`,`button`,1,`cell`,3,`--%NS%tone`],[1,`cell`,`other`],[1,`sr-only`],[`aria-hidden`,`true`,1,`name`],[`type`,`button`,1,`cell`,3,`focus`,`click`],[1,`name`,`mono`],[1,`ms`]],template:function(e,t){e&1&&M(0,Ej,3,1,`ul`,0)(1,Dj,2,0,`p`,1),e&2&&N(+!t.cells().length)},styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1609,7 +1609,7 @@ button.cell[_ngcontent-%COMP%]:focus-visible { .empty[_ngcontent-%COMP%] { margin: 8px 0; color: var(--%NS%text-2); -}`]})},Aj=(e,t)=>t.id;function jj(e,t){if(e&1){let e=H();L(0,`button`,15),U(`click`,function(){return T(e),E(G(2).clear())}),J(1,`Clear`),R()}}function Mj(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return T(e),E(G().toggle())}),z(1,`span`,13),J(2),R(),M(3,jj,2,0,`button`,14)}if(e&2){let e=G();q(`on`,e.recording()),I(`disabled`,!e.pageId()),k(2),X(` `,e.recording()?`Stop recording`:`Record`,` `),k(),N(e.cycles().length?3:-1)}}function Nj(e,t){if(e&1){let e=H();L(0,`p`,6)(1,`span`,16),J(2,`Imported recording`),R(),L(3,`span`,17),J(4),R(),L(5,`button`,15),U(`click`,function(){return T(e),E(G().closeImport())}),J(6,`Back to live recording`),R()()}e&2&&(k(4),Y(t.fileName))}function Pj(e,t){e&1&&z(0,`app-angular-unavailable`,8),e&2&&I(`page`,G().angularPage())}function Fj(e,t){e&1&&(L(0,`p`,10),J(1,`Angular profiling stays on until the page reloads.`),R())}function Ij(e,t){e&1&&z(0,`app-angular-unavailable`,21),e&2&&I(`page`,G(2).angularPage())}function Lj(e,t){if(e&1){let e=H();L(0,`div`,18)(1,`span`,19),J(2,`Live views`),R(),L(3,`button`,20),U(`click`,function(){T(e);let t=G();return E(t.setView(`flash`,!t.views().flash))}),z(4,`span`,13),J(5,` Flash checks `),R(),L(6,`button`,20),U(`click`,function(){T(e);let t=G();return E(t.setView(`track`,!t.views().track))}),z(7,`span`,13),J(8,` Performance track `),R(),L(9,`button`,20),U(`click`,function(){return T(e),E(G().setView(`angularProfiling`,!0))}),z(10,`span`,13),J(11,` Angular profiling `),R()(),L(12,`p`,7),J(13,` Flash checks draws a box over each component on the page as Angular checks it, with its name and how often it was checked, fading over a second. Performance track adds a Pangular track to the Chrome Performance panel with every component check, hook and output. Angular profiling turns on Angular's own track there. `),R(),M(14,Fj,2,0,`p`,10)(15,Ij,1,1,`app-angular-unavailable`,21)}if(e&2){let e=G();k(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().flash),k(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().track),k(3),I(`disabled`,!e.canShowViews()||e.views().angularProfiling||!e.views().angularProfilingAvailable),j(`aria-pressed`,e.views().angularProfiling),k(5),N(e.views().angularProfiling?14:e.views().angularProfilingAvailable?-1:15)}}function Rj(e,t){if(e&1&&(L(0,`p`,10),J(1),R()),e&2){let e=t.$implicit;k(),Y(e)}}function zj(e,t){if(e&1&&(L(0,`p`,24),J(1),R()),e&2){let e=G(2);k(),X(` `,e.range()?`The picked cycles have no timed spans, so there is no flame graph for them.`:`This recording has no timed spans, so there is no flame graph. A recording from an older version, or a file saved without spans, has none.`,` `)}}function Bj(e,t){e&1&&(L(0,`p`,10),J(1,` For picked cycles, totals come from the 10 slowest components each cycle lists. `),R())}function Vj(e,t){if(e&1){let e=H();L(0,`h3`),J(1,`Cycles`),R(),L(2,`app-cd-cycle-chart`,22),cv(`rangeChange`,function(t){T(e);let n=G();return sv(n.range,t)||(n.range=t),E(t)}),R(),L(3,`app-cd-flame-graph`,23),U(`pick`,function(t){return T(e),E(G().showComponent.emit(t))}),R(),M(4,zj,2,1,`p`,24),L(5,`h3`),J(6,`Self time by component`),R(),M(7,Bj,2,0,`p`,10),L(8,`app-cd-treemap`,25),U(`pick`,function(t){return T(e),E(G().showComponent.emit(t))}),R()}if(e&2){let e=G();k(2),I(`cycles`,e.cycles()),ov(`range`,e.range),k(),I(`cycles`,e.picked())(`names`,e.spanNames())(`scope`,e.scope()),k(),N(e.hasSpans()?-1:4),k(3),N(e.range()?7:-1),k(),I(`stats`,e.stats())(`scope`,e.scope())}}function Hj(e,t){if(e&1&&(L(0,`tr`)(1,`td`,17),J(2),R(),L(3,`td`,31),J(4),R(),L(5,`td`,31),J(6),R(),L(7,`td`,31),J(8),R()()),e&2){let e=t.$implicit,n=G(2);k(2),Y(e.name),k(2),Y(e.checks),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function Uj(e,t){e&1&&(L(0,`tr`)(1,`td`,32),J(2,`No component time in the picked cycles.`),R()())}function Wj(e,t){if(e&1&&(L(0,`span`,34),J(1,`from `),L(2,`span`,17),J(3),R()()),e&2){let e=G(3);k(3),Y(e.causeText(t))}}function Gj(e,t){if(e&1&&(L(0,`span`,34),J(1,`after `),L(2,`span`,17),J(3),R()()),e&2){let e=G().$implicit;k(3),Y(e.trigger)}}function Kj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit;k(),X(``,e.unchanged,` changed nothing`)}}function qj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);k(),X(`hooks `,t.ms(e.hookMs))}}function Jj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);k(),X(`afterRender `,t.ms(e.afterRenderMs))}}function Yj(e,t){if(e&1&&(L(0,`span`,36),J(1,` slowest `),L(2,`span`,17),J(3),R(),J(4),R()),e&2){let e=t,n=G(3);k(3),Y(e.name),k(),X(` `,n.ms(e.ms),` `)}}function Xj(e,t){if(e&1&&(L(0,`li`)(1,`span`,33),J(2),R(),L(3,`span`,17),J(4),R(),L(5,`span`),J(6),R(),M(7,Wj,4,1,`span`,34)(8,Gj,4,1,`span`,34),M(9,Kj,2,1,`span`,35),M(10,qj,2,1,`span`,35),M(11,Jj,2,1,`span`,35),M(12,Yj,5,2,`span`,36),R()),e&2){let e,n,r=t.$implicit,i=G(2);k(2),Y(i.clock(r.at)),k(2),Y(i.ms(r.ms)),k(2),iv(` `,r.checks,` `,r.checks===1?`check`:`checks`,`, `,r.passes,` `,r.passes===1?`pass`:`passes`,` `),k(),N((e=r.cause)?7:r.trigger?8:-1,e),k(2),N(r.unchanged?9:-1),k(),N(r.hookMs?10:-1),k(),N(r.afterRenderMs?11:-1),k(),N((n=r.components[0])?12:-1,n)}}function Zj(e,t){if(e&1&&(L(0,`div`,26)(1,`div`)(2,`h3`),J(3),R(),L(4,`table`)(5,`thead`)(6,`tr`)(7,`th`,27),J(8,`Component`),R(),L(9,`th`,28),J(10,`Checks`),R(),L(11,`th`,28),J(12,`Self time`),R(),L(13,`th`,28),J(14,`Slowest`),R()()(),L(15,`tbody`),P(16,Hj,9,4,`tr`,null,kg,!1,Uj,3,0,`tr`),R()()(),L(19,`div`)(20,`h3`),J(21,`Latest cycles`),R(),L(22,`ol`,29),P(23,Xj,13,11,`li`,null,Aj),R()()(),z(25,`app-cd-timing`,30)(26,`app-cd-diagnosis`,30)),e&2){let e=G();k(3),X(` `,e.range()?`Slowest components in the picked cycles`:`Slowest components`,` `),k(13),F(e.slowest()),k(7),F(e.latest()),k(2),I(`page`,e.page()),k(),I(`page`,e.page())}}function Qj(e,t){e&1&&(L(0,`p`,11),J(1,`Use the app. Cycles show up here as Angular runs change detection.`),R())}var $j=10,eM=class e{livePage=$(null,{alias:`page`});pageId=$(null);rpc=$(null);angularPages=uO(()=>this.rpc());angularPage=Q(()=>dO(this.angularPages(),this.pageId()));showComponent=Rv();range=O(null);imported=O(null);page=Q(()=>this.imported()?.page??this.livePage());views=Fv(()=>this.livePage()?.options??{flash:!1,track:!1,angularProfiling:!1,angularProfilingAvailable:!0});canShowViews=Q(()=>!!this.pageId()&&this.livePage()?.supported!==!1);message=O(``);announcement=O(``);recording=Q(()=>this.page()?.recording===!0);cycles=Q(()=>this.page()?.cycles??[]);maxCycles=Q(()=>nD(this.rpc()).limits.cdCycles);picked=Q(()=>eA(this.cycles(),this.range()));hasSpans=Q(()=>this.picked().some(e=>e.spans?.length));spanNames=Q(()=>this.page()?.spanNames??[]);stats=Q(()=>this.range()?tA(this.picked()):[...this.page()?.components??[]].sort((e,t)=>t.ms-e.ms));scope=Q(()=>{let e=this.range()?this.picked():[];return e.length?e.length===1?`cycle ${e[0].id}`:`cycles ${e[0].id} to ${e.at(-1).id}`:`the recording`});slowest=Q(()=>this.stats().slice(0,$j));latest=Q(()=>this.cycles().slice(-30).reverse());capNotes=Q(()=>{let e=this.page()?.droppedClasses??0,t=this.page()?.droppedHosts??0,n=[];return e>0&&n.push(`${e} more component ${e===1?`class was`:`classes were`} checked than a recording keeps, so ${e===1?`it is`:`they are`} left out of these totals.`),t>0&&n.push(`${t} component ${t===1?`instance was`:`instances were`} checked past the 2000 a recording counts, so ${t===1?`its tree row shows`:`their tree rows show`} no check count.`),n});status=Q(()=>{if(this.message())return this.message();let e=this.cycles().length;return this.imported()?`${e} ${e===1?`cycle`:`cycles`} imported.`:this.recording()?`Recording. ${e} ${e===1?`cycle`:`cycles`} so far.`:e?`${e} ${e===1?`cycle`:`cycles`} recorded.`:``});ms(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}clock(e){return QO(e)}causeText(e){return Fk(e)}async toggle(){this.recording()?await this.send({on:!1},``,()=>{let e=this.cycles().length;return`Recording stopped. ${e} ${e===1?`cycle`:`cycles`} recorded.`}):await this.send({on:!0},`Starting…`,()=>`Recording started.`)}showImport(e){this.message.set(``),this.range.set(null),this.imported.set(e);let t=e.page.cycles.length;this.announce(`Imported ${e.fileName}: ${t} ${t===1?`cycle`:`cycles`}. Showing the imported recording.`)}closeImport(){this.imported.set(null),this.range.set(null),this.announce(`Showing the live recording.`)}async clear(){this.range.set(null),await this.send({clear:!0},``,()=>`Cleared the recorded cycles.`)}async setView(e,t){let n=this.views();this.views.set({...n,[e]:t});let r={flash:t?`Flash checks on.`:`Flash checks off.`,track:t?`Performance track on. Record in the Chrome Performance panel to see it.`:`Performance track off.`,angularProfiling:`Angular profiling on. It stays on until the page reloads.`}[e];await this.send({[e]:t},``,()=>r,`request-change-detection-options`)||this.views.set(n)}async send(e,t,n,r=`request-change-detection-record`){this.message.set(t);try{if(!this.rpc())throw Error(`no client`);return await VE(this.rpc(),r,{pageId:this.pageId(),...e}),this.message.set(``),this.announce(n()),!0}catch{let e=`Could not reach the page.`;return this.message.set(e),this.announce(e),!1}}announce(e){this.announcement.update(t=>t===e?`${e} `:e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-recording`]],inputs:{livePage:[1,`page`,`livePage`],pageId:[1,`pageId`],rpc:[1,`rpc`]},outputs:{showComponent:`showComponent`},decls:21,vars:12,consts:[[`aria-labelledby`,`cd-heading`,1,`cd`],[1,`cd-head`],[`id`,`cd-heading`],[3,`imported`,`page`,`maxCycles`],[1,`status`],[`role`,`status`,1,`sr-only`],[1,`imported`],[1,`hint`],[`capability`,`profiler`,`missing`,``,`compact`,``,3,`page`],[`what`,`cycles`,`limit`,`cdCycles`,3,`dropped`,`max`],[1,`note`],[1,`empty`],[`type`,`button`,3,`click`,`disabled`],[`aria-hidden`,`true`,1,`dot`],[`type`,`button`],[`type`,`button`,3,`click`],[1,`badge`],[1,`mono`],[`role`,`group`,`aria-labelledby`,`cd-views-label`,1,`views`],[`id`,`cd-views-label`,1,`views-label`],[`type`,`button`,1,`view`,3,`click`,`disabled`],[`capability`,`angularProfiling`,`missing`,``,`compact`,``,3,`page`],[3,`rangeChange`,`cycles`,`range`],[3,`pick`,`cycles`,`names`,`scope`],[1,`spans-note`],[3,`pick`,`stats`,`scope`],[1,`cd-grid`],[`scope`,`col`],[`scope`,`col`,1,`num`],[`aria-label`,`Latest change detection cycles, newest first`,1,`cycles`],[3,`page`],[1,`num`],[`colspan`,`4`],[1,`when`],[1,`trigger`],[1,`timing`],[1,`top`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Change detection`),R(),M(4,Mj,4,5),L(5,`app-cd-transfer`,3),U(`imported`,function(e){return t.showImport(e)}),R(),L(6,`p`,4),J(7),R(),L(8,`p`,5),J(9),R()(),M(10,Nj,7,1,`p`,6),L(11,`p`,7),J(12,` Records each change detection cycle with Angular's profiler: how long it took, how many components it checked, what started it and which checks changed nothing. Tree rows show how often each instance was checked. Times come from a development build. While it records, the page also wraps Angular's scheduler, adds a signal write hook and watches DOM updates; all of it stops with the recording. `),R(),M(13,Pj,1,1,`app-angular-unavailable`,8),M(14,Lj,16,7),z(15,`app-limit-note`,9),P(16,Rj,2,1,`p`,10,Ag),M(18,Vj,9,9),M(19,Zj,27,4)(20,Qj,2,0,`p`,11),R()),e&2){let e;k(4),N(t.imported()?-1:4),k(),I(`page`,t.page())(`maxCycles`,t.maxCycles()),k(2),Y(t.status()),k(2),Y(t.announcement()),k(),N((e=t.imported())?10:-1,e),k(3),N(t.page()?.supported===!1?13:-1),k(),N(t.imported()?-1:14),k(),I(`dropped`,t.page()?.dropped??0)(`max`,t.maxCycles()),k(),F(t.capNotes()),k(2),N(t.cycles().length?18:-1),k(),N(t.page()?.components?.length?19:t.recording()?20:-1)}},dependencies:[hO,rk,hj,DA,vj,UA,ij,kj],styles:[`[_nghost-%COMP%] { +}`]})},jj=(e,t)=>t.id;function Mj(e,t){if(e&1){let e=H();L(0,`button`,15),U(`click`,function(){return T(e),E(G(2).clear())}),J(1,`Clear`),R()}}function Nj(e,t){if(e&1){let e=H();L(0,`button`,12),U(`click`,function(){return T(e),E(G().toggle())}),z(1,`span`,13),J(2),R(),M(3,Mj,2,0,`button`,14)}if(e&2){let e=G();q(`on`,e.recording()),I(`disabled`,!e.pageId()),k(2),X(` `,e.recording()?`Stop recording`:`Record`,` `),k(),N(e.cycles().length?3:-1)}}function Pj(e,t){if(e&1){let e=H();L(0,`p`,6)(1,`span`,16),J(2,`Imported recording`),R(),L(3,`span`,17),J(4),R(),L(5,`button`,15),U(`click`,function(){return T(e),E(G().closeImport())}),J(6,`Back to live recording`),R()()}e&2&&(k(4),Y(t.fileName))}function Fj(e,t){e&1&&z(0,`app-angular-unavailable`,8),e&2&&I(`page`,G().angularPage())}function Ij(e,t){e&1&&(L(0,`p`,10),J(1,`Angular profiling stays on until the page reloads.`),R())}function Lj(e,t){e&1&&z(0,`app-angular-unavailable`,21),e&2&&I(`page`,G(2).angularPage())}function Rj(e,t){if(e&1){let e=H();L(0,`div`,18)(1,`span`,19),J(2,`Live views`),R(),L(3,`button`,20),U(`click`,function(){T(e);let t=G();return E(t.setView(`flash`,!t.views().flash))}),z(4,`span`,13),J(5,` Flash checks `),R(),L(6,`button`,20),U(`click`,function(){T(e);let t=G();return E(t.setView(`track`,!t.views().track))}),z(7,`span`,13),J(8,` Performance track `),R(),L(9,`button`,20),U(`click`,function(){return T(e),E(G().setView(`angularProfiling`,!0))}),z(10,`span`,13),J(11,` Angular profiling `),R()(),L(12,`p`,7),J(13,` Flash checks draws a box over each component on the page as Angular checks it, with its name and how often it was checked, fading over a second. Performance track adds a Pangular track to the Chrome Performance panel with every component check, hook and output. Angular profiling turns on Angular's own track there. `),R(),M(14,Ij,2,0,`p`,10)(15,Lj,1,1,`app-angular-unavailable`,21)}if(e&2){let e=G();k(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().flash),k(3),I(`disabled`,!e.canShowViews()),j(`aria-pressed`,e.views().track),k(3),I(`disabled`,!e.canShowViews()||e.views().angularProfiling||!e.views().angularProfilingAvailable),j(`aria-pressed`,e.views().angularProfiling),k(5),N(e.views().angularProfiling?14:e.views().angularProfilingAvailable?-1:15)}}function zj(e,t){if(e&1&&(L(0,`p`,10),J(1),R()),e&2){let e=t.$implicit;k(),Y(e)}}function Bj(e,t){if(e&1&&(L(0,`p`,24),J(1),R()),e&2){let e=G(2);k(),X(` `,e.range()?`The picked cycles have no timed spans, so there is no flame graph for them.`:`This recording has no timed spans, so there is no flame graph. A recording from an older version, or a file saved without spans, has none.`,` `)}}function Vj(e,t){e&1&&(L(0,`p`,10),J(1,` For picked cycles, totals come from the 10 slowest components each cycle lists. `),R())}function Hj(e,t){if(e&1){let e=H();L(0,`h3`),J(1,`Cycles`),R(),L(2,`app-cd-cycle-chart`,22),cv(`rangeChange`,function(t){T(e);let n=G();return sv(n.range,t)||(n.range=t),E(t)}),R(),L(3,`app-cd-flame-graph`,23),U(`pick`,function(t){return T(e),E(G().showComponent.emit(t))}),R(),M(4,Bj,2,1,`p`,24),L(5,`h3`),J(6,`Self time by component`),R(),M(7,Vj,2,0,`p`,10),L(8,`app-cd-treemap`,25),U(`pick`,function(t){return T(e),E(G().showComponent.emit(t))}),R()}if(e&2){let e=G();k(2),I(`cycles`,e.cycles()),ov(`range`,e.range),k(),I(`cycles`,e.picked())(`names`,e.spanNames())(`scope`,e.scope()),k(),N(e.hasSpans()?-1:4),k(3),N(e.range()?7:-1),k(),I(`stats`,e.stats())(`scope`,e.scope())}}function Uj(e,t){if(e&1&&(L(0,`tr`)(1,`td`,17),J(2),R(),L(3,`td`,31),J(4),R(),L(5,`td`,31),J(6),R(),L(7,`td`,31),J(8),R()()),e&2){let e=t.$implicit,n=G(2);k(2),Y(e.name),k(2),Y(e.checks),k(2),Y(n.ms(e.ms)),k(2),Y(n.ms(e.maxMs))}}function Wj(e,t){e&1&&(L(0,`tr`)(1,`td`,32),J(2,`No component time in the picked cycles.`),R()())}function Gj(e,t){if(e&1&&(L(0,`span`,34),J(1,`from `),L(2,`span`,17),J(3),R()()),e&2){let e=G(3);k(3),Y(e.causeText(t))}}function Kj(e,t){if(e&1&&(L(0,`span`,34),J(1,`after `),L(2,`span`,17),J(3),R()()),e&2){let e=G().$implicit;k(3),Y(e.trigger)}}function qj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit;k(),X(``,e.unchanged,` changed nothing`)}}function Jj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);k(),X(`hooks `,t.ms(e.hookMs))}}function Yj(e,t){if(e&1&&(L(0,`span`,35),J(1),R()),e&2){let e=G().$implicit,t=G(2);k(),X(`afterRender `,t.ms(e.afterRenderMs))}}function Xj(e,t){if(e&1&&(L(0,`span`,36),J(1,` slowest `),L(2,`span`,17),J(3),R(),J(4),R()),e&2){let e=t,n=G(3);k(3),Y(e.name),k(),X(` `,n.ms(e.ms),` `)}}function Zj(e,t){if(e&1&&(L(0,`li`)(1,`span`,33),J(2),R(),L(3,`span`,17),J(4),R(),L(5,`span`),J(6),R(),M(7,Gj,4,1,`span`,34)(8,Kj,4,1,`span`,34),M(9,qj,2,1,`span`,35),M(10,Jj,2,1,`span`,35),M(11,Yj,2,1,`span`,35),M(12,Xj,5,2,`span`,36),R()),e&2){let e,n,r=t.$implicit,i=G(2);k(2),Y(i.clock(r.at)),k(2),Y(i.ms(r.ms)),k(2),iv(` `,r.checks,` `,r.checks===1?`check`:`checks`,`, `,r.passes,` `,r.passes===1?`pass`:`passes`,` `),k(),N((e=r.cause)?7:r.trigger?8:-1,e),k(2),N(r.unchanged?9:-1),k(),N(r.hookMs?10:-1),k(),N(r.afterRenderMs?11:-1),k(),N((n=r.components[0])?12:-1,n)}}function Qj(e,t){if(e&1&&(L(0,`div`,26)(1,`div`)(2,`h3`),J(3),R(),L(4,`table`)(5,`thead`)(6,`tr`)(7,`th`,27),J(8,`Component`),R(),L(9,`th`,28),J(10,`Checks`),R(),L(11,`th`,28),J(12,`Self time`),R(),L(13,`th`,28),J(14,`Slowest`),R()()(),L(15,`tbody`),P(16,Uj,9,4,`tr`,null,kg,!1,Wj,3,0,`tr`),R()()(),L(19,`div`)(20,`h3`),J(21,`Latest cycles`),R(),L(22,`ol`,29),P(23,Zj,13,11,`li`,null,jj),R()()(),z(25,`app-cd-timing`,30)(26,`app-cd-diagnosis`,30)),e&2){let e=G();k(3),X(` `,e.range()?`Slowest components in the picked cycles`:`Slowest components`,` `),k(13),F(e.slowest()),k(7),F(e.latest()),k(2),I(`page`,e.page()),k(),I(`page`,e.page())}}function $j(e,t){e&1&&(L(0,`p`,11),J(1,`Use the app. Cycles show up here as Angular runs change detection.`),R())}var eM=10,tM=class e{livePage=$(null,{alias:`page`});pageId=$(null);rpc=$(null);angularPages=uO(()=>this.rpc());angularPage=Q(()=>dO(this.angularPages(),this.pageId()));showComponent=Rv();range=O(null);imported=O(null);page=Q(()=>this.imported()?.page??this.livePage());views=Fv(()=>this.livePage()?.options??{flash:!1,track:!1,angularProfiling:!1,angularProfilingAvailable:!0});canShowViews=Q(()=>!!this.pageId()&&this.livePage()?.supported!==!1);message=O(``);announcement=O(``);recording=Q(()=>this.page()?.recording===!0);cycles=Q(()=>this.page()?.cycles??[]);maxCycles=Q(()=>nD(this.rpc()).limits.cdCycles);picked=Q(()=>eA(this.cycles(),this.range()));hasSpans=Q(()=>this.picked().some(e=>e.spans?.length));spanNames=Q(()=>this.page()?.spanNames??[]);stats=Q(()=>this.range()?tA(this.picked()):[...this.page()?.components??[]].sort((e,t)=>t.ms-e.ms));scope=Q(()=>{let e=this.range()?this.picked():[];return e.length?e.length===1?`cycle ${e[0].id}`:`cycles ${e[0].id} to ${e.at(-1).id}`:`the recording`});slowest=Q(()=>this.stats().slice(0,eM));latest=Q(()=>this.cycles().slice(-30).reverse());capNotes=Q(()=>{let e=this.page()?.droppedClasses??0,t=this.page()?.droppedHosts??0,n=[];return e>0&&n.push(`${e} more component ${e===1?`class was`:`classes were`} checked than a recording keeps, so ${e===1?`it is`:`they are`} left out of these totals.`),t>0&&n.push(`${t} component ${t===1?`instance was`:`instances were`} checked past the 2000 a recording counts, so ${t===1?`its tree row shows`:`their tree rows show`} no check count.`),n});status=Q(()=>{if(this.message())return this.message();let e=this.cycles().length;return this.imported()?`${e} ${e===1?`cycle`:`cycles`} imported.`:this.recording()?`Recording. ${e} ${e===1?`cycle`:`cycles`} so far.`:e?`${e} ${e===1?`cycle`:`cycles`} recorded.`:``});ms(e){return`${e<10?e.toFixed(2):Math.round(e)} ms`}clock(e){return QO(e)}causeText(e){return Fk(e)}async toggle(){this.recording()?await this.send({on:!1},``,()=>{let e=this.cycles().length;return`Recording stopped. ${e} ${e===1?`cycle`:`cycles`} recorded.`}):await this.send({on:!0},`Starting…`,()=>`Recording started.`)}showImport(e){this.message.set(``),this.range.set(null),this.imported.set(e);let t=e.page.cycles.length;this.announce(`Imported ${e.fileName}: ${t} ${t===1?`cycle`:`cycles`}. Showing the imported recording.`)}closeImport(){this.imported.set(null),this.range.set(null),this.announce(`Showing the live recording.`)}async clear(){this.range.set(null),await this.send({clear:!0},``,()=>`Cleared the recorded cycles.`)}async setView(e,t){let n=this.views();this.views.set({...n,[e]:t});let r={flash:t?`Flash checks on.`:`Flash checks off.`,track:t?`Performance track on. Record in the Chrome Performance panel to see it.`:`Performance track off.`,angularProfiling:`Angular profiling on. It stays on until the page reloads.`}[e];await this.send({[e]:t},``,()=>r,`request-change-detection-options`)||this.views.set(n)}async send(e,t,n,r=`request-change-detection-record`){this.message.set(t);try{if(!this.rpc())throw Error(`no client`);return await VE(this.rpc(),r,{pageId:this.pageId(),...e}),this.message.set(``),this.announce(n()),!0}catch{let e=`Could not reach the page.`;return this.message.set(e),this.announce(e),!1}}announce(e){this.announcement.update(t=>t===e?`${e} `:e)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-cd-recording`]],inputs:{livePage:[1,`page`,`livePage`],pageId:[1,`pageId`],rpc:[1,`rpc`]},outputs:{showComponent:`showComponent`},decls:21,vars:12,consts:[[`aria-labelledby`,`cd-heading`,1,`cd`],[1,`cd-head`],[`id`,`cd-heading`],[3,`imported`,`page`,`maxCycles`],[1,`status`],[`role`,`status`,1,`sr-only`],[1,`imported`],[1,`hint`],[`capability`,`profiler`,`missing`,``,`compact`,``,3,`page`],[`what`,`cycles`,`limit`,`cdCycles`,3,`dropped`,`max`],[1,`note`],[1,`empty`],[`type`,`button`,3,`click`,`disabled`],[`aria-hidden`,`true`,1,`dot`],[`type`,`button`],[`type`,`button`,3,`click`],[1,`badge`],[1,`mono`],[`role`,`group`,`aria-labelledby`,`cd-views-label`,1,`views`],[`id`,`cd-views-label`,1,`views-label`],[`type`,`button`,1,`view`,3,`click`,`disabled`],[`capability`,`angularProfiling`,`missing`,``,`compact`,``,3,`page`],[3,`rangeChange`,`cycles`,`range`],[3,`pick`,`cycles`,`names`,`scope`],[1,`spans-note`],[3,`pick`,`stats`,`scope`],[1,`cd-grid`],[`scope`,`col`],[`scope`,`col`,1,`num`],[`aria-label`,`Latest change detection cycles, newest first`,1,`cycles`],[3,`page`],[1,`num`],[`colspan`,`4`],[1,`when`],[1,`trigger`],[1,`timing`],[1,`top`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Change detection`),R(),M(4,Nj,4,5),L(5,`app-cd-transfer`,3),U(`imported`,function(e){return t.showImport(e)}),R(),L(6,`p`,4),J(7),R(),L(8,`p`,5),J(9),R()(),M(10,Pj,7,1,`p`,6),L(11,`p`,7),J(12,` Records each change detection cycle with Angular's profiler: how long it took, how many components it checked, what started it and which checks changed nothing. Tree rows show how often each instance was checked. Times come from a development build. While it records, the page also wraps Angular's scheduler, adds a signal write hook and watches DOM updates; all of it stops with the recording. `),R(),M(13,Fj,1,1,`app-angular-unavailable`,8),M(14,Rj,16,7),z(15,`app-limit-note`,9),P(16,zj,2,1,`p`,10,Ag),M(18,Hj,9,9),M(19,Qj,27,4)(20,$j,2,0,`p`,11),R()),e&2){let e;k(4),N(t.imported()?-1:4),k(),I(`page`,t.page())(`maxCycles`,t.maxCycles()),k(2),Y(t.status()),k(2),Y(t.announcement()),k(),N((e=t.imported())?10:-1,e),k(3),N(t.page()?.supported===!1?13:-1),k(),N(t.imported()?-1:14),k(),I(`dropped`,t.page()?.dropped??0)(`max`,t.maxCycles()),k(),F(t.capNotes()),k(2),N(t.cycles().length?18:-1),k(),N(t.page()?.components?.length?19:t.recording()?20:-1)}},dependencies:[hO,rk,gj,OA,yj,WA,aj,Aj],styles:[`[_nghost-%COMP%] { display: block; margin-top: 16px; } @@ -1811,7 +1811,7 @@ td.mono[_ngcontent-%COMP%] { .trigger[_ngcontent-%COMP%] .mono[_ngcontent-%COMP%], .top[_ngcontent-%COMP%] .mono[_ngcontent-%COMP%] { overflow-wrap: anywhere; -}`]})},tM=[`*`];function nM(e,t){e&1&&J(0),e&2&&Y(G(2).label())}function rM(e,t){e&1&&s_(0,0,null,nM,1,1)}function iM(e,t){if(e&1&&(L(0,`span`,4),J(1),R()),e&2){let e=G(2);k(),Y(e.message())}}function aM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){return T(e),E(G().open())}),Gg(1,3),R(),M(2,iM,2,1,`span`,4)}if(e&2){let e=G(),t=d_(1);I(`title`,`Open `+e.label()+` in your editor`),j(`aria-label`,`Open `+e.label()+` in your editor`),k(),I(`ngTemplateOutlet`,t),k(),N(e.message()?2:-1)}}function oM(e,t){if(e&1&&(L(0,`span`,1),Gg(1,3),R()),e&2){let e=G(),t=d_(1);I(`title`,e.label()),k(),I(`ngTemplateOutlet`,t)}}var sM=class e{source=O(O(null));client=Q(()=>this.source()());available=Q(()=>{let e=this.client();return!!e&&!UE(e)});use(e){this.source.set(e)}async open(e,t){if(!this.available())return{ok:!1,error:`No server is connected.`};try{let n=await VE(this.client(),`open-in-editor`,{file:e,...t?{line:t}:{}});return n?.ok?{ok:!0}:{ok:!1,error:n?.error??`The server did not open it.`}}catch{return{ok:!1,error:`The server did not open it.`}}}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})};function cM(e,t){return t?`${e}:${t}`:e}var lM=class e{editor=C(sM);file=$.required();line=$(void 0);label=Q(()=>cM(this.file(),this.line()));message=O(``);async open(){this.message.set(``);let e=await this.editor.open(this.file(),this.line()??void 0);e.ok||this.message.set(`Not opened: ${e.error}`)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-source-link`]],inputs:{file:[1,`file`],line:[1,`line`]},ngContentSelectors:tM,decls:4,vars:1,consts:[[`text`,``],[1,`source-text`,3,`title`],[`type`,`button`,1,`source-link`,3,`click`,`title`],[3,`ngTemplateOutlet`],[`role`,`alert`,1,`message`]],template:function(e,t){e&1&&(o_(),sg(0,rM,2,0,`ng-template`,null,0,Ev),M(2,aM,3,4)(3,oM,2,2,`span`,1)),e&2&&(k(2),N(t.editor.available()?2:3))},dependencies:[ub],styles:[`[_nghost-%COMP%] { +}`]})},nM=[`*`];function rM(e,t){e&1&&J(0),e&2&&Y(G(2).label())}function iM(e,t){e&1&&s_(0,0,null,rM,1,1)}function aM(e,t){if(e&1&&(L(0,`span`,4),J(1),R()),e&2){let e=G(2);k(),Y(e.message())}}function oM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){return T(e),E(G().open())}),Gg(1,3),R(),M(2,aM,2,1,`span`,4)}if(e&2){let e=G(),t=d_(1);I(`title`,`Open `+e.label()+` in your editor`),j(`aria-label`,`Open `+e.label()+` in your editor`),k(),I(`ngTemplateOutlet`,t),k(),N(e.message()?2:-1)}}function sM(e,t){if(e&1&&(L(0,`span`,1),Gg(1,3),R()),e&2){let e=G(),t=d_(1);I(`title`,e.label()),k(),I(`ngTemplateOutlet`,t)}}var cM=class e{source=O(O(null));client=Q(()=>this.source()());available=Q(()=>{let e=this.client();return!!e&&!UE(e)});use(e){this.source.set(e)}async open(e,t){if(!this.available())return{ok:!1,error:`No server is connected.`};try{let n=await VE(this.client(),`open-in-editor`,{file:e,...t?{line:t}:{}});return n?.ok?{ok:!0}:{ok:!1,error:n?.error??`The server did not open it.`}}catch{return{ok:!1,error:`The server did not open it.`}}}static ɵfac=function(t){return new(t||e)};static ɵprov=Nl({token:e,factory:e.ɵfac})};function lM(e,t){return t?`${e}:${t}`:e}var uM=class e{editor=C(cM);file=$.required();line=$(void 0);label=Q(()=>lM(this.file(),this.line()));message=O(``);async open(){this.message.set(``);let e=await this.editor.open(this.file(),this.line()??void 0);e.ok||this.message.set(`Not opened: ${e.error}`)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-source-link`]],inputs:{file:[1,`file`],line:[1,`line`]},ngContentSelectors:nM,decls:4,vars:1,consts:[[`text`,``],[1,`source-text`,3,`title`],[`type`,`button`,1,`source-link`,3,`click`,`title`],[3,`ngTemplateOutlet`],[`role`,`alert`,1,`message`]],template:function(e,t){e&1&&(o_(),sg(0,iM,2,0,`ng-template`,null,0,Ev),M(2,oM,3,4)(3,sM,2,2,`span`,1)),e&2&&(k(2),N(t.editor.available()?2:3))},dependencies:[ub],styles:[`[_nghost-%COMP%] { display: inline; min-width: 0; } @@ -1846,7 +1846,7 @@ td.mono[_ngcontent-%COMP%] { color: var(--%NS%danger-text); font-family: var(--%NS%font-sans); font-size: 0.92em; -}`]})},uM=[`field`],dM=[`editButton`],fM=[`valueBox`];function pM(e,t){if(e&1){let e=H();B(0,`div`,5)(1,`label`,6),J(2),V(),B(3,`input`,7,0),W(`input`,function(t){return T(e),E(G().draft.set(t.target.value))})(`keydown.enter`,function(t){T(e);let n=G();return t.preventDefault(),E(n.apply())})(`keydown.escape`,function(t){T(e);let n=G();return t.preventDefault(),t.stopPropagation(),E(n.cancel())}),V(),B(5,`button`,8),W(`click`,function(){return T(e),E(G().apply())}),J(6,`Apply`),V(),B(7,`button`,9),W(`click`,function(){return T(e),E(G().cancel())}),J(8,`Cancel`),V()(),B(9,`p`,10),J(10),V()}if(e&2){let e=G();k(),qg(`htmlFor`,e.fieldId),k(),X(`New value of `,e.prop().name,`, as JSON`),k(),qg(`id`,e.fieldId)(`value`,e.draft())(`readOnly`,e.busy()),j(`aria-busy`,e.busy()?`true`:null)(`aria-invalid`,e.error()?`true`:null)(`aria-describedby`,e.hintId+(e.error()?` `+e.errorId:``)),k(2),qg(`disabled`,e.busy()),k(4),qg(`id`,e.hintId),k(),X(` JSON, such as "text", 42, true or `,e.objectSample,`. Enter applies, Escape cancels. `)}}function mM(e,t){if(e&1&&(B(0,`pre`,null,1),J(2),xv(3,`json`),V()),e&2){let e=G(2);j(`tabindex`,e.scrollable()?0:null)(`role`,e.scrollable()?`region`:null)(`aria-label`,e.scrollable()?`Value of `+e.prop().name:null),k(2),Y(Cv(3,4,e.prop().value))}}function hM(e,t){if(e&1){let e=H();B(0,`button`,14,2),W(`click`,function(){return T(e),E(G(2).start())}),J(2,` Edit `),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()),j(`aria-label`,`Edit `+e.prop().name)}}function gM(e,t){if(e&1&&(B(0,`p`,13),J(1),V()),e&2){let e=G(2);k(),Y(e.prop().locked)}}function _M(e,t){if(e&1&&(B(0,`div`,11),M(1,mM,4,6,`pre`),M(2,hM,3,2,`button`,12),V(),M(3,gM,2,1,`p`,13)),e&2){let e=G();k(),N(e.bare()?-1:1),k(),N(e.editable()?2:-1),k(),N(e.writes()&&e.prop().locked?3:-1)}}function vM(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G();qg(`id`,e.errorId),k(),Y(e.error())}}var yM=0;function bM(e){let t=e.trim();if(!t)return{error:`Type a JSON value, such as "text", 42, true, null or [1, 2].`};try{return{value:JSON.parse(t)}}catch{return{error:`Not valid JSON. Put text in double quotes, such as "Paris".`}}}var xM=class e{prop=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);bare=$(!1);readDraft=$(null);fieldId=`prop-edit-${++yM}`;hintId=`${this.fieldId}-hint`;errorId=`${this.fieldId}-error`;objectSample=`{"a": 1}`;editing=O(!1);draft=O(``);busy=O(!1);error=O(``);done=O(``);editable=Q(()=>this.writes()&&!!this.prop().edit&&!!this.pageId()&&!!this.rpc());field=Jv(`field`);editButton=Jv(`editButton`);valueBox=Jv(`valueBox`);injector=C(Ts);scrollable=O(!1);constructor(){dy(()=>{this.prop();let e=this.valueBox()?.nativeElement;this.scrollable.set(!!e&&e.scrollHeight>e.clientHeight+1)})}async start(){let e=this.prop().value;this.error.set(``),this.done.set(``);let t=this.readDraft();if(t){this.busy.set(!0);let n=await t();if(this.busy.set(!1),n.error!==void 0){this.error.set(n.error);return}e=n.value}this.draft.set(e===void 0?``:JSON.stringify(e)),this.editing.set(!0),Hd(()=>{let e=this.field()?.nativeElement;e?.focus(),e?.select()},{injector:this.injector})}cancel(){this.editing()&&(this.editing.set(!1),this.busy.set(!1),this.error.set(``),this.focusEdit())}async apply(){if(this.busy())return;let e=bM(this.draft());if(`error`in e){this.error.set(e.error);return}let t=this.prop(),n=this.rpc(),r=this.pageId();if(!n||!r||!t.edit)return;this.busy.set(!0),this.error.set(``);let i;try{i=await n.scope(`pangular`).rpc.call(`request-component-edit`,{pageId:r,request:{id:this.componentId(),path:t.prop,value:e.value,kind:t.edit}})??{}}catch{i={error:`The devtools server did not answer. Try again.`}}this.busy.set(!1),this.editing()&&(i.ok?(this.editing.set(!1),this.done.set(`Set ${t.name}.`),this.focusEdit()):(this.error.set(i.error??`The page did not write it.`),this.field()?.nativeElement.focus()))}focusEdit(){Hd(()=>this.editButton()?.nativeElement.focus(),{injector:this.injector})}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-prop-value`]],viewQuery:function(e,t){e&1&&l_(t.field,uM,5)(t.editButton,dM,5)(t.valueBox,fM,5),e&2&&u_(3)},inputs:{prop:[1,`prop`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],bare:[1,`bare`],readDraft:[1,`readDraft`]},decls:5,vars:3,consts:[[`field`,``],[`valueBox`,``],[`editButton`,``],[`role`,`alert`,1,`error`,3,`id`],[`role`,`status`,1,`sr-only`],[1,`editor`],[1,`sr-only`,3,`for`],[`type`,`text`,`autocomplete`,`off`,`spellcheck`,`false`,1,`field`,`mono`,3,`input`,`keydown.enter`,`keydown.escape`,`id`,`value`,`readOnly`],[`type`,`button`,1,`primary`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[1,`hint`,3,`id`],[1,`view`],[`type`,`button`,1,`edit`,3,`disabled`],[1,`locked`],[`type`,`button`,1,`edit`,3,`click`,`disabled`]],template:function(e,t){e&1&&(M(0,pM,11,11)(1,_M,4,3),M(2,vM,2,2,`p`,3),B(3,`p`,4),J(4),V()),e&2&&(N(+!t.editing()),k(2),N(t.error()?2:-1),k(2),Y(t.done()))},dependencies:[gb],styles:[`[_nghost-%COMP%] { +}`]})},dM=[`field`],fM=[`editButton`],pM=[`valueBox`];function mM(e,t){if(e&1){let e=H();B(0,`div`,5)(1,`label`,6),J(2),V(),B(3,`input`,7,0),W(`input`,function(t){return T(e),E(G().draft.set(t.target.value))})(`keydown.enter`,function(t){T(e);let n=G();return t.preventDefault(),E(n.apply())})(`keydown.escape`,function(t){T(e);let n=G();return t.preventDefault(),t.stopPropagation(),E(n.cancel())}),V(),B(5,`button`,8),W(`click`,function(){return T(e),E(G().apply())}),J(6,`Apply`),V(),B(7,`button`,9),W(`click`,function(){return T(e),E(G().cancel())}),J(8,`Cancel`),V()(),B(9,`p`,10),J(10),V()}if(e&2){let e=G();k(),qg(`htmlFor`,e.fieldId),k(),X(`New value of `,e.prop().name,`, as JSON`),k(),qg(`id`,e.fieldId)(`value`,e.draft())(`readOnly`,e.busy()),j(`aria-busy`,e.busy()?`true`:null)(`aria-invalid`,e.error()?`true`:null)(`aria-describedby`,e.hintId+(e.error()?` `+e.errorId:``)),k(2),qg(`disabled`,e.busy()),k(4),qg(`id`,e.hintId),k(),X(` JSON, such as "text", 42, true or `,e.objectSample,`. Enter applies, Escape cancels. `)}}function hM(e,t){if(e&1&&(B(0,`pre`,null,1),J(2),xv(3,`json`),V()),e&2){let e=G(2);j(`tabindex`,e.scrollable()?0:null)(`role`,e.scrollable()?`region`:null)(`aria-label`,e.scrollable()?`Value of `+e.prop().name:null),k(2),Y(Cv(3,4,e.prop().value))}}function gM(e,t){if(e&1){let e=H();B(0,`button`,14,2),W(`click`,function(){return T(e),E(G(2).start())}),J(2,` Edit `),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()),j(`aria-label`,`Edit `+e.prop().name)}}function _M(e,t){if(e&1&&(B(0,`p`,13),J(1),V()),e&2){let e=G(2);k(),Y(e.prop().locked)}}function vM(e,t){if(e&1&&(B(0,`div`,11),M(1,hM,4,6,`pre`),M(2,gM,3,2,`button`,12),V(),M(3,_M,2,1,`p`,13)),e&2){let e=G();k(),N(e.bare()?-1:1),k(),N(e.editable()?2:-1),k(),N(e.writes()&&e.prop().locked?3:-1)}}function yM(e,t){if(e&1&&(B(0,`p`,3),J(1),V()),e&2){let e=G();qg(`id`,e.errorId),k(),Y(e.error())}}var bM=0;function xM(e){let t=e.trim();if(!t)return{error:`Type a JSON value, such as "text", 42, true, null or [1, 2].`};try{return{value:JSON.parse(t)}}catch{return{error:`Not valid JSON. Put text in double quotes, such as "Paris".`}}}var SM=class e{prop=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);bare=$(!1);readDraft=$(null);fieldId=`prop-edit-${++bM}`;hintId=`${this.fieldId}-hint`;errorId=`${this.fieldId}-error`;objectSample=`{"a": 1}`;editing=O(!1);draft=O(``);busy=O(!1);error=O(``);done=O(``);editable=Q(()=>this.writes()&&!!this.prop().edit&&!!this.pageId()&&!!this.rpc());field=Jv(`field`);editButton=Jv(`editButton`);valueBox=Jv(`valueBox`);injector=C(Ts);scrollable=O(!1);constructor(){dy(()=>{this.prop();let e=this.valueBox()?.nativeElement;this.scrollable.set(!!e&&e.scrollHeight>e.clientHeight+1)})}async start(){let e=this.prop().value;this.error.set(``),this.done.set(``);let t=this.readDraft();if(t){this.busy.set(!0);let n=await t();if(this.busy.set(!1),n.error!==void 0){this.error.set(n.error);return}e=n.value}this.draft.set(e===void 0?``:JSON.stringify(e)),this.editing.set(!0),Hd(()=>{let e=this.field()?.nativeElement;e?.focus(),e?.select()},{injector:this.injector})}cancel(){this.editing()&&(this.editing.set(!1),this.busy.set(!1),this.error.set(``),this.focusEdit())}async apply(){if(this.busy())return;let e=xM(this.draft());if(`error`in e){this.error.set(e.error);return}let t=this.prop(),n=this.rpc(),r=this.pageId();if(!n||!r||!t.edit)return;this.busy.set(!0),this.error.set(``);let i;try{i=await n.scope(`pangular`).rpc.call(`request-component-edit`,{pageId:r,request:{id:this.componentId(),path:t.prop,value:e.value,kind:t.edit}})??{}}catch{i={error:`The devtools server did not answer. Try again.`}}this.busy.set(!1),this.editing()&&(i.ok?(this.editing.set(!1),this.done.set(`Set ${t.name}.`),this.focusEdit()):(this.error.set(i.error??`The page did not write it.`),this.field()?.nativeElement.focus()))}focusEdit(){Hd(()=>this.editButton()?.nativeElement.focus(),{injector:this.injector})}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-prop-value`]],viewQuery:function(e,t){e&1&&l_(t.field,dM,5)(t.editButton,fM,5)(t.valueBox,pM,5),e&2&&u_(3)},inputs:{prop:[1,`prop`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],bare:[1,`bare`],readDraft:[1,`readDraft`]},decls:5,vars:3,consts:[[`field`,``],[`valueBox`,``],[`editButton`,``],[`role`,`alert`,1,`error`,3,`id`],[`role`,`status`,1,`sr-only`],[1,`editor`],[1,`sr-only`,3,`for`],[`type`,`text`,`autocomplete`,`off`,`spellcheck`,`false`,1,`field`,`mono`,3,`input`,`keydown.enter`,`keydown.escape`,`id`,`value`,`readOnly`],[`type`,`button`,1,`primary`,3,`click`,`disabled`],[`type`,`button`,3,`click`],[1,`hint`,3,`id`],[1,`view`],[`type`,`button`,1,`edit`,3,`disabled`],[1,`locked`],[`type`,`button`,1,`edit`,3,`click`,`disabled`]],template:function(e,t){e&1&&(M(0,mM,11,11)(1,vM,4,3),M(2,yM,2,2,`p`,3),B(3,`p`,4),J(4),V()),e&2&&(N(+!t.editing()),k(2),N(t.error()?2:-1),k(2),Y(t.done()))},dependencies:[gb],styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -1969,7 +1969,7 @@ button.edit[_ngcontent-%COMP%] { .error[_ngcontent-%COMP%] { color: var(--%NS%danger-text); -}`]})},SM=1e3,CM={depth:5,limit:100},wM=`[redacted]`;function TM(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function EM(e){return TM(e)&&typeof e.$more==`number`&&Object.keys(e).length===1}function DM(e){return TM(e)&&typeof e.$collapsed==`string`&&typeof e.size==`number`&&Object.keys(e).length===2}function OM(e){return e===`Array`?`array`:e===`Map`?`map`:e===`Set`?`set`:`object`}function kM(e){return e.$type===`Map`&&Array.isArray(e.entries)}function AM(e){return e.$type===`Set`&&Array.isArray(e.values)}function jM(e){return Object.keys(e).filter(e=>e!==`$type`&&e!==`$more`)}function MM(e){if(!e||typeof e!=`object`)return null;if(DM(e))return e.size<=0?null:{kind:OM(e.$collapsed),type:e.$collapsed,size:e.size,collapsed:!0};if(EM(e))return null;if(Array.isArray(e)){let t=e.at(-1),n=EM(t)?t.$more:0,r=e.length-+!!n+n;return r?{kind:`array`,type:`Array`,size:r,collapsed:!1}:null}let t=e;if(kM(t)||AM(t)){let e=typeof t.size==`number`?t.size:0,n=kM(t)?`map`:`set`;return e?{kind:n,type:n===`map`?`Map`:`Set`,size:e,collapsed:!1}:null}let n=typeof t.$more==`number`?t.$more:0,r=jM(t).length+n,i=typeof t.$type==`string`?t.$type:`Object`;return r?{kind:`object`,type:i,size:r,collapsed:!1}:null}function NM(e){if(typeof e==`string`)return JSON.stringify(e);let t=MM(e);if(t)return IM(t);try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function PM(e){let t=MM(e);if(!t||t.collapsed)return{children:[],more:0};if(Array.isArray(e)){let n=(EM(e.at(-1))?e.slice(0,-1):e).map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:n,more:t.size-n.length}}let n=e;if(t.kind===`map`){let e=n.entries.map((e,t)=>{let[n,r]=Array.isArray(e)?e:[void 0,e];return{key:String(t),label:NM(n),value:r}});return{children:e,more:Math.max(0,t.size-e.length)}}if(t.kind===`set`){let e=n.values.map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:e,more:Math.max(0,t.size-e.length)}}return{children:jM(n).map(e=>({key:e,label:e,value:n[e]})),more:typeof n.$more==`number`?n.$more:0}}function FM(e,t,n){return`${e} ${e===1?t:n}`}function IM(e){let t={array:FM(e.size,`item`,`items`),object:FM(e.size,`key`,`keys`),map:FM(e.size,`entry`,`entries`),set:FM(e.size,`value`,`values`)}[e.kind];return`${e.type} (${t})`}function LM(e,t){return JSON.stringify(t===void 0?e:[t,...e])}function RM(e,t){return e.map((e,n)=>n===0?e:(t?t[n-1]!==`object`:/^\d+$/.test(e))?`[${e}]`:`.${e}`).join(``)}function zM(e){return e.every(e=>e&&e===e.trim()&&!/[.[\]]/.test(e))?e.join(`.`):null}var BM=/^\[(Getter|Unreadable|Circular|Truncated|Function\b.*|Promise)\]$/;function VM(e){return e===null||typeof e==`boolean`?!0:typeof e==`number`?Number.isFinite(e):typeof e==`string`&&e!==wM&&!BM.test(e)&&!e.endsWith(`…`)}function HM(e,t){return!e||t.kind===`map`||t.kind===`set`||e===`signal`&&t.kind===`object`&&t.type!==`Object`?null:e}function UM(e,t,n,r,i=500){let a=[],o=r.trim().toLowerCase();if(!o)return a;let s=new Set,c=(e,t)=>{let r=LM(e);if(!(s.has(r)||a.length>=i)){s.add(r);for(let r of PM(t).children){let t=[...e,r.key];if(r.label.toLowerCase().includes(o)&&a.push(t),!MM(r.value))continue;let i=n(t)??(MM(r.value)?.collapsed?void 0:r.value);i!==void 0&&c(t,i)}}};return c(e,n(e)??t),a}var WM=(e,t)=>t.id;function GM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){T(e);let t=G().$implicit;return E(G(3).toggle(t))}),D(),L(1,`svg`,3),z(2,`path`,4),R(),_s(),L(3,`span`,14),J(4),R(),L(5,`span`,5),J(6),R()()}if(e&2){let e=G().$implicit;j(`aria-expanded`,e.open)(`aria-label`,e.label+`: `+e.text),k(4),X(``,e.label,`:`),k(2),Y(e.text)}}function KM(e,t){if(e&1&&z(0,`app-prop-value`,15),e&2){let e=G(5);I(`prop`,t)(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}function qM(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G(2).$implicit;k(),Y(e.text)}}function JM(e,t){if(e&1&&(L(0,`span`,14),J(1),R(),M(2,KM,1,5,`app-prop-value`,15)(3,qM,2,1,`span`,16)),e&2){let e,t=G().$implicit;k(),X(``,t.label,`:`),k(),N((e=t.edit)?2:3,e)}}function YM(e,t){if(e&1){let e=H();L(0,`button`,17),U(`click`,function(){T(e);let t=G().$implicit;return E(G(3).more(t))}),J(1),L(2,`span`,18),J(3),R()()}if(e&2){let e=G().$implicit,t=G(3);k(),X(` Show `,t.step(e),` more `),k(2),X(`(`,e.more,` not listed)`)}}function XM(e,t){e&1&&(L(0,`span`,12),J(1,`Reading from the page…`),R())}function ZM(e,t){if(e&1&&(L(0,`span`,13),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.text)}}function QM(e,t){if(e&1&&(L(0,`li`,9),M(1,GM,7,4,`button`,10)(2,JM,4,2)(3,YM,4,2,`button`,11)(4,XM,2,0,`span`,12)(5,ZM,2,1,`span`,13),R()),e&2){let e,n=t.$implicit;K(`padding-left`,n.depth*14,`px`),k(),N((e=n.kind)===`node`?1:e===`leaf`?2:e===`more`?3:e===`loading`?4:e===`error`?5:-1)}}function $M(e,t){if(e&1&&(L(0,`ul`,7),P(1,QM,6,3,`li`,8,WM),R()),e&2){let e=G(2);I(`id`,e.listId),j(`aria-label`,e.prop().name+` entries`),k(),F(e.rows())}}function eN(e,t){if(e&1){let e=H();L(0,`div`,1)(1,`button`,2),U(`click`,function(){return T(e),E(G().toggleRoot())}),D(),L(2,`svg`,3),z(3,`path`,4),R(),_s(),L(4,`span`,5),J(5),R()(),z(6,`app-prop-value`,6),R(),M(7,$M,3,2,`ul`,7)}if(e&2){let e=t,n=G();k(),j(`aria-expanded`,n.rootOpen())(`aria-controls`,n.rootOpen()?n.listId:null)(`aria-label`,n.prop().name+`: `+n.summaryOf(e)),k(4),Y(n.summaryOf(e)),k(),I(`bare`,!0)(`prop`,n.prop())(`componentId`,n.componentId())(`pageId`,n.pageId())(`rpc`,n.rpc())(`writes`,n.writes())(`readDraft`,n.readWhole),k(),N(n.rootOpen()?7:-1)}}function tN(e,t){if(e&1&&z(0,`app-prop-value`,0),e&2){let e=G();I(`prop`,e.prop())(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}var nN=0;function rN(e){if(e===void 0)return`undefined`;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function iN(e){if(Array.isArray(e))return e.every(iN);if(e&&typeof e==`object`){let t=e;return![`$collapsed`,`$more`,`$type`].some(e=>Object.hasOwn(t,e))&&Object.values(t).every(iN)}return VM(e)}var aN=class e{prop=$.required();store=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);directive=$(void 0);query=$(``);listId=`value-tree-${++nN}`;host=C(Il);pendingMore=null;constructor(){dy(()=>{let e=this.rows(),t=this.pendingMore;if(!t)return;let n=e.findIndex(e=>(e.kind===`leaf`||e.kind===`node`)&&!t.has(e.id));if(n<0)return;this.pendingMore=null;let r=document.activeElement;r&&r!==document.body&&r.isConnected||this.focusNear(n)})}rootPath=Q(()=>[this.prop().prop]);rootValue=Q(()=>this.store().level(this.rootPath(),this.directive())??this.prop().value);root=Q(()=>MM(this.rootValue()));needle=Q(()=>this.query().trim().toLowerCase());matches=Q(()=>{let e=this.needle(),t=this.prop();if(!e||[t.name,t.prop].some(t=>t.toLowerCase().includes(e)))return null;let n=this.store(),r=this.directive();return UM(this.rootPath(),this.rootValue(),e=>n.level(e,r),e)});rootOpen=Q(()=>!!this.matches()?.length||this.store().isOpen(this.rootPath(),this.directive()));rows=Q(()=>{let e=this.root();if(!e)return[];let t=this.store(),n=this.directive(),r=this.matches(),i=new Set,a=new Set;for(let e of r??[]){a.add(LM(e));for(let t=2;t<=e.length;t++)i.add(LM(e.slice(0,t)))}let o=this.prop(),s=this.writes()&&n===void 0,c=[],l=(e,o,d,f,p,m)=>{let{children:h,more:g}=PM(e);for(let e of h){let h=[...o,e.key],g=LM(h);if(r&&!m&&!i.has(g))continue;let _=MM(e.value),ee=LM(h,n);if(!_){let t=p&&VM(e.value)?zM(h):null;c.push({id:ee,kind:`leaf`,depth:f,path:h,label:e.label,text:rN(e.value),edit:s&&t&&p?{name:RM(h,[...d]),prop:t,value:e.value,edit:p}:void 0});continue}let te=!!r&&!m&&i.has(g)&&!a.has(g)||t.isOpen(h,n);if(c.push({id:ee,kind:`node`,depth:f,path:h,label:e.label,text:IM(_),container:_,open:te}),!te)continue;let ne=t.level(h,n)??(_.collapsed?void 0:e.value),re=[...d,_.kind];ne===void 0?t.errors().has(ee)?c.push({...u(h,f+1,`error`),text:t.errors().get(ee)}):c.push(u(h,f+1,`loading`)):l(ne,h,re,f+1,HM(p,_),m||a.has(g))}g>0&&(!r||m)&&c.push({...u(o,f,`more`),more:g,listed:h.length})},u=(e,t,r)=>({id:`${LM(e,n)}:${r}`,kind:r,depth:t,path:e,label:``,text:``});return l(this.rootValue(),this.rootPath(),[e.kind],0,s?HM(o.editInside??null,e):null,!r),c});readWhole=async()=>{let e=await this.store().read(this.rootPath(),CM.depth,CM.limit);return e.ok?iN(e.value)?{value:e.value}:{error:`Too large to edit as a whole. Open it to edit the values inside.`}:{error:e.error??`The page did not read it.`}};summaryOf(e){return IM(e)}toggleRoot(){this.pendingMore=null,this.store().toggle(this.rootPath(),this.directive(),!1)}toggle(e){this.pendingMore=null,this.store().toggle(e.path,this.directive(),!!e.container?.collapsed)}more(e){this.pendingMore=new Set(this.rows().map(e=>e.id)),this.store().more(e.path,this.directive(),e.listed??0)}focusNear(e){let t=this.host.nativeElement,n=Array.from(t.querySelectorAll(`#${this.listId} > li`)),r=e=>e?.querySelector(`button:not([disabled]), input, textarea, [tabindex="0"]`);(n.slice(e).map(r).find(Boolean)??n.slice(0,e).reverse().map(r).find(Boolean)??t.querySelector(`.root > .toggle`))?.focus()}step(e){return Math.min(100,e.more??0)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-value-tree`]],inputs:{prop:[1,`prop`],store:[1,`store`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],directive:[1,`directive`],query:[1,`query`]},decls:2,vars:1,consts:[[3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`root`],[`type`,`button`,1,`toggle`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m9 6 6 6-6 6`],[1,`summary`,`mono`],[1,`whole`,3,`bare`,`prop`,`componentId`,`pageId`,`rpc`,`writes`,`readDraft`],[1,`entries`,3,`id`],[1,`entry`,3,`padding-left`],[1,`entry`],[`type`,`button`,1,`toggle`],[`type`,`button`,1,`more`],[`role`,`status`,1,`muted`],[`role`,`alert`,1,`error`],[1,`key`,`mono`],[1,`leaf-edit`,3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`leaf`,`mono`],[`type`,`button`,1,`more`,3,`click`],[1,`muted`]],template:function(e,t){if(e&1&&M(0,eN,8,12)(1,tN,1,5,`app-prop-value`,0),e&2){let e;N((e=t.root())?0:1,e)}},dependencies:[xM],styles:[`[_nghost-%COMP%] { +}`]})},CM=1e3,wM={depth:5,limit:100},TM=`[redacted]`;function EM(e){return!!e&&typeof e==`object`&&!Array.isArray(e)}function DM(e){return EM(e)&&typeof e.$more==`number`&&Object.keys(e).length===1}function OM(e){return EM(e)&&typeof e.$collapsed==`string`&&typeof e.size==`number`&&Object.keys(e).length===2}function kM(e){return e===`Array`?`array`:e===`Map`?`map`:e===`Set`?`set`:`object`}function AM(e){return e.$type===`Map`&&Array.isArray(e.entries)}function jM(e){return e.$type===`Set`&&Array.isArray(e.values)}function MM(e){return Object.keys(e).filter(e=>e!==`$type`&&e!==`$more`)}function NM(e){if(!e||typeof e!=`object`)return null;if(OM(e))return e.size<=0?null:{kind:kM(e.$collapsed),type:e.$collapsed,size:e.size,collapsed:!0};if(DM(e))return null;if(Array.isArray(e)){let t=e.at(-1),n=DM(t)?t.$more:0,r=e.length-+!!n+n;return r?{kind:`array`,type:`Array`,size:r,collapsed:!1}:null}let t=e;if(AM(t)||jM(t)){let e=typeof t.size==`number`?t.size:0,n=AM(t)?`map`:`set`;return e?{kind:n,type:n===`map`?`Map`:`Set`,size:e,collapsed:!1}:null}let n=typeof t.$more==`number`?t.$more:0,r=MM(t).length+n,i=typeof t.$type==`string`?t.$type:`Object`;return r?{kind:`object`,type:i,size:r,collapsed:!1}:null}function PM(e){if(typeof e==`string`)return JSON.stringify(e);let t=NM(e);if(t)return LM(t);try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function FM(e){let t=NM(e);if(!t||t.collapsed)return{children:[],more:0};if(Array.isArray(e)){let n=(DM(e.at(-1))?e.slice(0,-1):e).map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:n,more:t.size-n.length}}let n=e;if(t.kind===`map`){let e=n.entries.map((e,t)=>{let[n,r]=Array.isArray(e)?e:[void 0,e];return{key:String(t),label:PM(n),value:r}});return{children:e,more:Math.max(0,t.size-e.length)}}if(t.kind===`set`){let e=n.values.map((e,t)=>({key:String(t),label:String(t),value:e}));return{children:e,more:Math.max(0,t.size-e.length)}}return{children:MM(n).map(e=>({key:e,label:e,value:n[e]})),more:typeof n.$more==`number`?n.$more:0}}function IM(e,t,n){return`${e} ${e===1?t:n}`}function LM(e){let t={array:IM(e.size,`item`,`items`),object:IM(e.size,`key`,`keys`),map:IM(e.size,`entry`,`entries`),set:IM(e.size,`value`,`values`)}[e.kind];return`${e.type} (${t})`}function RM(e,t){return JSON.stringify(t===void 0?e:[t,...e])}function zM(e,t){return e.map((e,n)=>n===0?e:(t?t[n-1]!==`object`:/^\d+$/.test(e))?`[${e}]`:`.${e}`).join(``)}function BM(e){return e.every(e=>e&&e===e.trim()&&!/[.[\]]/.test(e))?e.join(`.`):null}var VM=/^\[(Getter|Unreadable|Circular|Truncated|Function\b.*|Promise)\]$/;function HM(e){return e===null||typeof e==`boolean`?!0:typeof e==`number`?Number.isFinite(e):typeof e==`string`&&e!==TM&&!VM.test(e)&&!e.endsWith(`…`)}function UM(e,t){return!e||t.kind===`map`||t.kind===`set`||e===`signal`&&t.kind===`object`&&t.type!==`Object`?null:e}function WM(e,t,n,r,i=500){let a=[],o=r.trim().toLowerCase();if(!o)return a;let s=new Set,c=(e,t)=>{let r=RM(e);if(!(s.has(r)||a.length>=i)){s.add(r);for(let r of FM(t).children){let t=[...e,r.key];if(r.label.toLowerCase().includes(o)&&a.push(t),!NM(r.value))continue;let i=n(t)??(NM(r.value)?.collapsed?void 0:r.value);i!==void 0&&c(t,i)}}};return c(e,n(e)??t),a}var GM=(e,t)=>t.id;function KM(e,t){if(e&1){let e=H();L(0,`button`,2),U(`click`,function(){T(e);let t=G().$implicit;return E(G(3).toggle(t))}),D(),L(1,`svg`,3),z(2,`path`,4),R(),_s(),L(3,`span`,14),J(4),R(),L(5,`span`,5),J(6),R()()}if(e&2){let e=G().$implicit;j(`aria-expanded`,e.open)(`aria-label`,e.label+`: `+e.text),k(4),X(``,e.label,`:`),k(2),Y(e.text)}}function qM(e,t){if(e&1&&z(0,`app-prop-value`,15),e&2){let e=G(5);I(`prop`,t)(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}function JM(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G(2).$implicit;k(),Y(e.text)}}function YM(e,t){if(e&1&&(L(0,`span`,14),J(1),R(),M(2,qM,1,5,`app-prop-value`,15)(3,JM,2,1,`span`,16)),e&2){let e,t=G().$implicit;k(),X(``,t.label,`:`),k(),N((e=t.edit)?2:3,e)}}function XM(e,t){if(e&1){let e=H();L(0,`button`,17),U(`click`,function(){T(e);let t=G().$implicit;return E(G(3).more(t))}),J(1),L(2,`span`,18),J(3),R()()}if(e&2){let e=G().$implicit,t=G(3);k(),X(` Show `,t.step(e),` more `),k(2),X(`(`,e.more,` not listed)`)}}function ZM(e,t){e&1&&(L(0,`span`,12),J(1,`Reading from the page…`),R())}function QM(e,t){if(e&1&&(L(0,`span`,13),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.text)}}function $M(e,t){if(e&1&&(L(0,`li`,9),M(1,KM,7,4,`button`,10)(2,YM,4,2)(3,XM,4,2,`button`,11)(4,ZM,2,0,`span`,12)(5,QM,2,1,`span`,13),R()),e&2){let e,n=t.$implicit;K(`padding-left`,n.depth*14,`px`),k(),N((e=n.kind)===`node`?1:e===`leaf`?2:e===`more`?3:e===`loading`?4:e===`error`?5:-1)}}function eN(e,t){if(e&1&&(L(0,`ul`,7),P(1,$M,6,3,`li`,8,GM),R()),e&2){let e=G(2);I(`id`,e.listId),j(`aria-label`,e.prop().name+` entries`),k(),F(e.rows())}}function tN(e,t){if(e&1){let e=H();L(0,`div`,1)(1,`button`,2),U(`click`,function(){return T(e),E(G().toggleRoot())}),D(),L(2,`svg`,3),z(3,`path`,4),R(),_s(),L(4,`span`,5),J(5),R()(),z(6,`app-prop-value`,6),R(),M(7,eN,3,2,`ul`,7)}if(e&2){let e=t,n=G();k(),j(`aria-expanded`,n.rootOpen())(`aria-controls`,n.rootOpen()?n.listId:null)(`aria-label`,n.prop().name+`: `+n.summaryOf(e)),k(4),Y(n.summaryOf(e)),k(),I(`bare`,!0)(`prop`,n.prop())(`componentId`,n.componentId())(`pageId`,n.pageId())(`rpc`,n.rpc())(`writes`,n.writes())(`readDraft`,n.readWhole),k(),N(n.rootOpen()?7:-1)}}function nN(e,t){if(e&1&&z(0,`app-prop-value`,0),e&2){let e=G();I(`prop`,e.prop())(`componentId`,e.componentId())(`pageId`,e.pageId())(`rpc`,e.rpc())(`writes`,e.writes())}}var rN=0;function iN(e){if(e===void 0)return`undefined`;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function aN(e){if(Array.isArray(e))return e.every(aN);if(e&&typeof e==`object`){let t=e;return![`$collapsed`,`$more`,`$type`].some(e=>Object.hasOwn(t,e))&&Object.values(t).every(aN)}return HM(e)}var oN=class e{prop=$.required();store=$.required();componentId=$.required();pageId=$(null);rpc=$(null);writes=$(!1);directive=$(void 0);query=$(``);listId=`value-tree-${++rN}`;host=C(Il);pendingMore=null;constructor(){dy(()=>{let e=this.rows(),t=this.pendingMore;if(!t)return;let n=e.findIndex(e=>(e.kind===`leaf`||e.kind===`node`)&&!t.has(e.id));if(n<0)return;this.pendingMore=null;let r=document.activeElement;r&&r!==document.body&&r.isConnected||this.focusNear(n)})}rootPath=Q(()=>[this.prop().prop]);rootValue=Q(()=>this.store().level(this.rootPath(),this.directive())??this.prop().value);root=Q(()=>NM(this.rootValue()));needle=Q(()=>this.query().trim().toLowerCase());matches=Q(()=>{let e=this.needle(),t=this.prop();if(!e||[t.name,t.prop].some(t=>t.toLowerCase().includes(e)))return null;let n=this.store(),r=this.directive();return WM(this.rootPath(),this.rootValue(),e=>n.level(e,r),e)});rootOpen=Q(()=>!!this.matches()?.length||this.store().isOpen(this.rootPath(),this.directive()));rows=Q(()=>{let e=this.root();if(!e)return[];let t=this.store(),n=this.directive(),r=this.matches(),i=new Set,a=new Set;for(let e of r??[]){a.add(RM(e));for(let t=2;t<=e.length;t++)i.add(RM(e.slice(0,t)))}let o=this.prop(),s=this.writes()&&n===void 0,c=[],l=(e,o,d,f,p,m)=>{let{children:h,more:g}=FM(e);for(let e of h){let h=[...o,e.key],g=RM(h);if(r&&!m&&!i.has(g))continue;let _=NM(e.value),ee=RM(h,n);if(!_){let t=p&&HM(e.value)?BM(h):null;c.push({id:ee,kind:`leaf`,depth:f,path:h,label:e.label,text:iN(e.value),edit:s&&t&&p?{name:zM(h,[...d]),prop:t,value:e.value,edit:p}:void 0});continue}let te=!!r&&!m&&i.has(g)&&!a.has(g)||t.isOpen(h,n);if(c.push({id:ee,kind:`node`,depth:f,path:h,label:e.label,text:LM(_),container:_,open:te}),!te)continue;let ne=t.level(h,n)??(_.collapsed?void 0:e.value),re=[...d,_.kind];ne===void 0?t.errors().has(ee)?c.push({...u(h,f+1,`error`),text:t.errors().get(ee)}):c.push(u(h,f+1,`loading`)):l(ne,h,re,f+1,UM(p,_),m||a.has(g))}g>0&&(!r||m)&&c.push({...u(o,f,`more`),more:g,listed:h.length})},u=(e,t,r)=>({id:`${RM(e,n)}:${r}`,kind:r,depth:t,path:e,label:``,text:``});return l(this.rootValue(),this.rootPath(),[e.kind],0,s?UM(o.editInside??null,e):null,!r),c});readWhole=async()=>{let e=await this.store().read(this.rootPath(),wM.depth,wM.limit);return e.ok?aN(e.value)?{value:e.value}:{error:`Too large to edit as a whole. Open it to edit the values inside.`}:{error:e.error??`The page did not read it.`}};summaryOf(e){return LM(e)}toggleRoot(){this.pendingMore=null,this.store().toggle(this.rootPath(),this.directive(),!1)}toggle(e){this.pendingMore=null,this.store().toggle(e.path,this.directive(),!!e.container?.collapsed)}more(e){this.pendingMore=new Set(this.rows().map(e=>e.id)),this.store().more(e.path,this.directive(),e.listed??0)}focusNear(e){let t=this.host.nativeElement,n=Array.from(t.querySelectorAll(`#${this.listId} > li`)),r=e=>e?.querySelector(`button:not([disabled]), input, textarea, [tabindex="0"]`);(n.slice(e).map(r).find(Boolean)??n.slice(0,e).reverse().map(r).find(Boolean)??t.querySelector(`.root > .toggle`))?.focus()}step(e){return Math.min(100,e.more??0)}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-value-tree`]],inputs:{prop:[1,`prop`],store:[1,`store`],componentId:[1,`componentId`],pageId:[1,`pageId`],rpc:[1,`rpc`],writes:[1,`writes`],directive:[1,`directive`],query:[1,`query`]},decls:2,vars:1,consts:[[3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`root`],[`type`,`button`,1,`toggle`,3,`click`],[`viewBox`,`0 0 24 24`,`aria-hidden`,`true`,1,`chevron`],[`d`,`m9 6 6 6-6 6`],[1,`summary`,`mono`],[1,`whole`,3,`bare`,`prop`,`componentId`,`pageId`,`rpc`,`writes`,`readDraft`],[1,`entries`,3,`id`],[1,`entry`,3,`padding-left`],[1,`entry`],[`type`,`button`,1,`toggle`],[`type`,`button`,1,`more`],[`role`,`status`,1,`muted`],[`role`,`alert`,1,`error`],[1,`key`,`mono`],[1,`leaf-edit`,3,`prop`,`componentId`,`pageId`,`rpc`,`writes`],[1,`leaf`,`mono`],[`type`,`button`,1,`more`,3,`click`],[1,`muted`]],template:function(e,t){if(e&1&&M(0,tN,8,12)(1,nN,1,5,`app-prop-value`,0),e&2){let e;N((e=t.root())?0:1,e)}},dependencies:[SM],styles:[`[_nghost-%COMP%] { display: block; min-width: 0; } @@ -2091,7 +2091,7 @@ button.edit[_ngcontent-%COMP%] { .more[_ngcontent-%COMP%] { transition: none; } -}`]})};function oN(e,t){return e.length>t.length&&e.startsWith(`${t.slice(0,-1)},`)}var sN=class{target={rpc:null,pageId:null,componentId:null};fetched=O(new Map);pushed=O({});open=O(new Set);loading=O(new Set);errors=O(new Map);limits=new Map;generation=0;follow(e,t){let n=e.componentId===this.target.componentId&&e.pageId===this.target.pageId;this.target=e,n||(this.generation++,this.fetched.set(new Map),this.open.set(new Set),this.loading.set(new Set),this.errors.set(new Map),this.limits.clear()),this.pushed.set(t??{})}level(e,t){let n=LM(e,t),r=this.pushed();return Object.hasOwn(r,n)?r[n]:this.fetched().get(n)}isOpen(e,t){return this.open().has(LM(e,t))}toggle(e,t,n){let r=LM(e,t),i=new Set(this.open());if(i.has(r)){for(let e of i)(e===r||oN(e,r))&&i.delete(e);this.open.set(i),this.send({path:e,directive:t,forget:!0});return}i.add(r),this.open.set(i),n&&this.load(e,t,this.limits.get(r)??30)}more(e,t,n){let r=LM(e,t),i=Math.min(SM,Math.max(n,this.limits.get(r)??0)+100);this.limits.set(r,i),this.load(e,t,i)}async read(e,t,n){return this.send({path:e,depth:t,limit:n})}async load(e,t,n){let r=LM(e,t),i=this.generation;this.loading.update(e=>new Set(e).add(r));let a=await this.send({path:e,directive:t,limit:n,watch:!0});i===this.generation&&(this.loading.update(e=>{let t=new Set(e);return t.delete(r),t}),this.errors.update(e=>{let t=new Map(e);return a.ok?t.delete(r):t.set(r,a.error??`The page did not read it.`),t}),a.ok&&this.fetched.update(e=>new Map(e).set(r,a.value)))}async send(e){let{rpc:t,pageId:n,componentId:r}=this.target;if(!t||!n||!r)return{error:`No live page to read from.`};let{directive:i,...a}=e;try{return await t.scope(`pangular`).rpc.call(`request-component-value`,{pageId:n,request:{id:r,...a,...i===void 0?{}:{directive:i}}})??{}}catch{return{error:`The devtools server did not answer. Try again.`}}}};function cN(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(2);k(),X(`: `,e.label())}}function lN(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(3);k(),X(`: `,e.label())}}function uN(e,t){if(e&1){let e=H();B(0,`button`,4),W(`click`,function(){return T(e),E(G(2).store(`log`))}),J(1,` Log to console `),M(2,lN,2,1,`span`,1),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),k(2),N(e.label()?2:-1)}}function dN(e,t){if(e&1){let e=H();B(0,`button`,0),W(`click`,function(){return T(e),E(G().store())}),J(1,` Store as global `),M(2,cN,2,1,`span`,1),V(),M(3,uN,3,2,`button`,2),B(4,`span`,3),J(5),V()}if(e&2){let e=G();qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),k(2),N(e.label()?2:-1),k(),N(e.canLog()?3:-1),k(2),Y(e.message())}}var fN=class e{rpc=$(null);pageId=$(null);target=$.required();label=$(``);canLog=$(!1);staticReport=Q(()=>UE(this.rpc()));busy=O(!1);message=O(``);async store(e=`store`){let t=this.rpc(),n=this.pageId();if(t&&n){this.busy.set(!0),this.message.set(``);try{let r=await t.scope(`pangular`).rpc.call(`request-console-global`,{pageId:n,target:this.target(),...e===`log`?{mode:e}:{}}),i=e===`log`?r?.ok?`Logged in the page console.`:`Not logged.`:r?.ok&&r.name?`Stored as ${r.name}.`:`Not stored.`;this.message.set(r?.message||i)}catch{this.message.set(`Could not reach the page.`)}finally{this.busy.set(!1)}}}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-store-global`]],inputs:{rpc:[1,`rpc`],pageId:[1,`pageId`],target:[1,`target`],label:[1,`label`],canLog:[1,`canLog`]},decls:1,vars:1,consts:[[`type`,`button`,1,`store`,3,`click`,`disabled`],[1,`sr-only`],[`type`,`button`,1,`store`,`log`,3,`disabled`],[`role`,`status`,1,`status`],[`type`,`button`,1,`store`,`log`,3,`click`,`disabled`]],template:function(e,t){e&1&&M(0,dN,6,4),e&2&&N(t.staticReport()?-1:0)},styles:[`[_nghost-%COMP%] { +}`]})};function sN(e,t){return e.length>t.length&&e.startsWith(`${t.slice(0,-1)},`)}var cN=class{target={rpc:null,pageId:null,componentId:null};fetched=O(new Map);pushed=O({});open=O(new Set);loading=O(new Set);errors=O(new Map);limits=new Map;generation=0;follow(e,t){let n=e.componentId===this.target.componentId&&e.pageId===this.target.pageId;this.target=e,n||(this.generation++,this.fetched.set(new Map),this.open.set(new Set),this.loading.set(new Set),this.errors.set(new Map),this.limits.clear()),this.pushed.set(t??{})}level(e,t){let n=RM(e,t),r=this.pushed();return Object.hasOwn(r,n)?r[n]:this.fetched().get(n)}isOpen(e,t){return this.open().has(RM(e,t))}toggle(e,t,n){let r=RM(e,t),i=new Set(this.open());if(i.has(r)){for(let e of i)(e===r||sN(e,r))&&i.delete(e);this.open.set(i),this.send({path:e,directive:t,forget:!0});return}i.add(r),this.open.set(i),n&&this.load(e,t,this.limits.get(r)??30)}more(e,t,n){let r=RM(e,t),i=Math.min(CM,Math.max(n,this.limits.get(r)??0)+100);this.limits.set(r,i),this.load(e,t,i)}async read(e,t,n){return this.send({path:e,depth:t,limit:n})}async load(e,t,n){let r=RM(e,t),i=this.generation;this.loading.update(e=>new Set(e).add(r));let a=await this.send({path:e,directive:t,limit:n,watch:!0});i===this.generation&&(this.loading.update(e=>{let t=new Set(e);return t.delete(r),t}),this.errors.update(e=>{let t=new Map(e);return a.ok?t.delete(r):t.set(r,a.error??`The page did not read it.`),t}),a.ok&&this.fetched.update(e=>new Map(e).set(r,a.value)))}async send(e){let{rpc:t,pageId:n,componentId:r}=this.target;if(!t||!n||!r)return{error:`No live page to read from.`};let{directive:i,...a}=e;try{return await t.scope(`pangular`).rpc.call(`request-component-value`,{pageId:n,request:{id:r,...a,...i===void 0?{}:{directive:i}}})??{}}catch{return{error:`The devtools server did not answer. Try again.`}}}};function lN(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(2);k(),X(`: `,e.label())}}function uN(e,t){if(e&1&&(B(0,`span`,1),J(1),V()),e&2){let e=G(3);k(),X(`: `,e.label())}}function dN(e,t){if(e&1){let e=H();B(0,`button`,4),W(`click`,function(){return T(e),E(G(2).store(`log`))}),J(1,` Log to console `),M(2,uN,2,1,`span`,1),V()}if(e&2){let e=G(2);qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),k(2),N(e.label()?2:-1)}}function fN(e,t){if(e&1){let e=H();B(0,`button`,0),W(`click`,function(){return T(e),E(G().store())}),J(1,` Store as global `),M(2,lN,2,1,`span`,1),V(),M(3,dN,3,2,`button`,2),B(4,`span`,3),J(5),V()}if(e&2){let e=G();qg(`disabled`,e.busy()||!e.rpc()||!e.pageId()),k(2),N(e.label()?2:-1),k(),N(e.canLog()?3:-1),k(2),Y(e.message())}}var pN=class e{rpc=$(null);pageId=$(null);target=$.required();label=$(``);canLog=$(!1);staticReport=Q(()=>UE(this.rpc()));busy=O(!1);message=O(``);async store(e=`store`){let t=this.rpc(),n=this.pageId();if(t&&n){this.busy.set(!0),this.message.set(``);try{let r=await t.scope(`pangular`).rpc.call(`request-console-global`,{pageId:n,target:this.target(),...e===`log`?{mode:e}:{}}),i=e===`log`?r?.ok?`Logged in the page console.`:`Not logged.`:r?.ok&&r.name?`Stored as ${r.name}.`:`Not stored.`;this.message.set(r?.message||i)}catch{this.message.set(`Could not reach the page.`)}finally{this.busy.set(!1)}}}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-store-global`]],inputs:{rpc:[1,`rpc`],pageId:[1,`pageId`],target:[1,`target`],label:[1,`label`],canLog:[1,`canLog`]},decls:1,vars:1,consts:[[`type`,`button`,1,`store`,3,`click`,`disabled`],[1,`sr-only`],[`type`,`button`,1,`store`,`log`,3,`disabled`],[`role`,`status`,1,`status`],[`type`,`button`,1,`store`,`log`,3,`click`,`disabled`]],template:function(e,t){e&1&&M(0,fN,6,4),e&2&&N(t.staticReport()?-1:0)},styles:[`[_nghost-%COMP%] { display: inline-flex; flex-wrap: wrap; align-items: center; @@ -2111,7 +2111,7 @@ button.edit[_ngcontent-%COMP%] { .status[_ngcontent-%COMP%]:empty { display: none; -}`]})},pN=(e,t)=>t.id;function mN(e,t){if(e&1&&(L(0,`p`,4),J(1),R()),e&2){let e=G(2);k(),X(`The page has more @for blocks than the `,e.length,` listed.`)}}function hN(e,t){e&1&&(L(0,`span`,9),J(1,`@empty showing`),R())}function gN(e,t){e&1&&(L(0,`span`,10),J(1,`@empty`),R())}function _N(e,t){e&1&&(L(0,`span`,10),J(1,`renders nothing`),R())}function vN(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,6),U(`click`,function(){let t=T(e).$implicit;return E(G(3).showOwner.emit(t))})(`focus`,function(){let t=T(e).$implicit,n=G(3);return E(n.highlight.emit(n.target(t)))})(`blur`,function(){return T(e),E(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=T(e).$implicit,n=G(3);return E(n.highlight.emit(n.target(t)))})(`mouseleave`,function(){return T(e),E(G(3).highlight.emit(null))}),L(2,`span`,7),J(3),R(),L(4,`span`,8),J(5),R(),M(6,hN,2,0,`span`,9)(7,gN,2,0,`span`,10)(8,_N,2,0,`span`,10),L(9,`span`,11),J(10),R()()()}if(e&2){let e=t.$implicit,n=G(3);k(),j(`aria-disabled`,e.owner?null:`true`),k(2),Y(e.owner?.name??`Unknown component`),k(2),Z(` `,e.count,` `,e.count===1?`item`:`items`,` `),k(),N(e.showingEmpty?6:e.hasEmptyBlock?7:e.count===0?8:-1),k(4),Y(n.trackLabel(e))}}function yN(e,t){if(e&1&&(L(0,`section`,1)(1,`h2`,2),J(2,` @for blocks `),L(3,`span`,3),J(4),R()(),M(5,mN,2,1,`p`,4),L(6,`ul`,5),P(7,vN,11,6,`li`,null,pN),R()()),e&2){let e=G(),t=G();k(4),Y(t.truncated()?e.length+`+`:e.length),k(),N(t.truncated()?5:-1),k(2),F(e)}}function bN(e,t){e&1&&M(0,yN,9,2,`section`,1),e&2&&N(t.length?0:-1)}function xN(e,t){e&1&&z(0,`app-angular-unavailable`,0),e&2&&I(`page`,G().angular())}var SN={$index:`track $index`,item:`track item`,function:`track expression`},CN=class e{blocks=$(void 0);truncated=$(!1);supported=$(null);angular=$(null);showOwner=Rv();highlight=Rv();target(e){return e.rootIds[0]??e.owner?.id??null}trackLabel(e){return e.track?SN[e.track]:`track unknown`}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-for-blocks`]],inputs:{blocks:[1,`blocks`],truncated:[1,`truncated`],supported:[1,`supported`],angular:[1,`angular`]},outputs:{showOwner:`showOwner`,highlight:`highlight`},decls:2,vars:1,consts:[[`capability`,`forBlocks`,`missing`,``,`compact`,``,1,`for`,3,`page`],[`aria-labelledby`,`ct-for-title`,1,`for`],[`id`,`ct-for-title`,1,`for-title`],[1,`pill`],[1,`note`],[1,`for-list`],[`type`,`button`,1,`for-row`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`count`],[1,`flag`,`empty`],[1,`flag`],[1,`track`,`mono`]],template:function(e,t){if(e&1&&M(0,bN,1,1)(1,xN,1,1,`app-angular-unavailable`,0),e&2){let e;N((e=t.blocks())?0:t.supported()===!1?1:-1,e)}},dependencies:[hO],styles:[`[_nghost-%COMP%] { +}`]})},mN=(e,t)=>t.id;function hN(e,t){if(e&1&&(L(0,`p`,4),J(1),R()),e&2){let e=G(2);k(),X(`The page has more @for blocks than the `,e.length,` listed.`)}}function gN(e,t){e&1&&(L(0,`span`,9),J(1,`@empty showing`),R())}function _N(e,t){e&1&&(L(0,`span`,10),J(1,`@empty`),R())}function vN(e,t){e&1&&(L(0,`span`,10),J(1,`renders nothing`),R())}function yN(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,6),U(`click`,function(){let t=T(e).$implicit;return E(G(3).showOwner.emit(t))})(`focus`,function(){let t=T(e).$implicit,n=G(3);return E(n.highlight.emit(n.target(t)))})(`blur`,function(){return T(e),E(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=T(e).$implicit,n=G(3);return E(n.highlight.emit(n.target(t)))})(`mouseleave`,function(){return T(e),E(G(3).highlight.emit(null))}),L(2,`span`,7),J(3),R(),L(4,`span`,8),J(5),R(),M(6,gN,2,0,`span`,9)(7,_N,2,0,`span`,10)(8,vN,2,0,`span`,10),L(9,`span`,11),J(10),R()()()}if(e&2){let e=t.$implicit,n=G(3);k(),j(`aria-disabled`,e.owner?null:`true`),k(2),Y(e.owner?.name??`Unknown component`),k(2),Z(` `,e.count,` `,e.count===1?`item`:`items`,` `),k(),N(e.showingEmpty?6:e.hasEmptyBlock?7:e.count===0?8:-1),k(4),Y(n.trackLabel(e))}}function bN(e,t){if(e&1&&(L(0,`section`,1)(1,`h2`,2),J(2,` @for blocks `),L(3,`span`,3),J(4),R()(),M(5,hN,2,1,`p`,4),L(6,`ul`,5),P(7,yN,11,6,`li`,null,mN),R()()),e&2){let e=G(),t=G();k(4),Y(t.truncated()?e.length+`+`:e.length),k(),N(t.truncated()?5:-1),k(2),F(e)}}function xN(e,t){e&1&&M(0,bN,9,2,`section`,1),e&2&&N(t.length?0:-1)}function SN(e,t){e&1&&z(0,`app-angular-unavailable`,0),e&2&&I(`page`,G().angular())}var CN={$index:`track $index`,item:`track item`,function:`track expression`},wN=class e{blocks=$(void 0);truncated=$(!1);supported=$(null);angular=$(null);showOwner=Rv();highlight=Rv();target(e){return e.rootIds[0]??e.owner?.id??null}trackLabel(e){return e.track?CN[e.track]:`track unknown`}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-for-blocks`]],inputs:{blocks:[1,`blocks`],truncated:[1,`truncated`],supported:[1,`supported`],angular:[1,`angular`]},outputs:{showOwner:`showOwner`,highlight:`highlight`},decls:2,vars:1,consts:[[`capability`,`forBlocks`,`missing`,``,`compact`,``,1,`for`,3,`page`],[`aria-labelledby`,`ct-for-title`,1,`for`],[`id`,`ct-for-title`,1,`for-title`],[1,`pill`],[1,`note`],[1,`for-list`],[`type`,`button`,1,`for-row`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`],[1,`name`,`mono`],[1,`count`],[1,`flag`,`empty`],[1,`flag`],[1,`track`,`mono`]],template:function(e,t){if(e&1&&M(0,xN,1,1)(1,SN,1,1,`app-angular-unavailable`,0),e&2){let e;N((e=t.blocks())?0:t.supported()===!1?1:-1,e)}},dependencies:[hO],styles:[`[_nghost-%COMP%] { display: block; } @@ -2229,7 +2229,7 @@ button.edit[_ngcontent-%COMP%] { min-width: 0; text-overflow: ellipsis; white-space: nowrap; -}`]})},wN=(e,t)=>t.id;function TN(e,t){e&1&&(L(0,`p`,7),J(1,` This page cannot track destroyed components. It needs WeakRef, FinalizationRegistry and the Angular debug API of a development build. `),R())}function EN(e,t){if(e&1&&(L(0,`span`,18),J(1),R()),e&2){let e=G().$implicit,t=G(3);k(),Y(t.plural(e.subscriptions,`open subscription`))}}function DN(e,t){if(e&1&&(L(0,`li`,13)(1,`span`,14),J(2),R(),L(3,`span`,15),J(4),R(),L(5,`span`,16),J(6),R(),L(7,`span`,17),J(8),R(),M(9,EN,2,1,`span`,18),R()),e&2){let e=t.$implicit,n=G(3);k(2),Y(e.name),k(2),Y(e.route||`/`),k(2),X(``,n.plural(e.navigations,`navigation`),` ago`),k(2),Y(n.ageOf(e)),k(),N(e.subscriptions?9:-1)}}function ON(e,t){if(e&1&&(L(0,`p`,6),J(1),R(),L(2,`ul`,12),P(3,DN,10,5,`li`,13,wN),R()),e&2){let e=G(2);k(),Z(` Destroyed, yet still in memory after at least `,e.minNavigations,` navigations and `,e.minSeconds,` seconds. Take a heap snapshot, search for the class and read its retainers. `),k(2),F(e.retained().slice(0,e.shown))}}function kN(e,t){e&1&&(L(0,`p`,6),J(1,`No destroyed component is still in memory after a few navigations.`),R())}function AN(e,t){if(e&1&&(L(0,`p`,6),J(1),L(2,`span`,19),J(3),R(),J(4,`. Navigate a few times to see whether they stay. `),R()),e&2){let e=G(2);k(),X(` `,e.plural(e.recent().length,`instance`),` destroyed recently and not collected yet: `),k(2),Y(e.names(e.recent()))}}function jN(e,t){if(e&1&&(L(0,`p`,6),J(1,` Off the page but not destroyed (detached views, such as a route reuse cache): `),L(2,`span`,19),J(3),R(),J(4,`. `),R()),e&2){let e=G(2);k(3),Y(e.names(e.detached()))}}function MN(e,t){if(e&1&&(L(0,`span`,10),J(1),R()),e&2){let e=G();k(),Y(e.subscriptions.length)}}function NN(e,t){if(e&1&&(L(0,`span`,15),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.source)}}function PN(e,t){if(e&1&&(L(0,`li`,13)(1,`span`,14),J(2),R(),L(3,`span`,16),J(4),R(),L(5,`span`,18),J(6),R(),M(7,NN,2,1,`span`,15),R()),e&2){let e=t.$implicit;k(2),Y(e.name),k(2),X(``,e.count,` open`),k(2),X(` `,e.reason===`instance-destroyed`?`instance destroyed`:`no instance left`,` `),k(),N(e.source?7:-1)}}function FN(e,t){if(e&1&&(L(0,`p`,6),J(1,` Still open although the component that made them is gone. Tear them down with takeUntilDestroyed(), DestroyRef.onDestroy or the async pipe. `),R(),L(2,`ul`,12),P(3,PN,8,4,`li`,13,kg),R()),e&2){let e=G(2),t=G();k(3),F(e.subscriptions.slice(0,t.shown))}}function IN(e,t){e&1&&(L(0,`p`,6),J(1,`No subscription is still open after its component went away.`),R())}function LN(e,t){e&1&&(L(0,`p`,6),J(1,` Subscriptions are tied to component classes only; Angular 20 profiler hooks tie them to instances. `),R())}function RN(e,t){if(e&1&&(M(0,FN,5,0)(1,IN,2,0,`p`,6),M(2,LN,2,0,`p`,6)),e&2){let e=G();N(+!e.subscriptions.length),k(2),N(e.support.instances?-1:2)}}function zN(e,t){e&1&&(L(0,`p`,7),J(1,` Tracking could not start: the page has no RxJS the overlay can load. `),R())}function BN(e,t){e&1&&(L(0,`p`,6),J(1,` Off. Track subscriptions wraps Observable.prototype.subscribe on the page to record which component makes each subscription, until you stop it. Subscriptions made before you start are not seen, so reload or navigate again after starting. `),R())}function VN(e,t){e&1&&z(0,`app-angular-unavailable`,11),e&2&&I(`page`,G(2).angular())}function HN(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G().$implicit,t=G(3);k(),Y(t.plural(e.subscriptions,`subscription`))}}function UN(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,20),U(`click`,function(){let t=T(e).$implicit;return E(G(3).showComponent.emit(t.id))})(`focus`,function(){let t=T(e).$implicit;return E(G(3).highlight.emit(t.id))})(`blur`,function(){return T(e),E(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(3).highlight.emit(t.id))})(`mouseleave`,function(){return T(e),E(G(3).highlight.emit(null))}),L(2,`span`,14),J(3),R(),L(4,`span`,16),J(5),R(),M(6,HN,2,1,`span`,16),R()()}if(e&2){let e=t.$implicit,n=G(2),r=G();k(3),Y(e.name),k(2),Y(r.effectsText(e)),k(),N(n.support.subscriptions===`on`?6:-1)}}function WN(e,t){e&1&&(L(0,`p`,6),J(1,` Angular files a component's effects under the template its host sits in, so effects of components side by side in one template show as shared. `),R())}function GN(e,t){if(e&1&&(L(0,`ul`,12),P(1,UN,7,3,`li`,null,wN),R(),M(3,WN,2,0,`p`,6)),e&2){let e=G(),t=G();k(),F(e.components.slice(0,t.shown)),k(2),N(e.components.some(t.hasShared)?3:-1)}}function KN(e,t){e&1&&(L(0,`p`,6),J(1,`No component on the page has a live effect or a tracked subscription.`),R())}function qN(e,t){if(e&1&&(M(0,TN,2,0,`p`,7),L(1,`p`,8),J(2),R(),L(3,`h3`,9),J(4,` Still retained `),L(5,`span`,10),J(6),R()(),M(7,ON,5,2)(8,kN,2,0,`p`,6),M(9,AN,5,2,`p`,6),M(10,jN,5,1,`p`,6),L(11,`h3`,9),J(12,` Open subscriptions after destroy `),M(13,MN,2,1,`span`,10),R(),M(14,RN,3,2)(15,zN,2,0,`p`,7)(16,BN,2,0,`p`,6),L(17,`h3`,9),J(18,` Live effects and subscriptions `),L(19,`span`,10),J(20),R()(),M(21,VN,1,1,`app-angular-unavailable`,11),M(22,GN,4,1)(23,KN,2,0,`p`,6)),e&2){let e,n=t,r=G();N(n.support.retention?-1:0),k(2),rv(` `,r.plural(n.navigations,`navigation`),` · `,r.retained().length,` still retained · `,r.plural(n.totals.collected,`instance`),` collected `),k(4),Y(r.retained().length),k(),N(r.retained().length?7:8),k(2),N(r.recent().length?9:-1),k(),N(r.detached().length?10:-1),k(3),N(n.support.subscriptions===`on`?13:-1),k(),N((e=n.support.subscriptions)===`on`?14:e===`unavailable`?15:16),k(6),Y(n.components.length),k(),N(n.support.effects?-1:21),k(),N(n.components.length?22:23)}}function JN(e,t){e&1&&(L(0,`p`,6),J(1,`No leak data from this page yet. It comes with the next report.`),R())}var YN=20;function XN(e){let t=Math.max(0,Math.round(e/1e3));if(t<120)return`${t} s`;let n=Math.round(t/60);return n<120?`${n} min`:`${Math.round(n/60)} h`}var ZN=(e,t,n=`${t}s`)=>`${e} ${e===1?t:n}`,QN=class e{report=$(null);pageId=$(null);rpc=$(null);angular=$(null);now=$(()=>Date.now());showComponent=Rv();highlight=Rv();shown=YN;minNavigations=2;minSeconds=nE/1e3;plural=ZN;busy=O(!1);announcement=O(``);tracking=Q(()=>this.report()?.support.subscriptions===`on`);split=Q(()=>{let e=this.report(),t=[],n=[],r=[];if(!e)return{retained:t,recent:n,detached:r};for(let i of e.destroyed)i.detached?r.push(i):this.isRetained(e,i)?t.push(i):n.push(i);return{retained:t,recent:n,detached:r}});retained=Q(()=>this.split().retained);recent=Q(()=>this.split().recent);detached=Q(()=>this.split().detached);ageMs(e,t){return Math.max(0,this.now()()-e.reportedAt+(e.at-t.destroyedAt))}isRetained(e,t){return t.navigations>=2&&this.ageMs(e,t)>=1e4}ageOf(e){let t=this.report();return t?`${XN(this.ageMs(t,e))} old`:``}names(e){let t=[...new Set(e.map(e=>e.name))];return t.length>6?`${t.slice(0,6).join(`, `)} and more`:t.join(`, `)}hasShared(e){return!!e.sharedEffects}effectsText(e){let t=ZN(e.effects,`effect`);return e.sharedEffects?`${t}, ${e.sharedEffects} shared`:t}async toggle(){let e=this.pageId();if(!e||this.busy())return;let t=!this.tracking();this.busy.set(!0);try{await VE(this.rpc(),`request-leak-tracking`,{pageId:e,on:t}),this.announcement.set(t?`Tracking subscriptions. Reload or navigate to see subscriptions made at start.`:`Stopped tracking subscriptions.`)}catch{this.announcement.set(`Could not reach the page. Try again.`)}finally{this.busy.set(!1)}}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-leaks-section`]],inputs:{report:[1,`report`],pageId:[1,`pageId`],rpc:[1,`rpc`],angular:[1,`angular`],now:[1,`now`]},outputs:{showComponent:`showComponent`,highlight:`highlight`},decls:12,vars:5,consts:[[`aria-labelledby`,`ct-leaks-title`,1,`leaks`],[1,`head`],[`id`,`ct-leaks-title`],[`type`,`button`,1,`track`,3,`click`,`disabled`],[`role`,`status`,1,`sr-only`],[1,`hint`],[1,`note`],[`role`,`status`,1,`note`],[1,`stats`],[1,`sub`],[1,`pill`],[`capability`,`signalGraph`,`missing`,``,`compact`,``,3,`page`],[1,`rows`],[1,`row`],[1,`name`,`mono`],[1,`meta`,`mono`],[1,`count`],[1,`meta`],[1,`flag`,`warn`],[1,`mono`],[`type`,`button`,1,`row`,`live`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Leaks`),R(),L(4,`button`,3),U(`click`,function(){return t.toggle()}),J(5),R(),L(6,`p`,4),J(7),R()(),L(8,`p`,5),J(9,` Components that left the page but are still in memory, and the live effects and RxJS subscriptions of each component. The browser collects garbage when it decides, so a retained instance is a hint: check what holds it in the Chrome DevTools Memory panel. `),R(),M(10,qN,24,13)(11,JN,2,0,`p`,6),R()),e&2){let e;k(4),I(`disabled`,!t.pageId()||t.busy()||!t.report()),j(`aria-pressed`,t.tracking()),k(),X(` `,t.tracking()?`Stop tracking subscriptions`:`Track subscriptions`,` `),k(2),Y(t.announcement()),k(3),N((e=t.report())?10:11,e)}},dependencies:[hO],styles:[`[_nghost-%COMP%] { +}`]})},TN=(e,t)=>t.id;function EN(e,t){e&1&&(L(0,`p`,7),J(1,` This page cannot track destroyed components. It needs WeakRef, FinalizationRegistry and the Angular debug API of a development build. `),R())}function DN(e,t){if(e&1&&(L(0,`span`,18),J(1),R()),e&2){let e=G().$implicit,t=G(3);k(),Y(t.plural(e.subscriptions,`open subscription`))}}function ON(e,t){if(e&1&&(L(0,`li`,13)(1,`span`,14),J(2),R(),L(3,`span`,15),J(4),R(),L(5,`span`,16),J(6),R(),L(7,`span`,17),J(8),R(),M(9,DN,2,1,`span`,18),R()),e&2){let e=t.$implicit,n=G(3);k(2),Y(e.name),k(2),Y(e.route||`/`),k(2),X(``,n.plural(e.navigations,`navigation`),` ago`),k(2),Y(n.ageOf(e)),k(),N(e.subscriptions?9:-1)}}function kN(e,t){if(e&1&&(L(0,`p`,6),J(1),R(),L(2,`ul`,12),P(3,ON,10,5,`li`,13,TN),R()),e&2){let e=G(2);k(),Z(` Destroyed, yet still in memory after at least `,e.minNavigations,` navigations and `,e.minSeconds,` seconds. Take a heap snapshot, search for the class and read its retainers. `),k(2),F(e.retained().slice(0,e.shown))}}function AN(e,t){e&1&&(L(0,`p`,6),J(1,`No destroyed component is still in memory after a few navigations.`),R())}function jN(e,t){if(e&1&&(L(0,`p`,6),J(1),L(2,`span`,19),J(3),R(),J(4,`. Navigate a few times to see whether they stay. `),R()),e&2){let e=G(2);k(),X(` `,e.plural(e.recent().length,`instance`),` destroyed recently and not collected yet: `),k(2),Y(e.names(e.recent()))}}function MN(e,t){if(e&1&&(L(0,`p`,6),J(1,` Not counted: the last destroyed instance of a class with none left on the page, which Angular's development-mode DI debug data can keep alive: `),L(2,`span`,19),J(3),R(),J(4,`. `),R()),e&2){let e=G(2);k(3),Y(e.names(e.devHeld()))}}function NN(e,t){if(e&1&&(L(0,`p`,6),J(1,` Off the page but not destroyed (detached views, such as a route reuse cache): `),L(2,`span`,19),J(3),R(),J(4,`. `),R()),e&2){let e=G(2);k(3),Y(e.names(e.detached()))}}function PN(e,t){if(e&1&&(L(0,`span`,10),J(1),R()),e&2){let e=G();k(),Y(e.subscriptions.length)}}function FN(e,t){if(e&1&&(L(0,`span`,15),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.source)}}function IN(e,t){if(e&1&&(L(0,`li`,13)(1,`span`,14),J(2),R(),L(3,`span`,16),J(4),R(),L(5,`span`,18),J(6),R(),M(7,FN,2,1,`span`,15),R()),e&2){let e=t.$implicit;k(2),Y(e.name),k(2),X(``,e.count,` open`),k(2),X(` `,e.reason===`instance-destroyed`?`instance destroyed`:`no instance left`,` `),k(),N(e.source?7:-1)}}function LN(e,t){if(e&1&&(L(0,`p`,6),J(1,` Still open although the component that made them is gone. Tear them down with takeUntilDestroyed(), DestroyRef.onDestroy or the async pipe. `),R(),L(2,`ul`,12),P(3,IN,8,4,`li`,13,kg),R()),e&2){let e=G(2),t=G();k(3),F(e.subscriptions.slice(0,t.shown))}}function RN(e,t){e&1&&(L(0,`p`,6),J(1,`No subscription is still open after its component went away.`),R())}function zN(e,t){e&1&&(L(0,`p`,6),J(1,` Subscriptions are tied to component classes only; Angular 20 profiler hooks tie them to instances. `),R())}function BN(e,t){if(e&1&&(M(0,LN,5,0)(1,RN,2,0,`p`,6),M(2,zN,2,0,`p`,6)),e&2){let e=G();N(+!e.subscriptions.length),k(2),N(e.support.instances?-1:2)}}function VN(e,t){e&1&&(L(0,`p`,7),J(1,` Tracking could not start: the page has no RxJS the overlay can load. `),R())}function HN(e,t){e&1&&(L(0,`p`,6),J(1,` Off. Track subscriptions wraps Observable.prototype.subscribe on the page to record which component makes each subscription, until you stop it. Subscriptions made before you start are not seen, so reload or navigate again after starting. `),R())}function UN(e,t){e&1&&z(0,`app-angular-unavailable`,11),e&2&&I(`page`,G(2).angular())}function WN(e,t){if(e&1&&(L(0,`span`,16),J(1),R()),e&2){let e=G().$implicit,t=G(3);k(),Y(t.plural(e.subscriptions,`subscription`))}}function GN(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,20),U(`click`,function(){let t=T(e).$implicit;return E(G(3).showComponent.emit(t.id))})(`focus`,function(){let t=T(e).$implicit;return E(G(3).highlight.emit(t.id))})(`blur`,function(){return T(e),E(G(3).highlight.emit(null))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(3).highlight.emit(t.id))})(`mouseleave`,function(){return T(e),E(G(3).highlight.emit(null))}),L(2,`span`,14),J(3),R(),L(4,`span`,16),J(5),R(),M(6,WN,2,1,`span`,16),R()()}if(e&2){let e=t.$implicit,n=G(2),r=G();k(3),Y(e.name),k(2),Y(r.effectsText(e)),k(),N(n.support.subscriptions===`on`?6:-1)}}function KN(e,t){e&1&&(L(0,`p`,6),J(1,` Angular files a component's effects under the template its host sits in, so effects of components side by side in one template show as shared. `),R())}function qN(e,t){if(e&1&&(L(0,`ul`,12),P(1,GN,7,3,`li`,null,TN),R(),M(3,KN,2,0,`p`,6)),e&2){let e=G(),t=G();k(),F(e.components.slice(0,t.shown)),k(2),N(e.components.some(t.hasShared)?3:-1)}}function JN(e,t){e&1&&(L(0,`p`,6),J(1,`No component on the page has a live effect or a tracked subscription.`),R())}function YN(e,t){if(e&1&&(M(0,EN,2,0,`p`,7),L(1,`p`,8),J(2),R(),L(3,`h3`,9),J(4,` Still retained `),L(5,`span`,10),J(6),R()(),M(7,kN,5,2)(8,AN,2,0,`p`,6),M(9,jN,5,2,`p`,6),M(10,MN,5,1,`p`,6),M(11,NN,5,1,`p`,6),L(12,`h3`,9),J(13,` Open subscriptions after destroy `),M(14,PN,2,1,`span`,10),R(),M(15,BN,3,2)(16,VN,2,0,`p`,7)(17,HN,2,0,`p`,6),L(18,`h3`,9),J(19,` Live effects and subscriptions `),L(20,`span`,10),J(21),R()(),M(22,UN,1,1,`app-angular-unavailable`,11),M(23,qN,4,1)(24,JN,2,0,`p`,6)),e&2){let e,n=t,r=G();N(n.support.retention?-1:0),k(2),rv(` `,r.plural(n.navigations,`navigation`),` · `,r.retained().length,` still retained · `,r.plural(n.totals.collected,`instance`),` collected `),k(4),Y(r.retained().length),k(),N(r.retained().length?7:8),k(2),N(r.recent().length?9:-1),k(),N(r.devHeld().length?10:-1),k(),N(r.detached().length?11:-1),k(3),N(n.support.subscriptions===`on`?14:-1),k(),N((e=n.support.subscriptions)===`on`?15:e===`unavailable`?16:17),k(6),Y(n.components.length),k(),N(n.support.effects?-1:22),k(),N(n.components.length?23:24)}}function XN(e,t){e&1&&(L(0,`p`,6),J(1,`No leak data from this page yet. It comes with the next report.`),R())}var ZN=20;function QN(e){let t=Math.max(0,Math.round(e/1e3));if(t<120)return`${t} s`;let n=Math.round(t/60);return n<120?`${n} min`:`${Math.round(n/60)} h`}var $N=(e,t,n=`${t}s`)=>`${e} ${e===1?t:n}`,eP=class e{report=$(null);pageId=$(null);rpc=$(null);angular=$(null);now=$(()=>Date.now());showComponent=Rv();highlight=Rv();shown=ZN;minNavigations=2;minSeconds=nE/1e3;plural=$N;busy=O(!1);announcement=O(``);tracking=Q(()=>this.report()?.support.subscriptions===`on`);split=Q(()=>{let e=this.report(),t=[],n=[],r=[],i=[];if(!e)return{retained:t,recent:n,detached:r,devHeld:i};for(let a of e.destroyed)a.detached?r.push(a):a.devHeld?i.push(a):this.isRetained(e,a)?t.push(a):n.push(a);return{retained:t,recent:n,detached:r,devHeld:i}});retained=Q(()=>this.split().retained);recent=Q(()=>this.split().recent);detached=Q(()=>this.split().detached);devHeld=Q(()=>this.split().devHeld);ageMs(e,t){return Math.max(0,this.now()()-e.reportedAt+(e.at-t.destroyedAt))}isRetained(e,t){return t.navigations>=2&&this.ageMs(e,t)>=1e4}ageOf(e){let t=this.report();return t?`${QN(this.ageMs(t,e))} old`:``}names(e){let t=[...new Set(e.map(e=>e.name))];return t.length>6?`${t.slice(0,6).join(`, `)} and more`:t.join(`, `)}hasShared(e){return!!e.sharedEffects}effectsText(e){let t=$N(e.effects,`effect`);return e.sharedEffects?`${t}, ${e.sharedEffects} shared`:t}async toggle(){let e=this.pageId();if(!e||this.busy())return;let t=!this.tracking();this.busy.set(!0);try{await VE(this.rpc(),`request-leak-tracking`,{pageId:e,on:t}),this.announcement.set(t?`Tracking subscriptions. Reload or navigate to see subscriptions made at start.`:`Stopped tracking subscriptions.`)}catch{this.announcement.set(`Could not reach the page. Try again.`)}finally{this.busy.set(!1)}}static ɵfac=function(t){return new(t||e)};static ɵcmp=A({type:e,selectors:[[`app-leaks-section`]],inputs:{report:[1,`report`],pageId:[1,`pageId`],rpc:[1,`rpc`],angular:[1,`angular`],now:[1,`now`]},outputs:{showComponent:`showComponent`,highlight:`highlight`},decls:12,vars:5,consts:[[`aria-labelledby`,`ct-leaks-title`,1,`leaks`],[1,`head`],[`id`,`ct-leaks-title`],[`type`,`button`,1,`track`,3,`click`,`disabled`],[`role`,`status`,1,`sr-only`],[1,`hint`],[1,`note`],[`role`,`status`,1,`note`],[1,`stats`],[1,`sub`],[1,`pill`],[`capability`,`signalGraph`,`missing`,``,`compact`,``,3,`page`],[1,`rows`],[1,`row`],[1,`name`,`mono`],[1,`meta`,`mono`],[1,`count`],[1,`meta`],[1,`flag`,`warn`],[1,`mono`],[`type`,`button`,1,`row`,`live`,3,`click`,`focus`,`blur`,`mouseenter`,`mouseleave`]],template:function(e,t){if(e&1&&(L(0,`section`,0)(1,`div`,1)(2,`h2`,2),J(3,`Leaks`),R(),L(4,`button`,3),U(`click`,function(){return t.toggle()}),J(5,` Track subscriptions `),R(),L(6,`p`,4),J(7),R()(),L(8,`p`,5),J(9,` Components that left the page but are still in memory, and the live effects and RxJS subscriptions of each component. The browser collects garbage when it decides, so a retained instance is a hint: check what holds it in the Chrome DevTools Memory panel. `),R(),M(10,YN,25,14)(11,XN,2,0,`p`,6),R()),e&2){let e;k(4),I(`disabled`,!t.pageId()||!t.report()),j(`aria-pressed`,t.tracking())(`aria-disabled`,t.busy()||null),k(3),Y(t.announcement()),k(3),N((e=t.report())?10:11,e)}},dependencies:[hO],styles:[`[_nghost-%COMP%] { display: block; } @@ -2263,6 +2263,10 @@ h2[_ngcontent-%COMP%] { color: var(--%NS%accent-text); } +.track[aria-disabled=true][_ngcontent-%COMP%] { + cursor: progress; +} + .track[_ngcontent-%COMP%]:focus-visible { outline: 2px solid var(--%NS%accent); outline-offset: 2px; @@ -2381,7 +2385,7 @@ h2[_ngcontent-%COMP%] { border-color: color-mix(in srgb, var(--%NS%warn) 30%, transparent); background: color-mix(in srgb, var(--%NS%warn) 12%, transparent); color: var(--%NS%warn-text); -}`]})},$N=12,eP=900;function tP(e){for(let t=e.parentElement;t;t=t.parentElement){let e=getComputedStyle(t);if(/(auto|scroll|overlay)/.test(e.overflowY))return t}return null}var nP=class{options;injector=C(Ts);visibleTop=O(0);viewport=O(eP);rowHeight;host=null;scroller=null;detach=null;enabled;range;padTop;padBottom;constructor(e){this.options=e,this.rowHeight=O(e.estimate);let t=e.min??300;this.enabled=Q(()=>e.count()>t),this.range=Q(()=>{let t=e.count();if(!this.enabled())return{start:0,end:t};let n=this.rowHeight(),r=this.viewport(),i=Math.max(0,Math.min(this.visibleTop(),t*n-r)),a=Math.max(0,Math.min(t-1,Math.floor(i/n)-$N));return{start:a,end:Math.min(t,Math.max(a,Math.ceil((i+r)/n)+$N))}}),this.padTop=Q(()=>this.enabled()?this.range().start*this.rowHeight():0),this.padBottom=Q(()=>this.enabled()?(e.count()-this.range().end)*this.rowHeight():0),mc(()=>{e.count(),Hd(()=>this.update(),{injector:this.injector})}),C(Ds).onDestroy(()=>this.detach?.())}get count(){return this.options.count()}rendered(e){let{start:t,end:n}=this.range();return e>=t&&ethis.update();n.addEventListener(`scroll`,r,{passive:!0}),window.addEventListener(`resize`,r),this.detach=()=>{n.removeEventListener(`scroll`,r),window.removeEventListener(`resize`,r)},this.update()}update(){let e=this.host;if(e){if(this.scroller===e)this.place(e.scrollTop,e.clientHeight);else{let t=this.scroller?this.scroller.getBoundingClientRect().top:0,n=this.scroller?this.scroller.clientHeight:window.innerHeight;this.place(t-e.getBoundingClientRect().top,n)}this.options.fixed||this.measure()}}place(e,t){this.visibleTop.set(e),this.viewport.set(t>0?t:eP)}measure(){let e=this.host?.querySelectorAll(`[data-vindex]`);if(!e||e.length<2)return;let t=e[0].getBoundingClientRect(),n=(e[e.length-1].getBoundingClientRect().bottom-t.top)/e.length;n>4&&Math.abs(n-this.rowHeight())>1&&this.rowHeight.set(n)}reveal(e,t){if(this.enabled()&&!this.rendered(e)){let t=e*this.rowHeight(),n=this.viewport(),r=Math.max(0,t-n/2);if(this.place(r,n),this.host&&this.scroller===this.host)this.host.scrollTop=r;else if(this.host){let e=this.scroller?this.scroller.getBoundingClientRect().top:0,t=this.host.getBoundingClientRect().top-e+r;this.scroller?this.scroller.scrollTop+=t:window.scrollBy(0,t)}}t&&Hd(t,{injector:this.injector})}},rP=[`filterInput`],iP=[`treeEl`],aP=[`propFilterInput`],oP=()=>[],sP=e=>({kind:`component`,id:e}),cP=(e,t)=>t.row.node.id,lP=(e,t)=>t.outlet+t.route,uP=(e,t)=>t+e,dP=(e,t)=>t.formId,fP=(e,t)=>t.name+t.index,pP=(e,t)=>t.name,mP=(e,t)=>t.token+e,hP=(e,t)=>t.id;function gP(e,t){return this.sourceKey(t)}function _P(e,t){if(e&1){let e=H();L(0,`span`,35),J(1,`Page`),R(),L(2,`app-select`,36),U(`valueChange`,function(t){return T(e),E(G(2).selectPage(t))}),R()}if(e&2){let e=G(2);k(2),I(`options`,e.pageOptions())(`value`,e.page()?.pageId??null)}}function vP(e,t){if(e&1){let e=H();L(0,`button`,37),U(`click`,function(){return T(e),E(G(2).toggleDirectiveHosts())}),D(),L(1,`svg`,14),z(2,`path`,38)(3,`path`,39),R(),J(4,` Directive hosts `),R()}e&2&&j(`aria-pressed`,G(2).showDirectiveHosts())}function yP(e,t){if(e&1){let e=H();L(0,`button`,40),U(`click`,function(){T(e);let t=G(2);return E(t.picking()?t.cancelPick():t.pick())}),D(),L(1,`svg`,14),z(2,`path`,41),R(),J(3),R()}if(e&2){let e=G(2);q(`on`,e.picking()),k(3),X(` `,e.picking()?`Cancel pick`:`Pick component on page`,` `)}}function bP(e,t){if(e&1&&(L(0,`p`,21),J(1),R()),e&2){let e=G(2);k(),Y(e.pickMessage())}}function xP(e,t){if(e&1&&(L(0,`p`,22),J(1),R()),e&2){let e=G(2);k(),Y(e.truncationText())}}function SP(e,t){e&1&&(L(0,`p`,43),J(1,`The filter only searches the components the tree lists.`),R())}function CP(e,t){e&1&&(L(0,`p`,43),J(1,`Directive hosts are hidden, so they are not searched.`),R())}function wP(e,t){if(e&1){let e=H();L(0,`div`,25)(1,`p`,42),J(2),R(),M(3,SP,2,0,`p`,43),M(4,CP,2,0,`p`,43),L(5,`button`,44),U(`click`,function(){return T(e),E(G(2).clearFilter())}),J(6,`Clear filter`),R()()}if(e&2){let e=G(2);k(2),X(`No components match “`,e.filter().trim(),`”`),k(),N(e.page().truncated?3:-1),k(),N(!e.showDirectiveHosts()&&e.page().directiveHostCount?4:-1)}}function TP(e,t){if(e&1&&(L(0,`p`,26),J(1),R()),e&2){let e=G(2);k(),X(` `,e.rows().length,` rows. Rows render as you scroll, so the browser's find only sees the ones near view; the filter above searches them all. `)}}function EP(e,t){if(e&1){let e=H();L(0,`span`,52),U(`click`,function(t){T(e),G();let n=fv(0);return E(G(2).toggle(n.node.id,t))}),D(),L(1,`svg`,53),z(2,`path`,54),R()()}e&2&&(G(),q(`open`,fv(0).expanded))}function DP(e,t){e&1&&z(0,`span`,47)}function OP(e,t){if(e&1&&(L(0,`span`,55),J(1),R(),L(2,`span`,56),J(3),R(),L(4,`span`,24),J(5,`directive host`),R()),e&2){G();let e=fv(0),t=G(2);k(),X(`<`,e.node.tag,`>`),k(),j(`title`,e.node.directives?.join(`, `)),k(),Y(t.hostLabel(e.node))}}function kP(e,t){if(e&1&&(L(0,`span`,57),J(1),R(),L(2,`span`,58),J(3),R()),e&2){G();let e=fv(0);k(),Y(e.node.name),k(2),X(`<`,e.node.tag,`>`)}}function AP(e,t){if(e&1&&(L(0,`span`)(1,`span`,24),J(2,`Hydration: `),R(),J(3),R()),e&2){let e=t,n=G(3);M_(`hyd hyd-`+e),k(3),Y(n.hydrationText(e))}}function jP(e,t){if(e&1&&(L(0,`span`,49),J(1),R()),e&2){let e=t.$implicit;k(),Y(e.route||`/`)}}function MP(e,t){if(e&1&&(L(0,`span`,50),J(1),L(2,`span`,24),J(3),R()()),e&2){let e=t;k(),X(` `,e),k(2),X(` `,e===1?`check`:`checks`,` while recording`)}}function NP(e,t){if(e&1&&(L(0,`span`,51),J(1),L(2,`span`,24),J(3),R()()),e&2){G();let e=fv(0);j(`title`,e.node.directives.join(`, `)),k(),X(` +`,e.node.directives.length,` `),k(2),X(` `,e.node.directives.length===1?`directive`:`directives`,` `)}}function PP(e,t){if(e&1){let e=H();uv(0),L(1,`div`,45),U(`click`,function(){T(e);let t=fv(0);return E(G(2).select(t.node.id))})(`focus`,function(){T(e);let t=fv(0),n=G(2);return n.focusId.set(t.node.id),E(n.highlight(t.node.id))})(`blur`,function(){return T(e),E(G(2).highlight(null))})(`mouseenter`,function(){T(e);let t=fv(0);return E(G(2).highlight(t.node.id))})(`mouseleave`,function(){return T(e),E(G(2).highlight(null))}),M(2,EP,3,2,`span`,46)(3,DP,1,0,`span`,47),M(4,OP,6,3)(5,kP,4,2),M(6,AP,4,3,`span`,48),P(7,jP,2,1,`span`,49,lP),M(9,MP,4,2,`span`,50),M(10,NP,4,3,`span`,51),R()}if(e&2){let e,n,r=t.$implicit,i=G(2),a=dv(r.row);k(),K(`--%NS%depth`,a.depth),q(`selected`,i.selectedId()===a.node.id)(`dir-host`,a.node.kind===`directive`),j(`aria-level`,a.depth+1)(`aria-setsize`,a.setsize)(`aria-posinset`,a.posinset)(`aria-expanded`,a.hasChildren?a.expanded:null)(`aria-selected`,i.selectedId()===a.node.id)(`tabindex`,i.tabStop()===a.node.id?0:-1)(`data-vindex`,r.index)(`data-id`,a.node.id),k(),N(a.hasChildren?2:3),k(2),N(a.node.kind===`directive`?4:5),k(2),N((e=a.node.hydration)?6:-1,e),k(),F(i.routedById().get(a.node.id)??mv(20,oP)),k(2),N((n=i.cdHosts()[a.node.id])?9:-1,n),k(),N(a.node.kind!==`directive`&&a.node.directives?.length?10:-1)}}function FP(e,t){if(e&1&&(L(0,`li`,66),J(1),R()),e&2){let e=t.$implicit;k(),Y(e)}}function IP(e,t){if(e&1){let e=H();L(0,`div`,68)(1,`button`,44),U(`click`,function(){let t=T(e);return E(G(3).reveal(t.id,!0))}),J(2),R()()}e&2&&(k(2),X(` Show `,t.name,` `))}function LP(e,t){if(e&1&&(L(0,`section`,29)(1,`header`,59)(2,`span`,60),J(3,`directive host`),R(),L(4,`h2`,61),J(5),R(),L(6,`span`,62),J(7),R()(),L(8,`div`,63)(9,`h3`),J(10,` Directives `),L(11,`span`,64),J(12),R()(),L(13,`ul`,65),P(14,FP,2,1,`li`,66,uP),R()(),L(16,`div`,63)(17,`p`,67),J(18,` This element hosts directives but no component. Their inputs are bound in the template of the component that renders it. `),R(),M(19,IP,3,1,`div`,68),R()()),e&2){let e,n=t,r=G(2);k(5),X(`<`,n.tag,`>`),k(2),Y(r.hostLabel(n)),k(5),Y(n.directives?.length??0),k(2),F(n.directives??mv(4,oP)),k(5),N((e=r.ownerOf(n.id))?19:-1,e)}}function RP(e,t){if(e&1&&(L(0,`p`,69),z(1,`app-source-link`,73),R()),e&2){let e=t;k(),I(`file`,e.file)(`line`,e.line)}}function zP(e,t){if(e&1){let e=H();L(0,`div`,74)(1,`button`,44),U(`click`,function(){T(e);let t=G();return E(G(2).revealInElements(t))}),J(2,`Reveal in Elements`),R(),L(3,`button`,44),U(`click`,function(){T(e);let t=G();return E(G(2).openSource(t))}),J(4,`Open source`),R()(),L(5,`p`,75),J(6),R()}if(e&2){let e=G(3);k(6),Y(e.actionMessage())}}function BP(e,t){if(e&1){let e=H();L(0,`button`,77),U(`click`,function(){let t=T(e).$implicit;return E(G(5).showForm.emit(t.formId))}),J(1),R()}if(e&2){let e=t.$implicit;k(),X(` Show `,e.label,` in Forms `)}}function VP(e,t){if(e&1&&(L(0,`div`,70),P(1,BP,2,1,`button`,76,dP),R()),e&2){let e=G(),t=G(3);k(),F(t.formsIn(e.file))}}function HP(e,t){e&1&&M(0,VP,3,0,`div`,70),e&2&&N(G(3).formsIn(t.file).length?0:-1)}function UP(e,t){if(e&1){let e=H();L(0,`div`,70)(1,`button`,44),U(`click`,function(){T(e);let t=G();return E(G(2).openInjector(t))}),J(2,` Show in Injectors `),L(3,`span`,24),J(4),R()()()}if(e&2){let e=G();k(4),X(`: `,e.name)}}function WP(e,t){if(e&1&&z(0,`app-store-global`,71),e&2){let e=G(),t=G(2);I(`rpc`,t.rpc())(`pageId`,t.page()?.pageId)(`target`,hv(4,sP,e.id))(`label`,e.name)}}function GP(e,t){if(e&1&&(L(0,`dt`),J(1,`Routed`),R(),L(2,`dd`,79),J(3),R()),e&2){let e=t.$implicit;k(3),Z(``,e.route||`/`,` in outlet `,e.outlet)}}function KP(e,t){if(e&1&&(L(0,`span`,11),J(1),R()),e&2){let e=G(4);k(),Z(``,e.shownValues()?.count??0,` of `,e.valueTotal())}}function qP(e,t){if(e&1){let e=H();L(0,`div`,83)(1,`p`,42),J(2),R(),L(3,`p`,43),J(4,` The filter searches names, and the nested keys of values you opened. `),R(),L(5,`button`,44),U(`click`,function(){return T(e),E(G(5).clearPropFilter())}),J(6,`Clear filter`),R()()}if(e&2){let e=G(5);k(2),X(` No inputs, outputs or properties match “`,e.propFilter().trim(),`” `)}}function JP(e,t){if(e&1&&(L(0,`span`,87),J(1),R()),e&2){let e=G().$implicit;k(),X(`(`,e.prop,`)`)}}function YP(e,t){if(e&1&&(L(0,`li`,85)(1,`span`,86),J(2),M(3,JP,2,1,`span`,87),R(),z(4,`app-value-tree`,88),R()),e&2){let e=t.$implicit,n=G(4),r=G(3);k(2),X(` `,e.name,` `),k(),N(e.prop===e.name?-1:3),k(),I(`prop`,e)(`store`,r.values)(`query`,r.propFilter())(`componentId`,n.id)(`pageId`,r.page()?.pageId??null)(`rpc`,r.rpc())(`writes`,r.canEdit())}}function XP(e,t){if(e&1&&(L(0,`ul`,84),P(1,YP,5,9,`li`,85,pP),R()),e&2){let e=G(2);k(),F(e.inputs)}}function ZP(e,t){e&1&&(L(0,`p`,67),J(1,`No inputs.`),R())}function QP(e,t){if(e&1&&(L(0,`div`,63)(1,`h3`),J(2,` Inputs `),L(3,`span`,64),J(4),R()(),M(5,XP,3,0,`ul`,84)(6,ZP,2,0,`p`,67),R()),e&2){let e=G();k(4),Y(e.inputs.length),k(),N(e.inputs.length?5:6)}}function $P(e,t){if(e&1&&(L(0,`li`,90)(1,`span`,79),J(2),R(),L(3,`span`,91),J(4),R()()),e&2){let e=t.$implicit;q(`on`,e.listened),k(2),Y(e.name),k(2),Y(e.listened?`listened`:`no listener`)}}function eF(e,t){if(e&1&&(L(0,`ul`,65),P(1,$P,5,4,`li`,89,pP),R()),e&2){let e=G(2);k(),F(e.outputs)}}function tF(e,t){e&1&&(L(0,`p`,67),J(1,`No outputs.`),R())}function nF(e,t){if(e&1&&(L(0,`div`,63)(1,`h3`),J(2,` Outputs `),L(3,`span`,64),J(4),R()(),M(5,eF,3,0,`ul`,65)(6,tF,2,0,`p`,67),R()),e&2){let e=G();k(4),Y(e.outputs.length),k(),N(e.outputs.length?5:6)}}function rF(e,t){if(e&1&&(L(0,`span`,92),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.kind)}}function iF(e,t){if(e&1&&(L(0,`li`,85)(1,`span`,86),J(2),M(3,rF,2,1,`span`,92),R(),z(4,`app-value-tree`,88),R()),e&2){let e=t.$implicit,n=G(4),r=G(3);k(2),X(` `,e.name,` `),k(),N(e.kind?3:-1),k(),I(`prop`,e)(`store`,r.values)(`query`,r.propFilter())(`componentId`,n.id)(`pageId`,r.page()?.pageId??null)(`rpc`,r.rpc())(`writes`,r.canEdit())}}function aF(e,t){if(e&1&&(L(0,`ul`,84),P(1,iF,5,9,`li`,85,pP),R()),e&2){let e=G(2);k(),F(e.properties)}}function oF(e,t){e&1&&(L(0,`p`,67),J(1,`No other properties.`),R())}function sF(e,t){if(e&1&&(L(0,`div`,63)(1,`h3`),J(2,` Properties `),L(3,`span`,64),J(4),R()(),M(5,aF,3,0,`ul`,84)(6,oF,2,0,`p`,67),R()),e&2){let e=G();k(4),Y(e.properties.length),k(),N(e.properties.length?5:6)}}function cF(e,t){if(e&1&&(L(0,`li`,66),J(1),R()),e&2){let e=t.$implicit;k(),Y(e)}}function lF(e,t){if(e&1&&(L(0,`div`,63)(1,`h3`),J(2,` DOM listeners `),L(3,`span`,64),J(4),R()(),L(5,`ul`,65),P(6,cF,2,1,`li`,66,Ag),R()()),e&2){let e=G(2);k(4),Y(e.listeners.length),k(2),F(e.listeners)}}function uF(e,t){if(e&1&&(L(0,`li`,85)(1,`span`,86),J(2),R(),z(3,`app-value-tree`,93),R()),e&2){let e=t.$implicit,n=G(2).$implicit,r=G(2),i=G(3);k(2),Y(e.name),k(),I(`prop`,e)(`store`,i.values)(`query`,i.propFilter())(`directive`,n.index)(`componentId`,r.id)(`pageId`,i.page()?.pageId??null)(`rpc`,i.rpc())}}function dF(e,t){if(e&1&&(L(0,`ul`,84),P(1,uF,4,8,`li`,85,pP),R()),e&2){let e=G().$implicit;k(),F(e.inputs)}}function fF(e,t){if(e&1&&(L(0,`li`,90)(1,`span`,79),J(2),R(),L(3,`span`,91),J(4),R()()),e&2){let e=t.$implicit;q(`on`,e.listened),k(2),Y(e.name),k(2),Y(e.listened?`listened`:`no listener`)}}function pF(e,t){if(e&1&&(L(0,`ul`,65),P(1,fF,5,4,`li`,89,pP),R()),e&2){let e=G().$implicit;k(),F(e.outputs)}}function mF(e,t){e&1&&(L(0,`p`,67),J(1,`No inputs or outputs.`),R())}function hF(e,t){if(e&1&&(L(0,`div`,63)(1,`h3`)(2,`span`,79),J(3),R(),L(4,`span`,92),J(5,`directive on host`),R()(),M(6,dF,3,0,`ul`,84),M(7,pF,3,0,`ul`,65),M(8,mF,2,0,`p`,67),R()),e&2){let e=t.$implicit;k(3),Y(e.name),k(3),N(e.inputs.length?6:-1),k(),N(e.outputs.length?7:-1),k(),N(!e.inputs.length&&!e.outputs.length?8:-1)}}function gF(e,t){if(e&1&&(M(0,qP,7,1,`div`,83),M(1,QP,7,2,`div`,63),M(2,nF,7,2,`div`,63),M(3,sF,7,2,`div`,63),M(4,lF,8,1,`div`,63),P(5,hF,9,4,`div`,63,fP)),e&2){let e=t,n=G(),r=G(3);N(r.propQuery()&&!e.count?0:-1),k(),N(!r.propQuery()||e.inputs.length?1:-1),k(),N(!r.propQuery()||e.outputs.length?2:-1),k(),N(!r.propQuery()||e.properties.length?3:-1),k(),N(!r.propQuery()&&n.listeners.length?4:-1),k(),F(e.directives)}}function _F(e,t){if(e&1&&(L(0,`span`,92),J(1),R()),e&2){let e=t.$implicit;k(),Y(e)}}function vF(e,t){if(e&1&&(L(0,`span`,96),J(1,`from `),L(2,`span`,79),J(3),R()()),e&2){let e=G().$implicit;k(3),Y(e.providedByName??`an injector`)}}function yF(e,t){e&1&&(L(0,`span`,97),J(1,`not provided`),R())}function bF(e,t){if(e&1&&(L(0,`li`,94)(1,`span`,95),J(2),R(),P(3,_F,2,1,`span`,92,Ag),M(5,vF,4,1,`span`,96)(6,yF,2,0,`span`,97),R()),e&2){let e=t.$implicit;k(2),Y(e.token),k(),F(e.flags),k(2),N(e.providedBy?5:6)}}function xF(e,t){if(e&1&&(L(0,`ul`,82),P(1,bF,7,2,`li`,94,mP),R()),e&2){let e=G();k(),F(e.dependencies)}}function SF(e,t){e&1&&(L(0,`p`,67),J(1,`Nothing is injected through the constructor or inject().`),R())}function CF(e,t){if(e&1){let e=H();L(0,`dl`,78)(1,`dt`),J(2,`Change detection`),R(),L(3,`dd`),J(4),R(),L(5,`dt`),J(6,`Encapsulation`),R(),L(7,`dd`),J(8),R(),L(9,`dt`),J(10,`Host path`),R(),L(11,`dd`,79),J(12),R(),P(13,GP,4,2,null,null,lP),R(),L(15,`div`,80)(16,`div`,5),D(),L(17,`svg`,6),z(18,`circle`,7)(19,`path`,8),R(),_s(),L(20,`input`,81,2),U(`input`,function(t){return T(e),E(G(3).propFilter.set(t.target.value))})(`keydown.escape`,function(t){return T(e),E(G(3).clearPropFilter(t))}),R()(),M(22,KP,2,2,`span`,11),L(23,`p`,20),J(24),R()(),M(25,gF,7,5),L(26,`div`,63)(27,`h3`),J(28,` Injected `),L(29,`span`,64),J(30),R()(),M(31,xF,3,0,`ul`,82)(32,SF,2,0,`p`,67),R()}if(e&2){let e,n=t,r=G(),i=G(2);k(4),Y(n.changeDetection??`Unknown`),k(4),Y(n.encapsulation??`Unknown`),k(4),Y(n.path),k(),F(i.routedById().get(r.id)??mv(9,oP)),k(7),I(`value`,i.propFilter()),k(2),N(i.propQuery()?22:-1),k(2),Y(i.propFilterStatus()),k(),N((e=i.shownValues())?25:-1,e),k(5),Y(n.dependencies.length),k(),N(n.dependencies.length?31:32)}}function wF(e,t){e&1&&(L(0,`div`,72),z(1,`span`,98),L(2,`p`,43),J(3,`Reading live values from the page…`),R()())}function TF(e,t){if(e&1&&(L(0,`section`,29)(1,`header`,59)(2,`span`,60),J(3,`component`),R(),L(4,`h2`,61),J(5),R(),L(6,`span`,62),J(7),R(),M(8,RP,2,2,`p`,69),M(9,zP,7,1),M(10,HP,1,1),M(11,UP,5,1,`div`,70),M(12,WP,1,6,`app-store-global`,71),R(),M(13,CF,33,10)(14,wF,4,0,`div`,72),R()),e&2){let e,n,r,i=t,a=G(2);k(5),Y(i.name),k(2),X(`<`,i.tag,`>`),k(),N((e=a.whereOf(i))?8:-1,e),k(),N(a.devtoolsActions()?9:-1),k(),N((n=a.sourceFor(i))?10:-1,n),k(),N(a.canShowInjector()&&!a.staticReport()?11:-1),k(),N(!a.staticReport()&&!a.native()?12:-1),k(),N((r=a.detail())?13:14,r)}}function EF(e,t){e&1&&(L(0,`p`,42),J(1,`The selected component was destroyed`),R(),L(2,`p`,43)(3,`span`,79),J(4),R(),J(5,` is no longer on the page. Select another component to see its live values. `),R()),e&2&&(k(4),Y(t))}function DF(e,t){e&1&&(L(0,`p`,43),J(1,` Select a component to see its live inputs, properties, outputs, change detection and injected services. `),R())}function OF(e,t){if(e&1&&(L(0,`div`,30),M(1,EF,6,1)(2,DF,2,0,`p`,43),R()),e&2){let e,t=G(2);k(),N((e=t.destroyed())?1:2,e)}}function kF(e,t){e&1&&(L(0,`span`,92),J(1,`hydrate never`),R())}function AF(e,t){if(e&1&&(L(0,`span`,92),J(1),R()),e&2){let e=G().$implicit;k(),Y(e.hydration)}}function jF(e,t){if(e&1){let e=H();L(0,`li`)(1,`button`,101),U(`click`,function(){let t=T(e).$implicit;return E(G(3).showOwner(t))})(`focus`,function(){let t=T(e).$implicit;return E(G(3).highlightBlock(t))})(`blur`,function(){return T(e),E(G(3).highlight(null))})(`mouseenter`,function(){let t=T(e).$implicit;return E(G(3).highlightBlock(t))})(`mouseleave`,function(){return T(e),E(G(3).highlight(null))}),L(2,`span`,57),J(3),R(),L(4,`span`,102),J(5),R(),M(6,kF,2,0,`span`,92)(7,AF,2,1,`span`,92),L(8,`span`,103),J(9),R()()()}if(e&2){let e=t.$implicit;k(),j(`aria-disabled`,e.owner?null:`true`),k(2),Y(e.owner?.name??`Unknown component`),k(),M_(`defer-state-`+e.state),k(),Y(e.state),k(),N(e.hydrateNever?6:e.hydration===`not-configured`?-1:7),k(3),Y(e.triggers.join(`, `)||`no triggers`)}}function MF(e,t){if(e&1&&(L(0,`section`,31)(1,`h2`,99),J(2,` Defer blocks `),L(3,`span`,64),J(4),R()(),L(5,`ul`,100),P(6,jF,10,7,`li`,null,hP),R()()),e&2){let e=G(2);k(4),Y(e.deferCount()),k(2),F(e.deferBlocks())}}function NF(e,t){e&1&&z(0,`app-angular-unavailable`,32),e&2&&I(`page`,G(2).angularPage())}function PF(e,t){if(e&1){let e=H();L(0,`app-hydration-section`,104),U(`overlay`,function(t){return T(e),E(G(2).setHydrationOverlay(t))})(`showNode`,function(t){return T(e),E(G(2).revealNode(t))})(`highlight`,function(t){return T(e),E(G(2).highlight(t))}),R()}e&2&&I(`report`,G(2).page()?.hydration)}function FF(e,t){if(e&1){let e=H();L(0,`app-cd-recording`,105),U(`showComponent`,function(t){return T(e),E(G(2).showCdComponent(t))}),R(),L(1,`app-leaks-section`,106),U(`showComponent`,function(t){return T(e),E(G(2).revealNode(t))})(`highlight`,function(t){return T(e),E(G(2).highlight(t))}),R()}if(e&2){let e=G(2);I(`page`,e.cdPage())(`pageId`,e.page().pageId)(`rpc`,e.rpc()),k(),I(`report`,e.leaksPage())(`pageId`,e.page().pageId)(`rpc`,e.rpc())(`angular`,e.angularPage())}}function IF(e,t){if(e&1){let e=H();L(0,`p`,3),J(1,` Every component instance on the page, in the order Angular rendered them. Hover a row to highlight its host in the page, and select it to read its live inputs, properties, outputs and injected services. `),R(),L(2,`div`,4)(3,`div`,5),D(),L(4,`svg`,6),z(5,`circle`,7)(6,`path`,8),R(),_s(),L(7,`input`,9,0),U(`input`,function(t){return T(e),E(G().setFilter(t.target.value))})(`keydown.escape`,function(){return T(e),E(G().setFilter(``))}),R(),L(9,`span`,10),J(10,` Type plain text, a tag such as