@songram/songram-daw-engine 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../songram-daw/src/core/constants.ts","../../songram-daw/src/core/types/clip.ts","../../songram-daw/src/core/types/index.ts","../../songram-daw/src/core/utils/conversions.ts","../../songram-daw/src/core/utils/beatsAndBars.ts","../../songram-daw/src/core/utils/dBUtils.ts","../../songram-daw/src/core/clipTimeHelpers.ts","../../songram-daw/src/engine/operations/clipOperations.ts","../../songram-daw/src/engine/operations/viewportOperations.ts","../../songram-daw/src/engine/operations/timelineOperations.ts","../../songram-daw/src/engine/PlaylistEngine.ts","../../songram-daw/src/playout/fades.ts","../../songram-daw/src/playout/ToneTrack.ts","../../songram-daw/src/playout/MidiToneTrack.ts","../../songram-daw/src/playout/SoundFontToneTrack.ts","../../songram-daw/src/playout/TonePlayout.ts","../../songram-daw/src/playout/SoundFontCache.ts","../../songram-daw/src/playout/audioContext.ts","../../songram-daw/src/playout/mediaStreamSourceManager.ts","../../songram-daw/src/playout/TonePlayoutAdapter.ts","../../node_modules/.pnpm/midi-file@1.2.4/node_modules/midi-file/lib/midi-parser.js","../../node_modules/.pnpm/midi-file@1.2.4/node_modules/midi-file/lib/midi-writer.js","../../node_modules/.pnpm/midi-file@1.2.4/node_modules/midi-file/index.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/BinarySearch.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/Header.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/ControlChange.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/ControlChanges.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/PitchBend.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/InstrumentMaps.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/Instrument.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/Note.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/Track.js","../../node_modules/.pnpm/array-flatten@3.0.0/node_modules/array-flatten/dist.es2015/index.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/Encode.js","../../node_modules/.pnpm/@tonejs+midi@2.0.28/node_modules/@tonejs/midi/dist/Midi.js","../src/audio/midiParser.ts","../src/audio/midiController.ts","../src/events/EventBus.ts","../src/plugins/PluginHost.ts","../src/core/SongramEngine.ts"],"sourcesContent":["/**\n * Maximum width in CSS pixels for a single canvas chunk.\n * Canvas elements are split into chunks of this width to enable\n * horizontal virtual scrolling — only visible chunks are mounted.\n */\nexport const MAX_CANVAS_WIDTH = 1000;\n","/**\n * Clip-Based Model Types\n *\n * These types support a professional multi-track editing model where:\n * - Each track can contain multiple audio clips\n * - Clips can be positioned anywhere on the timeline\n * - Clips have independent trim points (offset/duration)\n * - Gaps between clips are silent\n * - Clips can overlap (for crossfades)\n */\n\nimport { Fade } from './index';\nimport type { RenderMode, SpectrogramConfig, ColorMapValue } from './spectrogram';\n\n/**\n * WaveformData object from waveform-data.js library.\n * Supports resample() and slice() for dynamic zoom levels.\n * See: https://github.com/bbc/waveform-data.js\n */\nexport interface WaveformDataObject {\n /** Sample rate of the original audio */\n readonly sample_rate: number;\n /** Number of audio samples per pixel */\n readonly scale: number;\n /** Length of waveform data in pixels */\n readonly length: number;\n /** Bit depth (8 or 16) */\n readonly bits: number;\n /** Duration in seconds */\n readonly duration: number;\n /** Number of channels */\n readonly channels: number;\n /** Get channel data */\n channel: (index: number) => {\n min_array: () => number[];\n max_array: () => number[];\n };\n /** Resample to different scale */\n resample: (options: { scale: number } | { width: number }) => WaveformDataObject;\n /** Slice a portion of the waveform */\n slice: (\n options: { startTime: number; endTime: number } | { startIndex: number; endIndex: number }\n ) => WaveformDataObject;\n}\n\n/**\n * Generic effects function type for track-level audio processing.\n *\n * The actual implementation receives Tone.js audio nodes. Using generic types\n * here to avoid circular dependencies with the playout package.\n *\n * @param graphEnd - The end of the track's audio graph (Tone.js Gain node)\n * @param destination - Where to connect the effects output (Tone.js ToneAudioNode)\n * @param isOffline - Whether rendering offline (for export)\n * @returns Optional cleanup function called when track is disposed\n *\n * @example\n * ```typescript\n * const trackEffects: TrackEffectsFunction = (graphEnd, destination, isOffline) => {\n * const reverb = new Tone.Reverb({ decay: 1.5 });\n * graphEnd.connect(reverb);\n * reverb.connect(destination);\n *\n * return () => {\n * reverb.dispose();\n * };\n * };\n * ```\n */\nexport type TrackEffectsFunction = (\n graphEnd: unknown,\n destination: unknown,\n isOffline: boolean\n) => void | (() => void);\n\n/**\n * Represents a single audio clip on the timeline\n *\n * IMPORTANT: All positions/durations are stored as SAMPLE COUNTS (integers)\n * to avoid floating-point precision errors. Convert to seconds only when\n * needed for playback using: seconds = samples / sampleRate\n *\n * Clips can be created with just waveformData (for instant visual rendering)\n * and have audioBuffer added later when audio finishes loading.\n */\nexport interface AudioClip {\n /** Unique identifier for this clip */\n id: string;\n\n /**\n * The audio buffer containing the audio data.\n * Optional for peaks-first rendering - can be added later.\n * Required for playback and editing operations.\n */\n audioBuffer?: AudioBuffer;\n\n /** Position on timeline where this clip starts (in samples at timeline sampleRate) */\n startSample: number;\n\n /** Duration of this clip (in samples) - how much of the audio buffer to play */\n durationSamples: number;\n\n /** Offset into the audio buffer where playback starts (in samples) - the \"trim start\" point */\n offsetSamples: number;\n\n /**\n * Sample rate for this clip's audio.\n * Required when audioBuffer is not provided (for peaks-first rendering).\n * When audioBuffer is present, this should match audioBuffer.sampleRate.\n */\n sampleRate: number;\n\n /**\n * Total duration of the source audio in samples.\n * Required when audioBuffer is not provided (for trim bounds calculation).\n * When audioBuffer is present, this should equal audioBuffer.length.\n */\n sourceDurationSamples: number;\n\n /** Optional fade in effect */\n fadeIn?: Fade;\n\n /** Optional fade out effect */\n fadeOut?: Fade;\n\n /** Clip-specific gain/volume multiplier (0.0 to 1.0+) */\n gain: number;\n\n /** Optional label/name for this clip */\n name?: string;\n\n /** Optional color for visual distinction */\n color?: string;\n\n /**\n * Pre-computed waveform data from waveform-data.js library.\n * When provided, the library will use this instead of computing peaks from the audioBuffer.\n * Supports resampling to different zoom levels and slicing for clip trimming.\n * Load with: `const waveformData = await loadWaveformData('/path/to/peaks.dat')`\n */\n waveformData?: WaveformDataObject;\n\n /**\n * MIDI note data — when present, this clip plays MIDI instead of audio.\n * The playout adapter uses this field to detect MIDI clips and route them\n * to MidiToneTrack (PolySynth) instead of ToneTrack (AudioBufferSourceNode).\n */\n midiNotes?: MidiNoteData[];\n\n /** MIDI channel (0-indexed). Channel 9 = GM percussion. */\n midiChannel?: number;\n\n /** MIDI program number (0-127). GM instrument number for SoundFont playback. */\n midiProgram?: number;\n}\n\n/**\n * Represents a track containing multiple audio clips\n */\nexport interface ClipTrack {\n /** Unique identifier for this track */\n id: string;\n\n /** Display name for this track */\n name: string;\n\n /** Array of audio clips on this track */\n clips: AudioClip[];\n\n /** Whether this track is muted */\n muted: boolean;\n\n /** Whether this track is soloed */\n soloed: boolean;\n\n /** Track volume (0.0 to 1.0+) */\n volume: number;\n\n /** Stereo pan (-1.0 = left, 0 = center, 1.0 = right) */\n pan: number;\n\n /** Optional track color for visual distinction */\n color?: string;\n\n /** Track height in pixels (for UI) */\n height?: number;\n\n /** Optional effects function for this track */\n effects?: TrackEffectsFunction;\n\n /** Visualization render mode. Default: 'waveform' */\n renderMode?: RenderMode;\n\n /** Per-track spectrogram configuration (FFT size, window, frequency scale, etc.) */\n spectrogramConfig?: SpectrogramConfig;\n\n /** Per-track spectrogram color map name or custom color array */\n spectrogramColorMap?: ColorMapValue;\n}\n\n/**\n * Represents the entire timeline/project\n */\nexport interface Timeline {\n /** All tracks in the timeline */\n tracks: ClipTrack[];\n\n /** Total timeline duration in seconds */\n duration: number;\n\n /** Sample rate for all audio (typically 44100 or 48000) */\n sampleRate: number;\n\n /** Optional project name */\n name?: string;\n\n /** Optional tempo (BPM) for grid snapping */\n tempo?: number;\n\n /** Optional time signature for grid snapping */\n timeSignature?: {\n numerator: number;\n denominator: number;\n };\n}\n\n/**\n * Options for creating a new audio clip (using sample counts)\n *\n * Either audioBuffer OR (sampleRate + sourceDurationSamples + waveformData) must be provided.\n * Providing waveformData without audioBuffer enables peaks-first rendering.\n */\nexport interface CreateClipOptions {\n /** Audio buffer - optional for peaks-first rendering */\n audioBuffer?: AudioBuffer;\n startSample: number; // Position on timeline (in samples)\n durationSamples?: number; // Defaults to full buffer/source duration (in samples)\n offsetSamples?: number; // Defaults to 0\n gain?: number; // Defaults to 1.0\n name?: string;\n color?: string;\n fadeIn?: Fade;\n fadeOut?: Fade;\n /** Pre-computed waveform data from waveform-data.js (e.g., from BBC audiowaveform) */\n waveformData?: WaveformDataObject;\n /** Sample rate - required if audioBuffer not provided */\n sampleRate?: number;\n /** Total source audio duration in samples - required if audioBuffer not provided */\n sourceDurationSamples?: number;\n /** MIDI note data — passed through to the created AudioClip */\n midiNotes?: MidiNoteData[];\n /** MIDI channel (0-indexed). Channel 9 = GM percussion. */\n midiChannel?: number;\n /** MIDI program number (0-127). GM instrument for SoundFont playback. */\n midiProgram?: number;\n}\n\n/**\n * Options for creating a new audio clip (using seconds for convenience)\n *\n * Either audioBuffer OR (sampleRate + sourceDuration + waveformData) must be provided.\n * Providing waveformData without audioBuffer enables peaks-first rendering.\n */\nexport interface CreateClipOptionsSeconds {\n /** Audio buffer - optional for peaks-first rendering */\n audioBuffer?: AudioBuffer;\n startTime: number; // Position on timeline (in seconds)\n duration?: number; // Defaults to full buffer/source duration (in seconds)\n offset?: number; // Defaults to 0 (in seconds)\n gain?: number; // Defaults to 1.0\n name?: string;\n color?: string;\n fadeIn?: Fade;\n fadeOut?: Fade;\n /** Pre-computed waveform data from waveform-data.js (e.g., from BBC audiowaveform) */\n waveformData?: WaveformDataObject;\n /** Sample rate - required if audioBuffer not provided */\n sampleRate?: number;\n /** Total source audio duration in seconds - required if audioBuffer not provided */\n sourceDuration?: number;\n /** MIDI note data — passed through to the created AudioClip */\n midiNotes?: MidiNoteData[];\n /** MIDI channel (0-indexed). Channel 9 = GM percussion. */\n midiChannel?: number;\n /** MIDI program number (0-127). GM instrument for SoundFont playback. */\n midiProgram?: number;\n}\n\n/**\n * Options for creating a new track\n */\nexport interface CreateTrackOptions {\n name: string;\n clips?: AudioClip[];\n muted?: boolean;\n soloed?: boolean;\n volume?: number;\n pan?: number;\n color?: string;\n height?: number;\n spectrogramConfig?: SpectrogramConfig;\n spectrogramColorMap?: ColorMapValue;\n}\n\n/**\n * Creates a new AudioClip with sensible defaults (using sample counts)\n *\n * For peaks-first rendering (no audioBuffer), sampleRate and sourceDurationSamples can be:\n * - Provided explicitly via options\n * - Derived from waveformData (sample_rate and duration properties)\n */\nexport function createClip(options: CreateClipOptions): AudioClip {\n const {\n audioBuffer,\n startSample,\n offsetSamples = 0,\n gain = 1.0,\n name,\n color,\n fadeIn,\n fadeOut,\n waveformData,\n midiNotes,\n midiChannel,\n midiProgram,\n } = options;\n\n // Determine sample rate: audioBuffer > explicit option > waveformData\n const sampleRate = audioBuffer?.sampleRate ?? options.sampleRate ?? waveformData?.sample_rate;\n\n // Determine source duration: audioBuffer > explicit option > waveformData (converted to samples)\n const sourceDurationSamples =\n audioBuffer?.length ??\n options.sourceDurationSamples ??\n (waveformData && sampleRate ? Math.ceil(waveformData.duration * sampleRate) : undefined);\n\n if (sampleRate === undefined) {\n throw new Error(\n 'createClip: sampleRate is required when audioBuffer is not provided (can use waveformData.sample_rate)'\n );\n }\n if (sourceDurationSamples === undefined) {\n throw new Error(\n 'createClip: sourceDurationSamples is required when audioBuffer is not provided (can use waveformData.duration)'\n );\n }\n\n // Warn if sample rates don't match\n if (audioBuffer && waveformData && audioBuffer.sampleRate !== waveformData.sample_rate) {\n console.warn(\n `Sample rate mismatch: audioBuffer (${audioBuffer.sampleRate}) vs waveformData (${waveformData.sample_rate}). ` +\n `Using audioBuffer sample rate. Waveform visualization may be slightly off.`\n );\n }\n\n // Default duration to full source duration\n const durationSamples = options.durationSamples ?? sourceDurationSamples;\n\n return {\n id: generateId(),\n audioBuffer,\n startSample,\n durationSamples,\n offsetSamples,\n sampleRate,\n sourceDurationSamples,\n gain,\n name,\n color,\n fadeIn,\n fadeOut,\n waveformData,\n midiNotes,\n midiChannel,\n midiProgram,\n };\n}\n\n/**\n * Creates a new AudioClip from time-based values (convenience function)\n * Converts seconds to samples using the audioBuffer's sampleRate or explicit sampleRate\n *\n * For peaks-first rendering (no audioBuffer), sampleRate and sourceDuration can be:\n * - Provided explicitly via options\n * - Derived from waveformData (sample_rate and duration properties)\n */\nexport function createClipFromSeconds(options: CreateClipOptionsSeconds): AudioClip {\n const {\n audioBuffer,\n startTime,\n offset = 0,\n gain = 1.0,\n name,\n color,\n fadeIn,\n fadeOut,\n waveformData,\n midiNotes,\n midiChannel,\n midiProgram,\n } = options;\n\n // Determine sample rate: audioBuffer > explicit option > waveformData\n const sampleRate = audioBuffer?.sampleRate ?? options.sampleRate ?? waveformData?.sample_rate;\n if (sampleRate === undefined) {\n throw new Error(\n 'createClipFromSeconds: sampleRate is required when audioBuffer is not provided (can use waveformData.sample_rate)'\n );\n }\n\n // Determine source duration: audioBuffer > explicit option > waveformData\n const sourceDuration = audioBuffer?.duration ?? options.sourceDuration ?? waveformData?.duration;\n if (sourceDuration === undefined) {\n throw new Error(\n 'createClipFromSeconds: sourceDuration is required when audioBuffer is not provided (can use waveformData.duration)'\n );\n }\n\n // Warn if sample rates don't match (could cause visual/audio sync issues)\n if (audioBuffer && waveformData && audioBuffer.sampleRate !== waveformData.sample_rate) {\n console.warn(\n `Sample rate mismatch: audioBuffer (${audioBuffer.sampleRate}) vs waveformData (${waveformData.sample_rate}). ` +\n `Using audioBuffer sample rate. Waveform visualization may be slightly off.`\n );\n }\n\n // Default clip duration to full source duration\n const duration = options.duration ?? sourceDuration;\n\n return createClip({\n audioBuffer,\n startSample: Math.round(startTime * sampleRate),\n durationSamples: Math.round(duration * sampleRate),\n offsetSamples: Math.round(offset * sampleRate),\n sampleRate,\n sourceDurationSamples: Math.ceil(sourceDuration * sampleRate),\n gain,\n name,\n color,\n fadeIn,\n fadeOut,\n waveformData,\n midiNotes,\n midiChannel,\n midiProgram,\n });\n}\n\n/**\n * Creates a new ClipTrack with sensible defaults\n */\nexport function createTrack(options: CreateTrackOptions): ClipTrack {\n const {\n name,\n clips = [],\n muted = false,\n soloed = false,\n volume = 1.0,\n pan = 0,\n color,\n height,\n spectrogramConfig,\n spectrogramColorMap,\n } = options;\n\n return {\n id: generateId(),\n name,\n clips,\n muted,\n soloed,\n volume,\n pan,\n color,\n height,\n spectrogramConfig,\n spectrogramColorMap,\n };\n}\n\n/**\n * Creates a new Timeline with sensible defaults\n */\nexport function createTimeline(\n tracks: ClipTrack[],\n sampleRate: number = 44100,\n options?: {\n name?: string;\n tempo?: number;\n timeSignature?: { numerator: number; denominator: number };\n }\n): Timeline {\n // Calculate total duration from all clips across all tracks (in seconds)\n const durationSamples = tracks.reduce((maxSamples, track) => {\n const trackSamples = track.clips.reduce((max, clip) => {\n return Math.max(max, clip.startSample + clip.durationSamples);\n }, 0);\n return Math.max(maxSamples, trackSamples);\n }, 0);\n\n const duration = durationSamples / sampleRate;\n\n return {\n tracks,\n duration,\n sampleRate,\n name: options?.name,\n tempo: options?.tempo,\n timeSignature: options?.timeSignature,\n };\n}\n\n/**\n * Generates a unique ID for clips and tracks\n */\nfunction generateId(): string {\n return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n}\n\n/**\n * MIDI note data for clips that play MIDI instead of audio.\n * When present on an AudioClip, the clip is treated as a MIDI clip\n * by the playout adapter.\n */\nexport interface MidiNoteData {\n /** MIDI note number (0-127) */\n midi: number;\n /** Note name in scientific pitch notation (\"C4\", \"G#3\") */\n name: string;\n /** Start time in seconds, relative to clip start */\n time: number;\n /** Duration in seconds */\n duration: number;\n /** Velocity (0-1 normalized) */\n velocity: number;\n /** MIDI channel (0-indexed). Channel 9 = GM percussion. Enables per-note routing in flattened tracks. */\n channel?: number;\n}\n\n/**\n * Utility: Get all clips within a sample range\n */\nexport function getClipsInRange(\n track: ClipTrack,\n startSample: number,\n endSample: number\n): AudioClip[] {\n return track.clips.filter((clip) => {\n const clipEnd = clip.startSample + clip.durationSamples;\n // Clip overlaps with range if:\n // - Clip starts before range ends AND\n // - Clip ends after range starts\n return clip.startSample < endSample && clipEnd > startSample;\n });\n}\n\n/**\n * Utility: Get all clips at a specific sample position\n */\nexport function getClipsAtSample(track: ClipTrack, sample: number): AudioClip[] {\n return track.clips.filter((clip) => {\n const clipEnd = clip.startSample + clip.durationSamples;\n return sample >= clip.startSample && sample < clipEnd;\n });\n}\n\n/**\n * Utility: Check if two clips overlap\n */\nexport function clipsOverlap(clip1: AudioClip, clip2: AudioClip): boolean {\n const clip1End = clip1.startSample + clip1.durationSamples;\n const clip2End = clip2.startSample + clip2.durationSamples;\n\n return clip1.startSample < clip2End && clip1End > clip2.startSample;\n}\n\n/**\n * Utility: Sort clips by startSample\n */\nexport function sortClipsByTime(clips: AudioClip[]): AudioClip[] {\n return [...clips].sort((a, b) => a.startSample - b.startSample);\n}\n\n/**\n * Utility: Find gaps between clips (silent regions)\n */\nexport interface Gap {\n startSample: number;\n endSample: number;\n durationSamples: number;\n}\n\nexport function findGaps(track: ClipTrack): Gap[] {\n if (track.clips.length === 0) return [];\n\n const sorted = sortClipsByTime(track.clips);\n const gaps: Gap[] = [];\n\n for (let i = 0; i < sorted.length - 1; i++) {\n const currentClipEnd = sorted[i].startSample + sorted[i].durationSamples;\n const nextClipStart = sorted[i + 1].startSample;\n\n if (nextClipStart > currentClipEnd) {\n gaps.push({\n startSample: currentClipEnd,\n endSample: nextClipStart,\n durationSamples: nextClipStart - currentClipEnd,\n });\n }\n }\n\n return gaps;\n}\n","/**\n * Peaks type - represents a typed array of interleaved min/max peak data\n */\nexport type Peaks = Int8Array | Int16Array;\n\n/**\n * Bits type - number of bits for peak data\n */\nexport type Bits = 8 | 16;\n\n/**\n * PeakData - result of peak extraction\n */\nexport interface PeakData {\n /** Number of peak pairs extracted */\n length: number;\n /** Array of peak data for each channel (interleaved min/max) */\n data: Peaks[];\n /** Bit depth of peak data */\n bits: Bits;\n}\n\nexport interface WaveformConfig {\n sampleRate: number;\n samplesPerPixel: number;\n waveHeight?: number;\n waveOutlineColor?: string;\n waveFillColor?: string;\n waveProgressColor?: string;\n}\n\nexport interface AudioBuffer {\n length: number;\n duration: number;\n numberOfChannels: number;\n sampleRate: number;\n getChannelData(channel: number): Float32Array;\n}\n\nexport interface Track {\n id: string;\n name: string;\n src?: string | AudioBuffer; // Support both URL strings and AudioBuffer objects\n gain: number;\n muted: boolean;\n soloed: boolean;\n stereoPan: number;\n startTime: number;\n endTime?: number;\n fadeIn?: Fade;\n fadeOut?: Fade;\n cueIn?: number;\n cueOut?: number;\n}\n\n/**\n * Simple fade configuration\n */\nexport interface Fade {\n /** Duration of the fade in seconds */\n duration: number;\n /** Type of fade curve (default: 'linear') */\n type?: FadeType;\n}\n\nexport type FadeType = 'logarithmic' | 'linear' | 'sCurve' | 'exponential';\n\nexport interface PlaylistConfig {\n samplesPerPixel?: number;\n waveHeight?: number;\n container?: HTMLElement;\n isAutomaticScroll?: boolean;\n timescale?: boolean;\n colors?: {\n waveOutlineColor?: string;\n waveFillColor?: string;\n waveProgressColor?: string;\n };\n controls?: {\n show?: boolean;\n width?: number;\n };\n zoomLevels?: number[];\n}\n\nexport interface PlayoutState {\n isPlaying: boolean;\n isPaused: boolean;\n cursor: number;\n duration: number;\n}\n\nexport interface TimeSelection {\n start: number;\n end: number;\n}\n\nexport enum InteractionState {\n Cursor = 'cursor',\n Select = 'select',\n Shift = 'shift',\n FadeIn = 'fadein',\n FadeOut = 'fadeout',\n}\n\n// Export clip-based model types\nexport * from './clip';\n\n// Export spectrogram types\nexport * from './spectrogram';\n\n// Export annotation types\nexport * from './annotations';\n","export function samplesToSeconds(samples: number, sampleRate: number): number {\n return samples / sampleRate;\n}\n\nexport function secondsToSamples(seconds: number, sampleRate: number): number {\n return Math.ceil(seconds * sampleRate);\n}\n\nexport function samplesToPixels(samples: number, samplesPerPixel: number): number {\n return Math.floor(samples / samplesPerPixel);\n}\n\nexport function pixelsToSamples(pixels: number, samplesPerPixel: number): number {\n return Math.floor(pixels * samplesPerPixel);\n}\n\nexport function pixelsToSeconds(\n pixels: number,\n samplesPerPixel: number,\n sampleRate: number\n): number {\n return (pixels * samplesPerPixel) / sampleRate;\n}\n\nexport function secondsToPixels(\n seconds: number,\n samplesPerPixel: number,\n sampleRate: number\n): number {\n return Math.ceil((seconds * sampleRate) / samplesPerPixel);\n}\n","/** Default PPQN matching Tone.js Transport (192 ticks per quarter note) */\nexport const PPQN = 192;\n\n/** Number of PPQN ticks per beat for the given time signature. */\nexport function ticksPerBeat(timeSignature: [number, number], ppqn = PPQN): number {\n const [, denominator] = timeSignature;\n return ppqn * (4 / denominator);\n}\n\n/** Number of PPQN ticks per bar for the given time signature. */\nexport function ticksPerBar(timeSignature: [number, number], ppqn = PPQN): number {\n const [numerator] = timeSignature;\n return numerator * ticksPerBeat(timeSignature, ppqn);\n}\n\n/** Convert PPQN ticks to sample count. Uses Math.round for integer sample alignment. */\nexport function ticksToSamples(\n ticks: number,\n bpm: number,\n sampleRate: number,\n ppqn = PPQN\n): number {\n return Math.round((ticks * 60 * sampleRate) / (bpm * ppqn));\n}\n\n/** Convert sample count to PPQN ticks. Inverse of ticksToSamples. */\nexport function samplesToTicks(\n samples: number,\n bpm: number,\n sampleRate: number,\n ppqn = PPQN\n): number {\n return Math.round((samples * ppqn * bpm) / (60 * sampleRate));\n}\n\n/** Snap a tick position to the nearest grid line (rounds to nearest). */\nexport function snapToGrid(ticks: number, gridSizeTicks: number): number {\n return Math.round(ticks / gridSizeTicks) * gridSizeTicks;\n}\n\n/** Format ticks as a 1-indexed bar.beat label. Beat 1 shows bar number only (e.g., \"3\" not \"3.1\"). */\nexport function ticksToBarBeatLabel(\n ticks: number,\n timeSignature: [number, number],\n ppqn = PPQN\n): string {\n const barTicks = ticksPerBar(timeSignature, ppqn);\n const beatTicks = ticksPerBeat(timeSignature, ppqn);\n const bar = Math.floor(ticks / barTicks) + 1;\n const beatInBar = Math.floor((ticks % barTicks) / beatTicks) + 1;\n if (beatInBar === 1) return `${bar}`;\n return `${bar}.${beatInBar}`;\n}\n","const DEFAULT_FLOOR = -100;\n\n/**\n * Convert a dB value to a normalized range.\n *\n * Maps dB values linearly: floor → 0, 0 dB → 1.\n * Values above 0 dB map to > 1 (e.g., +5 dB → 1.05 with default floor).\n *\n * @param dB - Decibel value (typically -Infinity to +5)\n * @param floor - Minimum dB value mapped to 0. Default: -100 (Firefox compat)\n * @returns Normalized value (0 at floor, 1 at 0 dB, >1 above 0 dB)\n */\nexport function dBToNormalized(dB: number, floor: number = DEFAULT_FLOOR): number {\n if (Number.isNaN(dB)) {\n console.warn('[songram-daw] dBToNormalized received NaN');\n return 0;\n }\n if (floor >= 0) {\n console.warn('[songram-daw] dBToNormalized floor must be negative, got:', floor);\n return 0;\n }\n if (!isFinite(dB) || dB <= floor) return 0;\n return (dB - floor) / -floor;\n}\n\n/**\n * Convert a normalized value back to dB.\n *\n * Maps linearly: 0 → floor, 1 → 0 dB.\n * Values above 1 map to positive dB (e.g., 1.05 → +5 dB with default floor).\n *\n * @param normalized - Normalized value (0 = floor, 1 = 0 dB)\n * @param floor - Minimum dB value (maps from 0). Must be negative. Default: -100\n * @returns dB value (floor at 0, 0 dB at 1, positive dB above 1)\n */\nexport function normalizedToDb(normalized: number, floor: number = DEFAULT_FLOOR): number {\n if (!isFinite(normalized)) return floor;\n if (floor >= 0) {\n console.warn('[songram-daw] normalizedToDb floor must be negative, got:', floor);\n return DEFAULT_FLOOR;\n }\n const clamped = Math.max(0, normalized);\n return clamped * -floor + floor;\n}\n\n/**\n * Convert a linear gain value (0-1+) to normalized 0-1 via dB.\n *\n * Combines gain-to-dB (20 * log10) with dBToNormalized for a consistent\n * mapping from raw AudioWorklet peak/RMS values to the 0-1 range used\n * by UI meter components.\n *\n * @param gain - Linear gain value (typically 0 to 1, can exceed 1)\n * @param floor - Minimum dB value mapped to 0. Default: -100\n * @returns Normalized value (0 at silence/floor, 1 at 0 dB, >1 above 0 dB)\n */\nexport function gainToNormalized(gain: number, floor: number = DEFAULT_FLOOR): number {\n if (gain <= 0) return 0;\n const db = 20 * Math.log10(gain);\n return dBToNormalized(db, floor);\n}\n","import type { AudioClip } from './types';\n\n/** Clip start position in seconds */\nexport function clipStartTime(clip: AudioClip): number {\n return clip.startSample / clip.sampleRate;\n}\n\n/** Clip end position in seconds (start + duration) */\nexport function clipEndTime(clip: AudioClip): number {\n return (clip.startSample + clip.durationSamples) / clip.sampleRate;\n}\n\n/** Clip offset into source audio in seconds */\nexport function clipOffsetTime(clip: AudioClip): number {\n return clip.offsetSamples / clip.sampleRate;\n}\n\n/** Clip duration in seconds */\nexport function clipDurationTime(clip: AudioClip): number {\n return clip.durationSamples / clip.sampleRate;\n}\n\n/**\n * Clip width in pixels at a given samplesPerPixel.\n * Shared by Clip.tsx (container sizing) and ChannelWithProgress.tsx (progress overlay)\n * to ensure pixel-perfect alignment. Floor-based endpoint subtraction guarantees\n * adjacent clips have no pixel gaps.\n */\nexport function clipPixelWidth(\n startSample: number,\n durationSamples: number,\n samplesPerPixel: number\n): number {\n return (\n Math.floor((startSample + durationSamples) / samplesPerPixel) -\n Math.floor(startSample / samplesPerPixel)\n );\n}\n","/**\n * Clip Operations\n *\n * Pure functions for constraining clip movement, boundary trimming,\n * and splitting clips on a timeline. All positions are in samples (integers).\n */\n\nimport type { AudioClip } from '../../core';\nimport { createClip } from '../../core';\n\n/**\n * Constrain clip movement delta to prevent overlaps with adjacent clips\n * and going before sample 0.\n *\n * @param clip - The clip being dragged\n * @param deltaSamples - Requested movement in samples (negative = left, positive = right)\n * @param sortedClips - All clips on the track, sorted by startSample\n * @param clipIndex - Index of the dragged clip in sortedClips\n * @returns Constrained delta that prevents overlaps\n */\nexport function constrainClipDrag(\n clip: AudioClip,\n deltaSamples: number,\n sortedClips: AudioClip[],\n clipIndex: number\n): number {\n let delta = deltaSamples;\n\n // Constraint 1: Cannot go before sample 0\n const minDelta = -clip.startSample;\n delta = Math.max(delta, minDelta);\n\n // Constraint 2: Cannot overlap previous clip\n if (clipIndex > 0) {\n const prevClip = sortedClips[clipIndex - 1];\n const prevClipEnd = prevClip.startSample + prevClip.durationSamples;\n // clip.startSample + delta >= prevClipEnd\n const minDeltaPrev = prevClipEnd - clip.startSample;\n delta = Math.max(delta, minDeltaPrev);\n }\n\n // Constraint 3: Cannot overlap next clip\n if (clipIndex < sortedClips.length - 1) {\n const nextClip = sortedClips[clipIndex + 1];\n // clip.startSample + clip.durationSamples + delta <= nextClip.startSample\n const maxDeltaNext = nextClip.startSample - (clip.startSample + clip.durationSamples);\n delta = Math.min(delta, maxDeltaNext);\n }\n\n return delta;\n}\n\n/**\n * Constrain boundary trim delta for left or right edge of a clip.\n *\n * LEFT boundary: delta moves the left edge (positive = shrink, negative = expand)\n * - startSample += delta, offsetSamples += delta, durationSamples -= delta\n *\n * RIGHT boundary: delta applied to durationSamples (positive = expand, negative = shrink)\n * - durationSamples += delta\n *\n * @param clip - The clip being trimmed\n * @param deltaSamples - Requested trim delta in samples\n * @param boundary - Which edge is being trimmed: 'left' or 'right'\n * @param sortedClips - All clips on the track, sorted by startSample\n * @param clipIndex - Index of the trimmed clip in sortedClips\n * @param minDurationSamples - Minimum allowed clip duration in samples\n * @returns Constrained delta\n */\nexport function constrainBoundaryTrim(\n clip: AudioClip,\n deltaSamples: number,\n boundary: 'left' | 'right',\n sortedClips: AudioClip[],\n clipIndex: number,\n minDurationSamples: number\n): number {\n let delta = deltaSamples;\n\n if (boundary === 'left') {\n // Constraint 1: startSample + delta >= 0\n delta = Math.max(delta, -clip.startSample);\n\n // Constraint 2: offsetSamples + delta >= 0\n delta = Math.max(delta, -clip.offsetSamples);\n\n // Constraint 3: Cannot overlap previous clip\n if (clipIndex > 0) {\n const prevClip = sortedClips[clipIndex - 1];\n const prevClipEnd = prevClip.startSample + prevClip.durationSamples;\n // startSample + delta >= prevClipEnd\n delta = Math.max(delta, prevClipEnd - clip.startSample);\n }\n\n // Constraint 4: durationSamples - delta >= minDurationSamples\n // delta <= durationSamples - minDurationSamples\n delta = Math.min(delta, clip.durationSamples - minDurationSamples);\n } else {\n // RIGHT boundary\n\n // Constraint 1: durationSamples + delta >= minDurationSamples\n // delta >= minDurationSamples - durationSamples\n delta = Math.max(delta, minDurationSamples - clip.durationSamples);\n\n // Constraint 2: offsetSamples + (durationSamples + delta) <= sourceDurationSamples\n // delta <= sourceDurationSamples - offsetSamples - durationSamples\n delta = Math.min(delta, clip.sourceDurationSamples - clip.offsetSamples - clip.durationSamples);\n\n // Constraint 3: startSample + (durationSamples + delta) <= nextClip.startSample\n if (clipIndex < sortedClips.length - 1) {\n const nextClip = sortedClips[clipIndex + 1];\n // delta <= nextClip.startSample - startSample - durationSamples\n delta = Math.min(delta, nextClip.startSample - clip.startSample - clip.durationSamples);\n }\n }\n\n return delta;\n}\n\n/**\n * Snap a split sample position to the nearest pixel boundary.\n *\n * @param splitSample - The sample position to snap\n * @param samplesPerPixel - Current zoom level (samples per pixel)\n * @returns Snapped sample position\n */\nexport function calculateSplitPoint(splitSample: number, samplesPerPixel: number): number {\n return Math.floor(splitSample / samplesPerPixel) * samplesPerPixel;\n}\n\n/**\n * Split a clip into two clips at the given sample position.\n *\n * The left clip retains the original fadeIn; the right clip retains the original fadeOut.\n * Both clips share the same waveformData reference.\n * If the clip has a name, suffixes \" (1)\" and \" (2)\" are appended.\n *\n * @param clip - The clip to split\n * @param splitSample - The timeline sample position where the split occurs\n * @returns Object with `left` and `right` AudioClip\n */\nexport function splitClip(\n clip: AudioClip,\n splitSample: number\n): { left: AudioClip; right: AudioClip } {\n const leftDuration = splitSample - clip.startSample;\n const rightDuration = clip.durationSamples - leftDuration;\n\n const leftName = clip.name ? `${clip.name} (1)` : undefined;\n const rightName = clip.name ? `${clip.name} (2)` : undefined;\n\n const left = createClip({\n startSample: clip.startSample,\n durationSamples: leftDuration,\n offsetSamples: clip.offsetSamples,\n sampleRate: clip.sampleRate,\n sourceDurationSamples: clip.sourceDurationSamples,\n gain: clip.gain,\n name: leftName,\n color: clip.color,\n fadeIn: clip.fadeIn,\n audioBuffer: clip.audioBuffer,\n waveformData: clip.waveformData,\n });\n\n const right = createClip({\n startSample: splitSample,\n durationSamples: rightDuration,\n offsetSamples: clip.offsetSamples + leftDuration,\n sampleRate: clip.sampleRate,\n sourceDurationSamples: clip.sourceDurationSamples,\n gain: clip.gain,\n name: rightName,\n color: clip.color,\n fadeOut: clip.fadeOut,\n audioBuffer: clip.audioBuffer,\n waveformData: clip.waveformData,\n });\n\n return { left, right };\n}\n\n/**\n * Check whether a clip can be split at the given sample position.\n *\n * The split point must be strictly inside the clip (not at start or end),\n * and both resulting clips must meet the minimum duration requirement.\n *\n * @param clip - The clip to check\n * @param sample - The timeline sample position to test\n * @param minDurationSamples - Minimum allowed clip duration in samples\n * @returns true if the split is valid\n */\nexport function canSplitAt(clip: AudioClip, sample: number, minDurationSamples: number): boolean {\n const clipEnd = clip.startSample + clip.durationSamples;\n\n // Must be strictly within clip bounds\n if (sample <= clip.startSample || sample >= clipEnd) {\n return false;\n }\n\n // Both resulting clips must meet minimum duration\n const leftDuration = sample - clip.startSample;\n const rightDuration = clipEnd - sample;\n\n return leftDuration >= minDurationSamples && rightDuration >= minDurationSamples;\n}\n","/**\n * Viewport operations for virtual scrolling.\n *\n * Pure math helpers that determine which portion of the timeline\n * is visible and which canvas chunks need to be mounted.\n */\n\n/**\n * Calculate the visible region with an overscan buffer for virtual scrolling.\n *\n * The buffer extends the visible range on both sides so that chunks are\n * mounted slightly before they scroll into view, preventing flicker.\n *\n * @param scrollLeft - Current horizontal scroll position in pixels\n * @param containerWidth - Width of the scroll container in pixels\n * @param bufferRatio - Multiplier for buffer size (default 1.5x container width)\n * @returns Object with visibleStart and visibleEnd in pixels\n */\nexport function calculateViewportBounds(\n scrollLeft: number,\n containerWidth: number,\n bufferRatio: number = 1.5\n): { visibleStart: number; visibleEnd: number } {\n const buffer = containerWidth * bufferRatio;\n return {\n visibleStart: Math.max(0, scrollLeft - buffer),\n visibleEnd: scrollLeft + containerWidth + buffer,\n };\n}\n\n/**\n * Get an array of chunk indices that overlap the visible viewport.\n *\n * Chunks are fixed-width segments of the total timeline width. Only chunks\n * that intersect [visibleStart, visibleEnd) are included. The last chunk\n * may be narrower than chunkWidth if totalWidth is not evenly divisible.\n *\n * @param totalWidth - Total width of the timeline in pixels\n * @param chunkWidth - Width of each chunk in pixels\n * @param visibleStart - Left edge of the visible region in pixels\n * @param visibleEnd - Right edge of the visible region in pixels\n * @returns Array of chunk indices (0-based) that are visible\n */\nexport function getVisibleChunkIndices(\n totalWidth: number,\n chunkWidth: number,\n visibleStart: number,\n visibleEnd: number\n): number[] {\n const totalChunks = Math.ceil(totalWidth / chunkWidth);\n const indices: number[] = [];\n\n for (let i = 0; i < totalChunks; i++) {\n const chunkLeft = i * chunkWidth;\n const thisChunkWidth = Math.min(totalWidth - chunkLeft, chunkWidth);\n const chunkEnd = chunkLeft + thisChunkWidth;\n\n if (chunkEnd <= visibleStart || chunkLeft >= visibleEnd) {\n continue;\n }\n\n indices.push(i);\n }\n\n return indices;\n}\n\n/**\n * Determine whether a scroll change is large enough to warrant\n * recalculating the viewport and re-rendering chunks.\n *\n * Small scroll movements are ignored to avoid excessive recomputation\n * during smooth scrolling.\n *\n * @param oldScrollLeft - Previous scroll position in pixels\n * @param newScrollLeft - Current scroll position in pixels\n * @param threshold - Minimum pixel delta to trigger an update (default 100)\n * @returns true if the scroll delta meets or exceeds the threshold\n */\nexport function shouldUpdateViewport(\n oldScrollLeft: number,\n newScrollLeft: number,\n threshold: number = 100\n): boolean {\n return Math.abs(oldScrollLeft - newScrollLeft) >= threshold;\n}\n","import type { ClipTrack } from '../../core';\n\n/**\n * Calculate total timeline duration in seconds from all tracks/clips.\n * Iterates all clips, finds the furthest clip end (startSample + durationSamples),\n * converts to seconds using each clip's sampleRate.\n *\n * @param tracks - Array of clip tracks\n * @returns Duration in seconds\n */\nexport function calculateDuration(tracks: ClipTrack[]): number {\n let maxDuration = 0;\n for (const track of tracks) {\n for (const clip of track.clips) {\n const clipEndSample = clip.startSample + clip.durationSamples;\n const clipEnd = clipEndSample / clip.sampleRate;\n maxDuration = Math.max(maxDuration, clipEnd);\n }\n }\n return maxDuration;\n}\n\n/**\n * Find the zoom level index closest to a given samplesPerPixel.\n * Returns exact match if found, otherwise the index whose value is\n * nearest to the target (by absolute difference).\n *\n * @param targetSamplesPerPixel - The samplesPerPixel value to find\n * @param zoomLevels - Array of available zoom levels (samplesPerPixel values)\n * @returns Index into the zoomLevels array\n */\nexport function findClosestZoomIndex(targetSamplesPerPixel: number, zoomLevels: number[]): number {\n if (zoomLevels.length === 0) return 0;\n\n let bestIndex = 0;\n let bestDiff = Math.abs(zoomLevels[0] - targetSamplesPerPixel);\n\n for (let i = 1; i < zoomLevels.length; i++) {\n const diff = Math.abs(zoomLevels[i] - targetSamplesPerPixel);\n if (diff < bestDiff) {\n bestDiff = diff;\n bestIndex = i;\n }\n }\n\n return bestIndex;\n}\n\n/**\n * Keep viewport centered during zoom changes.\n * Calculates center time from old zoom, computes new pixel position at new zoom,\n * and returns new scrollLeft clamped to >= 0.\n *\n * @param oldSamplesPerPixel - Previous zoom level\n * @param newSamplesPerPixel - New zoom level\n * @param scrollLeft - Current horizontal scroll position\n * @param containerWidth - Viewport width in pixels\n * @param sampleRate - Audio sample rate\n * @param controlWidth - Width of track controls panel (defaults to 0)\n * @returns New scrollLeft value\n */\nexport function calculateZoomScrollPosition(\n oldSamplesPerPixel: number,\n newSamplesPerPixel: number,\n scrollLeft: number,\n containerWidth: number,\n sampleRate: number,\n controlWidth: number = 0\n): number {\n const centerPixel = scrollLeft + containerWidth / 2 - controlWidth;\n const centerTime = (centerPixel * oldSamplesPerPixel) / sampleRate;\n const newCenterPixel = (centerTime * sampleRate) / newSamplesPerPixel;\n const newScrollLeft = newCenterPixel + controlWidth - containerWidth / 2;\n return Math.max(0, newScrollLeft);\n}\n\n/**\n * Clamp a seek position to the valid range [0, duration].\n *\n * @param time - Requested seek time in seconds\n * @param duration - Maximum duration in seconds\n * @returns Clamped time value\n */\nexport function clampSeekPosition(time: number, duration: number): number {\n return Math.max(0, Math.min(time, duration));\n}\n","/**\n * PlaylistEngine — Stateful, framework-agnostic timeline engine.\n *\n * Composes pure operations from ./operations with an event emitter\n * and optional PlayoutAdapter for audio playback delegation.\n */\n\nimport type { AudioClip, ClipTrack } from '../core';\nimport { sortClipsByTime } from '../core';\nimport {\n constrainClipDrag,\n constrainBoundaryTrim,\n canSplitAt,\n splitClip as splitClipOp,\n} from './operations/clipOperations';\nimport {\n calculateDuration,\n clampSeekPosition,\n findClosestZoomIndex,\n} from './operations/timelineOperations';\nimport type { PlayoutAdapter, EngineState, EngineEvents, PlaylistEngineOptions } from './types';\n\nconst DEFAULT_SAMPLE_RATE = 44100;\nconst DEFAULT_SAMPLES_PER_PIXEL = 1024;\nconst DEFAULT_ZOOM_LEVELS = [256, 512, 1024, 2048, 4096, 8192];\nconst DEFAULT_MIN_DURATION_SECONDS = 0.1;\n\ntype EventName = keyof EngineEvents;\n\nexport class PlaylistEngine {\n private _tracks: ClipTrack[] = [];\n private _currentTime = 0;\n private _playStartPosition = 0;\n private _isPlaying = false;\n private _selectedTrackId: string | null = null;\n private _sampleRate: number;\n private _zoomLevels: number[];\n private _zoomIndex: number;\n private _selectionStart = 0;\n private _selectionEnd = 0;\n private _masterVolume = 1.0;\n private _loopStart = 0;\n private _loopEnd = 0;\n private _isLoopEnabled = false;\n private _tracksVersion = 0;\n private _adapter: PlayoutAdapter | null;\n private _animFrameId: number | null = null;\n private _disposed = false;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n private _listeners: Map<string, Set<Function>> = new Map();\n\n constructor(options: PlaylistEngineOptions = {}) {\n this._sampleRate = options.sampleRate ?? DEFAULT_SAMPLE_RATE;\n this._zoomLevels = [...(options.zoomLevels ?? DEFAULT_ZOOM_LEVELS)];\n this._adapter = options.adapter ?? null;\n\n if (this._zoomLevels.length === 0) {\n throw new Error('PlaylistEngine: zoomLevels must not be empty');\n }\n\n const initialSpp = options.samplesPerPixel ?? DEFAULT_SAMPLES_PER_PIXEL;\n const zoomIndex = this._zoomLevels.indexOf(initialSpp);\n if (zoomIndex === -1) {\n throw new Error(\n `PlaylistEngine: samplesPerPixel ${initialSpp} is not in zoomLevels [${this._zoomLevels.join(', ')}]. ` +\n `Either pass a samplesPerPixel value that exists in zoomLevels, or include ${initialSpp} in your zoomLevels array.`\n );\n }\n this._zoomIndex = zoomIndex;\n }\n\n // ---------------------------------------------------------------------------\n // State snapshot\n // ---------------------------------------------------------------------------\n\n getState(): EngineState {\n return {\n tracks: this._tracks.map((t) => ({ ...t, clips: [...t.clips] })),\n tracksVersion: this._tracksVersion,\n duration: calculateDuration(this._tracks),\n currentTime: this._currentTime,\n isPlaying: this._isPlaying,\n samplesPerPixel: this._zoomLevels[this._zoomIndex],\n sampleRate: this._sampleRate,\n selectedTrackId: this._selectedTrackId,\n zoomIndex: this._zoomIndex,\n canZoomIn: this._zoomIndex > 0,\n canZoomOut: this._zoomIndex < this._zoomLevels.length - 1,\n selectionStart: this._selectionStart,\n selectionEnd: this._selectionEnd,\n masterVolume: this._masterVolume,\n loopStart: this._loopStart,\n loopEnd: this._loopEnd,\n isLoopEnabled: this._isLoopEnabled,\n };\n }\n\n // ---------------------------------------------------------------------------\n // Track Management\n // ---------------------------------------------------------------------------\n\n setTracks(tracks: ClipTrack[]): void {\n this._tracks = [...tracks];\n this._tracksVersion++;\n this._adapter?.setTracks(this._tracks);\n this._emitStateChange();\n }\n\n addTrack(track: ClipTrack): void {\n this._tracks = [...this._tracks, track];\n this._tracksVersion++;\n // Use incremental addTrack when the adapter supports it (avoids full rebuild)\n if (this._adapter?.addTrack) {\n this._adapter.addTrack(track);\n } else {\n this._adapter?.setTracks(this._tracks);\n }\n this._emitStateChange();\n }\n\n removeTrack(trackId: string): void {\n if (!this._tracks.some((t) => t.id === trackId)) return;\n this._tracks = this._tracks.filter((t) => t.id !== trackId);\n this._tracksVersion++;\n if (this._selectedTrackId === trackId) {\n this._selectedTrackId = null;\n }\n this._adapter?.setTracks(this._tracks);\n this._emitStateChange();\n }\n\n selectTrack(trackId: string | null): void {\n if (trackId === this._selectedTrackId) return;\n this._selectedTrackId = trackId;\n this._emitStateChange();\n }\n\n // ---------------------------------------------------------------------------\n // Clip Editing (delegates to operations/)\n // ---------------------------------------------------------------------------\n\n moveClip(trackId: string, clipId: string, deltaSamples: number): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (!track) {\n console.warn(`[songram-daw/engine] moveClip: track \"${trackId}\" not found`);\n return;\n }\n\n const clipIndex = track.clips.findIndex((c: AudioClip) => c.id === clipId);\n if (clipIndex === -1) {\n console.warn(\n `[songram-daw/engine] moveClip: clip \"${clipId}\" not found in track \"${trackId}\"`\n );\n return;\n }\n\n const clip = track.clips[clipIndex];\n const sortedClips = sortClipsByTime(track.clips);\n const sortedIndex = sortedClips.findIndex((c: AudioClip) => c.id === clipId);\n\n const constrainedDelta = constrainClipDrag(clip, deltaSamples, sortedClips, sortedIndex);\n\n if (constrainedDelta === 0) return;\n\n this._tracks = this._tracks.map((t) => {\n if (t.id !== trackId) return t;\n const newClips = t.clips.map((c: AudioClip, i: number) =>\n i === clipIndex\n ? {\n ...c,\n startSample: Math.floor(c.startSample + constrainedDelta),\n }\n : c\n );\n return { ...t, clips: newClips };\n });\n\n this._tracksVersion++;\n this._adapter?.setTracks(this._tracks);\n this._emitStateChange();\n }\n\n splitClip(trackId: string, clipId: string, atSample: number): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (!track) {\n console.warn(`[songram-daw/engine] splitClip: track \"${trackId}\" not found`);\n return;\n }\n\n const clipIndex = track.clips.findIndex((c: AudioClip) => c.id === clipId);\n if (clipIndex === -1) {\n console.warn(\n `[songram-daw/engine] splitClip: clip \"${clipId}\" not found in track \"${trackId}\"`\n );\n return;\n }\n\n const clip = track.clips[clipIndex];\n const minDuration = Math.floor(DEFAULT_MIN_DURATION_SECONDS * this._sampleRate);\n\n if (!canSplitAt(clip, atSample, minDuration)) {\n console.warn(\n `[songram-daw/engine] splitClip: cannot split clip \"${clipId}\" at sample ${atSample} ` +\n `(clip range: ${clip.startSample}–${clip.startSample + clip.durationSamples}, minDuration: ${minDuration})`\n );\n return;\n }\n\n const { left, right } = splitClipOp(clip, atSample);\n\n this._tracks = this._tracks.map((t) => {\n if (t.id !== trackId) return t;\n const newClips = [...t.clips];\n newClips.splice(clipIndex, 1, left, right);\n return { ...t, clips: newClips };\n });\n\n this._tracksVersion++;\n this._adapter?.setTracks(this._tracks);\n this._emitStateChange();\n }\n\n trimClip(\n trackId: string,\n clipId: string,\n boundary: 'left' | 'right',\n deltaSamples: number\n ): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (!track) {\n console.warn(`[songram-daw/engine] trimClip: track \"${trackId}\" not found`);\n return;\n }\n\n const clipIndex = track.clips.findIndex((c: AudioClip) => c.id === clipId);\n if (clipIndex === -1) {\n console.warn(\n `[songram-daw/engine] trimClip: clip \"${clipId}\" not found in track \"${trackId}\"`\n );\n return;\n }\n\n const clip = track.clips[clipIndex];\n const sortedClips = sortClipsByTime(track.clips);\n const sortedIndex = sortedClips.findIndex((c: AudioClip) => c.id === clipId);\n const minDuration = Math.floor(DEFAULT_MIN_DURATION_SECONDS * this._sampleRate);\n\n const constrained = constrainBoundaryTrim(\n clip,\n deltaSamples,\n boundary,\n sortedClips,\n sortedIndex,\n minDuration\n );\n\n if (constrained === 0) return;\n\n this._tracks = this._tracks.map((t) => {\n if (t.id !== trackId) return t;\n const newClips = t.clips.map((c: AudioClip, i: number) => {\n if (i !== clipIndex) return c;\n if (boundary === 'left') {\n return {\n ...c,\n startSample: c.startSample + constrained,\n offsetSamples: c.offsetSamples + constrained,\n durationSamples: c.durationSamples - constrained,\n };\n } else {\n return { ...c, durationSamples: c.durationSamples + constrained };\n }\n });\n return { ...t, clips: newClips };\n });\n\n this._tracksVersion++;\n this._adapter?.setTracks(this._tracks);\n this._emitStateChange();\n }\n\n // ---------------------------------------------------------------------------\n // Playback (delegates to adapter, no-ops without adapter)\n // ---------------------------------------------------------------------------\n\n async init(): Promise<void> {\n if (this._adapter) {\n await this._adapter.init();\n }\n }\n\n play(startTime?: number, endTime?: number): void {\n const prevCurrentTime = this._currentTime;\n const prevPlayStartPosition = this._playStartPosition;\n\n if (startTime !== undefined) {\n const duration = calculateDuration(this._tracks);\n this._currentTime = clampSeekPosition(startTime, duration);\n }\n\n // Remember where playback started (Audacity-style: stop returns here)\n this._playStartPosition = this._currentTime;\n\n if (this._adapter) {\n // Configure loop state BEFORE play(). The adapter caches loopStart/\n // loopEnd/enabled from setLoop(), then TonePlayout.play() applies\n // them to the Transport before transport.start() and advances\n // Clock._lastUpdate to skip stale ghost ticks.\n if (endTime !== undefined) {\n // Disable Transport loop for duration-limited playback (selection/annotation)\n this._adapter.setLoop(false, this._loopStart, this._loopEnd);\n } else if (this._isLoopEnabled) {\n // Activate Transport loop if starting before loopEnd. Starting at or\n // past loopEnd plays to the end without looping (click-past-loop behavior).\n const beforeLoopEnd = this._currentTime < this._loopEnd;\n this._adapter.setLoop(beforeLoopEnd, this._loopStart, this._loopEnd);\n }\n try {\n this._adapter.play(this._currentTime, endTime);\n } catch (err) {\n // Restore state so the engine isn't left with a moved playhead\n // but no audio. The throw propagates to the caller.\n this._currentTime = prevCurrentTime;\n this._playStartPosition = prevPlayStartPosition;\n throw err;\n }\n }\n\n this._isPlaying = true;\n this._startTimeUpdateLoop();\n this._emit('play');\n this._emitStateChange();\n }\n\n pause(): void {\n this._isPlaying = false;\n this._stopTimeUpdateLoop();\n this._adapter?.pause();\n if (this._adapter) {\n this._currentTime = this._adapter.getCurrentTime();\n }\n this._emit('pause');\n this._emitStateChange();\n }\n\n stop(): void {\n this._isPlaying = false;\n this._currentTime = this._playStartPosition;\n this._stopTimeUpdateLoop();\n this._adapter?.setLoop(false, this._loopStart, this._loopEnd);\n this._adapter?.stop();\n this._emit('stop');\n this._emitStateChange();\n }\n\n seek(time: number): void {\n const duration = calculateDuration(this._tracks);\n this._currentTime = clampSeekPosition(time, duration);\n this._adapter?.seek(this._currentTime);\n this._emitStateChange();\n }\n\n setMasterVolume(volume: number): void {\n if (volume === this._masterVolume) return;\n this._masterVolume = volume;\n this._adapter?.setMasterVolume(volume);\n this._emitStateChange();\n }\n\n getCurrentTime(): number {\n if (this._isPlaying && this._adapter) {\n return this._adapter.getCurrentTime();\n }\n return this._currentTime;\n }\n\n // ---------------------------------------------------------------------------\n // Selection & Loop\n // ---------------------------------------------------------------------------\n\n setSelection(start: number, end: number): void {\n const s = Math.min(start, end);\n const e = Math.max(start, end);\n if (s === this._selectionStart && e === this._selectionEnd) return;\n this._selectionStart = s;\n this._selectionEnd = e;\n this._emitStateChange();\n }\n\n setLoopRegion(start: number, end: number): void {\n const s = Math.min(start, end);\n const e = Math.max(start, end);\n if (s === this._loopStart && e === this._loopEnd) return;\n this._loopStart = s;\n this._loopEnd = e;\n this._adapter?.setLoop(\n this._isLoopEnabled && this._isBeforeLoopEnd(),\n this._loopStart,\n this._loopEnd\n );\n this._emitStateChange();\n }\n\n setLoopEnabled(enabled: boolean): void {\n if (enabled === this._isLoopEnabled) return;\n this._isLoopEnabled = enabled;\n this._adapter?.setLoop(enabled && this._isBeforeLoopEnd(), this._loopStart, this._loopEnd);\n this._emitStateChange();\n }\n\n // ---------------------------------------------------------------------------\n // Per-Track Audio (delegates to adapter)\n // ---------------------------------------------------------------------------\n\n setTrackVolume(trackId: string, volume: number): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (track) track.volume = volume;\n this._adapter?.setTrackVolume(trackId, volume);\n }\n\n setTrackMute(trackId: string, muted: boolean): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (track) track.muted = muted;\n this._adapter?.setTrackMute(trackId, muted);\n }\n\n setTrackSolo(trackId: string, soloed: boolean): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (track) track.soloed = soloed;\n this._adapter?.setTrackSolo(trackId, soloed);\n }\n\n setTrackPan(trackId: string, pan: number): void {\n const track = this._tracks.find((t) => t.id === trackId);\n if (track) track.pan = pan;\n this._adapter?.setTrackPan(trackId, pan);\n }\n\n // ---------------------------------------------------------------------------\n // Zoom\n // ---------------------------------------------------------------------------\n\n zoomIn(): void {\n if (this._zoomIndex > 0) {\n this._zoomIndex--;\n this._emitStateChange();\n }\n }\n\n zoomOut(): void {\n if (this._zoomIndex < this._zoomLevels.length - 1) {\n this._zoomIndex++;\n this._emitStateChange();\n }\n }\n\n setZoomLevel(samplesPerPixel: number): void {\n const newIndex = findClosestZoomIndex(samplesPerPixel, this._zoomLevels);\n if (newIndex === this._zoomIndex) return;\n this._zoomIndex = newIndex;\n this._emitStateChange();\n }\n\n // ---------------------------------------------------------------------------\n // Events\n // ---------------------------------------------------------------------------\n\n on<K extends EventName>(event: K, listener: EngineEvents[K]): void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event)!.add(listener);\n }\n\n off<K extends EventName>(event: K, listener: EngineEvents[K]): void {\n this._listeners.get(event)?.delete(listener);\n }\n\n // ---------------------------------------------------------------------------\n // Lifecycle\n // ---------------------------------------------------------------------------\n\n dispose(): void {\n if (this._disposed) return;\n this._disposed = true;\n this._stopTimeUpdateLoop();\n try {\n this._adapter?.dispose();\n } catch (err) {\n console.warn('[songram-daw/engine] Error disposing adapter:', err);\n }\n this._listeners.clear();\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private _emit(event: string, ...args: unknown[]): void {\n const listeners = this._listeners.get(event);\n if (listeners) {\n for (const listener of listeners) {\n try {\n listener(...args);\n } catch (error) {\n console.warn('[songram-daw/engine] Error in event listener:', error);\n }\n }\n }\n }\n\n /**\n * Returns whether the current playback position is before loopEnd.\n * Used by setLoopEnabled/setLoopRegion during playback — if past loopEnd,\n * Transport loop stays off so playback continues to the end.\n * Note: play() uses an inline check instead — _isPlaying is still false\n * when play() runs, and this method returns true unconditionally when\n * not playing.\n */\n private _isBeforeLoopEnd(): boolean {\n if (!this._isPlaying) return true;\n const t = this._adapter?.getCurrentTime() ?? this._currentTime;\n return t < this._loopEnd;\n }\n\n private _emitStateChange(): void {\n this._emit('statechange', this.getState());\n }\n\n private _startTimeUpdateLoop(): void {\n // Guard for Node.js / SSR environments where RAF is unavailable\n if (typeof requestAnimationFrame === 'undefined') return;\n\n this._stopTimeUpdateLoop();\n\n const tick = () => {\n if (this._disposed || !this._isPlaying) return;\n if (this._adapter) {\n this._currentTime = this._adapter.getCurrentTime();\n this._emit('timeupdate', this._currentTime);\n }\n this._animFrameId = requestAnimationFrame(tick);\n };\n\n this._animFrameId = requestAnimationFrame(tick);\n }\n\n private _stopTimeUpdateLoop(): void {\n if (this._animFrameId !== null && typeof cancelAnimationFrame !== 'undefined') {\n cancelAnimationFrame(this._animFrameId);\n this._animFrameId = null;\n }\n }\n}\n","/**\n * Fade utilities for Web Audio API\n *\n * Applies fade in/out envelopes to AudioParam (typically gain)\n * using various curve types.\n */\n\n/**\n * Access the underlying Web Audio AudioParam from a Tone.js Signal/Param wrapper.\n *\n * Tone.js wraps native AudioParam in its Signal class, but sometimes we need\n * direct access to the raw AudioParam for setValueAtTime/cancelScheduledValues\n * (e.g., when the AudioContext is suspended and Tone.js Signal doesn't propagate).\n *\n * This uses `_param` which is a private Tone.js 15.x internal.\n * Pin the Tone.js version carefully if upgrading.\n *\n * @param signal - A Tone.js Signal or Param wrapper (e.g., `gain.gain`)\n * @returns The underlying AudioParam, or undefined if not found\n */\nlet hasWarned = false;\n\nexport function getUnderlyingAudioParam(signal: unknown): AudioParam | undefined {\n const param = (signal as { _param?: AudioParam })._param;\n if (!param && !hasWarned) {\n hasWarned = true;\n console.warn(\n '[songram-daw] Unable to access Tone.js internal _param. ' +\n 'This likely means the Tone.js version is incompatible. ' +\n 'Mute scheduling may not work correctly.'\n );\n }\n return param;\n}\n\nexport type FadeType = 'linear' | 'logarithmic' | 'exponential' | 'sCurve';\n\n/**\n * Simple fade configuration - just duration and type\n */\nexport interface FadeConfig {\n /** Duration of the fade in seconds */\n duration: number;\n /** Type of fade curve (default: 'linear') */\n type?: FadeType;\n}\n\n/**\n * Generate a linear fade curve\n */\nexport function linearCurve(length: number, fadeIn: boolean): Float32Array {\n const curve = new Float32Array(length);\n const scale = length - 1;\n\n for (let i = 0; i < length; i++) {\n const x = i / scale;\n curve[i] = fadeIn ? x : 1 - x;\n }\n\n return curve;\n}\n\n/**\n * Generate an exponential fade curve\n */\nexport function exponentialCurve(length: number, fadeIn: boolean): Float32Array {\n const curve = new Float32Array(length);\n const scale = length - 1;\n\n for (let i = 0; i < length; i++) {\n const x = i / scale;\n const index = fadeIn ? i : length - 1 - i;\n curve[index] = Math.exp(2 * x - 1) / Math.E;\n }\n\n return curve;\n}\n\n/**\n * Generate an S-curve (sine-based smooth curve)\n */\nexport function sCurveCurve(length: number, fadeIn: boolean): Float32Array {\n const curve = new Float32Array(length);\n const phase = fadeIn ? Math.PI / 2 : -Math.PI / 2;\n\n for (let i = 0; i < length; i++) {\n curve[i] = Math.sin((Math.PI * i) / length - phase) / 2 + 0.5;\n }\n\n return curve;\n}\n\n/**\n * Generate a logarithmic fade curve\n */\nexport function logarithmicCurve(length: number, fadeIn: boolean, base: number = 10): Float32Array {\n const curve = new Float32Array(length);\n\n for (let i = 0; i < length; i++) {\n const index = fadeIn ? i : length - 1 - i;\n const x = i / length;\n curve[index] = Math.log(1 + base * x) / Math.log(1 + base);\n }\n\n return curve;\n}\n\n/**\n * Generate a fade curve of the specified type\n */\nexport function generateCurve(type: FadeType, length: number, fadeIn: boolean): Float32Array {\n switch (type) {\n case 'linear':\n return linearCurve(length, fadeIn);\n case 'exponential':\n return exponentialCurve(length, fadeIn);\n case 'sCurve':\n return sCurveCurve(length, fadeIn);\n case 'logarithmic':\n return logarithmicCurve(length, fadeIn);\n default:\n return linearCurve(length, fadeIn);\n }\n}\n\n/**\n * Apply a fade in to an AudioParam\n *\n * @param param - The AudioParam to apply the fade to (usually gain)\n * @param startTime - When the fade starts (in seconds, AudioContext time)\n * @param duration - Duration of the fade in seconds\n * @param type - Type of fade curve\n * @param startValue - Starting value (default: 0)\n * @param endValue - Ending value (default: 1)\n */\nexport function applyFadeIn(\n param: AudioParam,\n startTime: number,\n duration: number,\n type: FadeType = 'linear',\n startValue: number = 0,\n endValue: number = 1\n): void {\n if (duration <= 0) return;\n\n if (type === 'linear') {\n // Use native linear ramp for better performance\n param.setValueAtTime(startValue, startTime);\n param.linearRampToValueAtTime(endValue, startTime + duration);\n } else if (type === 'exponential') {\n // Exponential ramp can't start/end at 0, use small value\n param.setValueAtTime(Math.max(startValue, 0.001), startTime);\n param.exponentialRampToValueAtTime(Math.max(endValue, 0.001), startTime + duration);\n } else {\n // Use curve for sCurve and logarithmic\n const curve = generateCurve(type, 10000, true);\n // Scale curve to value range\n const scaledCurve = new Float32Array(curve.length);\n const range = endValue - startValue;\n for (let i = 0; i < curve.length; i++) {\n scaledCurve[i] = startValue + curve[i] * range;\n }\n param.setValueCurveAtTime(scaledCurve, startTime, duration);\n }\n}\n\n/**\n * Apply a fade out to an AudioParam\n *\n * @param param - The AudioParam to apply the fade to (usually gain)\n * @param startTime - When the fade starts (in seconds, AudioContext time)\n * @param duration - Duration of the fade in seconds\n * @param type - Type of fade curve\n * @param startValue - Starting value (default: 1)\n * @param endValue - Ending value (default: 0)\n */\nexport function applyFadeOut(\n param: AudioParam,\n startTime: number,\n duration: number,\n type: FadeType = 'linear',\n startValue: number = 1,\n endValue: number = 0\n): void {\n if (duration <= 0) return;\n\n if (type === 'linear') {\n // Use native linear ramp for better performance\n param.setValueAtTime(startValue, startTime);\n param.linearRampToValueAtTime(endValue, startTime + duration);\n } else if (type === 'exponential') {\n // Exponential ramp can't start/end at 0, use small value\n param.setValueAtTime(Math.max(startValue, 0.001), startTime);\n param.exponentialRampToValueAtTime(Math.max(endValue, 0.001), startTime + duration);\n } else {\n // Use curve for sCurve and logarithmic\n const curve = generateCurve(type, 10000, false);\n // Scale curve to value range\n const scaledCurve = new Float32Array(curve.length);\n const range = startValue - endValue;\n for (let i = 0; i < curve.length; i++) {\n scaledCurve[i] = endValue + curve[i] * range;\n }\n param.setValueCurveAtTime(scaledCurve, startTime, duration);\n }\n}\n","import {\n Volume,\n Gain,\n Panner,\n ToneAudioNode,\n getDestination,\n getTransport,\n getContext,\n} from 'tone';\nimport { Track, type Fade } from '../core';\nimport { applyFadeIn, applyFadeOut, getUnderlyingAudioParam } from './fades';\n\nexport type TrackEffectsFunction = (\n graphEnd: Gain,\n masterGainNode: ToneAudioNode,\n isOffline: boolean\n) => void | (() => void);\n\nexport interface ClipInfo {\n buffer: AudioBuffer;\n startTime: number; // When this clip starts in the track timeline (seconds)\n duration: number; // How long this clip plays (seconds)\n offset: number; // Where to start playing within the buffer (seconds)\n fadeIn?: Fade;\n fadeOut?: Fade;\n gain: number; // Clip-level gain\n}\n\nexport interface ToneTrackOptions {\n buffer?: AudioBuffer; // Legacy: single buffer (deprecated, use clips instead)\n clips?: ClipInfo[]; // Modern: array of clips\n track: Track;\n effects?: TrackEffectsFunction;\n destination?: ToneAudioNode;\n}\n\n/** Per-clip scheduling info and audio nodes */\ninterface ScheduledClip {\n clipInfo: ClipInfo;\n fadeGainNode: GainNode; // Native GainNode for per-clip fade envelope\n scheduleId: number; // Transport.schedule() event ID\n}\n\nexport class ToneTrack {\n private scheduledClips: ScheduledClip[];\n private activeSources: Set<AudioBufferSourceNode> = new Set();\n private volumeNode: Volume;\n private panNode: Panner;\n private muteGain: Gain;\n private track: Track;\n private effectsCleanup?: () => void;\n // Guard against ghost tick schedule callbacks. After stop/start cycles with\n // loops, stale Clock._lastUpdate causes ticks from the previous cycle to fire\n // Transport.schedule() callbacks at past positions (e.g., time 0 clips fire\n // when starting at offset 5s). Clips before this offset are handled by\n // startMidClipSources(); schedule callbacks should only create sources for\n // clips at/after this offset.\n private _scheduleGuardOffset = 0;\n\n constructor(options: ToneTrackOptions) {\n this.track = options.track;\n\n // Create shared track-level Tone.js nodes\n this.volumeNode = new Volume(this.gainToDb(options.track.gain));\n // Tone.js Panner defaults to channelCount: 1 + channelCountMode: 'explicit',\n // which forces stereo→mono downmix (1/√2 attenuation) before panning.\n // Override to channelCount: 2 to preserve stereo recordings.\n this.panNode = new Panner({ pan: options.track.stereoPan, channelCount: 2 });\n this.muteGain = new Gain(options.track.muted ? 0 : 1);\n\n // Chain shared Tone.js nodes: Volume → Pan → MuteGain\n this.volumeNode.chain(this.panNode, this.muteGain);\n\n // Connect to destination or apply effects chain\n const destination = options.destination || getDestination();\n if (options.effects) {\n const cleanup = options.effects(this.muteGain, destination, false);\n if (cleanup) {\n this.effectsCleanup = cleanup;\n }\n } else {\n this.muteGain.connect(destination);\n }\n\n // Create clips array - support both legacy single buffer and modern clips array\n const clipInfos: ClipInfo[] =\n options.clips ||\n (options.buffer\n ? [\n {\n buffer: options.buffer,\n startTime: 0,\n duration: options.buffer.duration,\n offset: 0,\n fadeIn: options.track.fadeIn,\n fadeOut: options.track.fadeOut,\n gain: 1,\n },\n ]\n : []);\n\n const transport = getTransport();\n const rawContext = getContext().rawContext as AudioContext;\n\n // Get the native AudioNode input of the Volume for native→Tone connection.\n // Volume.input is a Tone.js Gain<\"decibels\"> whose .input is the native GainNode.\n // Cast through unknown since Gain<\"decibels\"> and Gain<\"gain\"> don't overlap.\n const volumeNativeInput = (this.volumeNode.input as unknown as Gain).input;\n\n // Schedule each clip via Transport.schedule() with native AudioBufferSourceNode\n this.scheduledClips = clipInfos.map((clipInfo) => {\n // Native GainNode for per-clip fade envelope — created once, reused across play cycles\n const fadeGainNode = rawContext.createGain();\n fadeGainNode.gain.value = clipInfo.gain;\n fadeGainNode.connect(volumeNativeInput);\n\n // Schedule a permanent Transport event at the clip's absolute timeline position.\n // This callback fires on every play and every loop iteration when Transport\n // passes this point.\n const absTransportTime = this.track.startTime + clipInfo.startTime;\n const scheduleId = transport.schedule((audioContextTime: number) => {\n // Guard: ghost ticks from stale Clock._lastUpdate can fire this callback\n // at past positions (see Tone.js #1419). Clips before the play/loop offset\n // are already handled by startMidClipSources().\n if (absTransportTime < this._scheduleGuardOffset) {\n return;\n }\n this.startClipSource(clipInfo, fadeGainNode, audioContextTime);\n }, absTransportTime);\n\n return { clipInfo, fadeGainNode, scheduleId };\n });\n }\n\n /**\n * Create and start an AudioBufferSourceNode for a clip.\n * Sources are one-shot: each play or loop iteration creates a fresh one.\n */\n private startClipSource(\n clipInfo: ClipInfo,\n fadeGainNode: GainNode,\n audioContextTime: number,\n bufferOffset?: number,\n playDuration?: number\n ): void {\n const rawContext = getContext().rawContext as AudioContext;\n const source = rawContext.createBufferSource();\n source.buffer = clipInfo.buffer;\n source.connect(fadeGainNode);\n\n const offset = bufferOffset ?? clipInfo.offset;\n const duration = playDuration ?? clipInfo.duration;\n\n try {\n source.start(audioContextTime, offset, duration);\n } catch (err) {\n console.warn(\n `[songram-daw] Failed to start source on track \"${this.id}\" ` +\n `(time=${audioContextTime}, offset=${offset}, duration=${duration}):`,\n err\n );\n source.disconnect();\n return;\n }\n\n this.activeSources.add(source);\n source.onended = () => {\n this.activeSources.delete(source);\n };\n }\n\n /**\n * Set the schedule guard offset. Schedule callbacks for clips before this\n * offset are suppressed (already handled by startMidClipSources).\n * Must be called before transport.start() and in the loop handler.\n */\n setScheduleGuardOffset(offset: number): void {\n this._scheduleGuardOffset = offset;\n }\n\n /**\n * Start sources for clips that span the given Transport position.\n * Used for mid-playback seeking and loop boundary handling where\n * Transport.schedule() callbacks have already passed.\n *\n * Uses strict < for absClipStart to avoid double-creation with\n * schedule callbacks at exact Transport position (e.g., loopStart).\n */\n startMidClipSources(transportOffset: number, audioContextTime: number): void {\n for (const { clipInfo, fadeGainNode } of this.scheduledClips) {\n const absClipStart = this.track.startTime + clipInfo.startTime;\n const absClipEnd = absClipStart + clipInfo.duration;\n\n // Only handle clips that started before the transport position\n // but haven't ended yet (i.e., the transport is \"inside\" the clip)\n if (absClipStart < transportOffset && absClipEnd > transportOffset) {\n const elapsed = transportOffset - absClipStart;\n const adjustedOffset = clipInfo.offset + elapsed;\n const remainingDuration = clipInfo.duration - elapsed;\n this.startClipSource(\n clipInfo,\n fadeGainNode,\n audioContextTime,\n adjustedOffset,\n remainingDuration\n );\n }\n }\n }\n\n /**\n * Stop all active AudioBufferSourceNodes and clear the set.\n * Native AudioBufferSourceNodes ignore Transport state changes —\n * they must be explicitly stopped.\n */\n stopAllSources(): void {\n this.activeSources.forEach((source) => {\n try {\n source.stop();\n } catch (err) {\n console.warn(`[songram-daw] Error stopping source on track \"${this.id}\":`, err);\n }\n });\n this.activeSources.clear();\n }\n\n /**\n * Schedule fade envelopes for a clip at the given AudioContext time.\n * Uses native GainNode.gain (AudioParam) directly — no _param workaround needed.\n */\n private scheduleFades(\n scheduled: ScheduledClip,\n clipStartTime: number,\n clipOffset: number = 0\n ): void {\n const { clipInfo, fadeGainNode } = scheduled;\n const audioParam = fadeGainNode.gain;\n\n // Cancel any previous automation\n audioParam.cancelScheduledValues(0);\n\n // Calculate how much of the clip we're skipping (for seeking)\n const skipTime = clipOffset - clipInfo.offset;\n\n // Apply fade in if it exists and we haven't skipped past it\n if (clipInfo.fadeIn && skipTime < clipInfo.fadeIn.duration) {\n const fadeInDuration = clipInfo.fadeIn.duration;\n\n if (skipTime <= 0) {\n applyFadeIn(\n audioParam,\n clipStartTime,\n fadeInDuration,\n clipInfo.fadeIn.type || 'linear',\n 0,\n clipInfo.gain\n );\n } else {\n const remainingFadeDuration = fadeInDuration - skipTime;\n const fadeProgress = skipTime / fadeInDuration;\n const startValue = clipInfo.gain * fadeProgress;\n applyFadeIn(\n audioParam,\n clipStartTime,\n remainingFadeDuration,\n clipInfo.fadeIn.type || 'linear',\n startValue,\n clipInfo.gain\n );\n }\n } else {\n audioParam.setValueAtTime(clipInfo.gain, clipStartTime);\n }\n\n // Apply fade out if it exists\n if (clipInfo.fadeOut) {\n const fadeOutStart = clipInfo.duration - clipInfo.fadeOut.duration;\n const fadeOutStartInClip = fadeOutStart - skipTime;\n\n if (fadeOutStartInClip > 0) {\n const absoluteFadeOutStart = clipStartTime + fadeOutStartInClip;\n applyFadeOut(\n audioParam,\n absoluteFadeOutStart,\n clipInfo.fadeOut.duration,\n clipInfo.fadeOut.type || 'linear',\n clipInfo.gain,\n 0\n );\n } else if (fadeOutStartInClip > -clipInfo.fadeOut.duration) {\n const elapsedFadeOut = -fadeOutStartInClip;\n const remainingFadeDuration = clipInfo.fadeOut.duration - elapsedFadeOut;\n const fadeProgress = elapsedFadeOut / clipInfo.fadeOut.duration;\n const startValue = clipInfo.gain * (1 - fadeProgress);\n applyFadeOut(\n audioParam,\n clipStartTime,\n remainingFadeDuration,\n clipInfo.fadeOut.type || 'linear',\n startValue,\n 0\n );\n }\n }\n }\n\n /**\n * Prepare fade envelopes for all clips based on Transport offset.\n * Called before Transport.start() to schedule fades at correct AudioContext times.\n */\n prepareFades(when: number, transportOffset: number): void {\n this.scheduledClips.forEach((scheduled) => {\n const absClipStart = this.track.startTime + scheduled.clipInfo.startTime;\n const absClipEnd = absClipStart + scheduled.clipInfo.duration;\n\n if (transportOffset >= absClipEnd) return; // clip already finished\n\n if (transportOffset >= absClipStart) {\n // Mid-clip: playing now\n const clipOffset = transportOffset - absClipStart + scheduled.clipInfo.offset;\n this.scheduleFades(scheduled, when, clipOffset);\n } else {\n // Clip starts later\n const delay = absClipStart - transportOffset;\n this.scheduleFades(scheduled, when + delay, scheduled.clipInfo.offset);\n }\n });\n }\n\n /**\n * Cancel all scheduled fade automation and reset to nominal gain.\n * Called on pause/stop to prevent stale fade envelopes.\n */\n cancelFades(): void {\n this.scheduledClips.forEach(({ fadeGainNode, clipInfo }) => {\n const audioParam = fadeGainNode.gain;\n audioParam.cancelScheduledValues(0);\n audioParam.setValueAtTime(clipInfo.gain, 0);\n });\n }\n\n private gainToDb(gain: number): number {\n return 20 * Math.log10(gain);\n }\n\n setVolume(gain: number): void {\n this.track.gain = gain;\n this.volumeNode.volume.value = this.gainToDb(gain);\n }\n\n setPan(pan: number): void {\n this.track.stereoPan = pan;\n this.panNode.pan.value = pan;\n }\n\n setMute(muted: boolean): void {\n this.track.muted = muted;\n const value = muted ? 0 : 1;\n // Use setValueAtTime on the raw AudioParam to ensure the value is applied\n // even when the AudioContext is suspended. Setting .gain.value on the Tone.js\n // Signal wrapper doesn't propagate to the underlying AudioParam until the\n // context resumes, causing a brief audio glitch (e.g., all tracks audible\n // before solo muting takes effect).\n const audioParam = getUnderlyingAudioParam(this.muteGain.gain);\n audioParam?.setValueAtTime(value, 0);\n this.muteGain.gain.value = value;\n }\n\n setSolo(soloed: boolean): void {\n this.track.soloed = soloed;\n }\n\n dispose(): void {\n const transport = getTransport();\n\n if (this.effectsCleanup) {\n try {\n this.effectsCleanup();\n } catch (err) {\n console.warn(`[songram-daw] Error during track \"${this.id}\" effects cleanup:`, err);\n }\n }\n\n this.stopAllSources();\n\n // Clear Transport schedule events and disconnect native fade gain nodes\n this.scheduledClips.forEach((scheduled, index) => {\n try {\n transport.clear(scheduled.scheduleId);\n } catch (err) {\n console.warn(\n `[songram-daw] Error clearing schedule ${index} on track \"${this.id}\":`,\n err\n );\n }\n try {\n scheduled.fadeGainNode.disconnect();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disconnecting fadeGain ${index} on track \"${this.id}\":`,\n err\n );\n }\n });\n\n try {\n this.volumeNode.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing volumeNode on track \"${this.id}\":`, err);\n }\n try {\n this.panNode.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing panNode on track \"${this.id}\":`, err);\n }\n try {\n this.muteGain.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing muteGain on track \"${this.id}\":`, err);\n }\n }\n\n get id(): string {\n return this.track.id;\n }\n\n get duration(): number {\n if (this.scheduledClips.length === 0) return 0;\n const lastClip = this.scheduledClips[this.scheduledClips.length - 1];\n return lastClip.clipInfo.startTime + lastClip.clipInfo.duration;\n }\n\n get buffer(): AudioBuffer {\n return this.scheduledClips[0]?.clipInfo.buffer;\n }\n\n get muted(): boolean {\n return this.track.muted;\n }\n\n get startTime(): number {\n return this.track.startTime;\n }\n}\n","import {\n Volume,\n Gain,\n Panner,\n PolySynth,\n Synth,\n MembraneSynth,\n MetalSynth,\n NoiseSynth,\n Part,\n ToneAudioNode,\n getDestination,\n getContext,\n} from 'tone';\nimport type { SynthOptions } from 'tone';\nimport { Track } from '../core';\nimport type { MidiNoteData } from '../core';\nimport { getUnderlyingAudioParam } from './fades';\nimport type { TrackEffectsFunction } from './ToneTrack';\n\n/**\n * Shared interface for tracks managed by TonePlayout.\n * Both ToneTrack (audio) and MidiToneTrack (MIDI) implement this,\n * allowing TonePlayout to manage them uniformly.\n */\nexport interface PlayableTrack {\n id: string;\n startTime: number;\n muted: boolean;\n duration: number;\n stopAllSources(): void;\n startMidClipSources(offset: number, time: number): void;\n setScheduleGuardOffset(offset: number): void;\n prepareFades(when: number, offset: number): void;\n cancelFades(): void;\n setVolume(gain: number): void;\n setPan(pan: number): void;\n setMute(muted: boolean): void;\n setSolo(soloed: boolean): void;\n dispose(): void;\n}\n\nexport interface MidiClipInfo {\n notes: MidiNoteData[];\n startTime: number; // When this clip starts relative to track start (seconds)\n duration: number; // Clip duration (seconds)\n offset: number; // Trim offset into the MIDI data (seconds)\n}\n\nexport interface MidiToneTrackOptions {\n clips: MidiClipInfo[];\n track: Track;\n effects?: TrackEffectsFunction;\n destination?: ToneAudioNode;\n synthOptions?: Partial<SynthOptions>;\n}\n\n/**\n * Categorize GM percussion note numbers into synth types.\n * See: https://www.midi.org/specifications-old/item/gm-level-1-sound-set\n */\ntype DrumCategory = 'kick' | 'snare' | 'cymbal' | 'tom';\n\nfunction getDrumCategory(midiNote: number): DrumCategory {\n // Bass drums\n if (midiNote === 35 || midiNote === 36) return 'kick';\n // Snare, side stick, clap\n if (midiNote >= 37 && midiNote <= 40) return 'snare';\n // Toms (low floor tom through high tom)\n if (\n midiNote === 41 ||\n midiNote === 43 ||\n midiNote === 45 ||\n midiNote === 47 ||\n midiNote === 48 ||\n midiNote === 50\n )\n return 'tom';\n // Hi-hats, cymbals, bells, tambourine, cowbell, etc.\n return 'cymbal';\n}\n\n/** Per-clip scheduling info */\ninterface ScheduledMidiClip {\n clipInfo: MidiClipInfo;\n part: Part;\n}\n\n/**\n * MIDI track that always creates both melodic and percussion synths.\n * Per-note routing uses the `channel` field on each MidiNoteData:\n * channel 9 → percussion synths, all others → melodic PolySynth.\n * This enables flattened tracks (mixed channels) to play correctly.\n */\nexport class MidiToneTrack implements PlayableTrack {\n private scheduledClips: ScheduledMidiClip[];\n // Melodic synth — always created\n private synth: PolySynth;\n // Percussion synths — always created (PolySynth wrappers for polyphony)\n private kickSynth: PolySynth<MembraneSynth>;\n private snareSynth: NoiseSynth; // No pitch param, can't wrap in PolySynth\n private cymbalSynth: PolySynth<MetalSynth>;\n private tomSynth: PolySynth<MembraneSynth>;\n private volumeNode: Volume;\n private panNode: Panner;\n private muteGain: Gain;\n private track: Track;\n private effectsCleanup?: () => void;\n\n constructor(options: MidiToneTrackOptions) {\n this.track = options.track;\n\n // Create shared track-level Tone.js nodes (same chain as ToneTrack)\n this.volumeNode = new Volume(this.gainToDb(options.track.gain));\n this.panNode = new Panner(options.track.stereoPan);\n this.muteGain = new Gain(options.track.muted ? 0 : 1);\n this.volumeNode.chain(this.panNode, this.muteGain);\n\n // Melodic: PolySynth with basic Synth voice\n this.synth = new PolySynth(Synth, options.synthOptions);\n this.synth.connect(this.volumeNode);\n\n // Percussion: PolySynth wrappers for polyphonic playback\n this.kickSynth = new PolySynth(MembraneSynth, {\n voice: MembraneSynth,\n options: {\n pitchDecay: 0.05,\n octaves: 6,\n envelope: { attack: 0.001, decay: 0.4, sustain: 0, release: 0.1 },\n },\n } as never);\n this.snareSynth = new NoiseSynth({\n noise: { type: 'white' },\n envelope: { attack: 0.001, decay: 0.15, sustain: 0, release: 0.05 },\n });\n this.cymbalSynth = new PolySynth(MetalSynth, {\n voice: MetalSynth,\n options: {\n envelope: { attack: 0.001, decay: 0.3, release: 0.1 },\n harmonicity: 5.1,\n modulationIndex: 32,\n resonance: 4000,\n octaves: 1.5,\n },\n } as never);\n this.tomSynth = new PolySynth(MembraneSynth, {\n voice: MembraneSynth,\n options: {\n pitchDecay: 0.08,\n octaves: 4,\n envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 },\n },\n } as never);\n\n this.kickSynth.connect(this.volumeNode);\n this.snareSynth.connect(this.volumeNode);\n this.cymbalSynth.connect(this.volumeNode);\n this.tomSynth.connect(this.volumeNode);\n\n // Connect to destination or apply effects chain\n const destination = options.destination || getDestination();\n if (options.effects) {\n const cleanup = options.effects(this.muteGain, destination, false);\n if (cleanup) {\n this.effectsCleanup = cleanup;\n }\n } else {\n this.muteGain.connect(destination);\n }\n\n // Create a Tone.Part for each clip, scheduling notes relative to Transport\n this.scheduledClips = options.clips.map((clipInfo) => {\n // Filter notes within the clip's visible window (after trim offset)\n const visibleNotes = clipInfo.notes.filter((note) => {\n const noteEnd = note.time + note.duration;\n // Note must start before clip ends and end after clip's trim offset\n return note.time < clipInfo.offset + clipInfo.duration && noteEnd > clipInfo.offset;\n });\n\n // Create Part events with absolute Transport times\n const absClipStart = this.track.startTime + clipInfo.startTime;\n\n const partEvents = visibleNotes.map((note) => {\n // Adjust note timing relative to clip's trim offset\n const adjustedTime = note.time - clipInfo.offset;\n // Clamp to clip boundaries\n const clampedStart = Math.max(0, adjustedTime);\n const clampedDuration = Math.min(\n note.duration - Math.max(0, clipInfo.offset - note.time),\n clipInfo.duration - clampedStart\n );\n\n return {\n time: absClipStart + clampedStart,\n note: note.name,\n midi: note.midi,\n duration: Math.max(0, clampedDuration),\n velocity: note.velocity,\n channel: note.channel,\n };\n });\n\n const part = new Part((time, event) => {\n if (event.duration > 0) {\n this.triggerNote(\n event.midi,\n event.note,\n event.duration,\n time,\n event.velocity,\n event.channel\n );\n }\n }, partEvents);\n\n // Part starts automatically with Transport\n part.start(0);\n\n return { clipInfo, part };\n });\n }\n\n /**\n * Trigger a note using the appropriate synth.\n * Routes per-note: channel 9 → percussion synths, others → melodic PolySynth.\n */\n private triggerNote(\n midiNote: number,\n noteName: string,\n duration: number,\n time: number,\n velocity: number,\n channel?: number\n ): void {\n if (channel === 9) {\n const category = getDrumCategory(midiNote);\n switch (category) {\n case 'kick':\n this.kickSynth.triggerAttackRelease('C1', duration, time, velocity);\n break;\n case 'snare':\n // NoiseSynth is monophonic — wrap in try-catch for rare overlaps\n try {\n this.snareSynth.triggerAttackRelease(duration, time, velocity);\n } catch (err) {\n console.warn(\n '[songram-daw] Snare overlap — previous hit still decaying, skipped:',\n err\n );\n }\n break;\n case 'tom': {\n const tomPitches: Record<number, string> = {\n 41: 'G1',\n 43: 'A1',\n 45: 'C2',\n 47: 'D2',\n 48: 'E2',\n 50: 'G2',\n };\n this.tomSynth.triggerAttackRelease(\n tomPitches[midiNote] || 'C2',\n duration,\n time,\n velocity\n );\n break;\n }\n case 'cymbal':\n // PolySynth requires a note arg; MetalSynth uses it as fundamental frequency.\n // 'C4' provides a reasonable metallic timbre for all cymbal/hi-hat hits.\n this.cymbalSynth.triggerAttackRelease('C4', duration, time, velocity);\n break;\n }\n } else {\n this.synth.triggerAttackRelease(noteName, duration, time, velocity);\n }\n }\n\n private gainToDb(gain: number): number {\n return 20 * Math.log10(gain);\n }\n\n /**\n * No-op for MIDI — schedule guard is for AudioBufferSourceNode ghost tick prevention.\n * Tone.Part handles its own scheduling relative to Transport.\n */\n setScheduleGuardOffset(_offset: number): void {\n // No-op: Tone.Part handles scheduling internally\n }\n\n /**\n * For MIDI, mid-clip sources are notes that should already be sounding.\n * We trigger them with their remaining duration.\n */\n startMidClipSources(transportOffset: number, audioContextTime: number): void {\n for (const { clipInfo } of this.scheduledClips) {\n const absClipStart = this.track.startTime + clipInfo.startTime;\n const absClipEnd = absClipStart + clipInfo.duration;\n\n if (absClipStart < transportOffset && absClipEnd > transportOffset) {\n // Find notes that should be currently sounding\n for (const note of clipInfo.notes) {\n const adjustedTime = note.time - clipInfo.offset;\n const noteAbsStart = absClipStart + Math.max(0, adjustedTime);\n const noteAbsEnd = noteAbsStart + note.duration;\n\n if (noteAbsStart < transportOffset && noteAbsEnd > transportOffset) {\n const remainingDuration = noteAbsEnd - transportOffset;\n try {\n this.triggerNote(\n note.midi,\n note.name,\n remainingDuration,\n audioContextTime,\n note.velocity,\n note.channel\n );\n } catch (err) {\n console.warn(\n `[songram-daw] Failed to start mid-clip MIDI note \"${note.name}\" on track \"${this.id}\":`,\n err\n );\n }\n }\n }\n }\n }\n }\n\n /**\n * Stop all sounding notes and cancel scheduled Part events.\n */\n stopAllSources(): void {\n const now = getContext().rawContext.currentTime;\n try {\n this.synth.releaseAll(now);\n this.kickSynth.releaseAll(now);\n this.cymbalSynth.releaseAll(now);\n this.tomSynth.releaseAll(now);\n // NoiseSynth has no releaseAll — it decays naturally via short envelope\n } catch (err) {\n console.warn(`[songram-daw] Error releasing synth on track \"${this.id}\":`, err);\n }\n }\n\n /**\n * No-op for MIDI — MIDI uses note velocity, not gain fades.\n */\n prepareFades(_when: number, _offset: number): void {\n // No-op: MIDI clips don't use fade envelopes\n }\n\n /**\n * No-op for MIDI — no fade automation to cancel.\n */\n cancelFades(): void {\n // No-op: MIDI clips don't use fade envelopes\n }\n\n setVolume(gain: number): void {\n this.track.gain = gain;\n this.volumeNode.volume.value = this.gainToDb(gain);\n }\n\n setPan(pan: number): void {\n this.track.stereoPan = pan;\n this.panNode.pan.value = pan;\n }\n\n setMute(muted: boolean): void {\n this.track.muted = muted;\n const value = muted ? 0 : 1;\n const audioParam = getUnderlyingAudioParam(this.muteGain.gain);\n audioParam?.setValueAtTime(value, 0);\n this.muteGain.gain.value = value;\n }\n\n setSolo(soloed: boolean): void {\n this.track.soloed = soloed;\n }\n\n dispose(): void {\n if (this.effectsCleanup) {\n try {\n this.effectsCleanup();\n } catch (err) {\n console.warn(\n `[songram-daw] Error during MIDI track \"${this.id}\" effects cleanup:`,\n err\n );\n }\n }\n\n this.stopAllSources();\n\n // Dispose Parts\n this.scheduledClips.forEach(({ part }, index) => {\n try {\n part.dispose();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disposing Part ${index} on MIDI track \"${this.id}\":`,\n err\n );\n }\n });\n\n // Dispose all synths\n const synthsToDispose = [\n this.synth,\n this.kickSynth,\n this.snareSynth,\n this.cymbalSynth,\n this.tomSynth,\n ];\n for (const s of synthsToDispose) {\n try {\n s?.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing synth on MIDI track \"${this.id}\":`, err);\n }\n }\n try {\n this.volumeNode.dispose();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disposing volumeNode on MIDI track \"${this.id}\":`,\n err\n );\n }\n try {\n this.panNode.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing panNode on MIDI track \"${this.id}\":`, err);\n }\n try {\n this.muteGain.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing muteGain on MIDI track \"${this.id}\":`, err);\n }\n }\n\n get id(): string {\n return this.track.id;\n }\n\n get duration(): number {\n if (this.scheduledClips.length === 0) return 0;\n const lastClip = this.scheduledClips[this.scheduledClips.length - 1];\n return lastClip.clipInfo.startTime + lastClip.clipInfo.duration;\n }\n\n get muted(): boolean {\n return this.track.muted;\n }\n\n get startTime(): number {\n return this.track.startTime;\n }\n}\n","import { Volume, Gain, Panner, Part, ToneAudioNode, getDestination, getContext } from 'tone';\nimport { Track } from '../core';\nimport { getUnderlyingAudioParam } from './fades';\nimport type { TrackEffectsFunction } from './ToneTrack';\nimport type { PlayableTrack, MidiClipInfo } from './MidiToneTrack';\nimport type { SoundFontCache } from './SoundFontCache';\n\nexport interface SoundFontToneTrackOptions {\n clips: MidiClipInfo[];\n track: Track;\n soundFontCache: SoundFontCache;\n /** GM program number (0-127) for melodic instruments */\n programNumber?: number;\n /** Whether this track uses percussion bank (channel 9) */\n isPercussion?: boolean;\n effects?: TrackEffectsFunction;\n destination?: ToneAudioNode;\n}\n\n/** Per-clip scheduling info */\ninterface ScheduledMidiClip {\n clipInfo: MidiClipInfo;\n part: Part;\n}\n\n/**\n * MIDI track that uses SoundFont samples for playback.\n *\n * Instead of PolySynth synthesis, each note triggers the correct instrument\n * sample from an SF2 file, pitch-shifted via AudioBufferSourceNode.playbackRate.\n *\n * Audio graph per note:\n * AudioBufferSourceNode (native, one-shot, pitch-shifted)\n * → GainNode (native, per-note velocity)\n * → Volume.input (Tone.js, shared per-track)\n * → Panner → muteGain → effects/destination\n */\nexport class SoundFontToneTrack implements PlayableTrack {\n /** Rate-limit missing sample warnings — one per class lifetime */\n private static _missingSampleWarned = false;\n private scheduledClips: ScheduledMidiClip[];\n private activeSources: Set<AudioBufferSourceNode> = new Set();\n private soundFontCache: SoundFontCache;\n private programNumber: number;\n private bankNumber: number;\n private volumeNode: Volume;\n private panNode: Panner;\n private muteGain: Gain;\n private track: Track;\n private effectsCleanup?: () => void;\n\n constructor(options: SoundFontToneTrackOptions) {\n this.track = options.track;\n this.soundFontCache = options.soundFontCache;\n this.programNumber = options.programNumber ?? 0;\n // Bank 128 for percussion (channel 9), bank 0 for melodic\n this.bankNumber = options.isPercussion ? 128 : 0;\n\n // Create shared track-level Tone.js nodes (same chain as ToneTrack)\n this.volumeNode = new Volume(this.gainToDb(options.track.gain));\n this.panNode = new Panner(options.track.stereoPan);\n this.muteGain = new Gain(options.track.muted ? 0 : 1);\n this.volumeNode.chain(this.panNode, this.muteGain);\n\n // Connect to destination or apply effects chain\n const destination = options.destination || getDestination();\n if (options.effects) {\n const cleanup = options.effects(this.muteGain, destination, false);\n if (cleanup) {\n this.effectsCleanup = cleanup;\n }\n } else {\n this.muteGain.connect(destination);\n }\n\n // Create a Tone.Part for each clip, scheduling notes relative to Transport\n this.scheduledClips = options.clips.map((clipInfo) => {\n // Filter notes within the clip's visible window (after trim offset)\n const visibleNotes = clipInfo.notes.filter((note) => {\n const noteEnd = note.time + note.duration;\n return note.time < clipInfo.offset + clipInfo.duration && noteEnd > clipInfo.offset;\n });\n\n const absClipStart = this.track.startTime + clipInfo.startTime;\n\n const partEvents = visibleNotes.map((note) => {\n const adjustedTime = note.time - clipInfo.offset;\n const clampedStart = Math.max(0, adjustedTime);\n const clampedDuration = Math.min(\n note.duration - Math.max(0, clipInfo.offset - note.time),\n clipInfo.duration - clampedStart\n );\n\n return {\n time: absClipStart + clampedStart,\n note: note.name,\n midi: note.midi,\n duration: Math.max(0, clampedDuration),\n velocity: note.velocity,\n channel: note.channel,\n };\n });\n\n const part = new Part((time, event) => {\n if (event.duration > 0) {\n this.triggerNote(event.midi, event.duration, time, event.velocity, event.channel);\n }\n }, partEvents);\n\n part.start(0);\n\n return { clipInfo, part };\n });\n }\n\n /**\n * Trigger a note by creating a native AudioBufferSourceNode from the SoundFont cache.\n *\n * Per-note routing: channel 9 → bank 128 (drums), others → bank 0 with programNumber.\n */\n private triggerNote(\n midiNote: number,\n duration: number,\n time: number,\n velocity: number,\n channel?: number\n ): void {\n const bank = channel === 9 ? 128 : this.bankNumber;\n const preset = channel === 9 ? 0 : this.programNumber;\n\n const sfSample = this.soundFontCache.getAudioBuffer(midiNote, bank, preset);\n if (!sfSample) {\n if (!SoundFontToneTrack._missingSampleWarned) {\n console.warn(\n `[songram-daw] SoundFont sample not found for MIDI note ${midiNote} (bank ${bank}, preset ${preset}). ` +\n 'Subsequent missing samples will be silent.'\n );\n SoundFontToneTrack._missingSampleWarned = true;\n }\n return;\n }\n\n const rawContext = getContext().rawContext as BaseAudioContext;\n\n // Create AudioBufferSourceNode with optional looping\n const source = rawContext.createBufferSource();\n source.buffer = sfSample.buffer;\n source.playbackRate.value = sfSample.playbackRate;\n\n // Enable sample looping if SF2 zone defines loop mode\n if (sfSample.loopMode === 1 || sfSample.loopMode === 3) {\n source.loop = true;\n source.loopStart = sfSample.loopStart;\n source.loopEnd = sfSample.loopEnd;\n }\n\n // For non-looping samples (percussion, one-shots), use the sample's natural\n // buffer duration so cymbals/drums ring out fully. For looping samples\n // (sustained instruments), use the MIDI note duration for note-off timing.\n const sampleDuration = sfSample.buffer.duration / sfSample.playbackRate;\n const effectiveDuration =\n sfSample.loopMode === 0 ? Math.max(duration, sampleDuration) : duration;\n\n // Per-note gain with SF2 volume ADSR envelope\n const peakGain = velocity * velocity;\n const gainNode = rawContext.createGain();\n const { attackVolEnv, holdVolEnv, decayVolEnv, sustainVolEnv, releaseVolEnv } = sfSample;\n const sustainGain = peakGain * sustainVolEnv;\n\n // Attack: start silent, ramp to peak\n gainNode.gain.setValueAtTime(0, time);\n gainNode.gain.linearRampToValueAtTime(peakGain, time + attackVolEnv);\n // Hold at peak\n if (holdVolEnv > 0.001) {\n gainNode.gain.setValueAtTime(peakGain, time + attackVolEnv + holdVolEnv);\n }\n // Decay to sustain level\n const decayStart = time + attackVolEnv + holdVolEnv;\n gainNode.gain.linearRampToValueAtTime(sustainGain, decayStart + decayVolEnv);\n // Sustain holds until note-off, then release ramps to silence.\n // For short notes (duration < AHD), setValueAtTime at note-off cancels the\n // incomplete decay ramp — Web Audio handles this correctly.\n gainNode.gain.setValueAtTime(sustainGain, time + effectiveDuration);\n gainNode.gain.linearRampToValueAtTime(0, time + effectiveDuration + releaseVolEnv);\n\n // Connect: source → gainNode → Volume.input (Tone.js)\n source.connect(gainNode);\n gainNode.connect((this.volumeNode.input as unknown as Gain).input);\n\n // Track active sources for stopAllSources()\n this.activeSources.add(source);\n source.onended = () => {\n this.activeSources.delete(source);\n try {\n gainNode.disconnect();\n } catch (err) {\n console.warn('[songram-daw] GainNode already disconnected:', err);\n }\n };\n\n source.start(time);\n source.stop(time + effectiveDuration + releaseVolEnv);\n }\n\n private gainToDb(gain: number): number {\n return 20 * Math.log10(gain);\n }\n\n /**\n * No-op — Tone.Part handles scheduling internally, no ghost tick guard needed.\n */\n setScheduleGuardOffset(_offset: number): void {\n // No-op\n }\n\n /**\n * Start notes that should already be sounding at the current transport offset.\n */\n startMidClipSources(transportOffset: number, audioContextTime: number): void {\n for (const { clipInfo } of this.scheduledClips) {\n const absClipStart = this.track.startTime + clipInfo.startTime;\n const absClipEnd = absClipStart + clipInfo.duration;\n\n if (absClipStart < transportOffset && absClipEnd > transportOffset) {\n for (const note of clipInfo.notes) {\n const adjustedTime = note.time - clipInfo.offset;\n const noteAbsStart = absClipStart + Math.max(0, adjustedTime);\n const noteAbsEnd = noteAbsStart + note.duration;\n\n if (noteAbsStart < transportOffset && noteAbsEnd > transportOffset) {\n const remainingDuration = noteAbsEnd - transportOffset;\n try {\n this.triggerNote(\n note.midi,\n remainingDuration,\n audioContextTime,\n note.velocity,\n note.channel\n );\n } catch (err) {\n console.warn(\n `[songram-daw] Failed to start mid-clip SoundFont note on track \"${this.id}\":`,\n err\n );\n }\n }\n }\n }\n }\n }\n\n /**\n * Stop all active AudioBufferSourceNodes.\n */\n stopAllSources(): void {\n for (const source of this.activeSources) {\n try {\n source.stop();\n } catch (err) {\n console.warn('[songram-daw] Error stopping AudioBufferSourceNode:', err);\n }\n }\n this.activeSources.clear();\n }\n\n /** No-op for MIDI — MIDI uses note velocity, not gain fades. */\n prepareFades(_when: number, _offset: number): void {}\n\n /** No-op for MIDI — no fade automation to cancel. */\n cancelFades(): void {}\n\n setVolume(gain: number): void {\n this.track.gain = gain;\n this.volumeNode.volume.value = this.gainToDb(gain);\n }\n\n setPan(pan: number): void {\n this.track.stereoPan = pan;\n this.panNode.pan.value = pan;\n }\n\n setMute(muted: boolean): void {\n this.track.muted = muted;\n const value = muted ? 0 : 1;\n const audioParam = getUnderlyingAudioParam(this.muteGain.gain);\n audioParam?.setValueAtTime(value, 0);\n this.muteGain.gain.value = value;\n }\n\n setSolo(soloed: boolean): void {\n this.track.soloed = soloed;\n }\n\n dispose(): void {\n if (this.effectsCleanup) {\n try {\n this.effectsCleanup();\n } catch (err) {\n console.warn(\n `[songram-daw] Error during SoundFont track \"${this.id}\" effects cleanup:`,\n err\n );\n }\n }\n\n this.stopAllSources();\n\n // Dispose Parts\n this.scheduledClips.forEach(({ part }, index) => {\n try {\n part.dispose();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disposing Part ${index} on SoundFont track \"${this.id}\":`,\n err\n );\n }\n });\n\n try {\n this.volumeNode.dispose();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disposing volumeNode on SoundFont track \"${this.id}\":`,\n err\n );\n }\n try {\n this.panNode.dispose();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disposing panNode on SoundFont track \"${this.id}\":`,\n err\n );\n }\n try {\n this.muteGain.dispose();\n } catch (err) {\n console.warn(\n `[songram-daw] Error disposing muteGain on SoundFont track \"${this.id}\":`,\n err\n );\n }\n }\n\n get id(): string {\n return this.track.id;\n }\n\n get duration(): number {\n if (this.scheduledClips.length === 0) return 0;\n const lastClip = this.scheduledClips[this.scheduledClips.length - 1];\n return lastClip.clipInfo.startTime + lastClip.clipInfo.duration;\n }\n\n get muted(): boolean {\n return this.track.muted;\n }\n\n get startTime(): number {\n return this.track.startTime;\n }\n}\n","import {\n Volume,\n ToneAudioNode,\n getDestination,\n start,\n now,\n getTransport,\n getContext,\n BaseContext,\n} from 'tone';\nimport { ToneTrack, ToneTrackOptions } from './ToneTrack';\nimport { MidiToneTrack, MidiToneTrackOptions } from './MidiToneTrack';\nimport type { PlayableTrack } from './MidiToneTrack';\nimport { SoundFontToneTrack, SoundFontToneTrackOptions } from './SoundFontToneTrack';\n\nexport type EffectsFunction = (\n masterGainNode: Volume,\n destination: ToneAudioNode,\n isOffline: boolean\n) => void | (() => void);\n\nexport interface TonePlayoutOptions {\n tracks?: ToneTrack[];\n masterGain?: number;\n effects?: EffectsFunction;\n}\n\nexport class TonePlayout {\n private tracks: Map<string, PlayableTrack> = new Map();\n private masterVolume: Volume;\n private isInitialized = false;\n private soloedTracks: Set<string> = new Set();\n private manualMuteState: Map<string, boolean> = new Map();\n private effectsCleanup?: () => void;\n private onPlaybackCompleteCallback?: () => void;\n private _completionEventId: number | null = null;\n private _loopHandler: (() => void) | null = null;\n private _loopEnabled = false;\n private _loopStart = 0;\n private _loopEnd = 0;\n\n constructor(options: TonePlayoutOptions = {}) {\n this.masterVolume = new Volume(this.gainToDb(options.masterGain ?? 1));\n\n // Setup effects chain if provided, otherwise connect directly to destination\n if (options.effects) {\n const cleanup = options.effects(this.masterVolume, getDestination(), false);\n if (cleanup) {\n this.effectsCleanup = cleanup;\n }\n } else {\n this.masterVolume.toDestination();\n }\n\n if (options.tracks) {\n options.tracks.forEach((track) => {\n this.tracks.set(track.id, track);\n this.manualMuteState.set(track.id, track.muted);\n });\n }\n }\n\n private gainToDb(gain: number): number {\n return 20 * Math.log10(gain);\n }\n\n private clearCompletionEvent(): void {\n if (this._completionEventId !== null) {\n try {\n getTransport().clear(this._completionEventId);\n } catch (err) {\n console.warn('[songram-daw] Error clearing Transport completion event:', err);\n }\n this._completionEventId = null;\n }\n }\n\n async init(): Promise<void> {\n if (this.isInitialized) return;\n\n await start();\n this.isInitialized = true;\n }\n\n addTrack(trackOptions: ToneTrackOptions): ToneTrack {\n // Ensure tracks connect to master volume instead of destination\n const optionsWithDestination = {\n ...trackOptions,\n destination: this.masterVolume,\n };\n const toneTrack = new ToneTrack(optionsWithDestination);\n this.tracks.set(toneTrack.id, toneTrack);\n this.manualMuteState.set(toneTrack.id, trackOptions.track.muted ?? false);\n if (trackOptions.track.soloed) {\n this.soloedTracks.add(toneTrack.id);\n }\n return toneTrack;\n }\n\n addMidiTrack(trackOptions: MidiToneTrackOptions): MidiToneTrack {\n const optionsWithDestination = {\n ...trackOptions,\n destination: this.masterVolume,\n };\n const midiTrack = new MidiToneTrack(optionsWithDestination);\n this.tracks.set(midiTrack.id, midiTrack);\n this.manualMuteState.set(midiTrack.id, trackOptions.track.muted ?? false);\n if (trackOptions.track.soloed) {\n this.soloedTracks.add(midiTrack.id);\n }\n return midiTrack;\n }\n\n addSoundFontTrack(trackOptions: SoundFontToneTrackOptions): SoundFontToneTrack {\n const optionsWithDestination = {\n ...trackOptions,\n destination: this.masterVolume,\n };\n const sfTrack = new SoundFontToneTrack(optionsWithDestination);\n this.tracks.set(sfTrack.id, sfTrack);\n this.manualMuteState.set(sfTrack.id, trackOptions.track.muted ?? false);\n if (trackOptions.track.soloed) {\n this.soloedTracks.add(sfTrack.id);\n }\n return sfTrack;\n }\n\n /**\n * Apply solo muting after all tracks have been added.\n * Call this after adding all tracks to ensure solo logic is applied correctly.\n */\n applyInitialSoloState(): void {\n this.updateSoloMuting();\n }\n\n removeTrack(trackId: string): void {\n const track = this.tracks.get(trackId);\n if (track) {\n track.dispose();\n this.tracks.delete(trackId);\n this.manualMuteState.delete(trackId);\n this.soloedTracks.delete(trackId);\n }\n }\n\n getTrack(trackId: string): PlayableTrack | undefined {\n return this.tracks.get(trackId);\n }\n\n play(when?: number, offset?: number, duration?: number): void {\n if (!this.isInitialized) {\n throw new Error('[songram-daw] TonePlayout not initialized. Call init() first.');\n }\n\n const startTime = when ?? now();\n const transport = getTransport();\n\n this.clearCompletionEvent();\n\n const transportOffset = offset ?? 0;\n this.tracks.forEach((track) => {\n track.cancelFades();\n track.prepareFades(startTime, transportOffset);\n });\n\n // Schedule duration-limited stop via Transport\n if (duration !== undefined) {\n this._completionEventId = transport.scheduleOnce(() => {\n this._completionEventId = null;\n try {\n this.onPlaybackCompleteCallback?.();\n } catch (err) {\n console.warn('[songram-daw] Error in playback completion callback:', err);\n }\n }, transportOffset + duration);\n }\n\n // Start Transport — triggers schedule() callbacks for clips at/after offset\n try {\n // Stop all active native sources before restarting to prevent layered audio.\n // Native AudioBufferSourceNodes don't respond to Transport state changes.\n if (transport.state !== 'stopped') {\n transport.stop();\n }\n this.tracks.forEach((track) => track.stopAllSources());\n\n // Set loop boundaries BEFORE enabling loop. _processTick checks\n // `ticks >= _loopEnd` every tick; _loopEnd defaults to 0.\n transport.loopStart = this._loopStart;\n transport.loopEnd = this._loopEnd;\n transport.loop = this._loopEnabled;\n\n // Set schedule guard BEFORE transport.start(). Ghost ticks from stale\n // Clock._lastUpdate can fire schedule callbacks at past positions;\n // the guard suppresses callbacks for clips before the play offset\n // (those are handled by startMidClipSources below).\n this.tracks.forEach((track) => track.setScheduleGuardOffset(transportOffset));\n\n if (offset !== undefined) {\n transport.start(startTime, offset);\n } else {\n transport.start(startTime);\n }\n\n // Advance Clock._lastUpdate past the stop/start boundary.\n //\n // After stop/start cycles, _lastUpdate is stale (set by the previous\n // context tick, before our stop/start). The next Clock._loop() processes\n // ticks from [_lastUpdate, now()]. In the gap [_lastUpdate, startTime),\n // the TickSource is still \"started\" from the PREVIOUS play cycle with\n // its old tick offset. Those accumulated ticks can exceed _loopEnd,\n // causing _processTick to wrap immediately to loopStart.\n //\n // By advancing _lastUpdate to startTime, we skip the stale range.\n // The next Clock._loop() only processes [startTime, now()] — ticks\n // from the current play cycle with the correct offset.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Tone.js private internal, see CLAUDE.md ghost tick fix\n (transport as any)._clock._lastUpdate = startTime;\n\n // Start sources for clips that span the current Transport position.\n // Transport.schedule() only fires for clips at/after the offset;\n // clips whose start time is before the offset need manual creation.\n this.tracks.forEach((track) => {\n track.startMidClipSources(transportOffset, startTime);\n });\n } catch (err) {\n // Clean up scheduled events since Transport failed to start\n this.clearCompletionEvent();\n this.tracks.forEach((track) => track.cancelFades());\n console.warn(\n '[songram-daw] Transport.start() failed. Audio playback could not begin.',\n err\n );\n throw err;\n }\n }\n\n pause(): void {\n const transport = getTransport();\n try {\n transport.pause();\n } catch (err) {\n console.warn('[songram-daw] Transport.pause() failed:', err);\n }\n // Native AudioBufferSourceNodes ignore Transport state changes —\n // they must be explicitly stopped.\n this.tracks.forEach((track) => track.stopAllSources());\n this.tracks.forEach((track) => track.cancelFades());\n this.clearCompletionEvent();\n }\n\n stop(): void {\n const transport = getTransport();\n try {\n transport.stop();\n } catch (err) {\n console.warn('[songram-daw] Transport.stop() failed:', err);\n }\n // Remove loop handler before stopping sources. Prevents any deferred\n // loop event from creating new sources via startMidClipSources() after\n // stopAllSources() runs. Defense-in-depth — setLoop(false) should\n // already have removed it, but stop() must be self-contained.\n if (this._loopHandler) {\n try {\n transport.off('loop', this._loopHandler);\n } catch (err) {\n console.warn('[songram-daw] Error removing loop handler:', err);\n }\n this._loopHandler = null;\n }\n // Stop all native sources explicitly\n this.tracks.forEach((track) => {\n try {\n track.stopAllSources();\n } catch (err) {\n console.warn(`[songram-daw] Error stopping sources for track \"${track.id}\":`, err);\n }\n });\n this.tracks.forEach((track) => {\n try {\n track.cancelFades();\n } catch (err) {\n console.warn(`[songram-daw] Error canceling fades for track \"${track.id}\":`, err);\n }\n });\n this.clearCompletionEvent();\n }\n\n setMasterGain(gain: number): void {\n this.masterVolume.volume.value = this.gainToDb(gain);\n }\n\n setSolo(trackId: string, soloed: boolean): void {\n const track = this.tracks.get(trackId);\n if (track) {\n track.setSolo(soloed);\n if (soloed) {\n this.soloedTracks.add(trackId);\n } else {\n this.soloedTracks.delete(trackId);\n }\n this.updateSoloMuting();\n }\n }\n\n private updateSoloMuting(): void {\n const hasSoloedTracks = this.soloedTracks.size > 0;\n\n this.tracks.forEach((track, id) => {\n if (hasSoloedTracks) {\n if (!this.soloedTracks.has(id)) {\n track.setMute(true);\n } else {\n const manuallyMuted = this.manualMuteState.get(id) ?? false;\n track.setMute(manuallyMuted);\n }\n } else {\n const manuallyMuted = this.manualMuteState.get(id) ?? false;\n track.setMute(manuallyMuted);\n }\n });\n }\n\n setMute(trackId: string, muted: boolean): void {\n const track = this.tracks.get(trackId);\n if (track) {\n this.manualMuteState.set(trackId, muted);\n track.setMute(muted);\n }\n }\n\n setLoop(enabled: boolean, loopStart: number, loopEnd: number): void {\n // Update cached state first — play() uses these values to configure\n // the Transport on next start, so they must reflect the caller's intent\n // regardless of whether Transport property setting succeeds.\n this._loopEnabled = enabled;\n this._loopStart = loopStart;\n this._loopEnd = loopEnd;\n\n const transport = getTransport();\n try {\n // Set boundaries BEFORE enabling loop. Tone.js's _processTick checks\n // `ticks >= _loopEnd` on every tick. If we set transport.loop = true\n // first, a tick could fire before loopEnd is updated, seeing the stale\n // _loopEnd value (0 from Transport default) and wrapping immediately.\n transport.loopStart = loopStart;\n transport.loopEnd = loopEnd;\n transport.loop = enabled;\n } catch (err) {\n console.warn('[songram-daw] Error configuring Transport loop:', err);\n return;\n }\n\n if (enabled && !this._loopHandler) {\n this._loopHandler = () => {\n // On loop boundary: stop old sources, re-schedule fades, start mid-clip sources.\n // Event ordering in Transport's tick processing (Tone.js 15.x _processTick):\n // loopEnd → ticks reset → loopStart → loop → forEachAtTime(ticks)\n // Our loop handler fires BEFORE schedule callbacks, so:\n // 1. stopAllSources + cancelFades — clean slate\n // 2. startMidClipSources — for clips spanning loopStart boundary\n // 3. prepareFades — fresh fade envelopes\n // Then Transport fires schedule callbacks for clips at/after loopStart.\n const currentTime = now();\n this.tracks.forEach((track) => {\n try {\n track.stopAllSources();\n track.cancelFades();\n track.setScheduleGuardOffset(this._loopStart);\n track.startMidClipSources(this._loopStart, currentTime);\n track.prepareFades(currentTime, this._loopStart);\n } catch (err) {\n console.warn(\n `[songram-daw] Error re-scheduling track \"${track.id}\" on loop:`,\n err\n );\n }\n });\n };\n transport.on('loop', this._loopHandler);\n } else if (!enabled && this._loopHandler) {\n transport.off('loop', this._loopHandler);\n this._loopHandler = null;\n }\n }\n\n getCurrentTime(): number {\n return getTransport().seconds;\n }\n\n seekTo(time: number): void {\n getTransport().seconds = time;\n }\n\n dispose(): void {\n // Stop Transport and all active sources before disposing.\n // Without this, the global Transport singleton keeps firing scheduled\n // callbacks and native AudioBufferSourceNodes continue playing through\n // the shared AudioContext (e.g., during Docusaurus client-side navigation).\n try {\n this.stop();\n } catch (err) {\n console.warn('[songram-daw] Error stopping Transport during dispose:', err);\n }\n\n this.tracks.forEach((track) => {\n try {\n track.dispose();\n } catch (err) {\n console.warn(`[songram-daw] Error disposing track \"${track.id}\":`, err);\n }\n });\n this.tracks.clear();\n\n if (this.effectsCleanup) {\n try {\n this.effectsCleanup();\n } catch (err) {\n console.warn('[songram-daw] Error during master effects cleanup:', err);\n }\n }\n\n try {\n this.masterVolume.dispose();\n } catch (err) {\n console.warn('[songram-daw] Error disposing master volume:', err);\n }\n }\n\n get context(): BaseContext {\n return getContext();\n }\n\n get sampleRate(): number {\n return getContext().sampleRate;\n }\n\n setOnPlaybackComplete(callback: () => void): void {\n this.onPlaybackCompleteCallback = callback;\n }\n}\n","import { SoundFont2, GeneratorType } from 'soundfont2';\nimport type { Generator, ZoneMap } from 'soundfont2';\n\n/**\n * Result of looking up a MIDI note in the SoundFont.\n * Contains the AudioBuffer, playbackRate, loop points, and volume envelope.\n */\nexport interface SoundFontSample {\n /** Cached AudioBuffer for this sample */\n buffer: AudioBuffer;\n /** Playback rate to pitch-shift from originalPitch to target note */\n playbackRate: number;\n /** Loop mode: 0=no loop, 1=continuous, 3=sustain loop */\n loopMode: number;\n /** Loop start in seconds, relative to AudioBuffer start */\n loopStart: number;\n /** Loop end in seconds, relative to AudioBuffer start */\n loopEnd: number;\n /** Volume envelope attack time in seconds */\n attackVolEnv: number;\n /** Volume envelope hold time in seconds */\n holdVolEnv: number;\n /** Volume envelope decay time in seconds */\n decayVolEnv: number;\n /** Volume envelope sustain level as linear gain 0-1 */\n sustainVolEnv: number;\n /** Volume envelope release time in seconds */\n releaseVolEnv: number;\n}\n\n/**\n * Convert SF2 timecents to seconds.\n * SF2 formula: seconds = 2^(timecents / 1200)\n * Default -12000 timecents ≈ 0.001s (effectively instant).\n */\nexport function timecentsToSeconds(tc: number): number {\n return Math.pow(2, tc / 1200);\n}\n\n/** Max release time to prevent extremely long tails from stale generators */\nconst MAX_RELEASE_SECONDS = 5;\n\n/**\n * Get a numeric generator value from a zone map.\n */\nexport function getGeneratorValue(\n generators: ZoneMap<Generator>,\n type: GeneratorType\n): number | undefined {\n return generators[type]?.value;\n}\n\n/**\n * Convert Int16Array sample data to Float32Array.\n * SF2 samples are 16-bit signed integers; Web Audio needs Float32 [-1, 1].\n */\nexport function int16ToFloat32(samples: Int16Array): Float32Array {\n const floats = new Float32Array(samples.length);\n for (let i = 0; i < samples.length; i++) {\n floats[i] = samples[i] / 32768;\n }\n return floats;\n}\n\n/**\n * Input parameters for playback rate calculation.\n */\nexport interface PlaybackRateParams {\n /** Target MIDI note number (0-127) */\n midiNote: number;\n /** OverridingRootKey generator value, or undefined if not set */\n overrideRootKey: number | undefined;\n /** sample.header.originalPitch (255 means unpitched) */\n originalPitch: number;\n /** CoarseTune generator value in semitones (default 0) */\n coarseTune: number;\n /** FineTune generator value in cents (default 0) */\n fineTune: number;\n /** sample.header.pitchCorrection in cents (default 0) */\n pitchCorrection: number;\n}\n\n/**\n * Calculate playback rate for a MIDI note using the SF2 generator chain.\n *\n * SF2 root key resolution priority:\n * 1. OverridingRootKey generator (per-zone, most specific)\n * 2. sample.header.originalPitch (sample header)\n * 3. MIDI note 60 (middle C fallback)\n *\n * Tuning adjustments:\n * - CoarseTune generator (semitones, additive)\n * - FineTune generator (cents, additive)\n * - sample.header.pitchCorrection (cents, additive)\n */\nexport function calculatePlaybackRate(params: PlaybackRateParams): number {\n const { midiNote, overrideRootKey, originalPitch, coarseTune, fineTune, pitchCorrection } =\n params;\n\n // Resolve root key: OverridingRootKey → originalPitch → 60\n const rootKey =\n overrideRootKey !== undefined ? overrideRootKey : originalPitch !== 255 ? originalPitch : 60;\n\n // Total offset in semitones: target note - root key + tuning\n const totalSemitones = midiNote - rootKey + coarseTune + (fineTune + pitchCorrection) / 100;\n\n return Math.pow(2, totalSemitones / 12);\n}\n\n/**\n * Input parameters for loop and envelope extraction.\n */\nexport interface LoopAndEnvelopeParams {\n /** SF2 generators zone map */\n generators: ZoneMap<Generator>;\n /** Sample header with loop points and sample rate */\n header: {\n startLoop: number;\n endLoop: number;\n sampleRate: number;\n };\n}\n\n/**\n * Extract loop points and volume envelope data from per-zone generators.\n *\n * Loop points are stored as absolute indices into the SF2 sample pool.\n * We convert to AudioBuffer-relative seconds by subtracting header.start\n * and dividing by sampleRate.\n *\n * Volume envelope times are in SF2 timecents; sustain is centibels attenuation.\n */\nexport function extractLoopAndEnvelope(\n params: LoopAndEnvelopeParams\n): Omit<SoundFontSample, 'buffer' | 'playbackRate'> {\n const { generators, header } = params;\n\n // --- Loop points ---\n const loopMode = getGeneratorValue(generators, GeneratorType.SampleModes) ?? 0;\n\n // Compute actual loop positions (header + fine/coarse generator offsets)\n const rawLoopStart =\n header.startLoop +\n (getGeneratorValue(generators, GeneratorType.StartLoopAddrsOffset) ?? 0) +\n (getGeneratorValue(generators, GeneratorType.StartLoopAddrsCoarseOffset) ?? 0) * 32768;\n const rawLoopEnd =\n header.endLoop +\n (getGeneratorValue(generators, GeneratorType.EndLoopAddrsOffset) ?? 0) +\n (getGeneratorValue(generators, GeneratorType.EndLoopAddrsCoarseOffset) ?? 0) * 32768;\n\n // The soundfont2 library already converts startLoop/endLoop to be\n // relative to sample.data (subtracts header.start during parsing),\n // so we only need to divide by sampleRate to get seconds.\n const loopStart = rawLoopStart / header.sampleRate;\n const loopEnd = rawLoopEnd / header.sampleRate;\n\n // --- Volume envelope ---\n const attackVolEnv = timecentsToSeconds(\n getGeneratorValue(generators, GeneratorType.AttackVolEnv) ?? -12000\n );\n const holdVolEnv = timecentsToSeconds(\n getGeneratorValue(generators, GeneratorType.HoldVolEnv) ?? -12000\n );\n const decayVolEnv = timecentsToSeconds(\n getGeneratorValue(generators, GeneratorType.DecayVolEnv) ?? -12000\n );\n const releaseVolEnv = Math.min(\n timecentsToSeconds(getGeneratorValue(generators, GeneratorType.ReleaseVolEnv) ?? -12000),\n MAX_RELEASE_SECONDS\n );\n\n // SustainVolEnv is centibels attenuation: 0 = full volume, 1440 = silence\n // Convert to linear gain: 10^(-cb / 200)\n const sustainCb = getGeneratorValue(generators, GeneratorType.SustainVolEnv) ?? 0;\n const sustainVolEnv = Math.pow(10, -sustainCb / 200);\n\n return {\n loopMode,\n loopStart,\n loopEnd,\n attackVolEnv,\n holdVolEnv,\n decayVolEnv,\n sustainVolEnv,\n releaseVolEnv,\n };\n}\n\n/**\n * Caches parsed SoundFont2 data and AudioBuffers for efficient playback.\n *\n * AudioBuffers are created lazily on first access and cached by sample index.\n * Pitch calculation uses the SF2 generator chain:\n * OverridingRootKey → sample.header.originalPitch → fallback 60\n *\n * Audio graph per note:\n * AudioBufferSourceNode (playbackRate for pitch) → GainNode (velocity) → track chain\n */\nexport class SoundFontCache {\n private sf2: SoundFont2 | null = null;\n private audioBufferCache: Map<number, AudioBuffer> = new Map();\n private context: BaseAudioContext;\n\n /**\n * @param context Optional AudioContext for createBuffer(). If omitted, uses\n * an OfflineAudioContext which doesn't require user gesture — safe to\n * construct before user interaction (avoids Firefox autoplay warnings).\n */\n constructor(context?: BaseAudioContext) {\n // OfflineAudioContext only needs valid params; we never call startRendering().\n // It's used solely for createBuffer() which works identically to AudioContext.\n this.context = context ?? new OfflineAudioContext(1, 1, 44100);\n }\n\n /**\n * Load and parse an SF2 file from a URL.\n */\n async load(url: string, signal?: AbortSignal): Promise<void> {\n const response = await fetch(url, { signal });\n if (!response.ok) {\n throw new Error(`Failed to fetch SoundFont ${url}: ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n try {\n this.sf2 = new SoundFont2(new Uint8Array(arrayBuffer));\n } catch (err) {\n throw new Error(\n `Failed to parse SoundFont ${url}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n /**\n * Load from an already-fetched ArrayBuffer.\n */\n loadFromBuffer(data: ArrayBuffer): void {\n try {\n this.sf2 = new SoundFont2(new Uint8Array(data));\n } catch (err) {\n throw new Error(\n `Failed to parse SoundFont from buffer: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n get isLoaded(): boolean {\n return this.sf2 !== null;\n }\n\n /**\n * Look up a MIDI note and return the AudioBuffer + playbackRate.\n *\n * @param midiNote - MIDI note number (0-127)\n * @param bankNumber - Bank number (0 for melodic, 128 for percussion/drums)\n * @param presetNumber - GM program number (0-127)\n * @returns SoundFontSample or null if no sample found for this note\n */\n getAudioBuffer(\n midiNote: number,\n bankNumber: number = 0,\n presetNumber: number = 0\n ): SoundFontSample | null {\n if (!this.sf2) return null;\n\n const keyData = this.sf2.getKeyData(midiNote, bankNumber, presetNumber);\n if (!keyData) return null;\n\n const sample = keyData.sample;\n const sampleIndex = this.sf2.samples.indexOf(sample);\n\n // Get or create the AudioBuffer for this sample\n let buffer = this.audioBufferCache.get(sampleIndex);\n if (!buffer) {\n buffer = this.int16ToAudioBuffer(sample.data, sample.header.sampleRate);\n this.audioBufferCache.set(sampleIndex, buffer);\n }\n\n // Calculate playback rate using SF2 generator chain for root key.\n // Priority: OverridingRootKey generator → sample.header.originalPitch → 60\n const playbackRate = calculatePlaybackRate({\n midiNote,\n overrideRootKey: getGeneratorValue(keyData.generators, GeneratorType.OverridingRootKey),\n originalPitch: sample.header.originalPitch,\n coarseTune: getGeneratorValue(keyData.generators, GeneratorType.CoarseTune) ?? 0,\n fineTune: getGeneratorValue(keyData.generators, GeneratorType.FineTune) ?? 0,\n pitchCorrection: sample.header.pitchCorrection ?? 0,\n });\n\n // Extract per-zone loop points and volume envelope from generators\n const loopAndEnvelope = extractLoopAndEnvelope({\n generators: keyData.generators,\n header: keyData.sample.header,\n });\n\n return { buffer, playbackRate, ...loopAndEnvelope };\n }\n\n /**\n * Convert Int16Array sample data to an AudioBuffer.\n * Uses the extracted int16ToFloat32 for the conversion, then copies into an AudioBuffer.\n */\n private int16ToAudioBuffer(data: Int16Array, sampleRate: number): AudioBuffer {\n const floats = int16ToFloat32(data);\n const buffer = this.context.createBuffer(1, floats.length, sampleRate);\n buffer.getChannelData(0).set(floats);\n return buffer;\n }\n\n /**\n * Clear all cached AudioBuffers and release the parsed SF2.\n */\n dispose(): void {\n this.audioBufferCache.clear();\n this.sf2 = null;\n }\n}\n","/**\n * Global AudioContext Manager\n *\n * Provides a single AudioContext shared across the entire application.\n * This context is used by Tone.js for playback and by all recording/monitoring hooks.\n *\n * Uses Tone.js's Context class which wraps standardized-audio-context for\n * cross-browser compatibility (fixes Firefox AudioListener issues).\n */\n\nimport { Context, setContext } from 'tone';\n\nlet globalToneContext: Context | null = null;\n\n/**\n * Get the global Tone.js Context\n * This is the main context for cross-browser audio operations.\n * Use context.createAudioWorkletNode(), context.createMediaStreamSource(), etc.\n * @returns The Tone.js Context instance\n */\nexport function getGlobalContext(): Context {\n if (!globalToneContext) {\n globalToneContext = new Context();\n setContext(globalToneContext);\n }\n return globalToneContext;\n}\n\n/**\n * Get or create the global AudioContext\n * Uses Tone.js Context for cross-browser compatibility\n * @returns The global AudioContext instance (rawContext from Tone.Context)\n */\nexport function getGlobalAudioContext(): AudioContext {\n return getGlobalContext().rawContext as AudioContext;\n}\n\n/**\n * @deprecated Use getGlobalContext() instead\n * Get the Tone.js Context's rawContext typed as IAudioContext\n * @returns The rawContext cast as IAudioContext\n */\nexport function getGlobalToneContext(): Context {\n return getGlobalContext();\n}\n\n/**\n * Resume the global AudioContext if it's suspended\n * Should be called in response to a user gesture (e.g., button click)\n * @returns Promise that resolves when context is running\n */\nexport async function resumeGlobalAudioContext(): Promise<void> {\n const context = getGlobalContext();\n if (context.state !== 'running') {\n await context.resume();\n }\n}\n\n/**\n * Get the current state of the global AudioContext\n * @returns The AudioContext state ('suspended', 'running', or 'closed')\n */\nexport function getGlobalAudioContextState(): AudioContextState {\n return globalToneContext?.rawContext.state || 'suspended';\n}\n\n/**\n * Close the global AudioContext\n * Should only be called when the application is shutting down\n */\nexport async function closeGlobalAudioContext(): Promise<void> {\n if (globalToneContext && globalToneContext.rawContext.state !== 'closed') {\n await globalToneContext.close();\n globalToneContext = null;\n }\n}\n","/**\n * MediaStreamSource Manager\n *\n * Manages MediaStreamAudioSourceNode instances to ensure only one source\n * is created per MediaStream per AudioContext.\n *\n * Web Audio API constraint: You can only create one MediaStreamAudioSourceNode\n * per MediaStream per AudioContext. Multiple attempts will fail or disconnect\n * previous sources.\n *\n * This manager ensures a single source is shared across multiple consumers\n * (e.g., AnalyserNode for VU meter, AudioWorkletNode for recording).\n *\n * NOTE: With Tone.js Context, you can also use context.createMediaStreamSource()\n * directly, which handles cross-browser compatibility internally.\n */\n\nimport { getContext } from 'tone';\n\n// Map of MediaStream -> MediaStreamAudioSourceNode\nconst streamSources = new Map<MediaStream, MediaStreamAudioSourceNode>();\n\n// Map of MediaStream -> cleanup handlers\nconst streamCleanupHandlers = new Map<MediaStream, () => void>();\n\n/**\n * Get or create a MediaStreamAudioSourceNode for the given stream\n *\n * @param stream - The MediaStream to create a source for\n * @returns MediaStreamAudioSourceNode that can be connected to multiple nodes\n *\n * @example\n * ```typescript\n * const source = getMediaStreamSource(stream);\n *\n * // Multiple consumers can connect to the same source\n * source.connect(analyserNode); // For VU meter\n * source.connect(workletNode); // For recording\n * ```\n */\nexport function getMediaStreamSource(stream: MediaStream): MediaStreamAudioSourceNode {\n // Return existing source if we have one for this stream\n if (streamSources.has(stream)) {\n return streamSources.get(stream)!;\n }\n\n // Create new source using Tone.js's shared context for cross-browser compatibility\n const context = getContext();\n const source = context.createMediaStreamSource(stream);\n streamSources.set(stream, source);\n\n // Set up cleanup when stream ends\n const cleanup = () => {\n source.disconnect();\n streamSources.delete(stream);\n streamCleanupHandlers.delete(stream);\n\n // Remove event listener\n stream.removeEventListener('ended', cleanup);\n stream.removeEventListener('inactive', cleanup);\n };\n\n streamCleanupHandlers.set(stream, cleanup);\n\n // Clean up when stream ends or becomes inactive\n stream.addEventListener('ended', cleanup);\n stream.addEventListener('inactive', cleanup);\n\n return source;\n}\n\n/**\n * Manually release a MediaStreamSource\n *\n * Normally you don't need to call this - cleanup happens automatically\n * when the stream ends. Only call this if you need to force cleanup.\n *\n * @param stream - The MediaStream to release the source for\n */\nexport function releaseMediaStreamSource(stream: MediaStream): void {\n const cleanup = streamCleanupHandlers.get(stream);\n if (cleanup) {\n cleanup();\n }\n}\n\n/**\n * Check if a MediaStreamSource exists for the given stream\n *\n * @param stream - The MediaStream to check\n * @returns true if a source exists for this stream\n */\nexport function hasMediaStreamSource(stream: MediaStream): boolean {\n return streamSources.has(stream);\n}\n","import type { ClipTrack, Track } from '../core';\nimport {\n clipStartTime,\n clipEndTime,\n clipOffsetTime,\n clipDurationTime,\n} from '../core';\nimport type { PlayoutAdapter } from '../engine';\nimport { TonePlayout } from './TonePlayout';\nimport type { EffectsFunction } from './TonePlayout';\nimport type { ClipInfo } from './ToneTrack';\nimport type { MidiClipInfo } from './MidiToneTrack';\nimport type { SoundFontCache } from './SoundFontCache';\nimport { now } from 'tone';\n\nexport interface ToneAdapterOptions {\n effects?: EffectsFunction;\n /** When provided, MIDI clips use SoundFont sample playback instead of PolySynth */\n soundFontCache?: SoundFontCache;\n}\n\nexport function createToneAdapter(options?: ToneAdapterOptions): PlayoutAdapter {\n let playout: TonePlayout | null = null;\n let _isPlaying = false;\n let _playoutGeneration = 0;\n let _loopEnabled = false;\n let _loopStart = 0;\n let _loopEnd = 0;\n let _audioInitialized = false;\n\n // Add a single ClipTrack to the playout (shared by buildPlayout and addTrack)\n function addTrackToPlayout(p: TonePlayout, track: ClipTrack): void {\n const audioClips = track.clips.filter((c) => c.audioBuffer && !c.midiNotes);\n const midiClips = track.clips.filter((c) => c.midiNotes && c.midiNotes.length > 0);\n\n if (audioClips.length > 0) {\n const startTime = Math.min(...audioClips.map(clipStartTime));\n const endTime = Math.max(...audioClips.map(clipEndTime));\n\n const trackObj: Track = {\n id: track.id,\n name: track.name,\n gain: track.volume,\n muted: track.muted,\n soloed: track.soloed,\n stereoPan: track.pan,\n startTime,\n endTime,\n };\n\n const clipInfos: ClipInfo[] = audioClips.map((clip) => ({\n buffer: clip.audioBuffer!,\n startTime: clipStartTime(clip) - startTime,\n duration: clipDurationTime(clip),\n offset: clipOffsetTime(clip),\n fadeIn: clip.fadeIn,\n fadeOut: clip.fadeOut,\n gain: clip.gain,\n }));\n\n p.addTrack({\n clips: clipInfos,\n track: trackObj,\n effects: track.effects,\n });\n }\n\n if (midiClips.length > 0) {\n const startTime = Math.min(...midiClips.map(clipStartTime));\n const endTime = Math.max(...midiClips.map(clipEndTime));\n\n const trackId = audioClips.length > 0 ? `${track.id}:midi` : track.id;\n\n const trackObj: Track = {\n id: trackId,\n name: track.name,\n gain: track.volume,\n muted: track.muted,\n soloed: track.soloed,\n stereoPan: track.pan,\n startTime,\n endTime,\n };\n\n const midiClipInfos: MidiClipInfo[] = midiClips.map((clip) => ({\n notes: clip.midiNotes!,\n startTime: clipStartTime(clip) - startTime,\n duration: clipDurationTime(clip),\n offset: clipOffsetTime(clip),\n }));\n\n if (options?.soundFontCache?.isLoaded) {\n const firstClip = midiClips[0];\n const midiChannel = firstClip.midiChannel;\n const isPercussion = midiChannel === 9;\n const programNumber = firstClip.midiProgram ?? 0;\n\n p.addSoundFontTrack({\n clips: midiClipInfos,\n track: trackObj,\n soundFontCache: options.soundFontCache,\n programNumber,\n isPercussion,\n effects: track.effects,\n });\n } else {\n if (options?.soundFontCache) {\n console.warn(\n `[songram-daw] SoundFont not loaded for track \"${track.name}\" — falling back to PolySynth.`\n );\n }\n p.addMidiTrack({\n clips: midiClipInfos,\n track: trackObj,\n effects: track.effects,\n });\n }\n }\n }\n\n function buildPlayout(tracks: ClipTrack[]): void {\n if (playout) {\n try {\n playout.dispose();\n } catch (err) {\n console.warn('[songram-daw] Error disposing previous playout during rebuild:', err);\n }\n playout = null;\n }\n\n _playoutGeneration++;\n const generation = _playoutGeneration;\n\n playout = new TonePlayout({\n effects: options?.effects,\n });\n\n // If Tone.start() was already called (AudioContext resumed), carry\n // initialization forward. Tone.start() is safe to call multiple times —\n // it resolves immediately if the AudioContext is already running.\n if (_audioInitialized) {\n playout.init().catch((err) => {\n console.warn(\n '[songram-daw] Failed to re-initialize playout after rebuild. ' +\n 'Audio playback will require another user gesture.',\n err\n );\n _audioInitialized = false;\n });\n }\n\n for (const track of tracks) {\n addTrackToPlayout(playout, track);\n }\n playout.applyInitialSoloState();\n playout.setLoop(_loopEnabled, _loopStart, _loopEnd);\n\n playout.setOnPlaybackComplete(() => {\n if (generation === _playoutGeneration) {\n _isPlaying = false;\n }\n });\n }\n\n return {\n async init(): Promise<void> {\n if (playout) {\n await playout.init();\n _audioInitialized = true;\n }\n },\n\n setTracks(tracks: ClipTrack[]): void {\n buildPlayout(tracks);\n },\n\n addTrack(track: ClipTrack): void {\n if (!playout) {\n throw new Error(\n '[songram-daw] adapter.addTrack() called but no playout exists. ' +\n 'Call setTracks() first to initialize the playout.'\n );\n }\n addTrackToPlayout(playout, track);\n playout.applyInitialSoloState();\n },\n\n play(startTime: number, endTime?: number): void {\n if (!playout) {\n console.warn(\n '[songram-daw] adapter.play() called but no playout is available. ' +\n 'Tracks may not have been set, or the adapter was disposed.'\n );\n return;\n }\n const duration = endTime !== undefined ? endTime - startTime : undefined;\n playout.play(now(), startTime, duration);\n // Only set _isPlaying if play() didn't throw\n // (TonePlayout.play() re-throws after cleanup on Transport failure)\n _isPlaying = true;\n },\n\n pause(): void {\n playout?.pause();\n _isPlaying = false;\n },\n\n stop(): void {\n playout?.stop();\n _isPlaying = false;\n },\n\n seek(time: number): void {\n playout?.seekTo(time);\n },\n\n getCurrentTime(): number {\n return playout?.getCurrentTime() ?? 0;\n },\n\n isPlaying(): boolean {\n return _isPlaying;\n },\n\n setMasterVolume(volume: number): void {\n playout?.setMasterGain(volume);\n },\n\n setTrackVolume(trackId: string, volume: number): void {\n playout?.getTrack(trackId)?.setVolume(volume);\n },\n\n setTrackMute(trackId: string, muted: boolean): void {\n playout?.setMute(trackId, muted);\n },\n\n setTrackSolo(trackId: string, soloed: boolean): void {\n playout?.setSolo(trackId, soloed);\n },\n\n setTrackPan(trackId: string, pan: number): void {\n playout?.getTrack(trackId)?.setPan(pan);\n },\n\n setLoop(enabled: boolean, start: number, end: number): void {\n _loopEnabled = enabled;\n _loopStart = start;\n _loopEnd = end;\n playout?.setLoop(enabled, start, end);\n },\n\n dispose(): void {\n try {\n playout?.dispose();\n } catch (err) {\n console.warn('[songram-daw] Error disposing playout:', err);\n }\n playout = null;\n _isPlaying = false;\n },\n };\n}\n","// data can be any array-like object. It just needs to support .length, .slice, and an element getter []\n\nfunction parseMidi(data) {\n var p = new Parser(data)\n\n var headerChunk = p.readChunk()\n if (headerChunk.id != 'MThd')\n throw \"Bad MIDI file. Expected 'MHdr', got: '\" + headerChunk.id + \"'\"\n var header = parseHeader(headerChunk.data)\n\n var tracks = []\n for (var i=0; !p.eof() && i < header.numTracks; i++) {\n var trackChunk = p.readChunk()\n if (trackChunk.id != 'MTrk')\n throw \"Bad MIDI file. Expected 'MTrk', got: '\" + trackChunk.id + \"'\"\n var track = parseTrack(trackChunk.data)\n tracks.push(track)\n }\n\n return {\n header: header,\n tracks: tracks\n }\n}\n\n\nfunction parseHeader(data) {\n var p = new Parser(data)\n\n var format = p.readUInt16()\n var numTracks = p.readUInt16()\n\n var result = {\n format: format,\n numTracks: numTracks\n }\n\n var timeDivision = p.readUInt16()\n if (timeDivision & 0x8000) {\n result.framesPerSecond = 0x100 - (timeDivision >> 8)\n result.ticksPerFrame = timeDivision & 0xFF\n } else {\n result.ticksPerBeat = timeDivision\n }\n\n return result\n}\n\nfunction parseTrack(data) {\n var p = new Parser(data)\n\n var events = []\n while (!p.eof()) {\n var event = readEvent()\n events.push(event)\n }\n\n return events\n\n var lastEventTypeByte = null\n\n function readEvent() {\n var event = {}\n event.deltaTime = p.readVarInt()\n\n var eventTypeByte = p.readUInt8()\n\n if ((eventTypeByte & 0xf0) === 0xf0) {\n // system / meta event\n if (eventTypeByte === 0xff) {\n // meta event\n event.meta = true\n var metatypeByte = p.readUInt8()\n var length = p.readVarInt()\n switch (metatypeByte) {\n case 0x00:\n event.type = 'sequenceNumber'\n if (length !== 2) throw \"Expected length for sequenceNumber event is 2, got \" + length\n event.number = p.readUInt16()\n return event\n case 0x01:\n event.type = 'text'\n event.text = p.readString(length)\n return event\n case 0x02:\n event.type = 'copyrightNotice'\n event.text = p.readString(length)\n return event\n case 0x03:\n event.type = 'trackName'\n event.text = p.readString(length)\n return event\n case 0x04:\n event.type = 'instrumentName'\n event.text = p.readString(length)\n return event\n case 0x05:\n event.type = 'lyrics'\n event.text = p.readString(length)\n return event\n case 0x06:\n event.type = 'marker'\n event.text = p.readString(length)\n return event\n case 0x07:\n event.type = 'cuePoint'\n event.text = p.readString(length)\n return event\n case 0x20:\n event.type = 'channelPrefix'\n if (length != 1) throw \"Expected length for channelPrefix event is 1, got \" + length\n event.channel = p.readUInt8()\n return event\n case 0x21:\n event.type = 'portPrefix'\n if (length != 1) throw \"Expected length for portPrefix event is 1, got \" + length\n event.port = p.readUInt8()\n return event\n case 0x2f:\n event.type = 'endOfTrack'\n if (length != 0) throw \"Expected length for endOfTrack event is 0, got \" + length\n return event\n case 0x51:\n event.type = 'setTempo';\n if (length != 3) throw \"Expected length for setTempo event is 3, got \" + length\n event.microsecondsPerBeat = p.readUInt24()\n return event\n case 0x54:\n event.type = 'smpteOffset';\n if (length != 5) throw \"Expected length for smpteOffset event is 5, got \" + length\n var hourByte = p.readUInt8()\n var FRAME_RATES = { 0x00: 24, 0x20: 25, 0x40: 29, 0x60: 30 }\n event.frameRate = FRAME_RATES[hourByte & 0x60]\n event.hour = hourByte & 0x1f\n event.min = p.readUInt8()\n event.sec = p.readUInt8()\n event.frame = p.readUInt8()\n event.subFrame = p.readUInt8()\n return event\n case 0x58:\n event.type = 'timeSignature'\n if (length != 2 && length != 4) throw \"Expected length for timeSignature event is 4 or 2, got \" + length\n event.numerator = p.readUInt8()\n event.denominator = (1 << p.readUInt8())\n if (length === 4) {\n event.metronome = p.readUInt8()\n event.thirtyseconds = p.readUInt8()\n } else {\n event.metronome = 0x24\n event.thirtyseconds = 0x08\n }\n return event\n case 0x59:\n event.type = 'keySignature'\n if (length != 2) throw \"Expected length for keySignature event is 2, got \" + length\n event.key = p.readInt8()\n event.scale = p.readUInt8()\n return event\n case 0x7f:\n event.type = 'sequencerSpecific'\n event.data = p.readBytes(length)\n return event\n default:\n event.type = 'unknownMeta'\n event.data = p.readBytes(length)\n event.metatypeByte = metatypeByte\n return event\n }\n } else if (eventTypeByte == 0xf0) {\n event.type = 'sysEx'\n var length = p.readVarInt()\n event.data = p.readBytes(length)\n return event\n } else if (eventTypeByte == 0xf7) {\n event.type = 'endSysEx'\n var length = p.readVarInt()\n event.data = p.readBytes(length)\n return event\n } else {\n throw \"Unrecognised MIDI event type byte: \" + eventTypeByte\n }\n } else {\n // channel event\n var param1\n if ((eventTypeByte & 0x80) === 0) {\n // running status - reuse lastEventTypeByte as the event type.\n // eventTypeByte is actually the first parameter\n if (lastEventTypeByte === null)\n throw \"Running status byte encountered before status byte\"\n param1 = eventTypeByte\n eventTypeByte = lastEventTypeByte\n event.running = true\n } else {\n param1 = p.readUInt8()\n lastEventTypeByte = eventTypeByte\n }\n var eventType = eventTypeByte >> 4\n event.channel = eventTypeByte & 0x0f\n switch (eventType) {\n case 0x08:\n event.type = 'noteOff'\n event.noteNumber = param1\n event.velocity = p.readUInt8()\n return event\n case 0x09:\n var velocity = p.readUInt8()\n event.type = velocity === 0 ? 'noteOff' : 'noteOn'\n event.noteNumber = param1\n event.velocity = velocity\n if (velocity === 0) event.byte9 = true\n return event\n case 0x0a:\n event.type = 'noteAftertouch'\n event.noteNumber = param1\n event.amount = p.readUInt8()\n return event\n case 0x0b:\n event.type = 'controller'\n event.controllerType = param1\n event.value = p.readUInt8()\n return event\n case 0x0c:\n event.type = 'programChange'\n event.programNumber = param1\n return event\n case 0x0d:\n event.type = 'channelAftertouch'\n event.amount = param1\n return event\n case 0x0e:\n event.type = 'pitchBend'\n event.value = (param1 + (p.readUInt8() << 7)) - 0x2000\n return event\n default:\n throw \"Unrecognised MIDI event type: \" + eventType\n }\n }\n }\n}\n\nfunction Parser(data) {\n this.buffer = data\n this.bufferLen = this.buffer.length\n this.pos = 0\n}\n\nParser.prototype.eof = function() {\n return this.pos >= this.bufferLen\n}\n\nParser.prototype.readUInt8 = function() {\n var result = this.buffer[this.pos]\n this.pos += 1\n return result\n}\n\nParser.prototype.readInt8 = function() {\n var u = this.readUInt8()\n if (u & 0x80)\n return u - 0x100\n else\n return u\n}\n\nParser.prototype.readUInt16 = function() {\n var b0 = this.readUInt8(),\n b1 = this.readUInt8()\n\n return (b0 << 8) + b1\n}\n\nParser.prototype.readInt16 = function() {\n var u = this.readUInt16()\n if (u & 0x8000)\n return u - 0x10000\n else\n return u\n}\n\nParser.prototype.readUInt24 = function() {\n var b0 = this.readUInt8(),\n b1 = this.readUInt8(),\n b2 = this.readUInt8()\n\n return (b0 << 16) + (b1 << 8) + b2\n}\n\nParser.prototype.readInt24 = function() {\n var u = this.readUInt24()\n if (u & 0x800000)\n return u - 0x1000000\n else\n return u\n}\n\nParser.prototype.readUInt32 = function() {\n var b0 = this.readUInt8(),\n b1 = this.readUInt8(),\n b2 = this.readUInt8(),\n b3 = this.readUInt8()\n\n return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3\n}\n\nParser.prototype.readBytes = function(len) {\n var bytes = this.buffer.slice(this.pos, this.pos + len)\n this.pos += len\n return bytes\n}\n\nParser.prototype.readString = function(len) {\n var bytes = this.readBytes(len)\n return String.fromCharCode.apply(null, bytes)\n}\n\nParser.prototype.readVarInt = function() {\n var result = 0\n while (!this.eof()) {\n var b = this.readUInt8()\n if (b & 0x80) {\n result += (b & 0x7f)\n result <<= 7\n } else {\n // b is last byte\n return result + b\n }\n }\n // premature eof\n return result\n}\n\nParser.prototype.readChunk = function() {\n var id = this.readString(4)\n var length = this.readUInt32()\n var data = this.readBytes(length)\n return {\n id: id,\n length: length,\n data: data\n }\n}\n\nmodule.exports = parseMidi\n","// data should be the same type of format returned by parseMidi\n// for maximum compatibililty, returns an array of byte values, suitable for conversion to Buffer, Uint8Array, etc.\n\n// opts:\n// - running reuse previous eventTypeByte when possible, to compress file\n// - useByte9ForNoteOff use 0x09 for noteOff when velocity is zero\n\nfunction writeMidi(data, opts) {\n if (typeof data !== 'object')\n throw 'Invalid MIDI data'\n\n opts = opts || {}\n\n var header = data.header || {}\n var tracks = data.tracks || []\n var i, len = tracks.length\n\n var w = new Writer()\n writeHeader(w, header, len)\n\n for (i=0; i < len; i++) {\n writeTrack(w, tracks[i], opts)\n }\n\n return w.buffer\n}\n\nfunction writeHeader(w, header, numTracks) {\n var format = header.format == null ? 1 : header.format\n\n var timeDivision = 128\n if (header.timeDivision) {\n timeDivision = header.timeDivision\n } else if (header.ticksPerFrame && header.framesPerSecond) {\n timeDivision = (-(header.framesPerSecond & 0xFF) << 8) | (header.ticksPerFrame & 0xFF)\n } else if (header.ticksPerBeat) {\n timeDivision = header.ticksPerBeat & 0x7FFF\n }\n\n var h = new Writer()\n h.writeUInt16(format)\n h.writeUInt16(numTracks)\n h.writeUInt16(timeDivision)\n\n w.writeChunk('MThd', h.buffer)\n}\n\nfunction writeTrack(w, track, opts) {\n var t = new Writer()\n var i, len = track.length\n var eventTypeByte = null\n for (i=0; i < len; i++) {\n // Reuse last eventTypeByte when opts.running is set, or event.running is explicitly set on it.\n // parseMidi will set event.running for each event, so that we can get an exact copy by default.\n // Explicitly set opts.running to false, to override event.running and never reuse last eventTypeByte.\n if (opts.running === false || !opts.running && !track[i].running) eventTypeByte = null\n\n eventTypeByte = writeEvent(t, track[i], eventTypeByte, opts.useByte9ForNoteOff)\n }\n w.writeChunk('MTrk', t.buffer)\n}\n\nfunction writeEvent(w, event, lastEventTypeByte, useByte9ForNoteOff) {\n var type = event.type\n var deltaTime = event.deltaTime\n var text = event.text || ''\n var data = event.data || []\n var eventTypeByte = null\n w.writeVarInt(deltaTime)\n\n switch (type) {\n // meta events\n case 'sequenceNumber':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x00)\n w.writeVarInt(2)\n w.writeUInt16(event.number)\n break;\n\n case 'text':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x01)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'copyrightNotice':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x02)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'trackName':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x03)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'instrumentName':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x04)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'lyrics':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x05)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'marker':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x06)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'cuePoint':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x07)\n w.writeVarInt(text.length)\n w.writeString(text)\n break;\n\n case 'channelPrefix':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x20)\n w.writeVarInt(1)\n w.writeUInt8(event.channel)\n break;\n\n case 'portPrefix':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x21)\n w.writeVarInt(1)\n w.writeUInt8(event.port)\n break;\n\n case 'endOfTrack':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x2F)\n w.writeVarInt(0)\n break;\n\n case 'setTempo':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x51)\n w.writeVarInt(3)\n w.writeUInt24(event.microsecondsPerBeat)\n break;\n\n case 'smpteOffset':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x54)\n w.writeVarInt(5)\n var FRAME_RATES = { 24: 0x00, 25: 0x20, 29: 0x40, 30: 0x60 }\n var hourByte = (event.hour & 0x1F) | FRAME_RATES[event.frameRate]\n w.writeUInt8(hourByte)\n w.writeUInt8(event.min)\n w.writeUInt8(event.sec)\n w.writeUInt8(event.frame)\n w.writeUInt8(event.subFrame)\n break;\n\n case 'timeSignature':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x58)\n w.writeVarInt(4)\n w.writeUInt8(event.numerator)\n var denominator = Math.floor((Math.log(event.denominator) / Math.LN2)) & 0xFF\n w.writeUInt8(denominator)\n w.writeUInt8(event.metronome)\n w.writeUInt8(event.thirtyseconds || 8)\n break;\n\n case 'keySignature':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x59)\n w.writeVarInt(2)\n w.writeInt8(event.key)\n w.writeUInt8(event.scale)\n break;\n\n case 'sequencerSpecific':\n w.writeUInt8(0xFF)\n w.writeUInt8(0x7F)\n w.writeVarInt(data.length)\n w.writeBytes(data)\n break;\n\n case 'unknownMeta':\n if (event.metatypeByte != null) {\n w.writeUInt8(0xFF)\n w.writeUInt8(event.metatypeByte)\n w.writeVarInt(data.length)\n w.writeBytes(data)\n }\n break;\n\n // system-exclusive\n case 'sysEx':\n w.writeUInt8(0xF0)\n w.writeVarInt(data.length)\n w.writeBytes(data)\n break;\n\n case 'endSysEx':\n w.writeUInt8(0xF7)\n w.writeVarInt(data.length)\n w.writeBytes(data)\n break;\n\n // channel events\n case 'noteOff':\n // Use 0x90 when opts.useByte9ForNoteOff is set and velocity is zero, or when event.byte9 is explicitly set on it.\n // parseMidi will set event.byte9 for each event, so that we can get an exact copy by default.\n // Explicitly set opts.useByte9ForNoteOff to false, to override event.byte9 and always use 0x80 for noteOff events.\n var noteByte = ((useByte9ForNoteOff !== false && event.byte9) || (useByte9ForNoteOff && event.velocity == 0)) ? 0x90 : 0x80\n\n eventTypeByte = noteByte | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n w.writeUInt8(event.noteNumber)\n w.writeUInt8(event.velocity)\n break;\n\n case 'noteOn':\n eventTypeByte = 0x90 | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n w.writeUInt8(event.noteNumber)\n w.writeUInt8(event.velocity)\n break;\n\n case 'noteAftertouch':\n eventTypeByte = 0xA0 | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n w.writeUInt8(event.noteNumber)\n w.writeUInt8(event.amount)\n break;\n\n case 'controller':\n eventTypeByte = 0xB0 | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n w.writeUInt8(event.controllerType)\n w.writeUInt8(event.value)\n break;\n\n case 'programChange':\n eventTypeByte = 0xC0 | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n w.writeUInt8(event.programNumber)\n break;\n\n case 'channelAftertouch':\n eventTypeByte = 0xD0 | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n w.writeUInt8(event.amount)\n break;\n\n case 'pitchBend':\n eventTypeByte = 0xE0 | event.channel\n if (eventTypeByte !== lastEventTypeByte) w.writeUInt8(eventTypeByte)\n var value14 = 0x2000 + event.value\n var lsb14 = (value14 & 0x7F)\n var msb14 = (value14 >> 7) & 0x7F\n w.writeUInt8(lsb14)\n w.writeUInt8(msb14)\n break;\n\n default:\n throw 'Unrecognized event type: ' + type\n }\n return eventTypeByte\n}\n\n\nfunction Writer() {\n this.buffer = []\n}\n\nWriter.prototype.writeUInt8 = function(v) {\n this.buffer.push(v & 0xFF)\n}\nWriter.prototype.writeInt8 = Writer.prototype.writeUInt8\n\nWriter.prototype.writeUInt16 = function(v) {\n var b0 = (v >> 8) & 0xFF,\n b1 = v & 0xFF\n\n this.writeUInt8(b0)\n this.writeUInt8(b1)\n}\nWriter.prototype.writeInt16 = Writer.prototype.writeUInt16\n\nWriter.prototype.writeUInt24 = function(v) {\n var b0 = (v >> 16) & 0xFF,\n b1 = (v >> 8) & 0xFF,\n b2 = v & 0xFF\n\n this.writeUInt8(b0)\n this.writeUInt8(b1)\n this.writeUInt8(b2)\n}\nWriter.prototype.writeInt24 = Writer.prototype.writeUInt24\n\nWriter.prototype.writeUInt32 = function(v) {\n var b0 = (v >> 24) & 0xFF,\n b1 = (v >> 16) & 0xFF,\n b2 = (v >> 8) & 0xFF,\n b3 = v & 0xFF\n\n this.writeUInt8(b0)\n this.writeUInt8(b1)\n this.writeUInt8(b2)\n this.writeUInt8(b3)\n}\nWriter.prototype.writeInt32 = Writer.prototype.writeUInt32\n\n\nWriter.prototype.writeBytes = function(arr) {\n this.buffer = this.buffer.concat(Array.prototype.slice.call(arr, 0))\n}\n\nWriter.prototype.writeString = function(str) {\n var i, len = str.length, arr = []\n for (i=0; i < len; i++) {\n arr.push(str.codePointAt(i))\n }\n this.writeBytes(arr)\n}\n\nWriter.prototype.writeVarInt = function(v) {\n if (v < 0) throw \"Cannot write negative variable-length integer\"\n\n if (v <= 0x7F) {\n this.writeUInt8(v)\n } else {\n var i = v\n var bytes = []\n bytes.push(i & 0x7F)\n i >>= 7\n while (i) {\n var b = i & 0x7F | 0x80\n bytes.push(b)\n i >>= 7\n }\n this.writeBytes(bytes.reverse())\n }\n}\n\nWriter.prototype.writeChunk = function(id, data) {\n this.writeString(id)\n this.writeUInt32(data.length)\n this.writeBytes(data)\n}\n\nmodule.exports = writeMidi\n","exports.parseMidi = require('./lib/midi-parser')\nexports.writeMidi = require('./lib/midi-writer')\n","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.insert = exports.search = void 0;\n/**\n * Return the index of the element at or before the given property\n * @hidden\n */\nfunction search(array, value, prop) {\n if (prop === void 0) { prop = \"ticks\"; }\n var beginning = 0;\n var len = array.length;\n var end = len;\n if (len > 0 && array[len - 1][prop] <= value) {\n return len - 1;\n }\n while (beginning < end) {\n // calculate the midpoint for roughly equal partition\n var midPoint = Math.floor(beginning + (end - beginning) / 2);\n var event_1 = array[midPoint];\n var nextEvent = array[midPoint + 1];\n if (event_1[prop] === value) {\n // choose the last one that has the same value\n for (var i = midPoint; i < array.length; i++) {\n var testEvent = array[i];\n if (testEvent[prop] === value) {\n midPoint = i;\n }\n }\n return midPoint;\n }\n else if (event_1[prop] < value && nextEvent[prop] > value) {\n return midPoint;\n }\n else if (event_1[prop] > value) {\n // search lower\n end = midPoint;\n }\n else if (event_1[prop] < value) {\n // search upper\n beginning = midPoint + 1;\n }\n }\n return -1;\n}\nexports.search = search;\n/**\n * Does a binary search to insert the note\n * in the correct spot in the array\n * @hidden\n */\nfunction insert(array, event, prop) {\n if (prop === void 0) { prop = \"ticks\"; }\n if (array.length) {\n var index = search(array, event[prop], prop);\n array.splice(index + 1, 0, event);\n }\n else {\n array.push(event);\n }\n}\nexports.insert = insert;\n//# sourceMappingURL=BinarySearch.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Header = exports.keySignatureKeys = void 0;\nvar BinarySearch_1 = require(\"./BinarySearch\");\nvar privatePPQMap = new WeakMap();\n/**\n * @hidden\n */\nexports.keySignatureKeys = [\n \"Cb\",\n \"Gb\",\n \"Db\",\n \"Ab\",\n \"Eb\",\n \"Bb\",\n \"F\",\n \"C\",\n \"G\",\n \"D\",\n \"A\",\n \"E\",\n \"B\",\n \"F#\",\n \"C#\",\n];\n/**\n * The parsed MIDI file header.\n */\nvar Header = /** @class */ (function () {\n function Header(midiData) {\n var _this = this;\n /**\n * The array of all the tempo events.\n */\n this.tempos = [];\n /**\n * The time signatures.\n */\n this.timeSignatures = [];\n /**\n * The time signatures.\n */\n this.keySignatures = [];\n /**\n * Additional meta events.\n */\n this.meta = [];\n /**\n * The name of the MIDI file;\n */\n this.name = \"\";\n // Look through all the tracks for tempo changes.\n privatePPQMap.set(this, 480);\n if (midiData) {\n privatePPQMap.set(this, midiData.header.ticksPerBeat);\n // Check time signature and tempo events from all of the tracks.\n midiData.tracks.forEach(function (track) {\n track.forEach(function (event) {\n if (event.meta) {\n if (event.type === \"timeSignature\") {\n _this.timeSignatures.push({\n ticks: event.absoluteTime,\n timeSignature: [\n event.numerator,\n event.denominator,\n ],\n });\n }\n else if (event.type === \"setTempo\") {\n _this.tempos.push({\n bpm: 60000000 / event.microsecondsPerBeat,\n ticks: event.absoluteTime,\n });\n }\n else if (event.type === \"keySignature\") {\n _this.keySignatures.push({\n key: exports.keySignatureKeys[event.key + 7],\n scale: event.scale === 0 ? \"major\" : \"minor\",\n ticks: event.absoluteTime,\n });\n }\n }\n });\n });\n // Check the first track for other relevant data.\n var firstTrackCurrentTicks_1 = 0; // Used for absolute times.\n midiData.tracks[0].forEach(function (event) {\n firstTrackCurrentTicks_1 += event.deltaTime;\n if (event.meta) {\n if (event.type === \"trackName\") {\n _this.name = event.text;\n }\n else if (event.type === \"text\" ||\n event.type === \"cuePoint\" ||\n event.type === \"marker\" ||\n event.type === \"lyrics\") {\n _this.meta.push({\n text: event.text,\n ticks: firstTrackCurrentTicks_1,\n type: event.type,\n });\n }\n }\n });\n this.update();\n }\n }\n /**\n * This must be invoked after any changes are made to the tempo array\n * or the timeSignature array for the updated values to be reflected.\n */\n Header.prototype.update = function () {\n var _this = this;\n var currentTime = 0;\n var lastEventBeats = 0;\n // Make sure it's sorted;\n this.tempos.sort(function (a, b) { return a.ticks - b.ticks; });\n this.tempos.forEach(function (event, index) {\n var lastBPM = index > 0 ? _this.tempos[index - 1].bpm : _this.tempos[0].bpm;\n var beats = event.ticks / _this.ppq - lastEventBeats;\n var elapsedSeconds = (60 / lastBPM) * beats;\n event.time = elapsedSeconds + currentTime;\n currentTime = event.time;\n lastEventBeats += beats;\n });\n this.timeSignatures.sort(function (a, b) { return a.ticks - b.ticks; });\n this.timeSignatures.forEach(function (event, index) {\n var lastEvent = index > 0\n ? _this.timeSignatures[index - 1]\n : _this.timeSignatures[0];\n var elapsedBeats = (event.ticks - lastEvent.ticks) / _this.ppq;\n var elapsedMeasures = elapsedBeats /\n lastEvent.timeSignature[0] /\n (lastEvent.timeSignature[1] / 4);\n lastEvent.measures = lastEvent.measures || 0;\n event.measures = elapsedMeasures + lastEvent.measures;\n });\n };\n /**\n * Convert ticks into seconds based on the tempo changes.\n */\n Header.prototype.ticksToSeconds = function (ticks) {\n // Find the relevant position.\n var index = (0, BinarySearch_1.search)(this.tempos, ticks);\n if (index !== -1) {\n var tempo = this.tempos[index];\n var tempoTime = tempo.time;\n var elapsedBeats = (ticks - tempo.ticks) / this.ppq;\n return tempoTime + (60 / tempo.bpm) * elapsedBeats;\n }\n else {\n // Assume 120.\n var beats = ticks / this.ppq;\n return (60 / 120) * beats;\n }\n };\n /**\n * Convert ticks into measures based off of the time signatures.\n */\n Header.prototype.ticksToMeasures = function (ticks) {\n var index = (0, BinarySearch_1.search)(this.timeSignatures, ticks);\n if (index !== -1) {\n var timeSigEvent = this.timeSignatures[index];\n var elapsedBeats = (ticks - timeSigEvent.ticks) / this.ppq;\n return (timeSigEvent.measures +\n elapsedBeats /\n (timeSigEvent.timeSignature[0] /\n timeSigEvent.timeSignature[1]) /\n 4);\n }\n else {\n return ticks / this.ppq / 4;\n }\n };\n Object.defineProperty(Header.prototype, \"ppq\", {\n /**\n * The number of ticks per quarter note.\n */\n get: function () {\n return privatePPQMap.get(this);\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Convert seconds to ticks based on the tempo events.\n */\n Header.prototype.secondsToTicks = function (seconds) {\n // Find the relevant position.\n var index = (0, BinarySearch_1.search)(this.tempos, seconds, \"time\");\n if (index !== -1) {\n var tempo = this.tempos[index];\n var tempoTime = tempo.time;\n var elapsedTime = seconds - tempoTime;\n var elapsedBeats = elapsedTime / (60 / tempo.bpm);\n return Math.round(tempo.ticks + elapsedBeats * this.ppq);\n }\n else {\n // Assume 120.\n var beats = seconds / (60 / 120);\n return Math.round(beats * this.ppq);\n }\n };\n /**\n * Convert the header into an object.\n */\n Header.prototype.toJSON = function () {\n return {\n keySignatures: this.keySignatures,\n meta: this.meta,\n name: this.name,\n ppq: this.ppq,\n tempos: this.tempos.map(function (t) {\n return {\n bpm: t.bpm,\n ticks: t.ticks,\n };\n }),\n timeSignatures: this.timeSignatures,\n };\n };\n /**\n * Parse a header json object.\n */\n Header.prototype.fromJSON = function (json) {\n this.name = json.name;\n // Clone all the attributes.\n this.tempos = json.tempos.map(function (t) { return Object.assign({}, t); });\n this.timeSignatures = json.timeSignatures.map(function (t) {\n return Object.assign({}, t);\n });\n this.keySignatures = json.keySignatures.map(function (t) {\n return Object.assign({}, t);\n });\n this.meta = json.meta.map(function (t) { return Object.assign({}, t); });\n privatePPQMap.set(this, json.ppq);\n this.update();\n };\n /**\n * Update the tempo of the midi to a single tempo. Will remove and replace\n * any other tempos currently set and update all of the event timing.\n * @param bpm The tempo in beats per second.\n */\n Header.prototype.setTempo = function (bpm) {\n this.tempos = [\n {\n bpm: bpm,\n ticks: 0,\n },\n ];\n this.update();\n };\n return Header;\n}());\nexports.Header = Header;\n//# sourceMappingURL=Header.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.ControlChange = exports.controlChangeIds = exports.controlChangeNames = void 0;\n/**\n * A map of values to control change names\n * @hidden\n */\nexports.controlChangeNames = {\n 1: \"modulationWheel\",\n 2: \"breath\",\n 4: \"footController\",\n 5: \"portamentoTime\",\n 7: \"volume\",\n 8: \"balance\",\n 10: \"pan\",\n 64: \"sustain\",\n 65: \"portamentoTime\",\n 66: \"sostenuto\",\n 67: \"softPedal\",\n 68: \"legatoFootswitch\",\n 84: \"portamentoControl\",\n};\n/**\n * swap the keys and values\n * @hidden\n */\nexports.controlChangeIds = Object.keys(exports.controlChangeNames).reduce(function (obj, key) {\n obj[exports.controlChangeNames[key]] = key;\n return obj;\n}, {});\nvar privateHeaderMap = new WeakMap();\nvar privateCCNumberMap = new WeakMap();\n/**\n * Represents a control change event\n */\nvar ControlChange = /** @class */ (function () {\n /**\n * @param event\n * @param header\n */\n function ControlChange(event, header) {\n privateHeaderMap.set(this, header);\n privateCCNumberMap.set(this, event.controllerType);\n this.ticks = event.absoluteTime;\n this.value = event.value;\n }\n Object.defineProperty(ControlChange.prototype, \"number\", {\n /**\n * The controller number\n */\n get: function () {\n return privateCCNumberMap.get(this);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ControlChange.prototype, \"name\", {\n /**\n * return the common name of the control number if it exists\n */\n get: function () {\n if (exports.controlChangeNames[this.number]) {\n return exports.controlChangeNames[this.number];\n }\n else {\n return null;\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(ControlChange.prototype, \"time\", {\n /**\n * The time of the event in seconds\n */\n get: function () {\n var header = privateHeaderMap.get(this);\n return header.ticksToSeconds(this.ticks);\n },\n set: function (t) {\n var header = privateHeaderMap.get(this);\n this.ticks = header.secondsToTicks(t);\n },\n enumerable: false,\n configurable: true\n });\n ControlChange.prototype.toJSON = function () {\n return {\n number: this.number,\n ticks: this.ticks,\n time: this.time,\n value: this.value,\n };\n };\n return ControlChange;\n}());\nexports.ControlChange = ControlChange;\n//# sourceMappingURL=ControlChange.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.createControlChanges = void 0;\nvar ControlChange_1 = require(\"./ControlChange\");\n/**\n * Automatically creates an alias for named control values using Proxies\n * @hidden\n */\nfunction createControlChanges() {\n return new Proxy({}, {\n // tslint:disable-next-line: typedef\n get: function (target, handler) {\n if (target[handler]) {\n return target[handler];\n }\n else if (ControlChange_1.controlChangeIds.hasOwnProperty(handler)) {\n return target[ControlChange_1.controlChangeIds[handler]];\n }\n },\n // tslint:disable-next-line: typedef\n set: function (target, handler, value) {\n if (ControlChange_1.controlChangeIds.hasOwnProperty(handler)) {\n target[ControlChange_1.controlChangeIds[handler]] = value;\n }\n else {\n target[handler] = value;\n }\n return true;\n },\n });\n}\nexports.createControlChanges = createControlChanges;\n//# sourceMappingURL=ControlChanges.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.PitchBend = void 0;\nvar privateHeaderMap = new WeakMap();\n/**\n * Represents a pitch bend event.\n */\nvar PitchBend = /** @class */ (function () {\n /**\n * @param event\n * @param header\n */\n function PitchBend(event, header) {\n privateHeaderMap.set(this, header);\n this.ticks = event.absoluteTime;\n this.value = event.value;\n }\n Object.defineProperty(PitchBend.prototype, \"time\", {\n /**\n * The time of the event in seconds\n */\n get: function () {\n var header = privateHeaderMap.get(this);\n return header.ticksToSeconds(this.ticks);\n },\n set: function (t) {\n var header = privateHeaderMap.get(this);\n this.ticks = header.secondsToTicks(t);\n },\n enumerable: false,\n configurable: true\n });\n PitchBend.prototype.toJSON = function () {\n return {\n ticks: this.ticks,\n time: this.time,\n value: this.value,\n };\n };\n return PitchBend;\n}());\nexports.PitchBend = PitchBend;\n//# sourceMappingURL=PitchBend.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.DrumKitByPatchID = exports.InstrumentFamilyByID = exports.instrumentByPatchID = void 0;\nexports.instrumentByPatchID = [\n \"acoustic grand piano\",\n \"bright acoustic piano\",\n \"electric grand piano\",\n \"honky-tonk piano\",\n \"electric piano 1\",\n \"electric piano 2\",\n \"harpsichord\",\n \"clavi\",\n \"celesta\",\n \"glockenspiel\",\n \"music box\",\n \"vibraphone\",\n \"marimba\",\n \"xylophone\",\n \"tubular bells\",\n \"dulcimer\",\n \"drawbar organ\",\n \"percussive organ\",\n \"rock organ\",\n \"church organ\",\n \"reed organ\",\n \"accordion\",\n \"harmonica\",\n \"tango accordion\",\n \"acoustic guitar (nylon)\",\n \"acoustic guitar (steel)\",\n \"electric guitar (jazz)\",\n \"electric guitar (clean)\",\n \"electric guitar (muted)\",\n \"overdriven guitar\",\n \"distortion guitar\",\n \"guitar harmonics\",\n \"acoustic bass\",\n \"electric bass (finger)\",\n \"electric bass (pick)\",\n \"fretless bass\",\n \"slap bass 1\",\n \"slap bass 2\",\n \"synth bass 1\",\n \"synth bass 2\",\n \"violin\",\n \"viola\",\n \"cello\",\n \"contrabass\",\n \"tremolo strings\",\n \"pizzicato strings\",\n \"orchestral harp\",\n \"timpani\",\n \"string ensemble 1\",\n \"string ensemble 2\",\n \"synthstrings 1\",\n \"synthstrings 2\",\n \"choir aahs\",\n \"voice oohs\",\n \"synth voice\",\n \"orchestra hit\",\n \"trumpet\",\n \"trombone\",\n \"tuba\",\n \"muted trumpet\",\n \"french horn\",\n \"brass section\",\n \"synthbrass 1\",\n \"synthbrass 2\",\n \"soprano sax\",\n \"alto sax\",\n \"tenor sax\",\n \"baritone sax\",\n \"oboe\",\n \"english horn\",\n \"bassoon\",\n \"clarinet\",\n \"piccolo\",\n \"flute\",\n \"recorder\",\n \"pan flute\",\n \"blown bottle\",\n \"shakuhachi\",\n \"whistle\",\n \"ocarina\",\n \"lead 1 (square)\",\n \"lead 2 (sawtooth)\",\n \"lead 3 (calliope)\",\n \"lead 4 (chiff)\",\n \"lead 5 (charang)\",\n \"lead 6 (voice)\",\n \"lead 7 (fifths)\",\n \"lead 8 (bass + lead)\",\n \"pad 1 (new age)\",\n \"pad 2 (warm)\",\n \"pad 3 (polysynth)\",\n \"pad 4 (choir)\",\n \"pad 5 (bowed)\",\n \"pad 6 (metallic)\",\n \"pad 7 (halo)\",\n \"pad 8 (sweep)\",\n \"fx 1 (rain)\",\n \"fx 2 (soundtrack)\",\n \"fx 3 (crystal)\",\n \"fx 4 (atmosphere)\",\n \"fx 5 (brightness)\",\n \"fx 6 (goblins)\",\n \"fx 7 (echoes)\",\n \"fx 8 (sci-fi)\",\n \"sitar\",\n \"banjo\",\n \"shamisen\",\n \"koto\",\n \"kalimba\",\n \"bag pipe\",\n \"fiddle\",\n \"shanai\",\n \"tinkle bell\",\n \"agogo\",\n \"steel drums\",\n \"woodblock\",\n \"taiko drum\",\n \"melodic tom\",\n \"synth drum\",\n \"reverse cymbal\",\n \"guitar fret noise\",\n \"breath noise\",\n \"seashore\",\n \"bird tweet\",\n \"telephone ring\",\n \"helicopter\",\n \"applause\",\n \"gunshot\",\n];\nexports.InstrumentFamilyByID = [\n \"piano\",\n \"chromatic percussion\",\n \"organ\",\n \"guitar\",\n \"bass\",\n \"strings\",\n \"ensemble\",\n \"brass\",\n \"reed\",\n \"pipe\",\n \"synth lead\",\n \"synth pad\",\n \"synth effects\",\n \"world\",\n \"percussive\",\n \"sound effects\",\n];\nexports.DrumKitByPatchID = {\n 0: \"standard kit\",\n 8: \"room kit\",\n 16: \"power kit\",\n 24: \"electronic kit\",\n 25: \"tr-808 kit\",\n 32: \"jazz kit\",\n 40: \"brush kit\",\n 48: \"orchestra kit\",\n 56: \"sound fx kit\",\n};\n//# sourceMappingURL=InstrumentMaps.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Instrument = void 0;\nvar InstrumentMaps_1 = require(\"./InstrumentMaps\");\n/**\n * @hidden\n */\nvar privateTrackMap = new WeakMap();\n/**\n * Describes the MIDI instrument of a track.\n */\nvar Instrument = /** @class */ (function () {\n /**\n * @param trackData\n * @param track\n */\n function Instrument(trackData, track) {\n /**\n * The instrument number. Defaults to 0.\n */\n this.number = 0;\n privateTrackMap.set(this, track);\n this.number = 0;\n if (trackData) {\n var programChange = trackData.find(function (e) { return e.type === \"programChange\"; });\n // Set 'number' from 'programNumber' if exists.\n if (programChange) {\n this.number = programChange.programNumber;\n }\n }\n }\n Object.defineProperty(Instrument.prototype, \"name\", {\n /**\n * The common name of the instrument.\n */\n get: function () {\n if (this.percussion) {\n return InstrumentMaps_1.DrumKitByPatchID[this.number];\n }\n else {\n return InstrumentMaps_1.instrumentByPatchID[this.number];\n }\n },\n set: function (n) {\n var patchNumber = InstrumentMaps_1.instrumentByPatchID.indexOf(n);\n if (patchNumber !== -1) {\n this.number = patchNumber;\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Instrument.prototype, \"family\", {\n /**\n * The instrument family, e.g. \"piano\".\n */\n get: function () {\n if (this.percussion) {\n return \"drums\";\n }\n else {\n return InstrumentMaps_1.InstrumentFamilyByID[Math.floor(this.number / 8)];\n }\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Instrument.prototype, \"percussion\", {\n /**\n * If the instrument is a percussion instrument.\n */\n get: function () {\n var track = privateTrackMap.get(this);\n return track.channel === 9;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Convert it to JSON form.\n */\n Instrument.prototype.toJSON = function () {\n return {\n family: this.family,\n number: this.number,\n name: this.name\n };\n };\n /**\n * Convert from JSON form.\n */\n Instrument.prototype.fromJSON = function (json) {\n this.number = json.number;\n };\n return Instrument;\n}());\nexports.Instrument = Instrument;\n//# sourceMappingURL=Instrument.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Note = void 0;\n/**\n * Convert a MIDI note into a pitch.\n */\nfunction midiToPitch(midi) {\n var octave = Math.floor(midi / 12) - 1;\n return midiToPitchClass(midi) + octave.toString();\n}\n/**\n * Convert a MIDI note to a pitch class (just the pitch no octave).\n */\nfunction midiToPitchClass(midi) {\n var scaleIndexToNote = [\"C\", \"C#\", \"D\", \"D#\", \"E\", \"F\", \"F#\", \"G\", \"G#\", \"A\", \"A#\", \"B\"];\n var note = midi % 12;\n return scaleIndexToNote[note];\n}\n/**\n * Convert a pitch class to a MIDI note.\n */\nfunction pitchClassToMidi(pitch) {\n var scaleIndexToNote = [\"C\", \"C#\", \"D\", \"D#\", \"E\", \"F\", \"F#\", \"G\", \"G#\", \"A\", \"A#\", \"B\"];\n return scaleIndexToNote.indexOf(pitch);\n}\n/**\n * Convert a pitch to a MIDI number.\n */\n// tslint:disable-next-line: only-arrow-functions typedef\nvar pitchToMidi = (function () {\n var regexp = /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i;\n var noteToScaleIndex = {\n // tslint:disable-next-line: object-literal-sort-keys\n cbb: -2, cb: -1, c: 0, \"c#\": 1, cx: 2,\n dbb: 0, db: 1, d: 2, \"d#\": 3, dx: 4,\n ebb: 2, eb: 3, e: 4, \"e#\": 5, ex: 6,\n fbb: 3, fb: 4, f: 5, \"f#\": 6, fx: 7,\n gbb: 5, gb: 6, g: 7, \"g#\": 8, gx: 9,\n abb: 7, ab: 8, a: 9, \"a#\": 10, ax: 11,\n bbb: 9, bb: 10, b: 11, \"b#\": 12, bx: 13,\n };\n return function (note) {\n var split = regexp.exec(note);\n var pitch = split[1];\n var octave = split[2];\n var index = noteToScaleIndex[pitch.toLowerCase()];\n return index + (parseInt(octave, 10) + 1) * 12;\n };\n}());\nvar privateHeaderMap = new WeakMap();\n/**\n * A Note consists of a `noteOn` and `noteOff` event.\n */\nvar Note = /** @class */ (function () {\n function Note(noteOn, noteOff, header) {\n privateHeaderMap.set(this, header);\n this.midi = noteOn.midi;\n this.velocity = noteOn.velocity;\n this.noteOffVelocity = noteOff.velocity;\n this.ticks = noteOn.ticks;\n this.durationTicks = noteOff.ticks - noteOn.ticks;\n }\n Object.defineProperty(Note.prototype, \"name\", {\n /**\n * The note name and octave in scientific pitch notation, e.g. \"C4\".\n */\n get: function () {\n return midiToPitch(this.midi);\n },\n set: function (n) {\n this.midi = pitchToMidi(n);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Note.prototype, \"octave\", {\n /**\n * The notes octave number.\n */\n get: function () {\n return Math.floor(this.midi / 12) - 1;\n },\n set: function (o) {\n var diff = o - this.octave;\n this.midi += diff * 12;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Note.prototype, \"pitch\", {\n /**\n * The pitch class name. e.g. \"A\".\n */\n get: function () {\n return midiToPitchClass(this.midi);\n },\n set: function (p) {\n this.midi = 12 * (this.octave + 1) + pitchClassToMidi(p);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Note.prototype, \"duration\", {\n /**\n * The duration of the segment in seconds.\n */\n get: function () {\n var header = privateHeaderMap.get(this);\n return header.ticksToSeconds(this.ticks + this.durationTicks) - header.ticksToSeconds(this.ticks);\n },\n set: function (d) {\n var header = privateHeaderMap.get(this);\n var noteEndTicks = header.secondsToTicks(this.time + d);\n this.durationTicks = noteEndTicks - this.ticks;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Note.prototype, \"time\", {\n /**\n * The time of the event in seconds.\n */\n get: function () {\n var header = privateHeaderMap.get(this);\n return header.ticksToSeconds(this.ticks);\n },\n set: function (t) {\n var header = privateHeaderMap.get(this);\n this.ticks = header.secondsToTicks(t);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Note.prototype, \"bars\", {\n /**\n * The number of measures (and partial measures) to this beat.\n * Takes into account time signature changes.\n * @readonly\n */\n get: function () {\n var header = privateHeaderMap.get(this);\n return header.ticksToMeasures(this.ticks);\n },\n enumerable: false,\n configurable: true\n });\n Note.prototype.toJSON = function () {\n return {\n duration: this.duration,\n durationTicks: this.durationTicks,\n midi: this.midi,\n name: this.name,\n ticks: this.ticks,\n time: this.time,\n velocity: this.velocity,\n };\n };\n return Note;\n}());\nexports.Note = Note;\n//# sourceMappingURL=Note.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Track = void 0;\nvar BinarySearch_1 = require(\"./BinarySearch\");\nvar ControlChange_1 = require(\"./ControlChange\");\nvar ControlChanges_1 = require(\"./ControlChanges\");\nvar PitchBend_1 = require(\"./PitchBend\");\nvar Instrument_1 = require(\"./Instrument\");\nvar Note_1 = require(\"./Note\");\nvar privateHeaderMap = new WeakMap();\n/**\n * A Track is a collection of 'notes' and 'controlChanges'.\n */\nvar Track = /** @class */ (function () {\n function Track(trackData, header) {\n var _this = this;\n /**\n * The name of the track.\n */\n this.name = \"\";\n /**\n * The track's note events.\n */\n this.notes = [];\n /**\n * The control change events.\n */\n this.controlChanges = (0, ControlChanges_1.createControlChanges)();\n /**\n * The pitch bend events.\n */\n this.pitchBends = [];\n privateHeaderMap.set(this, header);\n if (trackData) {\n // Get the name of the track.\n var nameEvent = trackData.find(function (e) { return e.type === \"trackName\"; });\n // Set empty name if 'trackName' event isn't found.\n this.name = nameEvent ? nameEvent.text : \"\";\n }\n this.instrument = new Instrument_1.Instrument(trackData, this);\n // Defaults to 0.\n this.channel = 0;\n if (trackData) {\n var noteOns = trackData.filter(function (event) { return event.type === \"noteOn\"; });\n var noteOffs = trackData.filter(function (event) { return event.type === \"noteOff\"; });\n var _loop_1 = function () {\n var currentNote = noteOns.shift();\n // Set the channel based on the note.\n this_1.channel = currentNote.channel;\n // Find the corresponding note off.\n var offIndex = noteOffs.findIndex(function (note) {\n return note.noteNumber === currentNote.noteNumber &&\n note.absoluteTime >= currentNote.absoluteTime;\n });\n if (offIndex !== -1) {\n // Once it's got the note off, add it.\n var noteOff = noteOffs.splice(offIndex, 1)[0];\n this_1.addNote({\n durationTicks: noteOff.absoluteTime - currentNote.absoluteTime,\n midi: currentNote.noteNumber,\n noteOffVelocity: noteOff.velocity / 127,\n ticks: currentNote.absoluteTime,\n velocity: currentNote.velocity / 127,\n });\n }\n };\n var this_1 = this;\n while (noteOns.length) {\n _loop_1();\n }\n var controlChanges = trackData.filter(function (event) { return event.type === \"controller\"; });\n controlChanges.forEach(function (event) {\n _this.addCC({\n number: event.controllerType,\n ticks: event.absoluteTime,\n value: event.value / 127,\n });\n });\n var pitchBends = trackData.filter(function (event) { return event.type === \"pitchBend\"; });\n pitchBends.forEach(function (event) {\n _this.addPitchBend({\n ticks: event.absoluteTime,\n // Scale the value between -2^13 to 2^13 to -2 to 2.\n value: event.value / Math.pow(2, 13),\n });\n });\n var endOfTrackEvent = trackData.find(function (event) {\n return event.type === \"endOfTrack\";\n });\n this.endOfTrackTicks =\n endOfTrackEvent !== undefined\n ? endOfTrackEvent.absoluteTime\n : undefined;\n }\n }\n /**\n * Add a note to the notes array.\n * @param props The note properties to add.\n */\n Track.prototype.addNote = function (props) {\n var header = privateHeaderMap.get(this);\n var note = new Note_1.Note({\n midi: 0,\n ticks: 0,\n velocity: 1,\n }, {\n ticks: 0,\n velocity: 0,\n }, header);\n Object.assign(note, props);\n (0, BinarySearch_1.insert)(this.notes, note, \"ticks\");\n return this;\n };\n /**\n * Add a control change to the track.\n * @param props\n */\n Track.prototype.addCC = function (props) {\n var header = privateHeaderMap.get(this);\n var cc = new ControlChange_1.ControlChange({\n controllerType: props.number,\n }, header);\n delete props.number;\n Object.assign(cc, props);\n if (!Array.isArray(this.controlChanges[cc.number])) {\n this.controlChanges[cc.number] = [];\n }\n (0, BinarySearch_1.insert)(this.controlChanges[cc.number], cc, \"ticks\");\n return this;\n };\n /**\n * Add a control change to the track.\n */\n Track.prototype.addPitchBend = function (props) {\n var header = privateHeaderMap.get(this);\n var pb = new PitchBend_1.PitchBend({}, header);\n Object.assign(pb, props);\n (0, BinarySearch_1.insert)(this.pitchBends, pb, \"ticks\");\n return this;\n };\n Object.defineProperty(Track.prototype, \"duration\", {\n /**\n * The end time of the last event in the track.\n */\n get: function () {\n if (!this.notes.length) {\n return 0;\n }\n var maxDuration = this.notes[this.notes.length - 1].time +\n this.notes[this.notes.length - 1].duration;\n for (var i = 0; i < this.notes.length - 1; i++) {\n var duration = this.notes[i].time + this.notes[i].duration;\n if (maxDuration < duration) {\n maxDuration = duration;\n }\n }\n return maxDuration;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Track.prototype, \"durationTicks\", {\n /**\n * The end time of the last event in the track in ticks.\n */\n get: function () {\n if (!this.notes.length) {\n return 0;\n }\n var maxDuration = this.notes[this.notes.length - 1].ticks +\n this.notes[this.notes.length - 1].durationTicks;\n for (var i = 0; i < this.notes.length - 1; i++) {\n var duration = this.notes[i].ticks + this.notes[i].durationTicks;\n if (maxDuration < duration) {\n maxDuration = duration;\n }\n }\n return maxDuration;\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Assign the JSON values to this track.\n */\n Track.prototype.fromJSON = function (json) {\n var _this = this;\n this.name = json.name;\n this.channel = json.channel;\n this.instrument = new Instrument_1.Instrument(undefined, this);\n this.instrument.fromJSON(json.instrument);\n if (json.endOfTrackTicks !== undefined) {\n this.endOfTrackTicks = json.endOfTrackTicks;\n }\n for (var number in json.controlChanges) {\n if (json.controlChanges[number]) {\n json.controlChanges[number].forEach(function (cc) {\n _this.addCC({\n number: cc.number,\n ticks: cc.ticks,\n value: cc.value,\n });\n });\n }\n }\n json.notes.forEach(function (n) {\n _this.addNote({\n durationTicks: n.durationTicks,\n midi: n.midi,\n ticks: n.ticks,\n velocity: n.velocity,\n });\n });\n };\n /**\n * Convert the track into a JSON format.\n */\n Track.prototype.toJSON = function () {\n // Convert all the CCs to JSON.\n var controlChanges = {};\n for (var i = 0; i < 127; i++) {\n if (this.controlChanges.hasOwnProperty(i)) {\n controlChanges[i] = this.controlChanges[i].map(function (c) {\n return c.toJSON();\n });\n }\n }\n var json = {\n channel: this.channel,\n controlChanges: controlChanges,\n pitchBends: this.pitchBends.map(function (pb) { return pb.toJSON(); }),\n instrument: this.instrument.toJSON(),\n name: this.name,\n notes: this.notes.map(function (n) { return n.toJSON(); }),\n };\n if (this.endOfTrackTicks !== undefined) {\n json.endOfTrackTicks = this.endOfTrackTicks;\n }\n return json;\n };\n return Track;\n}());\nexports.Track = Track;\n//# sourceMappingURL=Track.js.map","/**\n * Flatten an array indefinitely.\n */\nexport function flatten(array) {\n var result = [];\n $flatten(array, result);\n return result;\n}\n/**\n * Internal flatten function recursively passes `result`.\n */\nfunction $flatten(array, result) {\n for (var i = 0; i < array.length; i++) {\n var value = array[i];\n if (Array.isArray(value)) {\n $flatten(value, result);\n }\n else {\n result.push(value);\n }\n }\n}\n//# sourceMappingURL=index.js.map","\"use strict\";\nvar __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n if (ar || !(i in from)) {\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n ar[i] = from[i];\n }\n }\n return to.concat(ar || Array.prototype.slice.call(from));\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.encode = void 0;\nvar midi_file_1 = require(\"midi-file\");\nvar Header_1 = require(\"./Header\");\nvar array_flatten_1 = require(\"array-flatten\");\nfunction encodeNote(note, channel) {\n return [{\n absoluteTime: note.ticks,\n channel: channel,\n deltaTime: 0,\n noteNumber: note.midi,\n type: \"noteOn\",\n velocity: Math.floor(note.velocity * 127),\n },\n {\n absoluteTime: note.ticks + note.durationTicks,\n channel: channel,\n deltaTime: 0,\n noteNumber: note.midi,\n type: \"noteOff\",\n velocity: Math.floor(note.noteOffVelocity * 127),\n }];\n}\nfunction encodeNotes(track) {\n return (0, array_flatten_1.flatten)(track.notes.map(function (note) { return encodeNote(note, track.channel); }));\n}\nfunction encodeControlChange(cc, channel) {\n return {\n absoluteTime: cc.ticks,\n channel: channel,\n controllerType: cc.number,\n deltaTime: 0,\n type: \"controller\",\n value: Math.floor(cc.value * 127),\n };\n}\nfunction encodeControlChanges(track) {\n var controlChanges = [];\n for (var i = 0; i < 127; i++) {\n if (track.controlChanges.hasOwnProperty(i)) {\n track.controlChanges[i].forEach(function (cc) {\n controlChanges.push(encodeControlChange(cc, track.channel));\n });\n }\n }\n return controlChanges;\n}\nfunction encodePitchBend(pb, channel) {\n return {\n absoluteTime: pb.ticks,\n channel: channel,\n deltaTime: 0,\n type: \"pitchBend\",\n value: pb.value,\n };\n}\nfunction encodePitchBends(track) {\n var pitchBends = [];\n track.pitchBends.forEach(function (pb) {\n pitchBends.push(encodePitchBend(pb, track.channel));\n });\n return pitchBends;\n}\nfunction encodeInstrument(track) {\n return {\n absoluteTime: 0,\n channel: track.channel,\n deltaTime: 0,\n programNumber: track.instrument.number,\n type: \"programChange\",\n };\n}\nfunction encodeTrackName(name) {\n return {\n absoluteTime: 0,\n deltaTime: 0,\n meta: true,\n text: name,\n type: \"trackName\",\n };\n}\nfunction encodeTempo(tempo) {\n return {\n absoluteTime: tempo.ticks,\n deltaTime: 0,\n meta: true,\n microsecondsPerBeat: Math.floor(60000000 / tempo.bpm),\n type: \"setTempo\",\n };\n}\nfunction encodeTimeSignature(timeSig) {\n return {\n absoluteTime: timeSig.ticks,\n deltaTime: 0,\n denominator: timeSig.timeSignature[1],\n meta: true,\n metronome: 24,\n numerator: timeSig.timeSignature[0],\n thirtyseconds: 8,\n type: \"timeSignature\",\n };\n}\n// function encodeMeta(event: )\nfunction encodeKeySignature(keySig) {\n var keyIndex = Header_1.keySignatureKeys.indexOf(keySig.key);\n return {\n absoluteTime: keySig.ticks,\n deltaTime: 0,\n key: keyIndex + 7,\n meta: true,\n scale: keySig.scale === \"major\" ? 0 : 1,\n type: \"keySignature\",\n };\n}\nfunction encodeText(textEvent) {\n return {\n absoluteTime: textEvent.ticks,\n deltaTime: 0,\n meta: true,\n text: textEvent.text,\n type: textEvent.type,\n };\n}\n/**\n * Convert the MIDI object to an array.\n */\nfunction encode(midi) {\n var midiData = {\n header: {\n format: 1,\n numTracks: midi.tracks.length + 1,\n ticksPerBeat: midi.header.ppq,\n },\n tracks: __spreadArray([\n __spreadArray(__spreadArray(__spreadArray(__spreadArray([\n // The name data.\n {\n absoluteTime: 0,\n deltaTime: 0,\n meta: true,\n text: midi.header.name,\n type: \"trackName\",\n }\n ], midi.header.keySignatures.map(function (keySig) { return encodeKeySignature(keySig); }), true), midi.header.meta.map(function (e) { return encodeText(e); }), true), midi.header.tempos.map(function (tempo) { return encodeTempo(tempo); }), true), midi.header.timeSignatures.map(function (timeSig) { return encodeTimeSignature(timeSig); }), true)\n ], midi.tracks.map(function (track) {\n return __spreadArray(__spreadArray(__spreadArray([\n // Add the name\n encodeTrackName(track.name),\n // the instrument\n encodeInstrument(track)\n ], encodeNotes(track), true), encodeControlChanges(track), true), encodePitchBends(track), true);\n }), true),\n };\n // Sort and set `deltaTime` of all of the tracks.\n midiData.tracks = midiData.tracks.map(function (track) {\n track = track.sort(function (a, b) { return a.absoluteTime - b.absoluteTime; });\n var lastTime = 0;\n track.forEach(function (note) {\n note.deltaTime = note.absoluteTime - lastTime;\n lastTime = note.absoluteTime;\n delete note.absoluteTime;\n });\n // End of track.\n track.push({\n deltaTime: 0,\n meta: true,\n type: \"endOfTrack\",\n });\n return track;\n });\n // Rreturn `midiData`.\n return new Uint8Array((0, midi_file_1.writeMidi)(midiData));\n}\nexports.encode = encode;\n//# sourceMappingURL=Encode.js.map","\"use strict\";\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __generator = (this && this.__generator) || function (thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (_) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n};\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.Header = exports.Track = exports.Midi = void 0;\nvar midi_file_1 = require(\"midi-file\");\nvar Header_1 = require(\"./Header\");\nvar Track_1 = require(\"./Track\");\nvar Encode_1 = require(\"./Encode\");\n/**\n * The main midi parsing class.\n */\nvar Midi = /** @class */ (function () {\n /**\n * Parse the midi data\n */\n function Midi(midiArray) {\n var _this = this;\n // Parse the MIDI data if there is any.\n var midiData = null;\n if (midiArray) {\n // Transform midiArray to ArrayLike<number>\n // only if it's an ArrayBuffer.\n var midiArrayLike = midiArray instanceof ArrayBuffer\n ? new Uint8Array(midiArray)\n : midiArray;\n // Parse MIDI data.\n midiData = (0, midi_file_1.parseMidi)(midiArrayLike);\n // Add the absolute times to each of the tracks.\n midiData.tracks.forEach(function (track) {\n var currentTicks = 0;\n track.forEach(function (event) {\n currentTicks += event.deltaTime;\n event.absoluteTime = currentTicks;\n });\n });\n // Ensure at most one instrument per track.\n midiData.tracks = splitTracks(midiData.tracks);\n }\n this.header = new Header_1.Header(midiData);\n this.tracks = [];\n // Parse MIDI data.\n if (midiArray) {\n // Format 0, everything is on the same track.\n this.tracks = midiData.tracks.map(function (trackData) { return new Track_1.Track(trackData, _this.header); });\n // If it's format 1 and there are no notes on the first track, remove it.\n if (midiData.header.format === 1 && this.tracks[0].duration === 0) {\n this.tracks.shift();\n }\n }\n }\n /**\n * Download and parse the MIDI file. Returns a promise\n * which resolves to the generated MIDI file.\n * @param url The URL to fetch.\n */\n Midi.fromUrl = function (url) {\n return __awaiter(this, void 0, void 0, function () {\n var response, arrayBuffer;\n return __generator(this, function (_a) {\n switch (_a.label) {\n case 0: return [4 /*yield*/, fetch(url)];\n case 1:\n response = _a.sent();\n if (!response.ok) return [3 /*break*/, 3];\n return [4 /*yield*/, response.arrayBuffer()];\n case 2:\n arrayBuffer = _a.sent();\n return [2 /*return*/, new Midi(arrayBuffer)];\n case 3: throw new Error(\"Could not load '\".concat(url, \"'\"));\n }\n });\n });\n };\n Object.defineProperty(Midi.prototype, \"name\", {\n /**\n * The name of the midi file, taken from the first track.\n */\n get: function () {\n return this.header.name;\n },\n set: function (n) {\n this.header.name = n;\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Midi.prototype, \"duration\", {\n /**\n * The total length of the file in seconds.\n */\n get: function () {\n // Get the max of the last note of all the tracks.\n var durations = this.tracks.map(function (t) { return t.duration; });\n return Math.max.apply(Math, durations);\n },\n enumerable: false,\n configurable: true\n });\n Object.defineProperty(Midi.prototype, \"durationTicks\", {\n /**\n * The total length of the file in ticks.\n */\n get: function () {\n // Get the max of the last note of all the tracks.\n var durationTicks = this.tracks.map(function (t) { return t.durationTicks; });\n return Math.max.apply(Math, durationTicks);\n },\n enumerable: false,\n configurable: true\n });\n /**\n * Add a track to the MIDI file.\n */\n Midi.prototype.addTrack = function () {\n var track = new Track_1.Track(undefined, this.header);\n this.tracks.push(track);\n return track;\n };\n /**\n * Encode the MIDI as a Uint8Array.\n */\n Midi.prototype.toArray = function () {\n return (0, Encode_1.encode)(this);\n };\n /**\n * Convert the MIDI object to JSON.\n */\n Midi.prototype.toJSON = function () {\n return {\n header: this.header.toJSON(),\n tracks: this.tracks.map(function (track) { return track.toJSON(); }),\n };\n };\n /**\n * Parse a JSON representation of the object. Will overwrite the current\n * tracks and header.\n */\n Midi.prototype.fromJSON = function (json) {\n var _this = this;\n this.header = new Header_1.Header();\n this.header.fromJSON(json.header);\n this.tracks = json.tracks.map(function (trackJSON) {\n var track = new Track_1.Track(undefined, _this.header);\n track.fromJSON(trackJSON);\n return track;\n });\n };\n /**\n * Clone the entire object MIDI object.\n */\n Midi.prototype.clone = function () {\n var midi = new Midi();\n midi.fromJSON(this.toJSON());\n return midi;\n };\n return Midi;\n}());\nexports.Midi = Midi;\nvar Track_2 = require(\"./Track\");\nObject.defineProperty(exports, \"Track\", { enumerable: true, get: function () { return Track_2.Track; } });\nvar Header_2 = require(\"./Header\");\nObject.defineProperty(exports, \"Header\", { enumerable: true, get: function () { return Header_2.Header; } });\n/**\n * Given a list of MIDI tracks, make sure that each channel corresponds to at\n * most one channel and at most one instrument. This means splitting up tracks\n * that contain more than one channel or instrument.\n */\nfunction splitTracks(tracks) {\n var newTracks = [];\n for (var i = 0; i < tracks.length; i++) {\n var defaultTrack = newTracks.length;\n // a map from [program, channel] tuples to new track numbers\n var trackMap = new Map();\n // a map from channel numbers to current program numbers\n var currentProgram = Array(16).fill(0);\n for (var _i = 0, _a = tracks[i]; _i < _a.length; _i++) {\n var event_1 = _a[_i];\n var targetTrack = defaultTrack;\n // If the event has a channel, we need to find that channel's current\n // program number and the appropriate track for this [program, channel]\n // pair.\n var channel = event_1.channel;\n if (channel !== undefined) {\n if (event_1.type === \"programChange\") {\n currentProgram[channel] = event_1.programNumber;\n }\n var program = currentProgram[channel];\n var trackKey = \"\".concat(program, \" \").concat(channel);\n if (trackMap.has(trackKey)) {\n targetTrack = trackMap.get(trackKey);\n }\n else {\n targetTrack = defaultTrack + trackMap.size;\n trackMap.set(trackKey, targetTrack);\n }\n }\n if (!newTracks[targetTrack]) {\n newTracks.push([]);\n }\n newTracks[targetTrack].push(event_1);\n }\n }\n return newTracks;\n}\n//# sourceMappingURL=Midi.js.map","/**\n * MIDI file parsing utilities using @tonejs/midi\n * \n * Provides functions to parse Standard MIDI Files (.mid) into\n * MidiNoteData format compatible with MidiToneTrack/SoundFontToneTrack.\n */\nimport { Midi } from '@tonejs/midi';\n\n/**\n * MIDI note data for clips that play MIDI instead of audio.\n * Matches the MidiNoteData interface from songram-daw core types.\n */\nexport interface MidiNoteData {\n /** MIDI note number (0-127) */\n midi: number;\n /** Note name in scientific pitch notation (\"C4\", \"G#3\") */\n name: string;\n /** Start time in seconds, relative to clip start */\n time: number;\n /** Duration in seconds */\n duration: number;\n /** Velocity (0-1 normalized) */\n velocity: number;\n /** MIDI channel (0-indexed). Channel 9 = GM percussion. */\n channel?: number;\n}\n\n/**\n * General MIDI instrument names (0-127)\n */\nconst GM_INSTRUMENTS: string[] = [\n // Piano (0-7)\n 'Acoustic Grand Piano', 'Bright Acoustic Piano', 'Electric Grand Piano', 'Honky-tonk Piano',\n 'Electric Piano 1', 'Electric Piano 2', 'Harpsichord', 'Clavinet',\n // Chromatic Percussion (8-15)\n 'Celesta', 'Glockenspiel', 'Music Box', 'Vibraphone',\n 'Marimba', 'Xylophone', 'Tubular Bells', 'Dulcimer',\n // Organ (16-23)\n 'Drawbar Organ', 'Percussive Organ', 'Rock Organ', 'Church Organ',\n 'Reed Organ', 'Accordion', 'Harmonica', 'Tango Accordion',\n // Guitar (24-31)\n 'Acoustic Guitar (nylon)', 'Acoustic Guitar (steel)', 'Electric Guitar (jazz)', 'Electric Guitar (clean)',\n 'Electric Guitar (muted)', 'Overdriven Guitar', 'Distortion Guitar', 'Guitar Harmonics',\n // Bass (32-39)\n 'Acoustic Bass', 'Electric Bass (finger)', 'Electric Bass (pick)', 'Fretless Bass',\n 'Slap Bass 1', 'Slap Bass 2', 'Synth Bass 1', 'Synth Bass 2',\n // Strings (40-47)\n 'Violin', 'Viola', 'Cello', 'Contrabass',\n 'Tremolo Strings', 'Pizzicato Strings', 'Orchestral Harp', 'Timpani',\n // Ensemble (48-55)\n 'String Ensemble 1', 'String Ensemble 2', 'Synth Strings 1', 'Synth Strings 2',\n 'Choir Aahs', 'Voice Oohs', 'Synth Voice', 'Orchestra Hit',\n // Brass (56-63)\n 'Trumpet', 'Trombone', 'Tuba', 'Muted Trumpet',\n 'French Horn', 'Brass Section', 'Synth Brass 1', 'Synth Brass 2',\n // Reed (64-71)\n 'Soprano Sax', 'Alto Sax', 'Tenor Sax', 'Baritone Sax',\n 'Oboe', 'English Horn', 'Bassoon', 'Clarinet',\n // Pipe (72-79)\n 'Piccolo', 'Flute', 'Recorder', 'Pan Flute',\n 'Blown Bottle', 'Shakuhachi', 'Whistle', 'Ocarina',\n // Synth Lead (80-87)\n 'Lead 1 (square)', 'Lead 2 (sawtooth)', 'Lead 3 (calliope)', 'Lead 4 (chiff)',\n 'Lead 5 (charang)', 'Lead 6 (voice)', 'Lead 7 (fifths)', 'Lead 8 (bass + lead)',\n // Synth Pad (88-95)\n 'Pad 1 (new age)', 'Pad 2 (warm)', 'Pad 3 (polysynth)', 'Pad 4 (choir)',\n 'Pad 5 (bowed)', 'Pad 6 (metallic)', 'Pad 7 (halo)', 'Pad 8 (sweep)',\n // Synth Effects (96-103)\n 'FX 1 (rain)', 'FX 2 (soundtrack)', 'FX 3 (crystal)', 'FX 4 (atmosphere)',\n 'FX 5 (brightness)', 'FX 6 (goblins)', 'FX 7 (echoes)', 'FX 8 (sci-fi)',\n // Ethnic (104-111)\n 'Sitar', 'Banjo', 'Shamisen', 'Koto',\n 'Kalimba', 'Bagpipe', 'Fiddle', 'Shanai',\n // Percussive (112-119)\n 'Tinkle Bell', 'Agogo', 'Steel Drums', 'Woodblock',\n 'Taiko Drum', 'Melodic Tom', 'Synth Drum', 'Reverse Cymbal',\n // Sound Effects (120-127)\n 'Guitar Fret Noise', 'Breath Noise', 'Seashore', 'Bird Tweet',\n 'Telephone Ring', 'Helicopter', 'Applause', 'Gunshot',\n];\n\n/**\n * Get GM instrument name from program number\n */\nexport function getInstrumentName(programNumber: number): string {\n return GM_INSTRUMENTS[programNumber] ?? `Program ${programNumber}`;\n}\n\n/**\n * Parsed MIDI track with notes and metadata\n */\nexport interface ParsedMidiTrack {\n /** Track name from MIDI file or generated */\n name: string;\n /** Notes in MidiNoteData format */\n notes: MidiNoteData[];\n /** Duration in seconds */\n duration: number;\n /** MIDI channel (0-indexed, 9 = percussion) */\n channel: number;\n /** GM instrument name */\n instrument: string;\n /** GM program number (0-127) */\n programNumber: number;\n}\n\n/**\n * Complete parsed MIDI file result\n */\nexport interface ParsedMidi {\n /** Parsed tracks (one per channel or merged if flatten=true) */\n tracks: ParsedMidiTrack[];\n /** Total duration in seconds */\n duration: number;\n /** Song name from MIDI header */\n name: string;\n /** Tempo in BPM (from first tempo event, default 120) */\n bpm: number;\n /** Time signature [numerator, denominator] */\n timeSignature: [number, number];\n}\n\nexport interface ParseMidiOptions {\n /** Merge all MIDI tracks into one (default: false) */\n flatten?: boolean;\n}\n\n/**\n * Parse a MIDI file from an ArrayBuffer\n * \n * @param data - MIDI file as ArrayBuffer\n * @param options - Parsing options\n * @returns Parsed MIDI data with tracks and metadata\n * \n * @example\n * ```typescript\n * const response = await fetch('/song.mid');\n * const buffer = await response.arrayBuffer();\n * const midi = parseMidiFile(buffer);\n * console.log(midi.tracks.length, 'tracks');\n * ```\n */\nexport function parseMidiFile(data: ArrayBuffer, options: ParseMidiOptions = {}): ParsedMidi {\n const { flatten = false } = options;\n const midi = new Midi(data);\n\n // Extract tempo and time signature\n const bpm = midi.header.tempos[0]?.bpm ?? 120;\n const timeSig = midi.header.timeSignatures[0];\n const timeSignature: [number, number] = timeSig \n ? [timeSig.timeSignature[0], timeSig.timeSignature[1]]\n : [4, 4];\n const name = midi.name || 'Untitled';\n\n // Group notes by channel\n const channelNotes = new Map<number, { notes: MidiNoteData[]; programNumber: number; name: string }>();\n\n for (const track of midi.tracks) {\n const channel = track.channel;\n const programNumber = track.instrument.number;\n const trackName = track.name || getInstrumentName(programNumber);\n\n if (!channelNotes.has(channel)) {\n channelNotes.set(channel, { notes: [], programNumber, name: trackName });\n }\n\n const channelData = channelNotes.get(channel)!;\n \n // Update name if this track has a more specific one\n if (track.name && !channelData.name.startsWith(track.name)) {\n channelData.name = track.name;\n }\n\n // Convert notes to MidiNoteData format\n for (const note of track.notes) {\n channelData.notes.push({\n midi: note.midi,\n name: note.name,\n time: note.time,\n duration: note.duration,\n velocity: note.velocity,\n channel: channel,\n });\n }\n }\n\n // Calculate total duration\n let totalDuration = 0;\n channelNotes.forEach(({ notes }) => {\n for (const note of notes) {\n const noteEnd = note.time + note.duration;\n if (noteEnd > totalDuration) {\n totalDuration = noteEnd;\n }\n }\n });\n\n if (flatten) {\n // Merge all tracks into one\n const allNotes: MidiNoteData[] = [];\n channelNotes.forEach(({ notes }) => {\n allNotes.push(...notes);\n });\n // Sort by time\n allNotes.sort((a, b) => a.time - b.time);\n\n return {\n tracks: [{\n name: name,\n notes: allNotes,\n duration: totalDuration,\n channel: 0,\n instrument: 'Mixed',\n programNumber: 0,\n }],\n duration: totalDuration,\n name,\n bpm,\n timeSignature,\n };\n }\n\n // Create separate track for each channel\n const tracks: ParsedMidiTrack[] = [];\n channelNotes.forEach(({ notes, programNumber, name: trackName }, channel) => {\n if (notes.length === 0) return;\n\n // Sort notes by time\n notes.sort((a, b) => a.time - b.time);\n\n // Calculate track duration\n let trackDuration = 0;\n for (const note of notes) {\n const noteEnd = note.time + note.duration;\n if (noteEnd > trackDuration) {\n trackDuration = noteEnd;\n }\n }\n\n tracks.push({\n name: trackName,\n notes,\n duration: trackDuration,\n channel,\n instrument: channel === 9 ? 'Percussion' : getInstrumentName(programNumber),\n programNumber,\n });\n });\n\n return {\n tracks,\n duration: totalDuration,\n name,\n bpm,\n timeSignature,\n };\n}\n\n/**\n * Fetch and parse a MIDI file from a URL\n * \n * @param url - URL to MIDI file\n * @param options - Parsing options\n * @param signal - Optional AbortSignal for cancellation\n * @returns Promise resolving to parsed MIDI data\n * \n * @example\n * ```typescript\n * const midi = await parseMidiUrl('/songs/demo.mid');\n * for (const track of midi.tracks) {\n * console.log(track.name, track.notes.length, 'notes');\n * }\n * ```\n */\nexport async function parseMidiUrl(\n url: string,\n options: ParseMidiOptions = {},\n signal?: AbortSignal\n): Promise<ParsedMidi> {\n const response = await fetch(url, { signal });\n if (!response.ok) {\n throw new Error(`Failed to fetch MIDI file: ${response.status} ${response.statusText}`);\n }\n const buffer = await response.arrayBuffer();\n return parseMidiFile(buffer, options);\n}\n\n/**\n * Convert MIDI note number to note name with octave\n * @param midiNote - MIDI note number (0-127)\n * @returns Note name like \"C4\", \"F#3\", \"Bb5\"\n */\nexport function midiNoteToName(midiNote: number): string {\n const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];\n const octave = Math.floor(midiNote / 12) - 1;\n const noteName = noteNames[midiNote % 12];\n return `${noteName}${octave}`;\n}\n\n/**\n * Convert note name to MIDI note number\n * @param name - Note name like \"C4\", \"F#3\", \"Bb5\" \n * @returns MIDI note number (0-127)\n */\nexport function noteNameToMidi(name: string): number {\n const match = name.match(/^([A-Ga-g])([#b]?)(-?\\d+)$/);\n if (!match) throw new Error(`Invalid note name: ${name}`);\n \n const [, note, accidental, octaveStr] = match;\n const noteMap: Record<string, number> = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 };\n let semitone = noteMap[note.toUpperCase()];\n if (accidental === '#') semitone += 1;\n if (accidental === 'b') semitone -= 1;\n const octave = parseInt(octaveStr, 10);\n return (octave + 1) * 12 + semitone;\n}\n","/**\n * Web MIDI API utilities for connecting MIDI controllers\n * \n * Enables real-time MIDI input from hardware controllers for\n * live playing, recording, and DAW control.\n */\n\nexport interface MidiInputDevice {\n id: string;\n name: string;\n manufacturer: string;\n state: 'connected' | 'disconnected';\n}\n\nexport interface MidiOutputDevice {\n id: string;\n name: string;\n manufacturer: string;\n state: 'connected' | 'disconnected';\n}\n\nexport interface MidiMessage {\n /** MIDI command (note on, note off, CC, etc.) */\n command: number;\n /** MIDI channel (0-15) */\n channel: number;\n /** Note number or CC number */\n data1: number;\n /** Velocity or CC value */\n data2: number;\n /** Raw MIDI bytes */\n raw: Uint8Array;\n /** Timestamp */\n timestamp: number;\n}\n\nexport type MidiMessageCallback = (message: MidiMessage) => void;\n\n// MIDI command bytes (status byte >> 4)\nexport const MIDI_COMMANDS = {\n NOTE_OFF: 0x8,\n NOTE_ON: 0x9,\n POLY_AFTERTOUCH: 0xA,\n CONTROL_CHANGE: 0xB,\n PROGRAM_CHANGE: 0xC,\n CHANNEL_AFTERTOUCH: 0xD,\n PITCH_BEND: 0xE,\n} as const;\n\n// Common CC numbers\nexport const MIDI_CC = {\n MODULATION: 1,\n BREATH: 2,\n VOLUME: 7,\n PAN: 10,\n EXPRESSION: 11,\n SUSTAIN: 64,\n PORTAMENTO: 65,\n SOSTENUTO: 66,\n SOFT_PEDAL: 67,\n ALL_SOUND_OFF: 120,\n RESET_ALL: 121,\n ALL_NOTES_OFF: 123,\n} as const;\n\n/**\n * Parse a raw MIDI message into structured data\n */\nexport function parseMidiMessage(data: Uint8Array, timestamp: number): MidiMessage {\n const status = data[0];\n const command = (status >> 4) & 0xF;\n const channel = status & 0xF;\n \n return {\n command,\n channel,\n data1: data[1] ?? 0,\n data2: data[2] ?? 0,\n raw: data,\n timestamp,\n };\n}\n\n/**\n * Check if Web MIDI API is supported\n */\nexport function isWebMidiSupported(): boolean {\n return typeof navigator !== 'undefined' && 'requestMIDIAccess' in navigator;\n}\n\n/**\n * Request Web MIDI API access\n * @param sysex - Whether to request SysEx access (default: false)\n */\nexport async function requestMidiAccess(sysex = false): Promise<MIDIAccess | null> {\n if (!isWebMidiSupported()) {\n console.warn('[MIDI] Web MIDI API not supported in this browser');\n return null;\n }\n \n try {\n const access = await navigator.requestMIDIAccess({ sysex });\n return access;\n } catch (error) {\n console.error('[MIDI] Failed to request MIDI access:', error);\n return null;\n }\n}\n\n/**\n * Get list of connected MIDI input devices\n */\nexport function getMidiInputs(access: MIDIAccess): MidiInputDevice[] {\n const inputs: MidiInputDevice[] = [];\n access.inputs.forEach((input) => {\n inputs.push({\n id: input.id,\n name: input.name || 'Unknown Device',\n manufacturer: input.manufacturer || 'Unknown',\n state: input.state as 'connected' | 'disconnected',\n });\n });\n return inputs;\n}\n\n/**\n * Get list of connected MIDI output devices\n */\nexport function getMidiOutputs(access: MIDIAccess): MidiOutputDevice[] {\n const outputs: MidiOutputDevice[] = [];\n access.outputs.forEach((output) => {\n outputs.push({\n id: output.id,\n name: output.name || 'Unknown Device',\n manufacturer: output.manufacturer || 'Unknown',\n state: output.state as 'connected' | 'disconnected',\n });\n });\n return outputs;\n}\n\n/**\n * MIDI Controller Manager - handles connections and message routing\n */\nexport class MidiController {\n private access: MIDIAccess | null = null;\n private activeInputId: string | null = null;\n private messageCallbacks: Set<MidiMessageCallback> = new Set();\n private stateChangeCallbacks: Set<() => void> = new Set();\n \n /**\n * Initialize MIDI access\n */\n async init(sysex = false): Promise<boolean> {\n this.access = await requestMidiAccess(sysex);\n if (!this.access) return false;\n \n // Listen for device connection changes\n this.access.onstatechange = () => {\n this.stateChangeCallbacks.forEach(cb => cb());\n };\n \n return true;\n }\n \n /**\n * Check if initialized\n */\n get isInitialized(): boolean {\n return this.access !== null;\n }\n \n /**\n * Get available input devices\n */\n getInputs(): MidiInputDevice[] {\n if (!this.access) return [];\n return getMidiInputs(this.access);\n }\n \n /**\n * Get available output devices\n */\n getOutputs(): MidiOutputDevice[] {\n if (!this.access) return [];\n return getMidiOutputs(this.access);\n }\n \n /**\n * Connect to a specific MIDI input\n */\n connectInput(deviceId: string): boolean {\n if (!this.access) return false;\n \n // Disconnect from current input\n this.disconnectInput();\n \n const input = this.access.inputs.get(deviceId);\n if (!input) {\n console.warn(`[MIDI] Input device not found: ${deviceId}`);\n return false;\n }\n \n this.activeInputId = deviceId;\n input.onmidimessage = (event) => {\n if (!event.data) return;\n const message = parseMidiMessage(event.data, event.timeStamp);\n this.messageCallbacks.forEach(cb => cb(message));\n };\n \n console.log(`[MIDI] Connected to input: ${input.name}`);\n return true;\n }\n \n /**\n * Connect to the first available MIDI input\n */\n connectFirstInput(): boolean {\n const inputs = this.getInputs();\n if (inputs.length === 0) return false;\n return this.connectInput(inputs[0].id);\n }\n \n /**\n * Disconnect from current MIDI input\n */\n disconnectInput(): void {\n if (!this.access || !this.activeInputId) return;\n \n const input = this.access.inputs.get(this.activeInputId);\n if (input) {\n input.onmidimessage = null;\n }\n this.activeInputId = null;\n }\n \n /**\n * Get the currently connected input ID\n */\n get connectedInputId(): string | null {\n return this.activeInputId;\n }\n \n /**\n * Subscribe to MIDI messages\n */\n onMessage(callback: MidiMessageCallback): () => void {\n this.messageCallbacks.add(callback);\n return () => this.messageCallbacks.delete(callback);\n }\n \n /**\n * Subscribe to device state changes (connect/disconnect)\n */\n onStateChange(callback: () => void): () => void {\n this.stateChangeCallbacks.add(callback);\n return () => this.stateChangeCallbacks.delete(callback);\n }\n \n /**\n * Send MIDI message to an output device\n */\n sendMessage(deviceId: string, data: number[]): boolean {\n if (!this.access) return false;\n \n const output = this.access.outputs.get(deviceId);\n if (!output) return false;\n \n output.send(data);\n return true;\n }\n \n /**\n * Clean up resources\n */\n dispose(): void {\n this.disconnectInput();\n this.messageCallbacks.clear();\n this.stateChangeCallbacks.clear();\n this.access = null;\n }\n}\n\n/**\n * Create a configured note on message\n */\nexport function createNoteOn(channel: number, note: number, velocity: number): number[] {\n return [0x90 | (channel & 0xF), note & 0x7F, velocity & 0x7F];\n}\n\n/**\n * Create a note off message\n */\nexport function createNoteOff(channel: number, note: number, velocity = 0): number[] {\n return [0x80 | (channel & 0xF), note & 0x7F, velocity & 0x7F];\n}\n\n/**\n * Create a control change message\n */\nexport function createControlChange(channel: number, cc: number, value: number): number[] {\n return [0xB0 | (channel & 0xF), cc & 0x7F, value & 0x7F];\n}\n","import EventEmitter from 'eventemitter3';\n\ntype EventHandler = (...args: any[]) => void;\n\nexport interface SongramEngineEventMap {\n ready: () => void;\n dispose: () => void;\n statechange: (state: unknown) => void;\n timeupdate: (time: number) => void;\n play: () => void;\n pause: () => void;\n stop: () => void;\n 'transport:seek': (time: number) => void;\n 'tracks:set': (trackIds: string[]) => void;\n 'tracks:add': (trackId: string) => void;\n 'tracks:remove': (trackId: string) => void;\n 'plugins:registered': (pluginId: string) => void;\n 'plugins:unregistered': (pluginId: string) => void;\n 'assistant:request': (payload: AssistantRequestEvent) => void;\n}\n\nexport interface AssistantRequestEvent {\n assistantId: string;\n action: string;\n payload?: unknown;\n}\n\nexport class EventBus<TEvents extends object> {\n private readonly emitter = new EventEmitter();\n\n on<K extends keyof TEvents>(event: K, listener: TEvents[K]): void {\n this.emitter.on(String(event), listener as EventHandler);\n }\n\n off<K extends keyof TEvents>(event: K, listener: TEvents[K]): void {\n this.emitter.off(String(event), listener as EventHandler);\n }\n\n once<K extends keyof TEvents>(event: K, listener: TEvents[K]): void {\n this.emitter.once(String(event), listener as EventHandler);\n }\n\n emit<K extends keyof TEvents>(\n event: K,\n ...args: TEvents[K] extends (...params: infer TArgs) => void ? TArgs : never\n ): void {\n this.emitter.emit(String(event), ...args);\n }\n\n removeAllListeners(): void {\n this.emitter.removeAllListeners();\n }\n}\n","import type { EventBus, SongramEngineEventMap } from '../events';\n\nexport type SongramPluginKind = 'general' | 'effect' | 'instrument' | 'assistant';\n\nexport interface SongramPluginContext {\n events: EventBus<SongramEngineEventMap>;\n requestAssistant: (assistantId: string, action: string, payload?: unknown) => void;\n}\n\nexport interface EnginePlugin {\n id: string;\n kind?: SongramPluginKind;\n setup?: (context: SongramPluginContext) => void | (() => void | Promise<void>) | Promise<void>;\n}\n\nexport interface EffectPlugin extends EnginePlugin {\n kind: 'effect';\n}\n\nexport interface InstrumentPlugin extends EnginePlugin {\n kind: 'instrument';\n}\n\nexport interface AssistantPlugin extends EnginePlugin {\n kind: 'assistant';\n capabilities?: string[];\n}\n\nexport class PluginHost {\n private readonly plugins = new Map<string, EnginePlugin>();\n private readonly disposers = new Map<string, () => void | Promise<void>>();\n private readonly context: SongramPluginContext;\n\n constructor(context: SongramPluginContext) {\n this.context = context;\n }\n\n getAll(): EnginePlugin[] {\n return [...this.plugins.values()];\n }\n\n async register(plugin: EnginePlugin): Promise<void> {\n if (this.plugins.has(plugin.id)) {\n throw new Error(`Songram engine plugin \"${plugin.id}\" is already registered.`);\n }\n\n this.plugins.set(plugin.id, plugin);\n\n if (plugin.setup) {\n const disposer = await plugin.setup(this.context);\n if (typeof disposer === 'function') {\n this.disposers.set(plugin.id, disposer);\n }\n }\n\n this.context.events.emit('plugins:registered', plugin.id);\n }\n\n async unregister(pluginId: string): Promise<void> {\n const disposer = this.disposers.get(pluginId);\n if (disposer) {\n await disposer();\n this.disposers.delete(pluginId);\n }\n\n if (this.plugins.delete(pluginId)) {\n this.context.events.emit('plugins:unregistered', pluginId);\n }\n }\n\n async dispose(): Promise<void> {\n const pluginIds = [...this.plugins.keys()];\n for (const pluginId of pluginIds) {\n await this.unregister(pluginId);\n }\n }\n}\n","import { PlaylistEngine, createToneAdapter, type ClipTrack } from '../legacy';\nimport type {\n EngineState,\n PlaylistEngineOptions,\n PlayoutAdapter,\n ToneAdapterOptions,\n} from '../legacy';\nimport { EventBus, type SongramEngineEventMap } from '../events';\nimport { PluginHost, type EnginePlugin } from '../plugins';\n\nexport interface SongramEngineOptions extends Omit<PlaylistEngineOptions, 'adapter'> {\n adapter?: PlayoutAdapter;\n audio?: ToneAdapterOptions;\n plugins?: EnginePlugin[];\n}\n\nexport class SongramEngine {\n readonly events = new EventBus<SongramEngineEventMap>();\n readonly plugins = new PluginHost({\n events: this.events,\n requestAssistant: (assistantId, action, payload) => {\n this.events.emit('assistant:request', { assistantId, action, payload });\n },\n });\n\n readonly transport = {\n play: (startTime?: number, endTime?: number) => this.playlist.play(startTime, endTime),\n pause: () => this.playlist.pause(),\n stop: () => this.playlist.stop(),\n seek: (time: number) => {\n this.playlist.seek(time);\n this.events.emit('transport:seek', time);\n },\n getCurrentTime: () => this.playlist.getCurrentTime(),\n };\n\n readonly tracks = {\n set: (tracks: ClipTrack[]) => {\n this.playlist.setTracks(tracks);\n this.events.emit(\n 'tracks:set',\n tracks.map((track) => track.id)\n );\n },\n add: (track: ClipTrack) => {\n this.playlist.addTrack(track);\n this.events.emit('tracks:add', track.id);\n },\n remove: (trackId: string) => {\n this.playlist.removeTrack(trackId);\n this.events.emit('tracks:remove', trackId);\n },\n select: (trackId: string | null) => this.playlist.selectTrack(trackId),\n };\n\n readonly state = {\n getSnapshot: (): EngineState => this.playlist.getState(),\n };\n\n readonly playlist: PlaylistEngine;\n\n private readonly initialPlugins: EnginePlugin[];\n private readonly handleStateChange = (state: EngineState): void => {\n this.events.emit('statechange', state);\n };\n private readonly handleTimeUpdate = (time: number): void => {\n this.events.emit('timeupdate', time);\n };\n private readonly handlePlay = (): void => {\n this.events.emit('play');\n };\n private readonly handlePause = (): void => {\n this.events.emit('pause');\n };\n private readonly handleStop = (): void => {\n this.events.emit('stop');\n };\n\n constructor(options: SongramEngineOptions = {}) {\n const { adapter, audio, plugins = [], ...playlistOptions } = options;\n const resolvedAdapter = adapter ?? createToneAdapter(audio);\n\n this.playlist = new PlaylistEngine({\n ...playlistOptions,\n adapter: resolvedAdapter,\n });\n this.initialPlugins = plugins;\n\n this.playlist.on('statechange', this.handleStateChange);\n this.playlist.on('timeupdate', this.handleTimeUpdate);\n this.playlist.on('play', this.handlePlay);\n this.playlist.on('pause', this.handlePause);\n this.playlist.on('stop', this.handleStop);\n }\n\n async init(): Promise<void> {\n await this.playlist.init();\n\n for (const plugin of this.initialPlugins) {\n await this.plugins.register(plugin);\n }\n\n this.events.emit('ready');\n }\n\n async registerPlugin(plugin: EnginePlugin): Promise<void> {\n await this.plugins.register(plugin);\n }\n\n async unregisterPlugin(pluginId: string): Promise<void> {\n await this.plugins.unregister(pluginId);\n }\n\n async dispose(): Promise<void> {\n this.playlist.off('statechange', this.handleStateChange);\n this.playlist.off('timeupdate', this.handleTimeUpdate);\n this.playlist.off('play', this.handlePlay);\n this.playlist.off('pause', this.handlePause);\n this.playlist.off('stop', this.handleStop);\n\n this.playlist.dispose();\n await this.plugins.dispose();\n this.events.emit('dispose');\n this.events.removeAllListeners();\n }\n}\n\nexport function createSongramEngine(options: SongramEngineOptions = {}): SongramEngine {\n return new SongramEngine(options);\n}\n"],"names":["MAX_CANVAS_WIDTH","createClip","options","audioBuffer","startSample","offsetSamples","gain","name","color","fadeIn","fadeOut","waveformData","midiNotes","midiChannel","midiProgram","sampleRate","sourceDurationSamples","durationSamples","generateId","createClipFromSeconds","startTime","offset","sourceDuration","duration","createTrack","clips","muted","soloed","volume","pan","height","spectrogramConfig","spectrogramColorMap","createTimeline","tracks","maxSamples","track","trackSamples","max","clip","getClipsInRange","endSample","clipEnd","getClipsAtSample","sample","clipsOverlap","clip1","clip2","clip1End","clip2End","sortClipsByTime","a","b","findGaps","sorted","gaps","i","currentClipEnd","nextClipStart","InteractionState","samplesToSeconds","samples","secondsToSamples","seconds","samplesToPixels","samplesPerPixel","pixelsToSamples","pixels","pixelsToSeconds","secondsToPixels","PPQN","ticksPerBeat","timeSignature","ppqn","denominator","ticksPerBar","numerator","ticksToSamples","ticks","bpm","samplesToTicks","snapToGrid","gridSizeTicks","ticksToBarBeatLabel","barTicks","beatTicks","bar","beatInBar","DEFAULT_FLOOR","dBToNormalized","dB","floor","normalizedToDb","normalized","gainToNormalized","db","clipStartTime","clipEndTime","clipOffsetTime","clipDurationTime","clipPixelWidth","constrainClipDrag","deltaSamples","sortedClips","clipIndex","delta","minDelta","prevClip","minDeltaPrev","maxDeltaNext","constrainBoundaryTrim","boundary","minDurationSamples","prevClipEnd","nextClip","calculateSplitPoint","splitSample","splitClip","leftDuration","rightDuration","leftName","rightName","left","right","canSplitAt","calculateViewportBounds","scrollLeft","containerWidth","bufferRatio","buffer","getVisibleChunkIndices","totalWidth","chunkWidth","visibleStart","visibleEnd","totalChunks","indices","chunkLeft","thisChunkWidth","shouldUpdateViewport","oldScrollLeft","newScrollLeft","threshold","calculateDuration","maxDuration","findClosestZoomIndex","targetSamplesPerPixel","zoomLevels","bestIndex","bestDiff","diff","calculateZoomScrollPosition","oldSamplesPerPixel","newSamplesPerPixel","controlWidth","clampSeekPosition","time","DEFAULT_SAMPLE_RATE","DEFAULT_SAMPLES_PER_PIXEL","DEFAULT_ZOOM_LEVELS","DEFAULT_MIN_DURATION_SECONDS","PlaylistEngine","initialSpp","zoomIndex","trackId","t","clipId","c","sortedIndex","constrainedDelta","newClips","atSample","minDuration","splitClipOp","constrained","endTime","prevCurrentTime","prevPlayStartPosition","beforeLoopEnd","err","start","end","s","e","enabled","newIndex","event","listener","args","listeners","error","tick","hasWarned","getUnderlyingAudioParam","signal","param","linearCurve","length","curve","scale","x","exponentialCurve","index","sCurveCurve","phase","logarithmicCurve","base","generateCurve","type","applyFadeIn","startValue","endValue","scaledCurve","range","applyFadeOut","ToneTrack","Volume","Panner","Gain","destination","getDestination","cleanup","clipInfos","transport","getTransport","rawContext","getContext","volumeNativeInput","clipInfo","fadeGainNode","absTransportTime","scheduleId","audioContextTime","bufferOffset","playDuration","source","transportOffset","absClipStart","absClipEnd","elapsed","adjustedOffset","remainingDuration","scheduled","clipOffset","audioParam","skipTime","fadeInDuration","remainingFadeDuration","fadeProgress","fadeOutStartInClip","absoluteFadeOutStart","elapsedFadeOut","when","delay","value","lastClip","getDrumCategory","midiNote","MidiToneTrack","PolySynth","Synth","MembraneSynth","NoiseSynth","MetalSynth","visibleNotes","note","noteEnd","partEvents","adjustedTime","clampedStart","clampedDuration","part","Part","noteName","velocity","channel","tomPitches","_offset","noteAbsStart","noteAbsEnd","now","_when","synthsToDispose","_SoundFontToneTrack","bank","preset","sfSample","sampleDuration","effectiveDuration","peakGain","gainNode","attackVolEnv","holdVolEnv","decayVolEnv","sustainVolEnv","releaseVolEnv","sustainGain","decayStart","SoundFontToneTrack","TonePlayout","trackOptions","optionsWithDestination","toneTrack","midiTrack","sfTrack","hasSoloedTracks","id","manuallyMuted","loopStart","loopEnd","currentTime","callback","timecentsToSeconds","tc","MAX_RELEASE_SECONDS","getGeneratorValue","generators","int16ToFloat32","floats","calculatePlaybackRate","params","overrideRootKey","originalPitch","coarseTune","fineTune","pitchCorrection","totalSemitones","extractLoopAndEnvelope","header","loopMode","GeneratorType","rawLoopStart","rawLoopEnd","sustainCb","SoundFontCache","context","url","response","arrayBuffer","SoundFont2","data","bankNumber","presetNumber","keyData","sampleIndex","playbackRate","loopAndEnvelope","globalToneContext","getGlobalContext","Context","setContext","getGlobalAudioContext","getGlobalToneContext","resumeGlobalAudioContext","getGlobalAudioContextState","closeGlobalAudioContext","streamSources","streamCleanupHandlers","getMediaStreamSource","stream","releaseMediaStreamSource","hasMediaStreamSource","createToneAdapter","playout","_isPlaying","_playoutGeneration","_loopEnabled","_loopStart","_loopEnd","_audioInitialized","addTrackToPlayout","p","audioClips","midiClips","trackObj","midiClipInfos","firstClip","isPercussion","programNumber","buildPlayout","generation","parseMidi","Parser","headerChunk","parseHeader","trackChunk","parseTrack","format","numTracks","result","timeDivision","events","readEvent","lastEventTypeByte","eventTypeByte","metatypeByte","hourByte","FRAME_RATES","param1","eventType","u","b0","b1","b2","b3","len","bytes","midiParser","writeMidi","opts","w","Writer","writeHeader","writeTrack","h","writeEvent","useByte9ForNoteOff","deltaTime","text","noteByte","value14","lsb14","msb14","v","arr","str","midiWriter","midiFile","require$$0","require$$1","BinarySearch","search","array","prop","beginning","midPoint","event_1","nextEvent","testEvent","insert","exports","BinarySearch_1","privatePPQMap","Header","midiData","_this","firstTrackCurrentTicks_1","lastEventBeats","lastBPM","beats","elapsedSeconds","lastEvent","elapsedBeats","elapsedMeasures","tempo","tempoTime","timeSigEvent","elapsedTime","json","obj","key","privateHeaderMap","privateCCNumberMap","ControlChange","ControlChanges","ControlChange_1","createControlChanges","target","handler","PitchBend_1","PitchBend","InstrumentMaps","Instrument_1","InstrumentMaps_1","privateTrackMap","Instrument","trackData","programChange","n","patchNumber","Note_1","midiToPitch","midi","octave","midiToPitchClass","scaleIndexToNote","pitchClassToMidi","pitch","pitchToMidi","regexp","noteToScaleIndex","split","Note","noteOn","noteOff","o","d","noteEndTicks","Track_1","ControlChanges_1","require$$2","require$$3","require$$4","require$$5","Track","nameEvent","noteOns","noteOffs","_loop_1","currentNote","this_1","offIndex","controlChanges","pitchBends","endOfTrackEvent","props","cc","pb","number","flatten","$flatten","__spreadArray","this","to","from","pack","l","ar","Encode","midi_file_1","Header_1","array_flatten_1","encodeNote","encodeNotes","encodeControlChange","encodeControlChanges","encodePitchBend","encodePitchBends","encodeInstrument","encodeTrackName","encodeTempo","encodeTimeSignature","timeSig","encodeKeySignature","keySig","keyIndex","encodeText","textEvent","encode","lastTime","__awaiter","thisArg","_arguments","P","generator","adopt","resolve","reject","fulfilled","step","rejected","__generator","body","_","f","y","g","verb","op","Encode_1","Midi","midiArray","midiArrayLike","currentTicks","splitTracks","_a","durations","durationTicks","trackJSON","Track_2","Header_2","newTracks","defaultTrack","trackMap","currentProgram","_i","targetTrack","program","trackKey","GM_INSTRUMENTS","getInstrumentName","parseMidiFile","channelNotes","trackName","channelData","totalDuration","notes","allNotes","trackDuration","parseMidiUrl","midiNoteToName","noteNames","noteNameToMidi","match","accidental","octaveStr","semitone","MIDI_COMMANDS","MIDI_CC","parseMidiMessage","timestamp","status","command","isWebMidiSupported","requestMidiAccess","sysex","getMidiInputs","access","inputs","input","getMidiOutputs","outputs","output","MidiController","cb","deviceId","message","createNoteOn","createNoteOff","createControlChange","EventBus","EventEmitter","PluginHost","plugin","disposer","pluginId","pluginIds","SongramEngine","assistantId","action","payload","state","adapter","audio","plugins","playlistOptions","resolvedAdapter","createSongramEngine"],"mappings":";;;AAKO,MAAMA,KAAmB;ACkTzB,SAASC,GAAWC,GAAuC;AAChE,QAAM;AAAA,IACJ,aAAAC;AAAA,IACA,aAAAC;AAAA,IACA,eAAAC,IAAgB;AAAA,IAChB,MAAAC,IAAO;AAAA,IACP,MAAAC;AAAA,IACA,OAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC;AAAA,IACA,cAAAC;AAAA,IACA,WAAAC;AAAA,IACA,aAAAC;AAAA,IACA,aAAAC;AAAA,EAAA,IACEZ,GAGEa,IAAaZ,GAAa,cAAcD,EAAQ,cAAcS,GAAc,aAG5EK,IACJb,GAAa,UACbD,EAAQ,0BACPS,KAAgBI,IAAa,KAAK,KAAKJ,EAAa,WAAWI,CAAU,IAAI;AAEhF,MAAIA,MAAe;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAGJ,MAAIC,MAA0B;AAC5B,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,EAAIb,KAAeQ,KAAgBR,EAAY,eAAeQ,EAAa,eACzE,QAAQ;AAAA,IACN,sCAAsCR,EAAY,UAAU,sBAAsBQ,EAAa,WAAW;AAAA,EAAA;AAM9G,QAAMM,IAAkBf,EAAQ,mBAAmBc;AAEnD,SAAO;AAAA,IACL,IAAIE,GAAA;AAAA,IACJ,aAAAf;AAAA,IACA,aAAAC;AAAA,IACA,iBAAAa;AAAA,IACA,eAAAZ;AAAA,IACA,YAAAU;AAAA,IACA,uBAAAC;AAAA,IACA,MAAAV;AAAA,IACA,MAAAC;AAAA,IACA,OAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC;AAAA,IACA,cAAAC;AAAA,IACA,WAAAC;AAAA,IACA,aAAAC;AAAA,IACA,aAAAC;AAAA,EAAA;AAEJ;AAUO,SAASK,GAAsBjB,GAA8C;AAClF,QAAM;AAAA,IACJ,aAAAC;AAAA,IACA,WAAAiB;AAAA,IACA,QAAAC,IAAS;AAAA,IACT,MAAAf,IAAO;AAAA,IACP,MAAAC;AAAA,IACA,OAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC;AAAA,IACA,cAAAC;AAAA,IACA,WAAAC;AAAA,IACA,aAAAC;AAAA,IACA,aAAAC;AAAA,EAAA,IACEZ,GAGEa,IAAaZ,GAAa,cAAcD,EAAQ,cAAcS,GAAc;AAClF,MAAII,MAAe;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,QAAMO,IAAiBnB,GAAa,YAAYD,EAAQ,kBAAkBS,GAAc;AACxF,MAAIW,MAAmB;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAKJ,EAAInB,KAAeQ,KAAgBR,EAAY,eAAeQ,EAAa,eACzE,QAAQ;AAAA,IACN,sCAAsCR,EAAY,UAAU,sBAAsBQ,EAAa,WAAW;AAAA,EAAA;AAM9G,QAAMY,IAAWrB,EAAQ,YAAYoB;AAErC,SAAOrB,GAAW;AAAA,IAChB,aAAAE;AAAA,IACA,aAAa,KAAK,MAAMiB,IAAYL,CAAU;AAAA,IAC9C,iBAAiB,KAAK,MAAMQ,IAAWR,CAAU;AAAA,IACjD,eAAe,KAAK,MAAMM,IAASN,CAAU;AAAA,IAC7C,YAAAA;AAAA,IACA,uBAAuB,KAAK,KAAKO,IAAiBP,CAAU;AAAA,IAC5D,MAAAT;AAAA,IACA,MAAAC;AAAA,IACA,OAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC;AAAA,IACA,cAAAC;AAAA,IACA,WAAAC;AAAA,IACA,aAAAC;AAAA,IACA,aAAAC;AAAA,EAAA,CACD;AACH;AAKO,SAASU,GAAYtB,GAAwC;AAClE,QAAM;AAAA,IACJ,MAAAK;AAAA,IACA,OAAAkB,IAAQ,CAAA;AAAA,IACR,OAAAC,IAAQ;AAAA,IACR,QAAAC,IAAS;AAAA,IACT,QAAAC,IAAS;AAAA,IACT,KAAAC,IAAM;AAAA,IACN,OAAArB;AAAA,IACA,QAAAsB;AAAA,IACA,mBAAAC;AAAA,IACA,qBAAAC;AAAA,EAAA,IACE9B;AAEJ,SAAO;AAAA,IACL,IAAIgB,GAAA;AAAA,IACJ,MAAAX;AAAA,IACA,OAAAkB;AAAA,IACA,OAAAC;AAAA,IACA,QAAAC;AAAA,IACA,QAAAC;AAAA,IACA,KAAAC;AAAA,IACA,OAAArB;AAAA,IACA,QAAAsB;AAAA,IACA,mBAAAC;AAAA,IACA,qBAAAC;AAAA,EAAA;AAEJ;AAKO,SAASC,GACdC,GACAnB,IAAqB,OACrBb,GAKU;AASV,QAAMqB,IAPkBW,EAAO,OAAO,CAACC,GAAYC,MAAU;AAC3D,UAAMC,IAAeD,EAAM,MAAM,OAAO,CAACE,GAAKC,MACrC,KAAK,IAAID,GAAKC,EAAK,cAAcA,EAAK,eAAe,GAC3D,CAAC;AACJ,WAAO,KAAK,IAAIJ,GAAYE,CAAY;AAAA,EAC1C,GAAG,CAAC,IAE+BtB;AAEnC,SAAO;AAAA,IACL,QAAAmB;AAAA,IACA,UAAAX;AAAA,IACA,YAAAR;AAAA,IACA,MAAMb,GAAS;AAAA,IACf,OAAOA,GAAS;AAAA,IAChB,eAAeA,GAAS;AAAA,EAAA;AAE5B;AAKA,SAASgB,KAAqB;AAC5B,SAAO,GAAG,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AACjE;AAyBO,SAASsB,GACdJ,GACAhC,GACAqC,GACa;AACb,SAAOL,EAAM,MAAM,OAAO,CAACG,MAAS;AAClC,UAAMG,IAAUH,EAAK,cAAcA,EAAK;AAIxC,WAAOA,EAAK,cAAcE,KAAaC,IAAUtC;AAAA,EACnD,CAAC;AACH;AAKO,SAASuC,GAAiBP,GAAkBQ,GAA6B;AAC9E,SAAOR,EAAM,MAAM,OAAO,CAACG,MAAS;AAClC,UAAMG,IAAUH,EAAK,cAAcA,EAAK;AACxC,WAAOK,KAAUL,EAAK,eAAeK,IAASF;AAAA,EAChD,CAAC;AACH;AAKO,SAASG,GAAaC,GAAkBC,GAA2B;AACxE,QAAMC,IAAWF,EAAM,cAAcA,EAAM,iBACrCG,IAAWF,EAAM,cAAcA,EAAM;AAE3C,SAAOD,EAAM,cAAcG,KAAYD,IAAWD,EAAM;AAC1D;AAKO,SAASG,GAAgBzB,GAAiC;AAC/D,SAAO,CAAC,GAAGA,CAAK,EAAE,KAAK,CAAC0B,GAAGC,MAAMD,EAAE,cAAcC,EAAE,WAAW;AAChE;AAWO,SAASC,GAASjB,GAAyB;AAChD,MAAIA,EAAM,MAAM,WAAW,UAAU,CAAA;AAErC,QAAMkB,IAASJ,GAAgBd,EAAM,KAAK,GACpCmB,IAAc,CAAA;AAEpB,WAASC,IAAI,GAAGA,IAAIF,EAAO,SAAS,GAAGE,KAAK;AAC1C,UAAMC,IAAiBH,EAAOE,CAAC,EAAE,cAAcF,EAAOE,CAAC,EAAE,iBACnDE,IAAgBJ,EAAOE,IAAI,CAAC,EAAE;AAEpC,IAAIE,IAAgBD,KAClBF,EAAK,KAAK;AAAA,MACR,aAAaE;AAAA,MACb,WAAWC;AAAA,MACX,iBAAiBA,IAAgBD;AAAA,IAAA,CAClC;AAAA,EAEL;AAEA,SAAOF;AACT;ACngBO,IAAKI,uBAAAA,OACVA,EAAA,SAAS,UACTA,EAAA,SAAS,UACTA,EAAA,QAAQ,SACRA,EAAA,SAAS,UACTA,EAAA,UAAU,WALAA,IAAAA,MAAA,CAAA,CAAA;ACjGL,SAASC,GAAiBC,GAAiB9C,GAA4B;AAC5E,SAAO8C,IAAU9C;AACnB;AAEO,SAAS+C,GAAiBC,GAAiBhD,GAA4B;AAC5E,SAAO,KAAK,KAAKgD,IAAUhD,CAAU;AACvC;AAEO,SAASiD,GAAgBH,GAAiBI,GAAiC;AAChF,SAAO,KAAK,MAAMJ,IAAUI,CAAe;AAC7C;AAEO,SAASC,GAAgBC,GAAgBF,GAAiC;AAC/E,SAAO,KAAK,MAAME,IAASF,CAAe;AAC5C;AAEO,SAASG,GACdD,GACAF,GACAlD,GACQ;AACR,SAAQoD,IAASF,IAAmBlD;AACtC;AAEO,SAASsD,GACdN,GACAE,GACAlD,GACQ;AACR,SAAO,KAAK,KAAMgD,IAAUhD,IAAckD,CAAe;AAC3D;AC7BO,MAAMK,IAAO;AAGb,SAASC,GAAaC,GAAiCC,IAAOH,GAAc;AACjF,QAAM,CAAA,EAAGI,CAAW,IAAIF;AACxB,SAAOC,KAAQ,IAAIC;AACrB;AAGO,SAASC,GAAYH,GAAiCC,IAAOH,GAAc;AAChF,QAAM,CAACM,CAAS,IAAIJ;AACpB,SAAOI,IAAYL,GAAaC,GAAeC,CAAI;AACrD;AAGO,SAASI,GACdC,GACAC,GACAhE,GACA0D,IAAOH,GACC;AACR,SAAO,KAAK,MAAOQ,IAAQ,KAAK/D,KAAegE,IAAMN,EAAK;AAC5D;AAGO,SAASO,GACdnB,GACAkB,GACAhE,GACA0D,IAAOH,GACC;AACR,SAAO,KAAK,MAAOT,IAAUY,IAAOM,KAAQ,KAAKhE,EAAW;AAC9D;AAGO,SAASkE,GAAWH,GAAeI,GAA+B;AACvE,SAAO,KAAK,MAAMJ,IAAQI,CAAa,IAAIA;AAC7C;AAGO,SAASC,GACdL,GACAN,GACAC,IAAOH,GACC;AACR,QAAMc,IAAWT,GAAYH,GAAeC,CAAI,GAC1CY,IAAYd,GAAaC,GAAeC,CAAI,GAC5Ca,IAAM,KAAK,MAAMR,IAAQM,CAAQ,IAAI,GACrCG,IAAY,KAAK,MAAOT,IAAQM,IAAYC,CAAS,IAAI;AAC/D,SAAIE,MAAc,IAAU,GAAGD,CAAG,KAC3B,GAAGA,CAAG,IAAIC,CAAS;AAC5B;ACpDA,MAAMC,IAAgB;AAYf,SAASC,GAAeC,GAAYC,IAAgBH,GAAuB;AAChF,SAAI,OAAO,MAAME,CAAE,KACjB,QAAQ,KAAK,2CAA2C,GACjD,KAELC,KAAS,KACX,QAAQ,KAAK,6DAA6DA,CAAK,GACxE,KAEL,CAAC,SAASD,CAAE,KAAKA,KAAMC,IAAc,KACjCD,IAAKC,KAAS,CAACA;AACzB;AAYO,SAASC,GAAeC,GAAoBF,IAAgBH,GAAuB;AACxF,SAAK,SAASK,CAAU,IACpBF,KAAS,KACX,QAAQ,KAAK,6DAA6DA,CAAK,GACxEH,KAEO,KAAK,IAAI,GAAGK,CAAU,IACrB,CAACF,IAAQA,IANQA;AAOpC;AAaO,SAASG,GAAiBxF,GAAcqF,IAAgBH,GAAuB;AACpF,MAAIlF,KAAQ,EAAG,QAAO;AACtB,QAAMyF,IAAK,KAAK,KAAK,MAAMzF,CAAI;AAC/B,SAAOmF,GAAeM,GAAIJ,CAAK;AACjC;ACzDO,SAASK,EAAczD,GAAyB;AACrD,SAAOA,EAAK,cAAcA,EAAK;AACjC;AAGO,SAAS0D,GAAY1D,GAAyB;AACnD,UAAQA,EAAK,cAAcA,EAAK,mBAAmBA,EAAK;AAC1D;AAGO,SAAS2D,GAAe3D,GAAyB;AACtD,SAAOA,EAAK,gBAAgBA,EAAK;AACnC;AAGO,SAAS4D,GAAiB5D,GAAyB;AACxD,SAAOA,EAAK,kBAAkBA,EAAK;AACrC;AAQO,SAAS6D,GACdhG,GACAa,GACAgD,GACQ;AACR,SACE,KAAK,OAAO7D,IAAca,KAAmBgD,CAAe,IAC5D,KAAK,MAAM7D,IAAc6D,CAAe;AAE5C;ACjBO,SAASoC,GACd9D,GACA+D,GACAC,GACAC,GACQ;AACR,MAAIC,IAAQH;AAGZ,QAAMI,IAAW,CAACnE,EAAK;AAIvB,MAHAkE,IAAQ,KAAK,IAAIA,GAAOC,CAAQ,GAG5BF,IAAY,GAAG;AACjB,UAAMG,IAAWJ,EAAYC,IAAY,CAAC,GAGpCI,IAFcD,EAAS,cAAcA,EAAS,kBAEjBpE,EAAK;AACxC,IAAAkE,IAAQ,KAAK,IAAIA,GAAOG,CAAY;AAAA,EACtC;AAGA,MAAIJ,IAAYD,EAAY,SAAS,GAAG;AAGtC,UAAMM,IAFWN,EAAYC,IAAY,CAAC,EAEZ,eAAejE,EAAK,cAAcA,EAAK;AACrE,IAAAkE,IAAQ,KAAK,IAAIA,GAAOI,CAAY;AAAA,EACtC;AAEA,SAAOJ;AACT;AAmBO,SAASK,GACdvE,GACA+D,GACAS,GACAR,GACAC,GACAQ,GACQ;AACR,MAAIP,IAAQH;AAEZ,MAAIS,MAAa,QAAQ;AAQvB,QANAN,IAAQ,KAAK,IAAIA,GAAO,CAAClE,EAAK,WAAW,GAGzCkE,IAAQ,KAAK,IAAIA,GAAO,CAAClE,EAAK,aAAa,GAGvCiE,IAAY,GAAG;AACjB,YAAMG,IAAWJ,EAAYC,IAAY,CAAC,GACpCS,IAAcN,EAAS,cAAcA,EAAS;AAEpD,MAAAF,IAAQ,KAAK,IAAIA,GAAOQ,IAAc1E,EAAK,WAAW;AAAA,IACxD;AAIA,IAAAkE,IAAQ,KAAK,IAAIA,GAAOlE,EAAK,kBAAkByE,CAAkB;AAAA,EACnE,WAKEP,IAAQ,KAAK,IAAIA,GAAOO,IAAqBzE,EAAK,eAAe,GAIjEkE,IAAQ,KAAK,IAAIA,GAAOlE,EAAK,wBAAwBA,EAAK,gBAAgBA,EAAK,eAAe,GAG1FiE,IAAYD,EAAY,SAAS,GAAG;AACtC,UAAMW,IAAWX,EAAYC,IAAY,CAAC;AAE1C,IAAAC,IAAQ,KAAK,IAAIA,GAAOS,EAAS,cAAc3E,EAAK,cAAcA,EAAK,eAAe;AAAA,EACxF;AAGF,SAAOkE;AACT;AASO,SAASU,GAAoBC,GAAqBnD,GAAiC;AACxF,SAAO,KAAK,MAAMmD,IAAcnD,CAAe,IAAIA;AACrD;AAaO,SAASoD,GACd9E,GACA6E,GACuC;AACvC,QAAME,IAAeF,IAAc7E,EAAK,aAClCgF,IAAgBhF,EAAK,kBAAkB+E,GAEvCE,IAAWjF,EAAK,OAAO,GAAGA,EAAK,IAAI,SAAS,QAC5CkF,IAAYlF,EAAK,OAAO,GAAGA,EAAK,IAAI,SAAS,QAE7CmF,IAAOzH,GAAW;AAAA,IACtB,aAAasC,EAAK;AAAA,IAClB,iBAAiB+E;AAAA,IACjB,eAAe/E,EAAK;AAAA,IACpB,YAAYA,EAAK;AAAA,IACjB,uBAAuBA,EAAK;AAAA,IAC5B,MAAMA,EAAK;AAAA,IACX,MAAMiF;AAAA,IACN,OAAOjF,EAAK;AAAA,IACZ,QAAQA,EAAK;AAAA,IACb,aAAaA,EAAK;AAAA,IAClB,cAAcA,EAAK;AAAA,EAAA,CACpB,GAEKoF,IAAQ1H,GAAW;AAAA,IACvB,aAAamH;AAAA,IACb,iBAAiBG;AAAA,IACjB,eAAehF,EAAK,gBAAgB+E;AAAA,IACpC,YAAY/E,EAAK;AAAA,IACjB,uBAAuBA,EAAK;AAAA,IAC5B,MAAMA,EAAK;AAAA,IACX,MAAMkF;AAAA,IACN,OAAOlF,EAAK;AAAA,IACZ,SAASA,EAAK;AAAA,IACd,aAAaA,EAAK;AAAA,IAClB,cAAcA,EAAK;AAAA,EAAA,CACpB;AAED,SAAO,EAAE,MAAAmF,GAAM,OAAAC,EAAA;AACjB;AAaO,SAASC,GAAWrF,GAAiBK,GAAgBoE,GAAqC;AAC/F,QAAMtE,IAAUH,EAAK,cAAcA,EAAK;AAGxC,MAAIK,KAAUL,EAAK,eAAeK,KAAUF;AAC1C,WAAO;AAIT,QAAM4E,IAAe1E,IAASL,EAAK,aAC7BgF,IAAgB7E,IAAUE;AAEhC,SAAO0E,KAAgBN,KAAsBO,KAAiBP;AAChE;AC5LO,SAASa,GACdC,GACAC,GACAC,IAAsB,KACwB;AAC9C,QAAMC,IAASF,IAAiBC;AAChC,SAAO;AAAA,IACL,cAAc,KAAK,IAAI,GAAGF,IAAaG,CAAM;AAAA,IAC7C,YAAYH,IAAaC,IAAiBE;AAAA,EAAA;AAE9C;AAeO,SAASC,GACdC,GACAC,GACAC,GACAC,GACU;AACV,QAAMC,IAAc,KAAK,KAAKJ,IAAaC,CAAU,GAC/CI,IAAoB,CAAA;AAE1B,WAAShF,IAAI,GAAGA,IAAI+E,GAAa/E,KAAK;AACpC,UAAMiF,IAAYjF,IAAI4E,GAChBM,IAAiB,KAAK,IAAIP,IAAaM,GAAWL,CAAU;AAGlE,IAFiBK,IAAYC,KAEbL,KAAgBI,KAAaH,KAI7CE,EAAQ,KAAKhF,CAAC;AAAA,EAChB;AAEA,SAAOgF;AACT;AAcO,SAASG,GACdC,GACAC,GACAC,IAAoB,KACX;AACT,SAAO,KAAK,IAAIF,IAAgBC,CAAa,KAAKC;AACpD;AC3EO,SAASC,EAAkB7G,GAA6B;AAC7D,MAAI8G,IAAc;AAClB,aAAW5G,KAASF;AAClB,eAAWK,KAAQH,EAAM,OAAO;AAE9B,YAAMM,KADgBH,EAAK,cAAcA,EAAK,mBACdA,EAAK;AACrC,MAAAyG,IAAc,KAAK,IAAIA,GAAatG,CAAO;AAAA,IAC7C;AAEF,SAAOsG;AACT;AAWO,SAASC,GAAqBC,GAA+BC,GAA8B;AAChG,MAAIA,EAAW,WAAW,EAAG,QAAO;AAEpC,MAAIC,IAAY,GACZC,IAAW,KAAK,IAAIF,EAAW,CAAC,IAAID,CAAqB;AAE7D,WAAS,IAAI,GAAG,IAAIC,EAAW,QAAQ,KAAK;AAC1C,UAAMG,IAAO,KAAK,IAAIH,EAAW,CAAC,IAAID,CAAqB;AAC3D,IAAII,IAAOD,MACTA,IAAWC,GACXF,IAAY;AAAA,EAEhB;AAEA,SAAOA;AACT;AAeO,SAASG,GACdC,GACAC,GACA3B,GACAC,GACAhH,GACA2I,IAAuB,GACf;AAIR,QAAMb,KAHcf,IAAaC,IAAiB,IAAI2B,KACpBF,IAAsBzI,IACnBA,IAAc0I,IACZC,IAAe3B,IAAiB;AACvE,SAAO,KAAK,IAAI,GAAGc,CAAa;AAClC;AASO,SAASc,GAAkBC,GAAcrI,GAA0B;AACxE,SAAO,KAAK,IAAI,GAAG,KAAK,IAAIqI,GAAMrI,CAAQ,CAAC;AAC7C;AC/DA,MAAMsI,KAAsB,OACtBC,KAA4B,MAC5BC,KAAsB,CAAC,KAAK,KAAK,MAAM,MAAM,MAAM,IAAI,GACvDC,KAA+B;AAI9B,MAAMC,GAAe;AAAA,EAsB1B,YAAY/J,IAAiC,IAAI;AAK/C,QA1BF,KAAQ,UAAuB,CAAA,GAC/B,KAAQ,eAAe,GACvB,KAAQ,qBAAqB,GAC7B,KAAQ,aAAa,IACrB,KAAQ,mBAAkC,MAI1C,KAAQ,kBAAkB,GAC1B,KAAQ,gBAAgB,GACxB,KAAQ,gBAAgB,GACxB,KAAQ,aAAa,GACrB,KAAQ,WAAW,GACnB,KAAQ,iBAAiB,IACzB,KAAQ,iBAAiB,GAEzB,KAAQ,eAA8B,MACtC,KAAQ,YAAY,IAEpB,KAAQ,iCAA6C,IAAA,GAGnD,KAAK,cAAcA,EAAQ,cAAc2J,IACzC,KAAK,cAAc,CAAC,GAAI3J,EAAQ,cAAc6J,EAAoB,GAClE,KAAK,WAAW7J,EAAQ,WAAW,MAE/B,KAAK,YAAY,WAAW;AAC9B,YAAM,IAAI,MAAM,8CAA8C;AAGhE,UAAMgK,IAAahK,EAAQ,mBAAmB4J,IACxCK,IAAY,KAAK,YAAY,QAAQD,CAAU;AACrD,QAAIC,MAAc;AAChB,YAAM,IAAI;AAAA,QACR,mCAAmCD,CAAU,0BAA0B,KAAK,YAAY,KAAK,IAAI,CAAC,gFACnBA,CAAU;AAAA,MAAA;AAG7F,SAAK,aAAaC;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAMA,WAAwB;AACtB,WAAO;AAAA,MACL,QAAQ,KAAK,QAAQ,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,KAAK,IAAI;AAAA,MAC/D,eAAe,KAAK;AAAA,MACpB,UAAUpB,EAAkB,KAAK,OAAO;AAAA,MACxC,aAAa,KAAK;AAAA,MAClB,WAAW,KAAK;AAAA,MAChB,iBAAiB,KAAK,YAAY,KAAK,UAAU;AAAA,MACjD,YAAY,KAAK;AAAA,MACjB,iBAAiB,KAAK;AAAA,MACtB,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK,aAAa;AAAA,MAC7B,YAAY,KAAK,aAAa,KAAK,YAAY,SAAS;AAAA,MACxD,gBAAgB,KAAK;AAAA,MACrB,cAAc,KAAK;AAAA,MACnB,cAAc,KAAK;AAAA,MACnB,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK;AAAA,MACd,eAAe,KAAK;AAAA,IAAA;AAAA,EAExB;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU7G,GAA2B;AACnC,SAAK,UAAU,CAAC,GAAGA,CAAM,GACzB,KAAK,kBACL,KAAK,UAAU,UAAU,KAAK,OAAO,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,SAASE,GAAwB;AAC/B,SAAK,UAAU,CAAC,GAAG,KAAK,SAASA,CAAK,GACtC,KAAK,kBAED,KAAK,UAAU,WACjB,KAAK,SAAS,SAASA,CAAK,IAE5B,KAAK,UAAU,UAAU,KAAK,OAAO,GAEvC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,YAAYgI,GAAuB;AACjC,IAAK,KAAK,QAAQ,KAAK,CAACC,MAAMA,EAAE,OAAOD,CAAO,MAC9C,KAAK,UAAU,KAAK,QAAQ,OAAO,CAACC,MAAMA,EAAE,OAAOD,CAAO,GAC1D,KAAK,kBACD,KAAK,qBAAqBA,MAC5B,KAAK,mBAAmB,OAE1B,KAAK,UAAU,UAAU,KAAK,OAAO,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,YAAYA,GAA8B;AACxC,IAAIA,MAAY,KAAK,qBACrB,KAAK,mBAAmBA,GACxB,KAAK,iBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAMA,SAASA,GAAiBE,GAAgBhE,GAA4B;AACpE,UAAMlE,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,QAAI,CAAChI,GAAO;AACV,cAAQ,KAAK,yCAAyCgI,CAAO,aAAa;AAC1E;AAAA,IACF;AAEA,UAAM5D,IAAYpE,EAAM,MAAM,UAAU,CAACmI,MAAiBA,EAAE,OAAOD,CAAM;AACzE,QAAI9D,MAAc,IAAI;AACpB,cAAQ;AAAA,QACN,wCAAwC8D,CAAM,yBAAyBF,CAAO;AAAA,MAAA;AAEhF;AAAA,IACF;AAEA,UAAM7H,IAAOH,EAAM,MAAMoE,CAAS,GAC5BD,IAAcrD,GAAgBd,EAAM,KAAK,GACzCoI,IAAcjE,EAAY,UAAU,CAACgE,MAAiBA,EAAE,OAAOD,CAAM,GAErEG,IAAmBpE,GAAkB9D,GAAM+D,GAAcC,GAAaiE,CAAW;AAEvF,IAAIC,MAAqB,MAEzB,KAAK,UAAU,KAAK,QAAQ,IAAI,CAACJ,MAAM;AACrC,UAAIA,EAAE,OAAOD,EAAS,QAAOC;AAC7B,YAAMK,IAAWL,EAAE,MAAM;AAAA,QAAI,CAACE,GAAc/G,MAC1CA,MAAMgD,IACF;AAAA,UACE,GAAG+D;AAAA,UACH,aAAa,KAAK,MAAMA,EAAE,cAAcE,CAAgB;AAAA,QAAA,IAE1DF;AAAA,MAAA;AAEN,aAAO,EAAE,GAAGF,GAAG,OAAOK,EAAA;AAAA,IACxB,CAAC,GAED,KAAK,kBACL,KAAK,UAAU,UAAU,KAAK,OAAO,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,UAAUN,GAAiBE,GAAgBK,GAAwB;AACjE,UAAMvI,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,QAAI,CAAChI,GAAO;AACV,cAAQ,KAAK,0CAA0CgI,CAAO,aAAa;AAC3E;AAAA,IACF;AAEA,UAAM5D,IAAYpE,EAAM,MAAM,UAAU,CAACmI,MAAiBA,EAAE,OAAOD,CAAM;AACzE,QAAI9D,MAAc,IAAI;AACpB,cAAQ;AAAA,QACN,yCAAyC8D,CAAM,yBAAyBF,CAAO;AAAA,MAAA;AAEjF;AAAA,IACF;AAEA,UAAM7H,IAAOH,EAAM,MAAMoE,CAAS,GAC5BoE,IAAc,KAAK,MAAMZ,KAA+B,KAAK,WAAW;AAE9E,QAAI,CAACpC,GAAWrF,GAAMoI,GAAUC,CAAW,GAAG;AAC5C,cAAQ;AAAA,QACN,sDAAsDN,CAAM,eAAeK,CAAQ,iBACjEpI,EAAK,WAAW,IAAIA,EAAK,cAAcA,EAAK,eAAe,kBAAkBqI,CAAW;AAAA,MAAA;AAE5G;AAAA,IACF;AAEA,UAAM,EAAE,MAAAlD,GAAM,OAAAC,EAAA,IAAUkD,GAAYtI,GAAMoI,CAAQ;AAElD,SAAK,UAAU,KAAK,QAAQ,IAAI,CAACN,MAAM;AACrC,UAAIA,EAAE,OAAOD,EAAS,QAAOC;AAC7B,YAAMK,IAAW,CAAC,GAAGL,EAAE,KAAK;AAC5B,aAAAK,EAAS,OAAOlE,GAAW,GAAGkB,GAAMC,CAAK,GAClC,EAAE,GAAG0C,GAAG,OAAOK,EAAA;AAAA,IACxB,CAAC,GAED,KAAK,kBACL,KAAK,UAAU,UAAU,KAAK,OAAO,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,SACEN,GACAE,GACAvD,GACAT,GACM;AACN,UAAMlE,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,QAAI,CAAChI,GAAO;AACV,cAAQ,KAAK,yCAAyCgI,CAAO,aAAa;AAC1E;AAAA,IACF;AAEA,UAAM5D,IAAYpE,EAAM,MAAM,UAAU,CAACmI,MAAiBA,EAAE,OAAOD,CAAM;AACzE,QAAI9D,MAAc,IAAI;AACpB,cAAQ;AAAA,QACN,wCAAwC8D,CAAM,yBAAyBF,CAAO;AAAA,MAAA;AAEhF;AAAA,IACF;AAEA,UAAM7H,IAAOH,EAAM,MAAMoE,CAAS,GAC5BD,IAAcrD,GAAgBd,EAAM,KAAK,GACzCoI,IAAcjE,EAAY,UAAU,CAACgE,MAAiBA,EAAE,OAAOD,CAAM,GACrEM,IAAc,KAAK,MAAMZ,KAA+B,KAAK,WAAW,GAExEc,IAAchE;AAAA,MAClBvE;AAAA,MACA+D;AAAA,MACAS;AAAA,MACAR;AAAA,MACAiE;AAAA,MACAI;AAAA,IAAA;AAGF,IAAIE,MAAgB,MAEpB,KAAK,UAAU,KAAK,QAAQ,IAAI,CAACT,MAAM;AACrC,UAAIA,EAAE,OAAOD,EAAS,QAAOC;AAC7B,YAAMK,IAAWL,EAAE,MAAM,IAAI,CAACE,GAAc/G,MACtCA,MAAMgD,IAAkB+D,IACxBxD,MAAa,SACR;AAAA,QACL,GAAGwD;AAAA,QACH,aAAaA,EAAE,cAAcO;AAAA,QAC7B,eAAeP,EAAE,gBAAgBO;AAAA,QACjC,iBAAiBP,EAAE,kBAAkBO;AAAA,MAAA,IAGhC,EAAE,GAAGP,GAAG,iBAAiBA,EAAE,kBAAkBO,EAAA,CAEvD;AACD,aAAO,EAAE,GAAGT,GAAG,OAAOK,EAAA;AAAA,IACxB,CAAC,GAED,KAAK,kBACL,KAAK,UAAU,UAAU,KAAK,OAAO,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAsB;AAC1B,IAAI,KAAK,YACP,MAAM,KAAK,SAAS,KAAA;AAAA,EAExB;AAAA,EAEA,KAAKtJ,GAAoB2J,GAAwB;AAC/C,UAAMC,IAAkB,KAAK,cACvBC,IAAwB,KAAK;AAEnC,QAAI7J,MAAc,QAAW;AAC3B,YAAMG,IAAWwH,EAAkB,KAAK,OAAO;AAC/C,WAAK,eAAeY,GAAkBvI,GAAWG,CAAQ;AAAA,IAC3D;AAKA,QAFA,KAAK,qBAAqB,KAAK,cAE3B,KAAK,UAAU;AAKjB,UAAIwJ,MAAY;AAEd,aAAK,SAAS,QAAQ,IAAO,KAAK,YAAY,KAAK,QAAQ;AAAA,eAClD,KAAK,gBAAgB;AAG9B,cAAMG,IAAgB,KAAK,eAAe,KAAK;AAC/C,aAAK,SAAS,QAAQA,GAAe,KAAK,YAAY,KAAK,QAAQ;AAAA,MACrE;AACA,UAAI;AACF,aAAK,SAAS,KAAK,KAAK,cAAcH,CAAO;AAAA,MAC/C,SAASI,GAAK;AAGZ,mBAAK,eAAeH,GACpB,KAAK,qBAAqBC,GACpBE;AAAA,MACR;AAAA,IACF;AAEA,SAAK,aAAa,IAClB,KAAK,qBAAA,GACL,KAAK,MAAM,MAAM,GACjB,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,QAAc;AACZ,SAAK,aAAa,IAClB,KAAK,oBAAA,GACL,KAAK,UAAU,MAAA,GACX,KAAK,aACP,KAAK,eAAe,KAAK,SAAS,eAAA,IAEpC,KAAK,MAAM,OAAO,GAClB,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,OAAa;AACX,SAAK,aAAa,IAClB,KAAK,eAAe,KAAK,oBACzB,KAAK,oBAAA,GACL,KAAK,UAAU,QAAQ,IAAO,KAAK,YAAY,KAAK,QAAQ,GAC5D,KAAK,UAAU,KAAA,GACf,KAAK,MAAM,MAAM,GACjB,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,KAAKvB,GAAoB;AACvB,UAAMrI,IAAWwH,EAAkB,KAAK,OAAO;AAC/C,SAAK,eAAeY,GAAkBC,GAAMrI,CAAQ,GACpD,KAAK,UAAU,KAAK,KAAK,YAAY,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,gBAAgBK,GAAsB;AACpC,IAAIA,MAAW,KAAK,kBACpB,KAAK,gBAAgBA,GACrB,KAAK,UAAU,gBAAgBA,CAAM,GACrC,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,iBAAyB;AACvB,WAAI,KAAK,cAAc,KAAK,WACnB,KAAK,SAAS,eAAA,IAEhB,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAMA,aAAawJ,GAAeC,GAAmB;AAC7C,UAAMC,IAAI,KAAK,IAAIF,GAAOC,CAAG,GACvBE,IAAI,KAAK,IAAIH,GAAOC,CAAG;AAC7B,IAAIC,MAAM,KAAK,mBAAmBC,MAAM,KAAK,kBAC7C,KAAK,kBAAkBD,GACvB,KAAK,gBAAgBC,GACrB,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,cAAcH,GAAeC,GAAmB;AAC9C,UAAMC,IAAI,KAAK,IAAIF,GAAOC,CAAG,GACvBE,IAAI,KAAK,IAAIH,GAAOC,CAAG;AAC7B,IAAIC,MAAM,KAAK,cAAcC,MAAM,KAAK,aACxC,KAAK,aAAaD,GAClB,KAAK,WAAWC,GAChB,KAAK,UAAU;AAAA,MACb,KAAK,kBAAkB,KAAK,iBAAA;AAAA,MAC5B,KAAK;AAAA,MACL,KAAK;AAAA,IAAA,GAEP,KAAK,iBAAA;AAAA,EACP;AAAA,EAEA,eAAeC,GAAwB;AACrC,IAAIA,MAAY,KAAK,mBACrB,KAAK,iBAAiBA,GACtB,KAAK,UAAU,QAAQA,KAAW,KAAK,oBAAoB,KAAK,YAAY,KAAK,QAAQ,GACzF,KAAK,iBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAMA,eAAepB,GAAiBxI,GAAsB;AACpD,UAAMQ,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,IAAIhI,QAAa,SAASR,IAC1B,KAAK,UAAU,eAAewI,GAASxI,CAAM;AAAA,EAC/C;AAAA,EAEA,aAAawI,GAAiB1I,GAAsB;AAClD,UAAMU,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,IAAIhI,QAAa,QAAQV,IACzB,KAAK,UAAU,aAAa0I,GAAS1I,CAAK;AAAA,EAC5C;AAAA,EAEA,aAAa0I,GAAiBzI,GAAuB;AACnD,UAAMS,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,IAAIhI,QAAa,SAAST,IAC1B,KAAK,UAAU,aAAayI,GAASzI,CAAM;AAAA,EAC7C;AAAA,EAEA,YAAYyI,GAAiBvI,GAAmB;AAC9C,UAAMO,IAAQ,KAAK,QAAQ,KAAK,CAACiI,MAAMA,EAAE,OAAOD,CAAO;AACvD,IAAIhI,QAAa,MAAMP,IACvB,KAAK,UAAU,YAAYuI,GAASvI,CAAG;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAMA,SAAe;AACb,IAAI,KAAK,aAAa,MACpB,KAAK,cACL,KAAK,iBAAA;AAAA,EAET;AAAA,EAEA,UAAgB;AACd,IAAI,KAAK,aAAa,KAAK,YAAY,SAAS,MAC9C,KAAK,cACL,KAAK,iBAAA;AAAA,EAET;AAAA,EAEA,aAAaoC,GAA+B;AAC1C,UAAMwH,IAAWxC,GAAqBhF,GAAiB,KAAK,WAAW;AACvE,IAAIwH,MAAa,KAAK,eACtB,KAAK,aAAaA,GAClB,KAAK,iBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA,EAMA,GAAwBC,GAAUC,GAAiC;AACjE,IAAK,KAAK,WAAW,IAAID,CAAK,KAC5B,KAAK,WAAW,IAAIA,GAAO,oBAAI,KAAK,GAEtC,KAAK,WAAW,IAAIA,CAAK,EAAG,IAAIC,CAAQ;AAAA,EAC1C;AAAA,EAEA,IAAyBD,GAAUC,GAAiC;AAClE,SAAK,WAAW,IAAID,CAAK,GAAG,OAAOC,CAAQ;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AACd,QAAI,MAAK,WACT;AAAA,WAAK,YAAY,IACjB,KAAK,oBAAA;AACL,UAAI;AACF,aAAK,UAAU,QAAA;AAAA,MACjB,SAASR,GAAK;AACZ,gBAAQ,KAAK,iDAAiDA,CAAG;AAAA,MACnE;AACA,WAAK,WAAW,MAAA;AAAA;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAMQ,MAAMO,MAAkBE,GAAuB;AACrD,UAAMC,IAAY,KAAK,WAAW,IAAIH,CAAK;AAC3C,QAAIG;AACF,iBAAWF,KAAYE;AACrB,YAAI;AACF,UAAAF,EAAS,GAAGC,CAAI;AAAA,QAClB,SAASE,GAAO;AACd,kBAAQ,KAAK,iDAAiDA,CAAK;AAAA,QACrE;AAAA,EAGN;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,mBAA4B;AAClC,WAAK,KAAK,cACA,KAAK,UAAU,eAAA,KAAoB,KAAK,gBACvC,KAAK,WAFa;AAAA,EAG/B;AAAA,EAEQ,mBAAyB;AAC/B,SAAK,MAAM,eAAe,KAAK,SAAA,CAAU;AAAA,EAC3C;AAAA,EAEQ,uBAA6B;AAEnC,QAAI,OAAO,wBAA0B,IAAa;AAElD,SAAK,oBAAA;AAEL,UAAMC,IAAO,MAAM;AACjB,MAAI,KAAK,aAAa,CAAC,KAAK,eACxB,KAAK,aACP,KAAK,eAAe,KAAK,SAAS,eAAA,GAClC,KAAK,MAAM,cAAc,KAAK,YAAY,IAE5C,KAAK,eAAe,sBAAsBA,CAAI;AAAA,IAChD;AAEA,SAAK,eAAe,sBAAsBA,CAAI;AAAA,EAChD;AAAA,EAEQ,sBAA4B;AAClC,IAAI,KAAK,iBAAiB,QAAQ,OAAO,uBAAyB,QAChE,qBAAqB,KAAK,YAAY,GACtC,KAAK,eAAe;AAAA,EAExB;AACF;ACrhBA,IAAIC,KAAY;AAET,SAASC,GAAwBC,GAAyC;AAC/E,QAAMC,IAASD,EAAmC;AAClD,SAAI,CAACC,KAAS,CAACH,OACbA,KAAY,IACZ,QAAQ;AAAA,IACN;AAAA,EAAA,IAKGG;AACT;AAiBO,SAASC,GAAYC,GAAgB5L,GAA+B;AACzE,QAAM6L,IAAQ,IAAI,aAAaD,CAAM,GAC/BE,IAAQF,IAAS;AAEvB,WAAS,IAAI,GAAG,IAAIA,GAAQ,KAAK;AAC/B,UAAMG,IAAI,IAAID;AACd,IAAAD,EAAM,CAAC,IAAI7L,IAAS+L,IAAI,IAAIA;AAAA,EAC9B;AAEA,SAAOF;AACT;AAKO,SAASG,GAAiBJ,GAAgB5L,GAA+B;AAC9E,QAAM6L,IAAQ,IAAI,aAAaD,CAAM,GAC/BE,IAAQF,IAAS;AAEvB,WAAS,IAAI,GAAG,IAAIA,GAAQ,KAAK;AAC/B,UAAMG,IAAI,IAAID,GACRG,IAAQjM,IAAS,IAAI4L,IAAS,IAAI;AACxC,IAAAC,EAAMI,CAAK,IAAI,KAAK,IAAI,IAAIF,IAAI,CAAC,IAAI,KAAK;AAAA,EAC5C;AAEA,SAAOF;AACT;AAKO,SAASK,GAAYN,GAAgB5L,GAA+B;AACzE,QAAM6L,IAAQ,IAAI,aAAaD,CAAM,GAC/BO,IAAQnM,IAAS,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK;AAEhD,WAAS,IAAI,GAAG,IAAI4L,GAAQ;AAC1B,IAAAC,EAAM,CAAC,IAAI,KAAK,IAAK,KAAK,KAAK,IAAKD,IAASO,CAAK,IAAI,IAAI;AAG5D,SAAON;AACT;AAKO,SAASO,GAAiBR,GAAgB5L,GAAiBqM,IAAe,IAAkB;AACjG,QAAMR,IAAQ,IAAI,aAAaD,CAAM;AAErC,WAAS,IAAI,GAAG,IAAIA,GAAQ,KAAK;AAC/B,UAAMK,IAAQjM,IAAS,IAAI4L,IAAS,IAAI,GAClCG,IAAI,IAAIH;AACd,IAAAC,EAAMI,CAAK,IAAI,KAAK,IAAI,IAAII,IAAON,CAAC,IAAI,KAAK,IAAI,IAAIM,CAAI;AAAA,EAC3D;AAEA,SAAOR;AACT;AAKO,SAASS,GAAcC,GAAgBX,GAAgB5L,GAA+B;AAC3F,UAAQuM,GAAA;AAAA,IACN,KAAK;AACH,aAAOZ,GAAYC,GAAQ5L,CAAM;AAAA,IACnC,KAAK;AACH,aAAOgM,GAAiBJ,GAAQ5L,CAAM;AAAA,IACxC,KAAK;AACH,aAAOkM,GAAYN,GAAQ5L,CAAM;AAAA,IACnC,KAAK;AACH,aAAOoM,GAAiBR,GAAQ5L,CAAM;AAAA,IACxC;AACE,aAAO2L,GAAYC,GAAQ5L,CAAM;AAAA,EAAA;AAEvC;AAYO,SAASwM,GACdd,GACA/K,GACAG,GACAyL,IAAiB,UACjBE,IAAqB,GACrBC,IAAmB,GACb;AACN,MAAI,EAAA5L,KAAY;AAEhB,QAAIyL,MAAS;AAEX,MAAAb,EAAM,eAAee,GAAY9L,CAAS,GAC1C+K,EAAM,wBAAwBgB,GAAU/L,IAAYG,CAAQ;AAAA,aACnDyL,MAAS;AAElB,MAAAb,EAAM,eAAe,KAAK,IAAIe,GAAY,IAAK,GAAG9L,CAAS,GAC3D+K,EAAM,6BAA6B,KAAK,IAAIgB,GAAU,IAAK,GAAG/L,IAAYG,CAAQ;AAAA,SAC7E;AAEL,YAAM+K,IAAQS,GAAcC,GAAM,KAAO,EAAI,GAEvCI,IAAc,IAAI,aAAad,EAAM,MAAM,GAC3Ce,IAAQF,IAAWD;AACzB,eAAS1J,IAAI,GAAGA,IAAI8I,EAAM,QAAQ9I;AAChC,QAAA4J,EAAY5J,CAAC,IAAI0J,IAAaZ,EAAM9I,CAAC,IAAI6J;AAE3C,MAAAlB,EAAM,oBAAoBiB,GAAahM,GAAWG,CAAQ;AAAA,IAC5D;AACF;AAYO,SAAS+L,GACdnB,GACA/K,GACAG,GACAyL,IAAiB,UACjBE,IAAqB,GACrBC,IAAmB,GACb;AACN,MAAI,EAAA5L,KAAY;AAEhB,QAAIyL,MAAS;AAEX,MAAAb,EAAM,eAAee,GAAY9L,CAAS,GAC1C+K,EAAM,wBAAwBgB,GAAU/L,IAAYG,CAAQ;AAAA,aACnDyL,MAAS;AAElB,MAAAb,EAAM,eAAe,KAAK,IAAIe,GAAY,IAAK,GAAG9L,CAAS,GAC3D+K,EAAM,6BAA6B,KAAK,IAAIgB,GAAU,IAAK,GAAG/L,IAAYG,CAAQ;AAAA,SAC7E;AAEL,YAAM+K,IAAQS,GAAcC,GAAM,KAAO,EAAK,GAExCI,IAAc,IAAI,aAAad,EAAM,MAAM,GAC3Ce,IAAQH,IAAaC;AAC3B,eAAS3J,IAAI,GAAGA,IAAI8I,EAAM,QAAQ9I;AAChC,QAAA4J,EAAY5J,CAAC,IAAI2J,IAAWb,EAAM9I,CAAC,IAAI6J;AAEzC,MAAAlB,EAAM,oBAAoBiB,GAAahM,GAAWG,CAAQ;AAAA,IAC5D;AACF;AClKO,MAAMgM,GAAU;AAAA,EAgBrB,YAAYrN,GAA2B;AAdvC,SAAQ,oCAAgD,IAAA,GAYxD,KAAQ,uBAAuB,GAG7B,KAAK,QAAQA,EAAQ,OAGrB,KAAK,aAAa,IAAIsN,EAAO,KAAK,SAAStN,EAAQ,MAAM,IAAI,CAAC,GAI9D,KAAK,UAAU,IAAIuN,GAAO,EAAE,KAAKvN,EAAQ,MAAM,WAAW,cAAc,GAAG,GAC3E,KAAK,WAAW,IAAIwN,GAAKxN,EAAQ,MAAM,QAAQ,IAAI,CAAC,GAGpD,KAAK,WAAW,MAAM,KAAK,SAAS,KAAK,QAAQ;AAGjD,UAAMyN,IAAczN,EAAQ,eAAe0N,EAAA;AAC3C,QAAI1N,EAAQ,SAAS;AACnB,YAAM2N,IAAU3N,EAAQ,QAAQ,KAAK,UAAUyN,GAAa,EAAK;AACjE,MAAIE,MACF,KAAK,iBAAiBA;AAAA,IAE1B;AACE,WAAK,SAAS,QAAQF,CAAW;AAInC,UAAMG,IACJ5N,EAAQ,UACPA,EAAQ,SACL;AAAA,MACE;AAAA,QACE,QAAQA,EAAQ;AAAA,QAChB,WAAW;AAAA,QACX,UAAUA,EAAQ,OAAO;AAAA,QACzB,QAAQ;AAAA,QACR,QAAQA,EAAQ,MAAM;AAAA,QACtB,SAASA,EAAQ,MAAM;AAAA,QACvB,MAAM;AAAA,MAAA;AAAA,IACR,IAEF,KAEA6N,IAAYC,EAAA,GACZC,IAAaC,IAAa,YAK1BC,IAAqB,KAAK,WAAW,MAA0B;AAGrE,SAAK,iBAAiBL,EAAU,IAAI,CAACM,MAAa;AAEhD,YAAMC,IAAeJ,EAAW,WAAA;AAChC,MAAAI,EAAa,KAAK,QAAQD,EAAS,MACnCC,EAAa,QAAQF,CAAiB;AAKtC,YAAMG,IAAmB,KAAK,MAAM,YAAYF,EAAS,WACnDG,IAAaR,EAAU,SAAS,CAACS,MAA6B;AAIlE,QAAIF,IAAmB,KAAK,wBAG5B,KAAK,gBAAgBF,GAAUC,GAAcG,CAAgB;AAAA,MAC/D,GAAGF,CAAgB;AAEnB,aAAO,EAAE,UAAAF,GAAU,cAAAC,GAAc,YAAAE,EAAA;AAAA,IACnC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,gBACNH,GACAC,GACAG,GACAC,GACAC,GACM;AAEN,UAAMC,IADaT,IAAa,WACN,mBAAA;AAC1B,IAAAS,EAAO,SAASP,EAAS,QACzBO,EAAO,QAAQN,CAAY;AAE3B,UAAMhN,IAASoN,KAAgBL,EAAS,QAClC7M,IAAWmN,KAAgBN,EAAS;AAE1C,QAAI;AACF,MAAAO,EAAO,MAAMH,GAAkBnN,GAAQE,CAAQ;AAAA,IACjD,SAAS4J,GAAK;AACZ,cAAQ;AAAA,QACN,kDAAkD,KAAK,EAAE,WAC9CqD,CAAgB,YAAYnN,CAAM,cAAcE,CAAQ;AAAA,QACnE4J;AAAA,MAAA,GAEFwD,EAAO,WAAA;AACP;AAAA,IACF;AAEA,SAAK,cAAc,IAAIA,CAAM,GAC7BA,EAAO,UAAU,MAAM;AACrB,WAAK,cAAc,OAAOA,CAAM;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,uBAAuBtN,GAAsB;AAC3C,SAAK,uBAAuBA;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,oBAAoBuN,GAAyBJ,GAAgC;AAC3E,eAAW,EAAE,UAAAJ,GAAU,cAAAC,EAAA,KAAkB,KAAK,gBAAgB;AAC5D,YAAMQ,IAAe,KAAK,MAAM,YAAYT,EAAS,WAC/CU,IAAaD,IAAeT,EAAS;AAI3C,UAAIS,IAAeD,KAAmBE,IAAaF,GAAiB;AAClE,cAAMG,IAAUH,IAAkBC,GAC5BG,IAAiBZ,EAAS,SAASW,GACnCE,IAAoBb,EAAS,WAAWW;AAC9C,aAAK;AAAA,UACHX;AAAA,UACAC;AAAA,UACAG;AAAA,UACAQ;AAAA,UACAC;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAuB;AACrB,SAAK,cAAc,QAAQ,CAACN,MAAW;AACrC,UAAI;AACF,QAAAA,EAAO,KAAA;AAAA,MACT,SAASxD,GAAK;AACZ,gBAAQ,KAAK,iDAAiD,KAAK,EAAE,MAAMA,CAAG;AAAA,MAChF;AAAA,IACF,CAAC,GACD,KAAK,cAAc,MAAA;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cACN+D,GACAlJ,GACAmJ,IAAqB,GACf;AACN,UAAM,EAAE,UAAAf,GAAU,cAAAC,EAAA,IAAiBa,GAC7BE,IAAaf,EAAa;AAGhC,IAAAe,EAAW,sBAAsB,CAAC;AAGlC,UAAMC,IAAWF,IAAaf,EAAS;AAGvC,QAAIA,EAAS,UAAUiB,IAAWjB,EAAS,OAAO,UAAU;AAC1D,YAAMkB,IAAiBlB,EAAS,OAAO;AAEvC,UAAIiB,KAAY;AACd,QAAApC;AAAA,UACEmC;AAAA,UACApJ;AAAA,UACAsJ;AAAA,UACAlB,EAAS,OAAO,QAAQ;AAAA,UACxB;AAAA,UACAA,EAAS;AAAA,QAAA;AAAA,WAEN;AACL,cAAMmB,IAAwBD,IAAiBD,GACzCG,IAAeH,IAAWC,GAC1BpC,IAAakB,EAAS,OAAOoB;AACnC,QAAAvC;AAAA,UACEmC;AAAA,UACApJ;AAAA,UACAuJ;AAAA,UACAnB,EAAS,OAAO,QAAQ;AAAA,UACxBlB;AAAA,UACAkB,EAAS;AAAA,QAAA;AAAA,MAEb;AAAA,IACF;AACE,MAAAgB,EAAW,eAAehB,EAAS,MAAMpI,CAAa;AAIxD,QAAIoI,EAAS,SAAS;AAEpB,YAAMqB,IADerB,EAAS,WAAWA,EAAS,QAAQ,WAChBiB;AAE1C,UAAII,IAAqB,GAAG;AAC1B,cAAMC,IAAuB1J,IAAgByJ;AAC7C,QAAAnC;AAAA,UACE8B;AAAA,UACAM;AAAA,UACAtB,EAAS,QAAQ;AAAA,UACjBA,EAAS,QAAQ,QAAQ;AAAA,UACzBA,EAAS;AAAA,UACT;AAAA,QAAA;AAAA,MAEJ,WAAWqB,IAAqB,CAACrB,EAAS,QAAQ,UAAU;AAC1D,cAAMuB,IAAiB,CAACF,GAClBF,IAAwBnB,EAAS,QAAQ,WAAWuB,GACpDH,IAAeG,IAAiBvB,EAAS,QAAQ,UACjDlB,IAAakB,EAAS,QAAQ,IAAIoB;AACxC,QAAAlC;AAAA,UACE8B;AAAA,UACApJ;AAAA,UACAuJ;AAAA,UACAnB,EAAS,QAAQ,QAAQ;AAAA,UACzBlB;AAAA,UACA;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa0C,GAAchB,GAA+B;AACxD,SAAK,eAAe,QAAQ,CAACM,MAAc;AACzC,YAAML,IAAe,KAAK,MAAM,YAAYK,EAAU,SAAS,WACzDJ,IAAaD,IAAeK,EAAU,SAAS;AAErD,UAAI,EAAAN,KAAmBE;AAEvB,YAAIF,KAAmBC,GAAc;AAEnC,gBAAMM,IAAaP,IAAkBC,IAAeK,EAAU,SAAS;AACvE,eAAK,cAAcA,GAAWU,GAAMT,CAAU;AAAA,QAChD,OAAO;AAEL,gBAAMU,IAAQhB,IAAeD;AAC7B,eAAK,cAAcM,GAAWU,IAAOC,GAAOX,EAAU,SAAS,MAAM;AAAA,QACvE;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAoB;AAClB,SAAK,eAAe,QAAQ,CAAC,EAAE,cAAAb,GAAc,UAAAD,QAAe;AAC1D,YAAMgB,IAAaf,EAAa;AAChC,MAAAe,EAAW,sBAAsB,CAAC,GAClCA,EAAW,eAAehB,EAAS,MAAM,CAAC;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA,EAEQ,SAAS9N,GAAsB;AACrC,WAAO,KAAK,KAAK,MAAMA,CAAI;AAAA,EAC7B;AAAA,EAEA,UAAUA,GAAoB;AAC5B,SAAK,MAAM,OAAOA,GAClB,KAAK,WAAW,OAAO,QAAQ,KAAK,SAASA,CAAI;AAAA,EACnD;AAAA,EAEA,OAAOuB,GAAmB;AACxB,SAAK,MAAM,YAAYA,GACvB,KAAK,QAAQ,IAAI,QAAQA;AAAA,EAC3B;AAAA,EAEA,QAAQH,GAAsB;AAC5B,SAAK,MAAM,QAAQA;AACnB,UAAMoO,IAAQpO,IAAQ,IAAI;AAO1B,IADmBuK,GAAwB,KAAK,SAAS,IAAI,GACjD,eAAe6D,GAAO,CAAC,GACnC,KAAK,SAAS,KAAK,QAAQA;AAAA,EAC7B;AAAA,EAEA,QAAQnO,GAAuB;AAC7B,SAAK,MAAM,SAASA;AAAA,EACtB;AAAA,EAEA,UAAgB;AACd,UAAMoM,IAAYC,EAAA;AAElB,QAAI,KAAK;AACP,UAAI;AACF,aAAK,eAAA;AAAA,MACP,SAAS7C,GAAK;AACZ,gBAAQ,KAAK,qCAAqC,KAAK,EAAE,sBAAsBA,CAAG;AAAA,MACpF;AAGF,SAAK,eAAA,GAGL,KAAK,eAAe,QAAQ,CAAC+D,GAAWxC,MAAU;AAChD,UAAI;AACF,QAAAqB,EAAU,MAAMmB,EAAU,UAAU;AAAA,MACtC,SAAS/D,GAAK;AACZ,gBAAQ;AAAA,UACN,yCAAyCuB,CAAK,cAAc,KAAK,EAAE;AAAA,UACnEvB;AAAA,QAAA;AAAA,MAEJ;AACA,UAAI;AACF,QAAA+D,EAAU,aAAa,WAAA;AAAA,MACzB,SAAS/D,GAAK;AACZ,gBAAQ;AAAA,UACN,8CAA8CuB,CAAK,cAAc,KAAK,EAAE;AAAA,UACxEvB;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF,CAAC;AAED,QAAI;AACF,WAAK,WAAW,QAAA;AAAA,IAClB,SAASA,GAAK;AACZ,cAAQ,KAAK,sDAAsD,KAAK,EAAE,MAAMA,CAAG;AAAA,IACrF;AACA,QAAI;AACF,WAAK,QAAQ,QAAA;AAAA,IACf,SAASA,GAAK;AACZ,cAAQ,KAAK,mDAAmD,KAAK,EAAE,MAAMA,CAAG;AAAA,IAClF;AACA,QAAI;AACF,WAAK,SAAS,QAAA;AAAA,IAChB,SAASA,GAAK;AACZ,cAAQ,KAAK,oDAAoD,KAAK,EAAE,MAAMA,CAAG;AAAA,IACnF;AAAA,EACF;AAAA,EAEA,IAAI,KAAa;AACf,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,WAAmB;AACrB,QAAI,KAAK,eAAe,WAAW,EAAG,QAAO;AAC7C,UAAM4E,IAAW,KAAK,eAAe,KAAK,eAAe,SAAS,CAAC;AACnE,WAAOA,EAAS,SAAS,YAAYA,EAAS,SAAS;AAAA,EACzD;AAAA,EAEA,IAAI,SAAsB;AACxB,WAAO,KAAK,eAAe,CAAC,GAAG,SAAS;AAAA,EAC1C;AAAA,EAEA,IAAI,QAAiB;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AC5XA,SAASC,GAAgBC,GAAgC;AAEvD,SAAIA,MAAa,MAAMA,MAAa,KAAW,SAE3CA,KAAY,MAAMA,KAAY,KAAW,UAG3CA,MAAa,MACbA,MAAa,MACbA,MAAa,MACbA,MAAa,MACbA,MAAa,MACbA,MAAa,KAEN,QAEF;AACT;AAcO,MAAMC,GAAuC;AAAA,EAelD,YAAYhQ,GAA+B;AACzC,SAAK,QAAQA,EAAQ,OAGrB,KAAK,aAAa,IAAIsN,EAAO,KAAK,SAAStN,EAAQ,MAAM,IAAI,CAAC,GAC9D,KAAK,UAAU,IAAIuN,GAAOvN,EAAQ,MAAM,SAAS,GACjD,KAAK,WAAW,IAAIwN,GAAKxN,EAAQ,MAAM,QAAQ,IAAI,CAAC,GACpD,KAAK,WAAW,MAAM,KAAK,SAAS,KAAK,QAAQ,GAGjD,KAAK,QAAQ,IAAIiQ,EAAUC,IAAOlQ,EAAQ,YAAY,GACtD,KAAK,MAAM,QAAQ,KAAK,UAAU,GAGlC,KAAK,YAAY,IAAIiQ,EAAUE,GAAe;AAAA,MAC5C,OAAOA;AAAA,MACP,SAAS;AAAA,QACP,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,UAAU,EAAE,QAAQ,MAAO,OAAO,KAAK,SAAS,GAAG,SAAS,IAAA;AAAA,MAAI;AAAA,IAClE,CACQ,GACV,KAAK,aAAa,IAAIC,GAAW;AAAA,MAC/B,OAAO,EAAE,MAAM,QAAA;AAAA,MACf,UAAU,EAAE,QAAQ,MAAO,OAAO,MAAM,SAAS,GAAG,SAAS,KAAA;AAAA,IAAK,CACnE,GACD,KAAK,cAAc,IAAIH,EAAUI,IAAY;AAAA,MAC3C,OAAOA;AAAA,MACP,SAAS;AAAA,QACP,UAAU,EAAE,QAAQ,MAAO,OAAO,KAAK,SAAS,IAAA;AAAA,QAChD,aAAa;AAAA,QACb,iBAAiB;AAAA,QACjB,WAAW;AAAA,QACX,SAAS;AAAA,MAAA;AAAA,IACX,CACQ,GACV,KAAK,WAAW,IAAIJ,EAAUE,GAAe;AAAA,MAC3C,OAAOA;AAAA,MACP,SAAS;AAAA,QACP,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,UAAU,EAAE,QAAQ,MAAO,OAAO,KAAK,SAAS,GAAG,SAAS,IAAA;AAAA,MAAI;AAAA,IAClE,CACQ,GAEV,KAAK,UAAU,QAAQ,KAAK,UAAU,GACtC,KAAK,WAAW,QAAQ,KAAK,UAAU,GACvC,KAAK,YAAY,QAAQ,KAAK,UAAU,GACxC,KAAK,SAAS,QAAQ,KAAK,UAAU;AAGrC,UAAM1C,IAAczN,EAAQ,eAAe0N,EAAA;AAC3C,QAAI1N,EAAQ,SAAS;AACnB,YAAM2N,IAAU3N,EAAQ,QAAQ,KAAK,UAAUyN,GAAa,EAAK;AACjE,MAAIE,MACF,KAAK,iBAAiBA;AAAA,IAE1B;AACE,WAAK,SAAS,QAAQF,CAAW;AAInC,SAAK,iBAAiBzN,EAAQ,MAAM,IAAI,CAACkO,MAAa;AAEpD,YAAMoC,IAAepC,EAAS,MAAM,OAAO,CAACqC,MAAS;AACnD,cAAMC,IAAUD,EAAK,OAAOA,EAAK;AAEjC,eAAOA,EAAK,OAAOrC,EAAS,SAASA,EAAS,YAAYsC,IAAUtC,EAAS;AAAA,MAC/E,CAAC,GAGKS,IAAe,KAAK,MAAM,YAAYT,EAAS,WAE/CuC,IAAaH,EAAa,IAAI,CAACC,MAAS;AAE5C,cAAMG,IAAeH,EAAK,OAAOrC,EAAS,QAEpCyC,IAAe,KAAK,IAAI,GAAGD,CAAY,GACvCE,IAAkB,KAAK;AAAA,UAC3BL,EAAK,WAAW,KAAK,IAAI,GAAGrC,EAAS,SAASqC,EAAK,IAAI;AAAA,UACvDrC,EAAS,WAAWyC;AAAA,QAAA;AAGtB,eAAO;AAAA,UACL,MAAMhC,IAAegC;AAAA,UACrB,MAAMJ,EAAK;AAAA,UACX,MAAMA,EAAK;AAAA,UACX,UAAU,KAAK,IAAI,GAAGK,CAAe;AAAA,UACrC,UAAUL,EAAK;AAAA,UACf,SAASA,EAAK;AAAA,QAAA;AAAA,MAElB,CAAC,GAEKM,IAAO,IAAIC,GAAK,CAACpH,GAAM8B,MAAU;AACrC,QAAIA,EAAM,WAAW,KACnB,KAAK;AAAA,UACHA,EAAM;AAAA,UACNA,EAAM;AAAA,UACNA,EAAM;AAAA,UACN9B;AAAA,UACA8B,EAAM;AAAA,UACNA,EAAM;AAAA,QAAA;AAAA,MAGZ,GAAGiF,CAAU;AAGb,aAAAI,EAAK,MAAM,CAAC,GAEL,EAAE,UAAA3C,GAAU,MAAA2C,EAAA;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YACNd,GACAgB,GACA1P,GACAqI,GACAsH,GACAC,GACM;AACN,QAAIA,MAAY;AAEd,cADiBnB,GAAgBC,CAAQ,GACjC;AAAA,QACN,KAAK;AACH,eAAK,UAAU,qBAAqB,MAAM1O,GAAUqI,GAAMsH,CAAQ;AAClE;AAAA,QACF,KAAK;AAEH,cAAI;AACF,iBAAK,WAAW,qBAAqB3P,GAAUqI,GAAMsH,CAAQ;AAAA,UAC/D,SAAS/F,GAAK;AACZ,oBAAQ;AAAA,cACN;AAAA,cACAA;AAAA,YAAA;AAAA,UAEJ;AACA;AAAA,QACF,KAAK,OAAO;AACV,gBAAMiG,IAAqC;AAAA,YACzC,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,IAAI;AAAA,UAAA;AAEN,eAAK,SAAS;AAAA,YACZA,EAAWnB,CAAQ,KAAK;AAAA,YACxB1O;AAAA,YACAqI;AAAA,YACAsH;AAAA,UAAA;AAEF;AAAA,QACF;AAAA,QACA,KAAK;AAGH,eAAK,YAAY,qBAAqB,MAAM3P,GAAUqI,GAAMsH,CAAQ;AACpE;AAAA,MAAA;AAAA;AAGJ,WAAK,MAAM,qBAAqBD,GAAU1P,GAAUqI,GAAMsH,CAAQ;AAAA,EAEtE;AAAA,EAEQ,SAAS5Q,GAAsB;AACrC,WAAO,KAAK,KAAK,MAAMA,CAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,uBAAuB+Q,GAAuB;AAAA,EAE9C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,oBAAoBzC,GAAyBJ,GAAgC;AAC3E,eAAW,EAAE,UAAAJ,OAAc,KAAK,gBAAgB;AAC9C,YAAMS,IAAe,KAAK,MAAM,YAAYT,EAAS,WAC/CU,IAAaD,IAAeT,EAAS;AAE3C,UAAIS,IAAeD,KAAmBE,IAAaF;AAEjD,mBAAW6B,KAAQrC,EAAS,OAAO;AACjC,gBAAMwC,IAAeH,EAAK,OAAOrC,EAAS,QACpCkD,IAAezC,IAAe,KAAK,IAAI,GAAG+B,CAAY,GACtDW,IAAaD,IAAeb,EAAK;AAEvC,cAAIa,IAAe1C,KAAmB2C,IAAa3C,GAAiB;AAClE,kBAAMK,IAAoBsC,IAAa3C;AACvC,gBAAI;AACF,mBAAK;AAAA,gBACH6B,EAAK;AAAA,gBACLA,EAAK;AAAA,gBACLxB;AAAA,gBACAT;AAAA,gBACAiC,EAAK;AAAA,gBACLA,EAAK;AAAA,cAAA;AAAA,YAET,SAAStF,GAAK;AACZ,sBAAQ;AAAA,gBACN,qDAAqDsF,EAAK,IAAI,eAAe,KAAK,EAAE;AAAA,gBACpFtF;AAAA,cAAA;AAAA,YAEJ;AAAA,UACF;AAAA,QACF;AAAA,IAEJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAuB;AACrB,UAAMqG,IAAMtD,IAAa,WAAW;AACpC,QAAI;AACF,WAAK,MAAM,WAAWsD,CAAG,GACzB,KAAK,UAAU,WAAWA,CAAG,GAC7B,KAAK,YAAY,WAAWA,CAAG,GAC/B,KAAK,SAAS,WAAWA,CAAG;AAAA,IAE9B,SAASrG,GAAK;AACZ,cAAQ,KAAK,iDAAiD,KAAK,EAAE,MAAMA,CAAG;AAAA,IAChF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAasG,GAAeJ,GAAuB;AAAA,EAEnD;AAAA;AAAA;AAAA;AAAA,EAKA,cAAoB;AAAA,EAEpB;AAAA,EAEA,UAAU/Q,GAAoB;AAC5B,SAAK,MAAM,OAAOA,GAClB,KAAK,WAAW,OAAO,QAAQ,KAAK,SAASA,CAAI;AAAA,EACnD;AAAA,EAEA,OAAOuB,GAAmB;AACxB,SAAK,MAAM,YAAYA,GACvB,KAAK,QAAQ,IAAI,QAAQA;AAAA,EAC3B;AAAA,EAEA,QAAQH,GAAsB;AAC5B,SAAK,MAAM,QAAQA;AACnB,UAAMoO,IAAQpO,IAAQ,IAAI;AAE1B,IADmBuK,GAAwB,KAAK,SAAS,IAAI,GACjD,eAAe6D,GAAO,CAAC,GACnC,KAAK,SAAS,KAAK,QAAQA;AAAA,EAC7B;AAAA,EAEA,QAAQnO,GAAuB;AAC7B,SAAK,MAAM,SAASA;AAAA,EACtB;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK;AACP,UAAI;AACF,aAAK,eAAA;AAAA,MACP,SAASwJ,GAAK;AACZ,gBAAQ;AAAA,UACN,0CAA0C,KAAK,EAAE;AAAA,UACjDA;AAAA,QAAA;AAAA,MAEJ;AAGF,SAAK,eAAA,GAGL,KAAK,eAAe,QAAQ,CAAC,EAAE,MAAA4F,EAAA,GAAQrE,MAAU;AAC/C,UAAI;AACF,QAAAqE,EAAK,QAAA;AAAA,MACP,SAAS5F,GAAK;AACZ,gBAAQ;AAAA,UACN,sCAAsCuB,CAAK,mBAAmB,KAAK,EAAE;AAAA,UACrEvB;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF,CAAC;AAGD,UAAMuG,IAAkB;AAAA,MACtB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IAAA;AAEP,eAAWpG,KAAKoG;AACd,UAAI;AACF,QAAApG,GAAG,QAAA;AAAA,MACL,SAASH,GAAK;AACZ,gBAAQ,KAAK,sDAAsD,KAAK,EAAE,MAAMA,CAAG;AAAA,MACrF;AAEF,QAAI;AACF,WAAK,WAAW,QAAA;AAAA,IAClB,SAASA,GAAK;AACZ,cAAQ;AAAA,QACN,2DAA2D,KAAK,EAAE;AAAA,QAClEA;AAAA,MAAA;AAAA,IAEJ;AACA,QAAI;AACF,WAAK,QAAQ,QAAA;AAAA,IACf,SAASA,GAAK;AACZ,cAAQ,KAAK,wDAAwD,KAAK,EAAE,MAAMA,CAAG;AAAA,IACvF;AACA,QAAI;AACF,WAAK,SAAS,QAAA;AAAA,IAChB,SAASA,GAAK;AACZ,cAAQ,KAAK,yDAAyD,KAAK,EAAE,MAAMA,CAAG;AAAA,IACxF;AAAA,EACF;AAAA,EAEA,IAAI,KAAa;AACf,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,WAAmB;AACrB,QAAI,KAAK,eAAe,WAAW,EAAG,QAAO;AAC7C,UAAM4E,IAAW,KAAK,eAAe,KAAK,eAAe,SAAS,CAAC;AACnE,WAAOA,EAAS,SAAS,YAAYA,EAAS,SAAS;AAAA,EACzD;AAAA,EAEA,IAAI,QAAiB;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;ACvaO,MAAM4B,IAAN,MAAMA,EAA4C;AAAA,EAcvD,YAAYzR,GAAoC;AAVhD,SAAQ,oCAAgD,IAAA,GAWtD,KAAK,QAAQA,EAAQ,OACrB,KAAK,iBAAiBA,EAAQ,gBAC9B,KAAK,gBAAgBA,EAAQ,iBAAiB,GAE9C,KAAK,aAAaA,EAAQ,eAAe,MAAM,GAG/C,KAAK,aAAa,IAAIsN,EAAO,KAAK,SAAStN,EAAQ,MAAM,IAAI,CAAC,GAC9D,KAAK,UAAU,IAAIuN,GAAOvN,EAAQ,MAAM,SAAS,GACjD,KAAK,WAAW,IAAIwN,GAAKxN,EAAQ,MAAM,QAAQ,IAAI,CAAC,GACpD,KAAK,WAAW,MAAM,KAAK,SAAS,KAAK,QAAQ;AAGjD,UAAMyN,IAAczN,EAAQ,eAAe0N,EAAA;AAC3C,QAAI1N,EAAQ,SAAS;AACnB,YAAM2N,IAAU3N,EAAQ,QAAQ,KAAK,UAAUyN,GAAa,EAAK;AACjE,MAAIE,MACF,KAAK,iBAAiBA;AAAA,IAE1B;AACE,WAAK,SAAS,QAAQF,CAAW;AAInC,SAAK,iBAAiBzN,EAAQ,MAAM,IAAI,CAACkO,MAAa;AAEpD,YAAMoC,IAAepC,EAAS,MAAM,OAAO,CAACqC,MAAS;AACnD,cAAMC,IAAUD,EAAK,OAAOA,EAAK;AACjC,eAAOA,EAAK,OAAOrC,EAAS,SAASA,EAAS,YAAYsC,IAAUtC,EAAS;AAAA,MAC/E,CAAC,GAEKS,IAAe,KAAK,MAAM,YAAYT,EAAS,WAE/CuC,IAAaH,EAAa,IAAI,CAACC,MAAS;AAC5C,cAAMG,IAAeH,EAAK,OAAOrC,EAAS,QACpCyC,IAAe,KAAK,IAAI,GAAGD,CAAY,GACvCE,IAAkB,KAAK;AAAA,UAC3BL,EAAK,WAAW,KAAK,IAAI,GAAGrC,EAAS,SAASqC,EAAK,IAAI;AAAA,UACvDrC,EAAS,WAAWyC;AAAA,QAAA;AAGtB,eAAO;AAAA,UACL,MAAMhC,IAAegC;AAAA,UACrB,MAAMJ,EAAK;AAAA,UACX,MAAMA,EAAK;AAAA,UACX,UAAU,KAAK,IAAI,GAAGK,CAAe;AAAA,UACrC,UAAUL,EAAK;AAAA,UACf,SAASA,EAAK;AAAA,QAAA;AAAA,MAElB,CAAC,GAEKM,IAAO,IAAIC,GAAK,CAACpH,GAAM8B,MAAU;AACrC,QAAIA,EAAM,WAAW,KACnB,KAAK,YAAYA,EAAM,MAAMA,EAAM,UAAU9B,GAAM8B,EAAM,UAAUA,EAAM,OAAO;AAAA,MAEpF,GAAGiF,CAAU;AAEb,aAAAI,EAAK,MAAM,CAAC,GAEL,EAAE,UAAA3C,GAAU,MAAA2C,EAAA;AAAA,IACrB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,YACNd,GACA1O,GACAqI,GACAsH,GACAC,GACM;AACN,UAAMS,IAAOT,MAAY,IAAI,MAAM,KAAK,YAClCU,IAASV,MAAY,IAAI,IAAI,KAAK,eAElCW,IAAW,KAAK,eAAe,eAAe7B,GAAU2B,GAAMC,CAAM;AAC1E,QAAI,CAACC,GAAU;AACb,MAAKH,EAAmB,yBACtB,QAAQ;AAAA,QACN,0DAA0D1B,CAAQ,UAAU2B,CAAI,YAAYC,CAAM;AAAA,MAAA,GAGpGF,EAAmB,uBAAuB;AAE5C;AAAA,IACF;AAEA,UAAM1D,IAAaC,IAAa,YAG1BS,IAASV,EAAW,mBAAA;AAC1B,IAAAU,EAAO,SAASmD,EAAS,QACzBnD,EAAO,aAAa,QAAQmD,EAAS,eAGjCA,EAAS,aAAa,KAAKA,EAAS,aAAa,OACnDnD,EAAO,OAAO,IACdA,EAAO,YAAYmD,EAAS,WAC5BnD,EAAO,UAAUmD,EAAS;AAM5B,UAAMC,IAAiBD,EAAS,OAAO,WAAWA,EAAS,cACrDE,IACJF,EAAS,aAAa,IAAI,KAAK,IAAIvQ,GAAUwQ,CAAc,IAAIxQ,GAG3D0Q,IAAWf,IAAWA,GACtBgB,IAAWjE,EAAW,WAAA,GACtB,EAAE,cAAAkE,GAAc,YAAAC,GAAY,aAAAC,GAAa,eAAAC,GAAe,eAAAC,MAAkBT,GAC1EU,IAAcP,IAAWK;AAG/B,IAAAJ,EAAS,KAAK,eAAe,GAAGtI,CAAI,GACpCsI,EAAS,KAAK,wBAAwBD,GAAUrI,IAAOuI,CAAY,GAE/DC,IAAa,QACfF,EAAS,KAAK,eAAeD,GAAUrI,IAAOuI,IAAeC,CAAU;AAGzE,UAAMK,IAAa7I,IAAOuI,IAAeC;AACzC,IAAAF,EAAS,KAAK,wBAAwBM,GAAaC,IAAaJ,CAAW,GAI3EH,EAAS,KAAK,eAAeM,GAAa5I,IAAOoI,CAAiB,GAClEE,EAAS,KAAK,wBAAwB,GAAGtI,IAAOoI,IAAoBO,CAAa,GAGjF5D,EAAO,QAAQuD,CAAQ,GACvBA,EAAS,QAAS,KAAK,WAAW,MAA0B,KAAK,GAGjE,KAAK,cAAc,IAAIvD,CAAM,GAC7BA,EAAO,UAAU,MAAM;AACrB,WAAK,cAAc,OAAOA,CAAM;AAChC,UAAI;AACF,QAAAuD,EAAS,WAAA;AAAA,MACX,SAAS/G,GAAK;AACZ,gBAAQ,KAAK,gDAAgDA,CAAG;AAAA,MAClE;AAAA,IACF,GAEAwD,EAAO,MAAM/E,CAAI,GACjB+E,EAAO,KAAK/E,IAAOoI,IAAoBO,CAAa;AAAA,EACtD;AAAA,EAEQ,SAASjS,GAAsB;AACrC,WAAO,KAAK,KAAK,MAAMA,CAAI;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuB+Q,GAAuB;AAAA,EAE9C;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoBzC,GAAyBJ,GAAgC;AAC3E,eAAW,EAAE,UAAAJ,OAAc,KAAK,gBAAgB;AAC9C,YAAMS,IAAe,KAAK,MAAM,YAAYT,EAAS,WAC/CU,IAAaD,IAAeT,EAAS;AAE3C,UAAIS,IAAeD,KAAmBE,IAAaF;AACjD,mBAAW6B,KAAQrC,EAAS,OAAO;AACjC,gBAAMwC,IAAeH,EAAK,OAAOrC,EAAS,QACpCkD,IAAezC,IAAe,KAAK,IAAI,GAAG+B,CAAY,GACtDW,IAAaD,IAAeb,EAAK;AAEvC,cAAIa,IAAe1C,KAAmB2C,IAAa3C,GAAiB;AAClE,kBAAMK,IAAoBsC,IAAa3C;AACvC,gBAAI;AACF,mBAAK;AAAA,gBACH6B,EAAK;AAAA,gBACLxB;AAAA,gBACAT;AAAA,gBACAiC,EAAK;AAAA,gBACLA,EAAK;AAAA,cAAA;AAAA,YAET,SAAStF,GAAK;AACZ,sBAAQ;AAAA,gBACN,mEAAmE,KAAK,EAAE;AAAA,gBAC1EA;AAAA,cAAA;AAAA,YAEJ;AAAA,UACF;AAAA,QACF;AAAA,IAEJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAuB;AACrB,eAAWwD,KAAU,KAAK;AACxB,UAAI;AACF,QAAAA,EAAO,KAAA;AAAA,MACT,SAASxD,GAAK;AACZ,gBAAQ,KAAK,uDAAuDA,CAAG;AAAA,MACzE;AAEF,SAAK,cAAc,MAAA;AAAA,EACrB;AAAA;AAAA,EAGA,aAAasG,GAAeJ,GAAuB;AAAA,EAAC;AAAA;AAAA,EAGpD,cAAoB;AAAA,EAAC;AAAA,EAErB,UAAU/Q,GAAoB;AAC5B,SAAK,MAAM,OAAOA,GAClB,KAAK,WAAW,OAAO,QAAQ,KAAK,SAASA,CAAI;AAAA,EACnD;AAAA,EAEA,OAAOuB,GAAmB;AACxB,SAAK,MAAM,YAAYA,GACvB,KAAK,QAAQ,IAAI,QAAQA;AAAA,EAC3B;AAAA,EAEA,QAAQH,GAAsB;AAC5B,SAAK,MAAM,QAAQA;AACnB,UAAMoO,IAAQpO,IAAQ,IAAI;AAE1B,IADmBuK,GAAwB,KAAK,SAAS,IAAI,GACjD,eAAe6D,GAAO,CAAC,GACnC,KAAK,SAAS,KAAK,QAAQA;AAAA,EAC7B;AAAA,EAEA,QAAQnO,GAAuB;AAC7B,SAAK,MAAM,SAASA;AAAA,EACtB;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK;AACP,UAAI;AACF,aAAK,eAAA;AAAA,MACP,SAASwJ,GAAK;AACZ,gBAAQ;AAAA,UACN,+CAA+C,KAAK,EAAE;AAAA,UACtDA;AAAA,QAAA;AAAA,MAEJ;AAGF,SAAK,eAAA,GAGL,KAAK,eAAe,QAAQ,CAAC,EAAE,MAAA4F,EAAA,GAAQrE,MAAU;AAC/C,UAAI;AACF,QAAAqE,EAAK,QAAA;AAAA,MACP,SAAS5F,GAAK;AACZ,gBAAQ;AAAA,UACN,sCAAsCuB,CAAK,wBAAwB,KAAK,EAAE;AAAA,UAC1EvB;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF,CAAC;AAED,QAAI;AACF,WAAK,WAAW,QAAA;AAAA,IAClB,SAASA,GAAK;AACZ,cAAQ;AAAA,QACN,gEAAgE,KAAK,EAAE;AAAA,QACvEA;AAAA,MAAA;AAAA,IAEJ;AACA,QAAI;AACF,WAAK,QAAQ,QAAA;AAAA,IACf,SAASA,GAAK;AACZ,cAAQ;AAAA,QACN,6DAA6D,KAAK,EAAE;AAAA,QACpEA;AAAA,MAAA;AAAA,IAEJ;AACA,QAAI;AACF,WAAK,SAAS,QAAA;AAAA,IAChB,SAASA,GAAK;AACZ,cAAQ;AAAA,QACN,8DAA8D,KAAK,EAAE;AAAA,QACrEA;AAAA,MAAA;AAAA,IAEJ;AAAA,EACF;AAAA,EAEA,IAAI,KAAa;AACf,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,WAAmB;AACrB,QAAI,KAAK,eAAe,WAAW,EAAG,QAAO;AAC7C,UAAM4E,IAAW,KAAK,eAAe,KAAK,eAAe,SAAS,CAAC;AACnE,WAAOA,EAAS,SAAS,YAAYA,EAAS,SAAS;AAAA,EACzD;AAAA,EAEA,IAAI,QAAiB;AACnB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAnUE4B,EAAe,uBAAuB;AAFjC,IAAMe,KAANf;ACVA,MAAMgB,GAAY;AAAA,EAcvB,YAAYzS,IAA8B,IAAI;AAI5C,QAjBF,KAAQ,6BAAyC,IAAA,GAEjD,KAAQ,gBAAgB,IACxB,KAAQ,mCAAgC,IAAA,GACxC,KAAQ,sCAA4C,IAAA,GAGpD,KAAQ,qBAAoC,MAC5C,KAAQ,eAAoC,MAC5C,KAAQ,eAAe,IACvB,KAAQ,aAAa,GACrB,KAAQ,WAAW,GAGjB,KAAK,eAAe,IAAIsN,EAAO,KAAK,SAAStN,EAAQ,cAAc,CAAC,CAAC,GAGjEA,EAAQ,SAAS;AACnB,YAAM2N,IAAU3N,EAAQ,QAAQ,KAAK,cAAc0N,EAAA,GAAkB,EAAK;AAC1E,MAAIC,MACF,KAAK,iBAAiBA;AAAA,IAE1B;AACE,WAAK,aAAa,cAAA;AAGpB,IAAI3N,EAAQ,UACVA,EAAQ,OAAO,QAAQ,CAACkC,MAAU;AAChC,WAAK,OAAO,IAAIA,EAAM,IAAIA,CAAK,GAC/B,KAAK,gBAAgB,IAAIA,EAAM,IAAIA,EAAM,KAAK;AAAA,IAChD,CAAC;AAAA,EAEL;AAAA,EAEQ,SAAS9B,GAAsB;AACrC,WAAO,KAAK,KAAK,MAAMA,CAAI;AAAA,EAC7B;AAAA,EAEQ,uBAA6B;AACnC,QAAI,KAAK,uBAAuB,MAAM;AACpC,UAAI;AACF,QAAA0N,IAAe,MAAM,KAAK,kBAAkB;AAAA,MAC9C,SAAS7C,GAAK;AACZ,gBAAQ,KAAK,4DAA4DA,CAAG;AAAA,MAC9E;AACA,WAAK,qBAAqB;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,IAAI,KAAK,kBAET,MAAMC,GAAA,GACN,KAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,SAASwH,GAA2C;AAElD,UAAMC,IAAyB;AAAA,MAC7B,GAAGD;AAAA,MACH,aAAa,KAAK;AAAA,IAAA,GAEdE,IAAY,IAAIvF,GAAUsF,CAAsB;AACtD,gBAAK,OAAO,IAAIC,EAAU,IAAIA,CAAS,GACvC,KAAK,gBAAgB,IAAIA,EAAU,IAAIF,EAAa,MAAM,SAAS,EAAK,GACpEA,EAAa,MAAM,UACrB,KAAK,aAAa,IAAIE,EAAU,EAAE,GAE7BA;AAAA,EACT;AAAA,EAEA,aAAaF,GAAmD;AAC9D,UAAMC,IAAyB;AAAA,MAC7B,GAAGD;AAAA,MACH,aAAa,KAAK;AAAA,IAAA,GAEdG,IAAY,IAAI7C,GAAc2C,CAAsB;AAC1D,gBAAK,OAAO,IAAIE,EAAU,IAAIA,CAAS,GACvC,KAAK,gBAAgB,IAAIA,EAAU,IAAIH,EAAa,MAAM,SAAS,EAAK,GACpEA,EAAa,MAAM,UACrB,KAAK,aAAa,IAAIG,EAAU,EAAE,GAE7BA;AAAA,EACT;AAAA,EAEA,kBAAkBH,GAA6D;AAC7E,UAAMC,IAAyB;AAAA,MAC7B,GAAGD;AAAA,MACH,aAAa,KAAK;AAAA,IAAA,GAEdI,IAAU,IAAIN,GAAmBG,CAAsB;AAC7D,gBAAK,OAAO,IAAIG,EAAQ,IAAIA,CAAO,GACnC,KAAK,gBAAgB,IAAIA,EAAQ,IAAIJ,EAAa,MAAM,SAAS,EAAK,GAClEA,EAAa,MAAM,UACrB,KAAK,aAAa,IAAII,EAAQ,EAAE,GAE3BA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,wBAA8B;AAC5B,SAAK,iBAAA;AAAA,EACP;AAAA,EAEA,YAAY5I,GAAuB;AACjC,UAAMhI,IAAQ,KAAK,OAAO,IAAIgI,CAAO;AACrC,IAAIhI,MACFA,EAAM,QAAA,GACN,KAAK,OAAO,OAAOgI,CAAO,GAC1B,KAAK,gBAAgB,OAAOA,CAAO,GACnC,KAAK,aAAa,OAAOA,CAAO;AAAA,EAEpC;AAAA,EAEA,SAASA,GAA4C;AACnD,WAAO,KAAK,OAAO,IAAIA,CAAO;AAAA,EAChC;AAAA,EAEA,KAAKwF,GAAevO,GAAiBE,GAAyB;AAC5D,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,+DAA+D;AAGjF,UAAMH,IAAYwO,KAAQ4B,GAAA,GACpBzD,IAAYC,EAAA;AAElB,SAAK,qBAAA;AAEL,UAAMY,IAAkBvN,KAAU;AAClC,SAAK,OAAO,QAAQ,CAACe,MAAU;AAC7B,MAAAA,EAAM,YAAA,GACNA,EAAM,aAAahB,GAAWwN,CAAe;AAAA,IAC/C,CAAC,GAGGrN,MAAa,WACf,KAAK,qBAAqBwM,EAAU,aAAa,MAAM;AACrD,WAAK,qBAAqB;AAC1B,UAAI;AACF,aAAK,6BAAA;AAAA,MACP,SAAS5C,GAAK;AACZ,gBAAQ,KAAK,wDAAwDA,CAAG;AAAA,MAC1E;AAAA,IACF,GAAGyD,IAAkBrN,CAAQ;AAI/B,QAAI;AAGF,MAAIwM,EAAU,UAAU,aACtBA,EAAU,KAAA,GAEZ,KAAK,OAAO,QAAQ,CAAC3L,MAAUA,EAAM,gBAAgB,GAIrD2L,EAAU,YAAY,KAAK,YAC3BA,EAAU,UAAU,KAAK,UACzBA,EAAU,OAAO,KAAK,cAMtB,KAAK,OAAO,QAAQ,CAAC3L,MAAUA,EAAM,uBAAuBwM,CAAe,CAAC,GAExEvN,MAAW,SACb0M,EAAU,MAAM3M,GAAWC,CAAM,IAEjC0M,EAAU,MAAM3M,CAAS,GAgB1B2M,EAAkB,OAAO,cAAc3M,GAKxC,KAAK,OAAO,QAAQ,CAACgB,MAAU;AAC7B,QAAAA,EAAM,oBAAoBwM,GAAiBxN,CAAS;AAAA,MACtD,CAAC;AAAA,IACH,SAAS+J,GAAK;AAEZ,iBAAK,qBAAA,GACL,KAAK,OAAO,QAAQ,CAAC/I,MAAUA,EAAM,aAAa,GAClD,QAAQ;AAAA,QACN;AAAA,QACA+I;AAAA,MAAA,GAEIA;AAAA,IACR;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,UAAM4C,IAAYC,EAAA;AAClB,QAAI;AACF,MAAAD,EAAU,MAAA;AAAA,IACZ,SAAS5C,GAAK;AACZ,cAAQ,KAAK,2CAA2CA,CAAG;AAAA,IAC7D;AAGA,SAAK,OAAO,QAAQ,CAAC/I,MAAUA,EAAM,gBAAgB,GACrD,KAAK,OAAO,QAAQ,CAACA,MAAUA,EAAM,aAAa,GAClD,KAAK,qBAAA;AAAA,EACP;AAAA,EAEA,OAAa;AACX,UAAM2L,IAAYC,EAAA;AAClB,QAAI;AACF,MAAAD,EAAU,KAAA;AAAA,IACZ,SAAS5C,GAAK;AACZ,cAAQ,KAAK,0CAA0CA,CAAG;AAAA,IAC5D;AAKA,QAAI,KAAK,cAAc;AACrB,UAAI;AACF,QAAA4C,EAAU,IAAI,QAAQ,KAAK,YAAY;AAAA,MACzC,SAAS5C,GAAK;AACZ,gBAAQ,KAAK,8CAA8CA,CAAG;AAAA,MAChE;AACA,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,OAAO,QAAQ,CAAC/I,MAAU;AAC7B,UAAI;AACF,QAAAA,EAAM,eAAA;AAAA,MACR,SAAS+I,GAAK;AACZ,gBAAQ,KAAK,mDAAmD/I,EAAM,EAAE,MAAM+I,CAAG;AAAA,MACnF;AAAA,IACF,CAAC,GACD,KAAK,OAAO,QAAQ,CAAC/I,MAAU;AAC7B,UAAI;AACF,QAAAA,EAAM,YAAA;AAAA,MACR,SAAS+I,GAAK;AACZ,gBAAQ,KAAK,kDAAkD/I,EAAM,EAAE,MAAM+I,CAAG;AAAA,MAClF;AAAA,IACF,CAAC,GACD,KAAK,qBAAA;AAAA,EACP;AAAA,EAEA,cAAc7K,GAAoB;AAChC,SAAK,aAAa,OAAO,QAAQ,KAAK,SAASA,CAAI;AAAA,EACrD;AAAA,EAEA,QAAQ8J,GAAiBzI,GAAuB;AAC9C,UAAMS,IAAQ,KAAK,OAAO,IAAIgI,CAAO;AACrC,IAAIhI,MACFA,EAAM,QAAQT,CAAM,GAChBA,IACF,KAAK,aAAa,IAAIyI,CAAO,IAE7B,KAAK,aAAa,OAAOA,CAAO,GAElC,KAAK,iBAAA;AAAA,EAET;AAAA,EAEQ,mBAAyB;AAC/B,UAAM6I,IAAkB,KAAK,aAAa,OAAO;AAEjD,SAAK,OAAO,QAAQ,CAAC7Q,GAAO8Q,MAAO;AACjC,UAAID;AACF,YAAI,CAAC,KAAK,aAAa,IAAIC,CAAE;AAC3B,UAAA9Q,EAAM,QAAQ,EAAI;AAAA,aACb;AACL,gBAAM+Q,IAAgB,KAAK,gBAAgB,IAAID,CAAE,KAAK;AACtD,UAAA9Q,EAAM,QAAQ+Q,CAAa;AAAA,QAC7B;AAAA,WACK;AACL,cAAMA,IAAgB,KAAK,gBAAgB,IAAID,CAAE,KAAK;AACtD,QAAA9Q,EAAM,QAAQ+Q,CAAa;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,QAAQ/I,GAAiB1I,GAAsB;AAC7C,UAAMU,IAAQ,KAAK,OAAO,IAAIgI,CAAO;AACrC,IAAIhI,MACF,KAAK,gBAAgB,IAAIgI,GAAS1I,CAAK,GACvCU,EAAM,QAAQV,CAAK;AAAA,EAEvB;AAAA,EAEA,QAAQ8J,GAAkB4H,GAAmBC,GAAuB;AAIlE,SAAK,eAAe7H,GACpB,KAAK,aAAa4H,GAClB,KAAK,WAAWC;AAEhB,UAAMtF,IAAYC,EAAA;AAClB,QAAI;AAKF,MAAAD,EAAU,YAAYqF,GACtBrF,EAAU,UAAUsF,GACpBtF,EAAU,OAAOvC;AAAA,IACnB,SAASL,GAAK;AACZ,cAAQ,KAAK,mDAAmDA,CAAG;AACnE;AAAA,IACF;AAEA,IAAIK,KAAW,CAAC,KAAK,gBACnB,KAAK,eAAe,MAAM;AASxB,YAAM8H,IAAc9B,GAAA;AACpB,WAAK,OAAO,QAAQ,CAACpP,MAAU;AAC7B,YAAI;AACF,UAAAA,EAAM,eAAA,GACNA,EAAM,YAAA,GACNA,EAAM,uBAAuB,KAAK,UAAU,GAC5CA,EAAM,oBAAoB,KAAK,YAAYkR,CAAW,GACtDlR,EAAM,aAAakR,GAAa,KAAK,UAAU;AAAA,QACjD,SAASnI,GAAK;AACZ,kBAAQ;AAAA,YACN,4CAA4C/I,EAAM,EAAE;AAAA,YACpD+I;AAAA,UAAA;AAAA,QAEJ;AAAA,MACF,CAAC;AAAA,IACH,GACA4C,EAAU,GAAG,QAAQ,KAAK,YAAY,KAC7B,CAACvC,KAAW,KAAK,iBAC1BuC,EAAU,IAAI,QAAQ,KAAK,YAAY,GACvC,KAAK,eAAe;AAAA,EAExB;AAAA,EAEA,iBAAyB;AACvB,WAAOC,IAAe;AAAA,EACxB;AAAA,EAEA,OAAOpE,GAAoB;AACzB,IAAAoE,EAAA,EAAe,UAAUpE;AAAA,EAC3B;AAAA,EAEA,UAAgB;AAKd,QAAI;AACF,WAAK,KAAA;AAAA,IACP,SAASuB,GAAK;AACZ,cAAQ,KAAK,0DAA0DA,CAAG;AAAA,IAC5E;AAWA,QATA,KAAK,OAAO,QAAQ,CAAC/I,MAAU;AAC7B,UAAI;AACF,QAAAA,EAAM,QAAA;AAAA,MACR,SAAS+I,GAAK;AACZ,gBAAQ,KAAK,wCAAwC/I,EAAM,EAAE,MAAM+I,CAAG;AAAA,MACxE;AAAA,IACF,CAAC,GACD,KAAK,OAAO,MAAA,GAER,KAAK;AACP,UAAI;AACF,aAAK,eAAA;AAAA,MACP,SAASA,GAAK;AACZ,gBAAQ,KAAK,sDAAsDA,CAAG;AAAA,MACxE;AAGF,QAAI;AACF,WAAK,aAAa,QAAA;AAAA,IACpB,SAASA,GAAK;AACZ,cAAQ,KAAK,gDAAgDA,CAAG;AAAA,IAClE;AAAA,EACF;AAAA,EAEA,IAAI,UAAuB;AACzB,WAAO+C,EAAA;AAAA,EACT;AAAA,EAEA,IAAI,aAAqB;AACvB,WAAOA,IAAa;AAAA,EACtB;AAAA,EAEA,sBAAsBqF,GAA4B;AAChD,SAAK,6BAA6BA;AAAA,EACpC;AACF;ACrZO,SAASC,EAAmBC,GAAoB;AACrD,SAAO,KAAK,IAAI,GAAGA,IAAK,IAAI;AAC9B;AAGA,MAAMC,KAAsB;AAKrB,SAASC,EACdC,GACA5G,GACoB;AACpB,SAAO4G,EAAW5G,CAAI,GAAG;AAC3B;AAMO,SAAS6G,GAAehQ,GAAmC;AAChE,QAAMiQ,IAAS,IAAI,aAAajQ,EAAQ,MAAM;AAC9C,WAASL,IAAI,GAAGA,IAAIK,EAAQ,QAAQL;AAClC,IAAAsQ,EAAOtQ,CAAC,IAAIK,EAAQL,CAAC,IAAI;AAE3B,SAAOsQ;AACT;AAiCO,SAASC,GAAsBC,GAAoC;AACxE,QAAM,EAAE,UAAA/D,GAAU,iBAAAgE,GAAiB,eAAAC,GAAe,YAAAC,GAAY,UAAAC,GAAU,iBAAAC,MACtEL,GAOIM,IAAiBrE,KAHrBgE,MAAoB,SAAYA,IAAkBC,MAAkB,MAAMA,IAAgB,MAGhDC,KAAcC,IAAWC,KAAmB;AAExF,SAAO,KAAK,IAAI,GAAGC,IAAiB,EAAE;AACxC;AAyBO,SAASC,GACdP,GACkD;AAClD,QAAM,EAAE,YAAAJ,GAAY,QAAAY,EAAA,IAAWR,GAGzBS,IAAWd,EAAkBC,GAAYc,EAAc,WAAW,KAAK,GAGvEC,IACJH,EAAO,aACNb,EAAkBC,GAAYc,EAAc,oBAAoB,KAAK,MACrEf,EAAkBC,GAAYc,EAAc,0BAA0B,KAAK,KAAK,OAC7EE,IACJJ,EAAO,WACNb,EAAkBC,GAAYc,EAAc,kBAAkB,KAAK,MACnEf,EAAkBC,GAAYc,EAAc,wBAAwB,KAAK,KAAK,OAK3EtB,IAAYuB,IAAeH,EAAO,YAClCnB,IAAUuB,IAAaJ,EAAO,YAG9BrC,IAAeqB;AAAA,IACnBG,EAAkBC,GAAYc,EAAc,YAAY,KAAK;AAAA,EAAA,GAEzDtC,IAAaoB;AAAA,IACjBG,EAAkBC,GAAYc,EAAc,UAAU,KAAK;AAAA,EAAA,GAEvDrC,IAAcmB;AAAA,IAClBG,EAAkBC,GAAYc,EAAc,WAAW,KAAK;AAAA,EAAA,GAExDnC,IAAgB,KAAK;AAAA,IACzBiB,EAAmBG,EAAkBC,GAAYc,EAAc,aAAa,KAAK,KAAM;AAAA,IACvFhB;AAAA,EAAA,GAKImB,IAAYlB,EAAkBC,GAAYc,EAAc,aAAa,KAAK,GAC1EpC,IAAgB,KAAK,IAAI,IAAI,CAACuC,IAAY,GAAG;AAEnD,SAAO;AAAA,IACL,UAAAJ;AAAA,IACA,WAAArB;AAAA,IACA,SAAAC;AAAA,IACA,cAAAlB;AAAA,IACA,YAAAC;AAAA,IACA,aAAAC;AAAA,IACA,eAAAC;AAAA,IACA,eAAAC;AAAA,EAAA;AAEJ;AAYO,MAAMuC,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAU1B,YAAYC,GAA4B;AATxC,SAAQ,MAAyB,MACjC,KAAQ,uCAAiD,IAAA,GAWvD,KAAK,UAAUA,KAAW,IAAI,oBAAoB,GAAG,GAAG,KAAK;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAKC,GAAa9I,GAAqC;AAC3D,UAAM+I,IAAW,MAAM,MAAMD,GAAK,EAAE,QAAA9I,GAAQ;AAC5C,QAAI,CAAC+I,EAAS;AACZ,YAAM,IAAI,MAAM,6BAA6BD,CAAG,KAAKC,EAAS,UAAU,EAAE;AAE5E,UAAMC,IAAc,MAAMD,EAAS,YAAA;AACnC,QAAI;AACF,WAAK,MAAM,IAAIE,GAAW,IAAI,WAAWD,CAAW,CAAC;AAAA,IACvD,SAAS/J,GAAK;AACZ,YAAM,IAAI;AAAA,QACR,6BAA6B6J,CAAG,KAAK7J,aAAe,QAAQA,EAAI,UAAU,OAAOA,CAAG,CAAC;AAAA,MAAA;AAAA,IAEzF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAeiK,GAAyB;AACtC,QAAI;AACF,WAAK,MAAM,IAAID,GAAW,IAAI,WAAWC,CAAI,CAAC;AAAA,IAChD,SAASjK,GAAK;AACZ,YAAM,IAAI;AAAA,QACR,0CAA0CA,aAAe,QAAQA,EAAI,UAAU,OAAOA,CAAG,CAAC;AAAA,MAAA;AAAA,IAE9F;AAAA,EACF;AAAA,EAEA,IAAI,WAAoB;AACtB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,eACE8E,GACAoF,IAAqB,GACrBC,IAAuB,GACC;AACxB,QAAI,CAAC,KAAK,IAAK,QAAO;AAEtB,UAAMC,IAAU,KAAK,IAAI,WAAWtF,GAAUoF,GAAYC,CAAY;AACtE,QAAI,CAACC,EAAS,QAAO;AAErB,UAAM3S,IAAS2S,EAAQ,QACjBC,IAAc,KAAK,IAAI,QAAQ,QAAQ5S,CAAM;AAGnD,QAAIqF,IAAS,KAAK,iBAAiB,IAAIuN,CAAW;AAClD,IAAKvN,MACHA,IAAS,KAAK,mBAAmBrF,EAAO,MAAMA,EAAO,OAAO,UAAU,GACtE,KAAK,iBAAiB,IAAI4S,GAAavN,CAAM;AAK/C,UAAMwN,IAAe1B,GAAsB;AAAA,MACzC,UAAA9D;AAAA,MACA,iBAAiB0D,EAAkB4B,EAAQ,YAAYb,EAAc,iBAAiB;AAAA,MACtF,eAAe9R,EAAO,OAAO;AAAA,MAC7B,YAAY+Q,EAAkB4B,EAAQ,YAAYb,EAAc,UAAU,KAAK;AAAA,MAC/E,UAAUf,EAAkB4B,EAAQ,YAAYb,EAAc,QAAQ,KAAK;AAAA,MAC3E,iBAAiB9R,EAAO,OAAO,mBAAmB;AAAA,IAAA,CACnD,GAGK8S,IAAkBnB,GAAuB;AAAA,MAC7C,YAAYgB,EAAQ;AAAA,MACpB,QAAQA,EAAQ,OAAO;AAAA,IAAA,CACxB;AAED,WAAO,EAAE,QAAAtN,GAAQ,cAAAwN,GAAc,GAAGC,EAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,mBAAmBN,GAAkBrU,GAAiC;AAC5E,UAAM+S,IAASD,GAAeuB,CAAI,GAC5BnN,IAAS,KAAK,QAAQ,aAAa,GAAG6L,EAAO,QAAQ/S,CAAU;AACrE,WAAAkH,EAAO,eAAe,CAAC,EAAE,IAAI6L,CAAM,GAC5B7L;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACd,SAAK,iBAAiB,MAAA,GACtB,KAAK,MAAM;AAAA,EACb;AACF;AC/SA,IAAI0N,IAAoC;AAQjC,SAASC,KAA4B;AAC1C,SAAKD,MACHA,IAAoB,IAAIE,GAAA,GACxBC,GAAWH,CAAiB,IAEvBA;AACT;AAOO,SAASI,KAAsC;AACpD,SAAOH,KAAmB;AAC5B;AAOO,SAASI,KAAgC;AAC9C,SAAOJ,GAAA;AACT;AAOA,eAAsBK,KAA0C;AAC9D,QAAMlB,IAAUa,GAAA;AAChB,EAAIb,EAAQ,UAAU,aACpB,MAAMA,EAAQ,OAAA;AAElB;AAMO,SAASmB,KAAgD;AAC9D,SAAOP,GAAmB,WAAW,SAAS;AAChD;AAMA,eAAsBQ,KAAyC;AAC7D,EAAIR,KAAqBA,EAAkB,WAAW,UAAU,aAC9D,MAAMA,EAAkB,MAAA,GACxBA,IAAoB;AAExB;ACvDA,MAAMS,wBAAoB,IAAA,GAGpBC,yBAA4B,IAAA;AAiB3B,SAASC,GAAqBC,GAAiD;AAEpF,MAAIH,EAAc,IAAIG,CAAM;AAC1B,WAAOH,EAAc,IAAIG,CAAM;AAKjC,QAAM5H,IADUT,EAAA,EACO,wBAAwBqI,CAAM;AACrD,EAAAH,EAAc,IAAIG,GAAQ5H,CAAM;AAGhC,QAAMd,IAAU,MAAM;AACpB,IAAAc,EAAO,WAAA,GACPyH,EAAc,OAAOG,CAAM,GAC3BF,GAAsB,OAAOE,CAAM,GAGnCA,EAAO,oBAAoB,SAAS1I,CAAO,GAC3C0I,EAAO,oBAAoB,YAAY1I,CAAO;AAAA,EAChD;AAEA,SAAAwI,GAAsB,IAAIE,GAAQ1I,CAAO,GAGzC0I,EAAO,iBAAiB,SAAS1I,CAAO,GACxC0I,EAAO,iBAAiB,YAAY1I,CAAO,GAEpCc;AACT;AAUO,SAAS6H,GAAyBD,GAA2B;AAClE,QAAM1I,IAAUwI,GAAsB,IAAIE,CAAM;AAChD,EAAI1I,KACFA,EAAA;AAEJ;AAQO,SAAS4I,GAAqBF,GAA8B;AACjE,SAAOH,EAAc,IAAIG,CAAM;AACjC;ACzEO,SAASG,GAAkBxW,GAA8C;AAC9E,MAAIyW,IAA8B,MAC9BC,IAAa,IACbC,IAAqB,GACrBC,IAAe,IACfC,IAAa,GACbC,IAAW,GACXC,IAAoB;AAGxB,WAASC,EAAkBC,GAAgB/U,GAAwB;AACjE,UAAMgV,IAAahV,EAAM,MAAM,OAAO,CAACmI,MAAMA,EAAE,eAAe,CAACA,EAAE,SAAS,GACpE8M,IAAYjV,EAAM,MAAM,OAAO,CAACmI,MAAMA,EAAE,aAAaA,EAAE,UAAU,SAAS,CAAC;AAEjF,QAAI6M,EAAW,SAAS,GAAG;AACzB,YAAMhW,IAAY,KAAK,IAAI,GAAGgW,EAAW,IAAIpR,CAAa,CAAC,GACrD+E,IAAU,KAAK,IAAI,GAAGqM,EAAW,IAAInR,EAAW,CAAC,GAEjDqR,IAAkB;AAAA,QACtB,IAAIlV,EAAM;AAAA,QACV,MAAMA,EAAM;AAAA,QACZ,MAAMA,EAAM;AAAA,QACZ,OAAOA,EAAM;AAAA,QACb,QAAQA,EAAM;AAAA,QACd,WAAWA,EAAM;AAAA,QACjB,WAAAhB;AAAA,QACA,SAAA2J;AAAA,MAAA,GAGI+C,IAAwBsJ,EAAW,IAAI,CAAC7U,OAAU;AAAA,QACtD,QAAQA,EAAK;AAAA,QACb,WAAWyD,EAAczD,CAAI,IAAInB;AAAA,QACjC,UAAU+E,GAAiB5D,CAAI;AAAA,QAC/B,QAAQ2D,GAAe3D,CAAI;AAAA,QAC3B,QAAQA,EAAK;AAAA,QACb,SAASA,EAAK;AAAA,QACd,MAAMA,EAAK;AAAA,MAAA,EACX;AAEF,MAAA4U,EAAE,SAAS;AAAA,QACT,OAAOrJ;AAAA,QACP,OAAOwJ;AAAA,QACP,SAASlV,EAAM;AAAA,MAAA,CAChB;AAAA,IACH;AAEA,QAAIiV,EAAU,SAAS,GAAG;AACxB,YAAMjW,IAAY,KAAK,IAAI,GAAGiW,EAAU,IAAIrR,CAAa,CAAC,GACpD+E,IAAU,KAAK,IAAI,GAAGsM,EAAU,IAAIpR,EAAW,CAAC,GAIhDqR,IAAkB;AAAA,QACtB,IAHcF,EAAW,SAAS,IAAI,GAAGhV,EAAM,EAAE,UAAUA,EAAM;AAAA,QAIjE,MAAMA,EAAM;AAAA,QACZ,MAAMA,EAAM;AAAA,QACZ,OAAOA,EAAM;AAAA,QACb,QAAQA,EAAM;AAAA,QACd,WAAWA,EAAM;AAAA,QACjB,WAAAhB;AAAA,QACA,SAAA2J;AAAA,MAAA,GAGIwM,IAAgCF,EAAU,IAAI,CAAC9U,OAAU;AAAA,QAC7D,OAAOA,EAAK;AAAA,QACZ,WAAWyD,EAAczD,CAAI,IAAInB;AAAA,QACjC,UAAU+E,GAAiB5D,CAAI;AAAA,QAC/B,QAAQ2D,GAAe3D,CAAI;AAAA,MAAA,EAC3B;AAEF,UAAIrC,GAAS,gBAAgB,UAAU;AACrC,cAAMsX,IAAYH,EAAU,CAAC,GAEvBI,IADcD,EAAU,gBACO,GAC/BE,IAAgBF,EAAU,eAAe;AAE/C,QAAAL,EAAE,kBAAkB;AAAA,UAClB,OAAOI;AAAA,UACP,OAAOD;AAAA,UACP,gBAAgBpX,EAAQ;AAAA,UACxB,eAAAwX;AAAA,UACA,cAAAD;AAAA,UACA,SAASrV,EAAM;AAAA,QAAA,CAChB;AAAA,MACH;AACE,QAAIlC,GAAS,kBACX,QAAQ;AAAA,UACN,iDAAiDkC,EAAM,IAAI;AAAA,QAAA,GAG/D+U,EAAE,aAAa;AAAA,UACb,OAAOI;AAAA,UACP,OAAOD;AAAA,UACP,SAASlV,EAAM;AAAA,QAAA,CAChB;AAAA,IAEL;AAAA,EACF;AAEA,WAASuV,EAAazV,GAA2B;AAC/C,QAAIyU,GAAS;AACX,UAAI;AACF,QAAAA,EAAQ,QAAA;AAAA,MACV,SAASxL,GAAK;AACZ,gBAAQ,KAAK,kEAAkEA,CAAG;AAAA,MACpF;AACA,MAAAwL,IAAU;AAAA,IACZ;AAEA,IAAAE;AACA,UAAMe,IAAaf;AAEnB,IAAAF,IAAU,IAAIhE,GAAY;AAAA,MACxB,SAASzS,GAAS;AAAA,IAAA,CACnB,GAKG+W,KACFN,EAAQ,KAAA,EAAO,MAAM,CAACxL,MAAQ;AAC5B,cAAQ;AAAA,QACN;AAAA,QAEAA;AAAA,MAAA,GAEF8L,IAAoB;AAAA,IACtB,CAAC;AAGH,eAAW7U,KAASF;AAClB,MAAAgV,EAAkBP,GAASvU,CAAK;AAElC,IAAAuU,EAAQ,sBAAA,GACRA,EAAQ,QAAQG,GAAcC,GAAYC,CAAQ,GAElDL,EAAQ,sBAAsB,MAAM;AAClC,MAAIiB,MAAef,MACjBD,IAAa;AAAA,IAEjB,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAM,OAAsB;AAC1B,MAAID,MACF,MAAMA,EAAQ,KAAA,GACdM,IAAoB;AAAA,IAExB;AAAA,IAEA,UAAU/U,GAA2B;AACnC,MAAAyV,EAAazV,CAAM;AAAA,IACrB;AAAA,IAEA,SAASE,GAAwB;AAC/B,UAAI,CAACuU;AACH,cAAM,IAAI;AAAA,UACR;AAAA,QAAA;AAIJ,MAAAO,EAAkBP,GAASvU,CAAK,GAChCuU,EAAQ,sBAAA;AAAA,IACV;AAAA,IAEA,KAAKvV,GAAmB2J,GAAwB;AAC9C,UAAI,CAAC4L,GAAS;AACZ,gBAAQ;AAAA,UACN;AAAA,QAAA;AAGF;AAAA,MACF;AACA,YAAMpV,IAAWwJ,MAAY,SAAYA,IAAU3J,IAAY;AAC/D,MAAAuV,EAAQ,KAAKnF,MAAOpQ,GAAWG,CAAQ,GAGvCqV,IAAa;AAAA,IACf;AAAA,IAEA,QAAc;AACZ,MAAAD,GAAS,MAAA,GACTC,IAAa;AAAA,IACf;AAAA,IAEA,OAAa;AACX,MAAAD,GAAS,KAAA,GACTC,IAAa;AAAA,IACf;AAAA,IAEA,KAAKhN,GAAoB;AACvB,MAAA+M,GAAS,OAAO/M,CAAI;AAAA,IACtB;AAAA,IAEA,iBAAyB;AACvB,aAAO+M,GAAS,oBAAoB;AAAA,IACtC;AAAA,IAEA,YAAqB;AACnB,aAAOC;AAAA,IACT;AAAA,IAEA,gBAAgBhV,GAAsB;AACpC,MAAA+U,GAAS,cAAc/U,CAAM;AAAA,IAC/B;AAAA,IAEA,eAAewI,GAAiBxI,GAAsB;AACpD,MAAA+U,GAAS,SAASvM,CAAO,GAAG,UAAUxI,CAAM;AAAA,IAC9C;AAAA,IAEA,aAAawI,GAAiB1I,GAAsB;AAClD,MAAAiV,GAAS,QAAQvM,GAAS1I,CAAK;AAAA,IACjC;AAAA,IAEA,aAAa0I,GAAiBzI,GAAuB;AACnD,MAAAgV,GAAS,QAAQvM,GAASzI,CAAM;AAAA,IAClC;AAAA,IAEA,YAAYyI,GAAiBvI,GAAmB;AAC9C,MAAA8U,GAAS,SAASvM,CAAO,GAAG,OAAOvI,CAAG;AAAA,IACxC;AAAA,IAEA,QAAQ2J,GAAkBJ,GAAeC,GAAmB;AAC1D,MAAAyL,IAAetL,GACfuL,IAAa3L,GACb4L,IAAW3L,GACXsL,GAAS,QAAQnL,GAASJ,GAAOC,CAAG;AAAA,IACtC;AAAA,IAEA,UAAgB;AACd,UAAI;AACF,QAAAsL,GAAS,QAAA;AAAA,MACX,SAASxL,GAAK;AACZ,gBAAQ,KAAK,0CAA0CA,CAAG;AAAA,MAC5D;AACA,MAAAwL,IAAU,MACVC,IAAa;AAAA,IACf;AAAA,EAAA;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnQA,WAASiB,EAAUzC,GAAM;AACvB,QAAI+B,IAAI,IAAIW,EAAO1C,CAAI,GAEnB2C,IAAcZ,EAAE,UAAS;AAC7B,QAAIY,EAAY,MAAM;AACpB,YAAM,4CAA4CA,EAAY,KAAK;AAIrE,aAHIvD,IAASwD,EAAYD,EAAY,IAAI,GAErC7V,IAAS,CAAA,GACJsB,IAAE,GAAG,CAAC2T,EAAE,SAAS3T,IAAIgR,EAAO,WAAWhR,KAAK;AACnD,UAAIyU,IAAad,EAAE,UAAS;AAC5B,UAAIc,EAAW,MAAM;AACnB,cAAM,4CAA4CA,EAAW,KAAK;AACpE,UAAI7V,IAAQ8V,EAAWD,EAAW,IAAI;AACtC,MAAA/V,EAAO,KAAKE,CAAK;AAAA,IACrB;AAEE,WAAO;AAAA,MACL,QAAQoS;AAAA,MACR,QAAQtS;AAAA,IACZ;AAAA,EACA;AAGA,WAAS8V,EAAY5C,GAAM;AACzB,QAAI+B,IAAI,IAAIW,EAAO1C,CAAI,GAEnB+C,IAAShB,EAAE,WAAU,GACrBiB,IAAYjB,EAAE,WAAU,GAExBkB,IAAS;AAAA,MACX,QAAQF;AAAA,MACR,WAAWC;AAAA,IACf,GAEME,IAAenB,EAAE,WAAU;AAC/B,WAAImB,IAAe,SACjBD,EAAO,kBAAkB,OAASC,KAAgB,IAClDD,EAAO,gBAAgBC,IAAe,OAEtCD,EAAO,eAAeC,GAGjBD;AAAA,EACT;AAEA,WAASH,EAAW9C,GAAM;AAIxB,aAHI+B,IAAI,IAAIW,EAAO1C,CAAI,GAEnBmD,IAAS,CAAA,GACN,CAACpB,EAAE,SAAO;AACf,UAAIzL,IAAQ8M,EAAS;AACrB,MAAAD,EAAO,KAAK7M,CAAK;AAAA,IACrB;AAEE,WAAO6M;AAEP,QAAIE;AAEJ,aAASD,IAAY;AACnB,UAAI9M,IAAQ,CAAA;AACZ,MAAAA,EAAM,YAAYyL,EAAE,WAAU;AAE9B,UAAIuB,IAAgBvB,EAAE,UAAS;AAE/B,WAAKuB,IAAgB,SAAU;AAE7B,YAAIA,MAAkB,KAAM;AAE1B,UAAAhN,EAAM,OAAO;AACb,cAAIiN,IAAexB,EAAE,UAAS,GAC1B9K,IAAS8K,EAAE,WAAU;AACzB,kBAAQwB,GAAY;AAAA,YAClB,KAAK;AAEH,kBADAjN,EAAM,OAAO,kBACTW,MAAW,EAAG,OAAM,wDAAwDA;AAChF,qBAAAX,EAAM,SAASyL,EAAE,WAAU,GACpBzL;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,QACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,mBACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,aACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,kBACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,UACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,UACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,YACbA,EAAM,OAAOyL,EAAE,WAAW9K,CAAM,GACzBX;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,iBACTW,KAAU,EAAG,OAAM,uDAAuDA;AAC9E,qBAAAX,EAAM,UAAUyL,EAAE,UAAS,GACpBzL;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,cACTW,KAAU,EAAG,OAAM,oDAAoDA;AAC3E,qBAAAX,EAAM,OAAOyL,EAAE,UAAS,GACjBzL;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,cACTW,KAAU,EAAG,OAAM,oDAAoDA;AAC3E,qBAAOX;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,YACTW,KAAU,EAAG,OAAM,kDAAkDA;AACzE,qBAAAX,EAAM,sBAAsByL,EAAE,WAAU,GACjCzL;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,eACTW,KAAU,EAAG,OAAM,qDAAqDA;AAC5E,kBAAIuM,IAAWzB,EAAE,UAAS,GACtB0B,IAAc,EAAE,GAAM,IAAI,IAAM,IAAI,IAAM,IAAI,IAAM,GAAE;AAC1D,qBAAAnN,EAAM,YAAYmN,EAAYD,IAAW,EAAI,GAC7ClN,EAAM,OAAOkN,IAAW,IACxBlN,EAAM,MAAMyL,EAAE,UAAS,GACvBzL,EAAM,MAAMyL,EAAE,UAAS,GACvBzL,EAAM,QAAQyL,EAAE,UAAS,GACzBzL,EAAM,WAAWyL,EAAE,UAAS,GACrBzL;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,iBACTW,KAAU,KAAKA,KAAU,EAAG,OAAM,4DAA4DA;AAClG,qBAAAX,EAAM,YAAYyL,EAAE,UAAS,GAC7BzL,EAAM,cAAe,KAAKyL,EAAE,UAAS,GACjC9K,MAAW,KACbX,EAAM,YAAYyL,EAAE,UAAS,GAC7BzL,EAAM,gBAAgByL,EAAE,UAAS,MAEjCzL,EAAM,YAAY,IAClBA,EAAM,gBAAgB,IAEjBA;AAAA,YACT,KAAK;AAEH,kBADAA,EAAM,OAAO,gBACTW,KAAU,EAAG,OAAM,sDAAsDA;AAC7E,qBAAAX,EAAM,MAAMyL,EAAE,SAAQ,GACtBzL,EAAM,QAAQyL,EAAE,UAAS,GAClBzL;AAAA,YACT,KAAK;AACH,qBAAAA,EAAM,OAAO,qBACbA,EAAM,OAAOyL,EAAE,UAAU9K,CAAM,GACxBX;AAAA,YACT;AACE,qBAAAA,EAAM,OAAO,eACbA,EAAM,OAAOyL,EAAE,UAAU9K,CAAM,GAC/BX,EAAM,eAAeiN,GACdjN;AAAA,UACnB;AAAA,QACA,WAAiBgN,KAAiB,KAAM;AAChC,UAAAhN,EAAM,OAAO;AACb,cAAIW,IAAS8K,EAAE,WAAU;AACzB,iBAAAzL,EAAM,OAAOyL,EAAE,UAAU9K,CAAM,GACxBX;AAAA,QACf,WAAiBgN,KAAiB,KAAM;AAChC,UAAAhN,EAAM,OAAO;AACb,cAAIW,IAAS8K,EAAE,WAAU;AACzB,iBAAAzL,EAAM,OAAOyL,EAAE,UAAU9K,CAAM,GACxBX;AAAA,QACf;AACQ,gBAAM,wCAAwCgN;AAAA,WAE3C;AAEL,YAAII;AACJ,aAAKJ,IAAgB,SAAU,GAAG;AAGhC,cAAID,MAAsB;AACxB,kBAAM;AACR,UAAAK,IAASJ,GACTA,IAAgBD,GAChB/M,EAAM,UAAU;AAAA,QACxB;AACQ,UAAAoN,IAAS3B,EAAE,UAAS,GACpBsB,IAAoBC;AAEtB,YAAIK,IAAYL,KAAiB;AAEjC,gBADAhN,EAAM,UAAUgN,IAAgB,IACxBK,GAAS;AAAA,UACf,KAAK;AACH,mBAAArN,EAAM,OAAO,WACbA,EAAM,aAAaoN,GACnBpN,EAAM,WAAWyL,EAAE,UAAS,GACrBzL;AAAA,UACT,KAAK;AACH,gBAAIwF,IAAWiG,EAAE,UAAS;AAC1B,mBAAAzL,EAAM,OAAOwF,MAAa,IAAI,YAAY,UAC1CxF,EAAM,aAAaoN,GACnBpN,EAAM,WAAWwF,GACbA,MAAa,MAAGxF,EAAM,QAAQ,KAC3BA;AAAA,UACT,KAAK;AACH,mBAAAA,EAAM,OAAO,kBACbA,EAAM,aAAaoN,GACnBpN,EAAM,SAASyL,EAAE,UAAS,GACnBzL;AAAA,UACT,KAAK;AACH,mBAAAA,EAAM,OAAO,cACbA,EAAM,iBAAiBoN,GACvBpN,EAAM,QAAQyL,EAAE,UAAS,GAClBzL;AAAA,UACT,KAAK;AACH,mBAAAA,EAAM,OAAO,iBACbA,EAAM,gBAAgBoN,GACfpN;AAAA,UACT,KAAK;AACH,mBAAAA,EAAM,OAAO,qBACbA,EAAM,SAASoN,GACRpN;AAAA,UACT,KAAK;AACH,mBAAAA,EAAM,OAAO,aACbA,EAAM,QAASoN,KAAU3B,EAAE,UAAS,KAAM,KAAM,MACzCzL;AAAA,UACT;AACE,kBAAM,mCAAmCqN;AAAA,QACnD;AAAA,MACA;AAAA,IACA;AAAA,EACA;AAEA,WAASjB,EAAO1C,GAAM;AACpB,SAAK,SAASA,GACd,KAAK,YAAY,KAAK,OAAO,QAC7B,KAAK,MAAM;AAAA,EACb;AAEA,SAAA0C,EAAO,UAAU,MAAM,WAAW;AAChC,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B,GAEAA,EAAO,UAAU,YAAY,WAAW;AACtC,QAAIO,IAAS,KAAK,OAAO,KAAK,GAAG;AACjC,gBAAK,OAAO,GACLA;AAAA,EACT,GAEAP,EAAO,UAAU,WAAW,WAAW;AACrC,QAAIkB,IAAI,KAAK,UAAS;AACtB,WAAIA,IAAI,MACCA,IAAI,MAEJA;AAAA,EACX,GAEAlB,EAAO,UAAU,aAAa,WAAW;AACvC,QAAImB,IAAK,KAAK,UAAS,GACnBC,IAAK,KAAK,UAAS;AAErB,YAAQD,KAAM,KAAKC;AAAA,EACvB,GAEApB,EAAO,UAAU,YAAY,WAAW;AACtC,QAAIkB,IAAI,KAAK,WAAU;AACvB,WAAIA,IAAI,QACCA,IAAI,QAEJA;AAAA,EACX,GAEAlB,EAAO,UAAU,aAAa,WAAW;AACvC,QAAImB,IAAK,KAAK,UAAS,GACnBC,IAAK,KAAK,UAAS,GACnBC,IAAK,KAAK,UAAS;AAErB,YAAQF,KAAM,OAAOC,KAAM,KAAKC;AAAA,EACpC,GAEArB,EAAO,UAAU,YAAY,WAAW;AACtC,QAAIkB,IAAI,KAAK,WAAU;AACvB,WAAIA,IAAI,UACCA,IAAI,WAEJA;AAAA,EACX,GAEAlB,EAAO,UAAU,aAAa,WAAW;AACvC,QAAImB,IAAK,KAAK,UAAS,GACnBC,IAAK,KAAK,UAAS,GACnBC,IAAK,KAAK,UAAS,GACnBC,IAAK,KAAK,UAAS;AAErB,YAAQH,KAAM,OAAOC,KAAM,OAAOC,KAAM,KAAKC;AAAA,EACjD,GAEAtB,EAAO,UAAU,YAAY,SAASuB,GAAK;AACzC,QAAIC,IAAQ,KAAK,OAAO,MAAM,KAAK,KAAK,KAAK,MAAMD,CAAG;AACtD,gBAAK,OAAOA,GACLC;AAAA,EACT,GAEAxB,EAAO,UAAU,aAAa,SAASuB,GAAK;AAC1C,QAAIC,IAAQ,KAAK,UAAUD,CAAG;AAC9B,WAAO,OAAO,aAAa,MAAM,MAAMC,CAAK;AAAA,EAC9C,GAEAxB,EAAO,UAAU,aAAa,WAAW;AAEvC,aADIO,IAAS,GACN,CAAC,KAAK,SAAO;AAClB,UAAIjV,IAAI,KAAK,UAAS;AACtB,UAAIA,IAAI;AACN,QAAAiV,KAAWjV,IAAI,KACfiV,MAAW;AAAA;AAGX,eAAOA,IAASjV;AAAA,IAEtB;AAEE,WAAOiV;AAAA,EACT,GAEAP,EAAO,UAAU,YAAY,WAAW;AACtC,QAAI5E,IAAK,KAAK,WAAW,CAAC,GACtB7G,IAAS,KAAK,WAAU,GACxB+I,IAAO,KAAK,UAAU/I,CAAM;AAChC,WAAO;AAAA,MACL,IAAI6G;AAAA,MACJ,QAAQ7G;AAAA,MACR,MAAM+I;AAAA,IACV;AAAA,EACA,GAEAmE,IAAiB1B;;;;;;AC/UjB,WAAS2B,EAAUpE,GAAMqE,GAAM;AAC7B,QAAI,OAAOrE,KAAS;AAClB,YAAM;AAER,IAAAqE,IAAOA,KAAQ,CAAA;AAEf,QAAIjF,IAASY,EAAK,UAAU,CAAA,GACxBlT,IAASkT,EAAK,UAAU,CAAA,GACxB5R,GAAG6V,IAAMnX,EAAO,QAEhBwX,IAAI,IAAIC,EAAM;AAGlB,SAFAC,EAAYF,GAAGlF,GAAQ6E,CAAG,GAErB7V,IAAE,GAAGA,IAAI6V,GAAK7V;AACjB,MAAAqW,EAAWH,GAAGxX,EAAOsB,CAAC,GAAGiW,CAAI;AAG/B,WAAOC,EAAE;AAAA,EACX;AAEA,WAASE,EAAYF,GAAGlF,GAAQ4D,GAAW;AACzC,QAAID,IAAS3D,EAAO,UAAU,OAAO,IAAIA,EAAO,QAE5C8D,IAAe;AACnB,IAAI9D,EAAO,eACT8D,IAAe9D,EAAO,eACbA,EAAO,iBAAiBA,EAAO,kBACxC8D,IAAgB,EAAE9D,EAAO,kBAAkB,QAAS,IAAMA,EAAO,gBAAgB,MACxEA,EAAO,iBAChB8D,IAAe9D,EAAO,eAAe;AAGvC,QAAIsF,IAAI,IAAIH,EAAM;AAClB,IAAAG,EAAE,YAAY3B,CAAM,GACpB2B,EAAE,YAAY1B,CAAS,GACvB0B,EAAE,YAAYxB,CAAY,GAE1BoB,EAAE,WAAW,QAAQI,EAAE,MAAM;AAAA,EAC/B;AAEA,WAASD,EAAWH,GAAGtX,GAAOqX,GAAM;AAClC,QAAIpP,IAAI,IAAIsP,EAAM,GACdnW,GAAG6V,IAAMjX,EAAM,QACfsW,IAAgB;AACpB,SAAKlV,IAAE,GAAGA,IAAI6V,GAAK7V;AAIjB,OAAIiW,EAAK,YAAY,MAAS,CAACA,EAAK,WAAW,CAACrX,EAAMoB,CAAC,EAAE,aAASkV,IAAgB,OAElFA,IAAgBqB,EAAW1P,GAAGjI,EAAMoB,CAAC,GAAGkV,GAAee,EAAK,kBAAkB;AAEhF,IAAAC,EAAE,WAAW,QAAQrP,EAAE,MAAM;AAAA,EAC/B;AAEA,WAAS0P,EAAWL,GAAGhO,GAAO+M,GAAmBuB,GAAoB;AACnE,QAAIhN,IAAOtB,EAAM,MACbuO,IAAYvO,EAAM,WAClBwO,IAAOxO,EAAM,QAAQ,IACrB0J,IAAO1J,EAAM,QAAQ,CAAA,GACrBgN,IAAgB;AAGpB,YAFAgB,EAAE,YAAYO,CAAS,GAEfjN,GAAI;AAAA;AAAA,MAEV,KAAK;AACH,QAAA0M,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAY,CAAC,GACfA,EAAE,YAAYhO,EAAM,MAAM;AAC1B;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,CAAI,GACjBA,EAAE,YAAYQ,EAAK,MAAM,GACzBR,EAAE,YAAYQ,CAAI;AAClB;AAAA,MAEF,KAAK;AACH,QAAAR,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC,GACfA,EAAE,WAAWhO,EAAM,OAAO;AAC1B;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC,GACfA,EAAE,WAAWhO,EAAM,IAAI;AACvB;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC;AACf;AAAA,MAEF,KAAK;AACH,QAAAA,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC,GACfA,EAAE,YAAYhO,EAAM,mBAAmB;AACvC;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC;AACf,YAAIb,IAAc,EAAE,IAAI,GAAM,IAAI,IAAM,IAAI,IAAM,IAAI,GAAI,GACtDD,IAAYlN,EAAM,OAAO,KAAQmN,EAAYnN,EAAM,SAAS;AAChE,QAAAgO,EAAE,WAAWd,CAAQ,GACrBc,EAAE,WAAWhO,EAAM,GAAG,GACtBgO,EAAE,WAAWhO,EAAM,GAAG,GACtBgO,EAAE,WAAWhO,EAAM,KAAK,GACxBgO,EAAE,WAAWhO,EAAM,QAAQ;AAC3B;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC,GACfA,EAAE,WAAWhO,EAAM,SAAS;AAC5B,YAAIhH,IAAc,KAAK,MAAO,KAAK,IAAIgH,EAAM,WAAW,IAAI,KAAK,OAAQ;AACzE,QAAAgO,EAAE,WAAWhV,CAAW,GACxBgV,EAAE,WAAWhO,EAAM,SAAS,GAC5BgO,EAAE,WAAWhO,EAAM,iBAAiB,CAAC;AACrC;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,EAAI,GACjBA,EAAE,YAAY,CAAC,GACfA,EAAE,UAAUhO,EAAM,GAAG,GACrBgO,EAAE,WAAWhO,EAAM,KAAK;AACxB;AAAA,MAEF,KAAK;AACH,QAAAgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAW,GAAI,GACjBA,EAAE,YAAYtE,EAAK,MAAM,GACzBsE,EAAE,WAAWtE,CAAI;AACjB;AAAA,MAEF,KAAK;AACH,QAAI1J,EAAM,gBAAgB,SACxBgO,EAAE,WAAW,GAAI,GACjBA,EAAE,WAAWhO,EAAM,YAAY,GAC/BgO,EAAE,YAAYtE,EAAK,MAAM,GACzBsE,EAAE,WAAWtE,CAAI;AAEnB;AAAA;AAAA,MAGF,KAAK;AACH,QAAAsE,EAAE,WAAW,GAAI,GACjBA,EAAE,YAAYtE,EAAK,MAAM,GACzBsE,EAAE,WAAWtE,CAAI;AACjB;AAAA,MAEF,KAAK;AACH,QAAAsE,EAAE,WAAW,GAAI,GACjBA,EAAE,YAAYtE,EAAK,MAAM,GACzBsE,EAAE,WAAWtE,CAAI;AACjB;AAAA;AAAA,MAGF,KAAK;AAIH,YAAI+E,IAAaH,MAAuB,MAAStO,EAAM,SAAWsO,KAAsBtO,EAAM,YAAY,IAAM,MAAO;AAEvH,QAAAgN,IAAgByB,IAAWzO,EAAM,SAC7BgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa,GACnEgB,EAAE,WAAWhO,EAAM,UAAU,GAC7BgO,EAAE,WAAWhO,EAAM,QAAQ;AAC3B;AAAA,MAEF,KAAK;AACH,QAAAgN,IAAgB,MAAOhN,EAAM,SACzBgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa,GACnEgB,EAAE,WAAWhO,EAAM,UAAU,GAC7BgO,EAAE,WAAWhO,EAAM,QAAQ;AAC3B;AAAA,MAEF,KAAK;AACH,QAAAgN,IAAgB,MAAOhN,EAAM,SACzBgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa,GACnEgB,EAAE,WAAWhO,EAAM,UAAU,GAC7BgO,EAAE,WAAWhO,EAAM,MAAM;AACzB;AAAA,MAEF,KAAK;AACH,QAAAgN,IAAgB,MAAOhN,EAAM,SACzBgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa,GACnEgB,EAAE,WAAWhO,EAAM,cAAc,GACjCgO,EAAE,WAAWhO,EAAM,KAAK;AACxB;AAAA,MAEF,KAAK;AACH,QAAAgN,IAAgB,MAAOhN,EAAM,SACzBgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa,GACnEgB,EAAE,WAAWhO,EAAM,aAAa;AAChC;AAAA,MAEF,KAAK;AACH,QAAAgN,IAAgB,MAAOhN,EAAM,SACzBgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa,GACnEgB,EAAE,WAAWhO,EAAM,MAAM;AACzB;AAAA,MAEF,KAAK;AACH,QAAAgN,IAAgB,MAAOhN,EAAM,SACzBgN,MAAkBD,KAAmBiB,EAAE,WAAWhB,CAAa;AACnE,YAAI0B,IAAU,OAAS1O,EAAM,OACzB2O,IAASD,IAAU,KACnBE,IAASF,KAAW,IAAK;AAC7B,QAAAV,EAAE,WAAWW,CAAK,GAClBX,EAAE,WAAWY,CAAK;AACpB;AAAA,MAEA;AACE,cAAM,8BAA8BtN;AAAA,IAC1C;AACE,WAAO0L;AAAA,EACT;AAGA,WAASiB,IAAS;AAChB,SAAK,SAAS,CAAA;AAAA,EAChB;AAEA,SAAAA,EAAO,UAAU,aAAa,SAASY,GAAG;AACxC,SAAK,OAAO,KAAKA,IAAI,GAAI;AAAA,EAC3B,GACAZ,EAAO,UAAU,YAAYA,EAAO,UAAU,YAE9CA,EAAO,UAAU,cAAc,SAASY,GAAG;AACzC,QAAItB,IAAMsB,KAAK,IAAK,KAChBrB,IAAKqB,IAAI;AAEb,SAAK,WAAWtB,CAAE,GAClB,KAAK,WAAWC,CAAE;AAAA,EACpB,GACAS,EAAO,UAAU,aAAaA,EAAO,UAAU,aAE/CA,EAAO,UAAU,cAAc,SAASY,GAAG;AACzC,QAAItB,IAAMsB,KAAK,KAAM,KACjBrB,IAAMqB,KAAK,IAAK,KAChBpB,IAAKoB,IAAI;AAEb,SAAK,WAAWtB,CAAE,GAClB,KAAK,WAAWC,CAAE,GAClB,KAAK,WAAWC,CAAE;AAAA,EACpB,GACAQ,EAAO,UAAU,aAAaA,EAAO,UAAU,aAE/CA,EAAO,UAAU,cAAc,SAASY,GAAG;AACzC,QAAItB,IAAMsB,KAAK,KAAM,KACjBrB,IAAMqB,KAAK,KAAM,KACjBpB,IAAMoB,KAAK,IAAK,KAChBnB,IAAKmB,IAAI;AAEb,SAAK,WAAWtB,CAAE,GAClB,KAAK,WAAWC,CAAE,GAClB,KAAK,WAAWC,CAAE,GAClB,KAAK,WAAWC,CAAE;AAAA,EACpB,GACAO,EAAO,UAAU,aAAaA,EAAO,UAAU,aAG/CA,EAAO,UAAU,aAAa,SAASa,GAAK;AAC1C,SAAK,SAAS,KAAK,OAAO,OAAO,MAAM,UAAU,MAAM,KAAKA,GAAK,CAAC,CAAC;AAAA,EACrE,GAEAb,EAAO,UAAU,cAAc,SAASc,GAAK;AAC3C,QAAIjX,GAAG6V,IAAMoB,EAAI,QAAQD,IAAM,CAAA;AAC/B,SAAKhX,IAAE,GAAGA,IAAI6V,GAAK7V;AACjB,MAAAgX,EAAI,KAAKC,EAAI,YAAYjX,CAAC,CAAC;AAE7B,SAAK,WAAWgX,CAAG;AAAA,EACrB,GAEAb,EAAO,UAAU,cAAc,SAASY,GAAG;AACzC,QAAIA,IAAI,EAAG,OAAM;AAEjB,QAAIA,KAAK;AACP,WAAK,WAAWA,CAAC;AAAA,SACZ;AACL,UAAI/W,IAAI+W,GACJjB,IAAQ,CAAA;AAGZ,WAFAA,EAAM,KAAK9V,IAAI,GAAI,GACnBA,MAAM,GACCA,KAAG;AACR,YAAIJ,IAAII,IAAI,MAAO;AACnB,QAAA8V,EAAM,KAAKlW,CAAC,GACZI,MAAM;AAAA,MACZ;AACI,WAAK,WAAW8V,EAAM,QAAO,CAAE;AAAA,IACnC;AAAA,EACA,GAEAK,EAAO,UAAU,aAAa,SAASzG,GAAIkC,GAAM;AAC/C,SAAK,YAAYlC,CAAE,GACnB,KAAK,YAAYkC,EAAK,MAAM,GAC5B,KAAK,WAAWA,CAAI;AAAA,EACtB,GAEAsF,IAAiBlB;;;;wBCvWjBmB,EAAA,YAAoBC,GAAA,GACpBD,EAAA,YAAoBE,GAAA;;;;;UCApB,OAAO,eAAeC,GAAS,cAAc,EAAE,OAAO,IAAM,GAC5DA,EAAA,SAAiBA,EAAA,SAAiB;AAKlC,WAASC,EAAOC,GAAOlL,GAAOmL,GAAM;AAChC,IAAIA,MAAS,WAAUA,IAAO;AAC9B,QAAIC,IAAY,GACZ7B,IAAM2B,EAAM,QACZ3P,IAAMgO;AACV,QAAIA,IAAM,KAAK2B,EAAM3B,IAAM,CAAC,EAAE4B,CAAI,KAAKnL;AACnC,aAAOuJ,IAAM;AAEjB,WAAO6B,IAAY7P,KAAK;AAEpB,UAAI8P,IAAW,KAAK,MAAMD,KAAa7P,IAAM6P,KAAa,CAAC,GACvDE,IAAUJ,EAAMG,CAAQ,GACxBE,IAAYL,EAAMG,IAAW,CAAC;AAClC,UAAIC,EAAQH,CAAI,MAAMnL,GAAO;AAEzB,iBAAStM,IAAI2X,GAAU3X,IAAIwX,EAAM,QAAQxX,KAAK;AAC1C,cAAI8X,IAAYN,EAAMxX,CAAC;AACvB,UAAI8X,EAAUL,CAAI,MAAMnL,MACpBqL,IAAW3X;AAAA,QAE/B;AACY,eAAO2X;AAAA,MACnB,OACa;AAAA,YAAIC,EAAQH,CAAI,IAAInL,KAASuL,EAAUJ,CAAI,IAAInL;AAChD,iBAAOqL;AAEN,QAAIC,EAAQH,CAAI,IAAInL,IAErBzE,IAAM8P,IAEDC,EAAQH,CAAI,IAAInL,MAErBoL,IAAYC,IAAW;AAAA;AAAA,IAEnC;AACI,WAAO;AAAA,EACX;AACA,EAAAL,EAAA,SAAiBC;AAMjB,WAASQ,EAAOP,GAAOtP,GAAOuP,GAAM;AAEhC,QADIA,MAAS,WAAUA,IAAO,UAC1BD,EAAM,QAAQ;AACd,UAAItO,IAAQqO,EAAOC,GAAOtP,EAAMuP,CAAI,GAAGA,CAAI;AAC3C,MAAAD,EAAM,OAAOtO,IAAQ,GAAG,GAAGhB,CAAK;AAAA,IACxC;AAEQ,MAAAsP,EAAM,KAAKtP,CAAK;AAAA,EAExB;AACA,SAAAoP,EAAA,SAAiBS;;;;;AC3DjB,WAAO,eAAcC,GAAU,cAAc,EAAE,OAAO,IAAM,GAC5DA,EAAA,SAAiBA,EAAA,mBAA2B;AAC5C,QAAIC,IAAiBb,GAAA,GACjBc,IAAgB,oBAAI,QAAO;AAI/BF,IAAAA,EAAA,mBAA2B;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAKJ,QAAIG;AAAA;AAAA,OAAwB,WAAY;AACpC,iBAASA,EAAOC,GAAU;AACtB,cAAIC,IAAQ;AAuBZ,cAnBA,KAAK,SAAS,CAAA,GAId,KAAK,iBAAiB,CAAA,GAItB,KAAK,gBAAgB,CAAA,GAIrB,KAAK,OAAO,CAAA,GAIZ,KAAK,OAAO,IAEZH,EAAc,IAAI,MAAM,GAAG,GACvBE,GAAU;AACV,YAAAF,EAAc,IAAI,MAAME,EAAS,OAAO,YAAY,GAEpDA,EAAS,OAAO,QAAQ,SAAUxZ,GAAO;AACrC,cAAAA,EAAM,QAAQ,SAAUsJ,GAAO;AAC3B,gBAAIA,EAAM,SACFA,EAAM,SAAS,kBACfmQ,EAAM,eAAe,KAAK;AAAA,kBACtB,OAAOnQ,EAAM;AAAA,kBACb,eAAe;AAAA,oBACXA,EAAM;AAAA,oBACNA,EAAM;AAAA;gBAE1C,CAA6B,IAEIA,EAAM,SAAS,aACpBmQ,EAAM,OAAO,KAAK;AAAA,kBACd,KAAK,MAAWnQ,EAAM;AAAA,kBACtB,OAAOA,EAAM;AAAA,gBAC7C,CAA6B,IAEIA,EAAM,SAAS,kBACpBmQ,EAAM,cAAc,KAAK;AAAA,kBACrB,KAAKL,EAAQ,iBAAiB9P,EAAM,MAAM,CAAC;AAAA,kBAC3C,OAAOA,EAAM,UAAU,IAAI,UAAU;AAAA,kBACrC,OAAOA,EAAM;AAAA,gBAC7C,CAA6B;AAAA,cAG7B,CAAiB;AAAA,YACjB,CAAa;AAED,gBAAIoQ,IAA2B;AAC/B,YAAAF,EAAS,OAAO,CAAC,EAAE,QAAQ,SAAUlQ,GAAO;AACxC,cAAAoQ,KAA4BpQ,EAAM,WAC9BA,EAAM,SACFA,EAAM,SAAS,cACfmQ,EAAM,OAAOnQ,EAAM,QAEdA,EAAM,SAAS,UACpBA,EAAM,SAAS,cACfA,EAAM,SAAS,YACfA,EAAM,SAAS,aACfmQ,EAAM,KAAK,KAAK;AAAA,gBACZ,MAAMnQ,EAAM;AAAA,gBACZ,OAAOoQ;AAAA,gBACP,MAAMpQ,EAAM;AAAA,cACxC,CAAyB;AAAA,YAGzB,CAAa,GACD,KAAK,OAAM;AAAA,UACvB;AAAA,QACA;AAKI,eAAAiQ,EAAO,UAAU,SAAS,WAAY;AAClC,cAAIE,IAAQ,MACRvI,IAAc,GACdyI,IAAiB;AAErB,eAAK,OAAO,KAAK,SAAU5Y,GAAGC,GAAG;AAAE,mBAAOD,EAAE,QAAQC,EAAE;AAAA,UAAM,CAAE,GAC9D,KAAK,OAAO,QAAQ,SAAUsI,GAAOgB,GAAO;AACxC,gBAAIsP,IAAUtP,IAAQ,IAAImP,EAAM,OAAOnP,IAAQ,CAAC,EAAE,MAAMmP,EAAM,OAAO,CAAC,EAAE,KACpEI,IAAQvQ,EAAM,QAAQmQ,EAAM,MAAME,GAClCG,IAAkB,KAAKF,IAAWC;AACtC,YAAAvQ,EAAM,OAAOwQ,IAAiB5I,GAC9BA,IAAc5H,EAAM,MACpBqQ,KAAkBE;AAAA,UAC9B,CAAS,GACD,KAAK,eAAe,KAAK,SAAU9Y,GAAGC,GAAG;AAAE,mBAAOD,EAAE,QAAQC,EAAE;AAAA,UAAM,CAAE,GACtE,KAAK,eAAe,QAAQ,SAAUsI,GAAOgB,GAAO;AAChD,gBAAIyP,IAAYzP,IAAQ,IAClBmP,EAAM,eAAenP,IAAQ,CAAC,IAC9BmP,EAAM,eAAe,CAAC,GACxBO,KAAgB1Q,EAAM,QAAQyQ,EAAU,SAASN,EAAM,KACvDQ,IAAkBD,IAClBD,EAAU,cAAc,CAAC,KACxBA,EAAU,cAAc,CAAC,IAAI;AAClC,YAAAA,EAAU,WAAWA,EAAU,YAAY,GAC3CzQ,EAAM,WAAW2Q,IAAkBF,EAAU;AAAA,UACzD,CAAS;AAAA,QACT,GAIIR,EAAO,UAAU,iBAAiB,SAAU7W,GAAO;AAE/C,cAAI4H,QAAY+O,EAAe,QAAQ,KAAK,QAAQ3W,CAAK;AACzD,cAAI4H,MAAU,IAAI;AACd,gBAAI4P,IAAQ,KAAK,OAAO5P,CAAK,GACzB6P,IAAYD,EAAM,MAClBF,KAAgBtX,IAAQwX,EAAM,SAAS,KAAK;AAChD,mBAAOC,IAAa,KAAKD,EAAM,MAAOF;AAAA,UAClD,OACa;AAED,gBAAIH,IAAQnX,IAAQ,KAAK;AACzB,mBAAQ,KAAK,MAAOmX;AAAA,UAChC;AAAA,QACA,GAIIN,EAAO,UAAU,kBAAkB,SAAU7W,GAAO;AAChD,cAAI4H,QAAY+O,EAAe,QAAQ,KAAK,gBAAgB3W,CAAK;AACjE,cAAI4H,MAAU,IAAI;AACd,gBAAI8P,IAAe,KAAK,eAAe9P,CAAK,GACxC0P,KAAgBtX,IAAQ0X,EAAa,SAAS,KAAK;AACvD,mBAAQA,EAAa,WACjBJ,KACKI,EAAa,cAAc,CAAC,IACzBA,EAAa,cAAc,CAAC,KAChC;AAAA,UACpB;AAEY,mBAAO1X,IAAQ,KAAK,MAAM;AAAA,QAEtC,GACI,OAAO,eAAe6W,EAAO,WAAW,OAAO;AAAA;AAAA;AAAA;AAAA,UAI3C,KAAK,WAAY;AACb,mBAAOD,EAAc,IAAI,IAAI;AAAA,UACzC;AAAA,UACQ,YAAY;AAAA,UACZ,cAAc;AAAA,QACtB,CAAK,GAIDC,EAAO,UAAU,iBAAiB,SAAU5X,GAAS;AAEjD,cAAI2I,QAAY+O,EAAe,QAAQ,KAAK,QAAQ1X,GAAS,MAAM;AACnE,cAAI2I,MAAU,IAAI;AACd,gBAAI4P,IAAQ,KAAK,OAAO5P,CAAK,GACzB6P,IAAYD,EAAM,MAClBG,IAAc1Y,IAAUwY,GACxBH,IAAeK,KAAe,KAAKH,EAAM;AAC7C,mBAAO,KAAK,MAAMA,EAAM,QAAQF,IAAe,KAAK,GAAG;AAAA,UACnE,OACa;AAED,gBAAIH,IAAQlY,IAAW;AACvB,mBAAO,KAAK,MAAMkY,IAAQ,KAAK,GAAG;AAAA,UAC9C;AAAA,QACA,GAIIN,EAAO,UAAU,SAAS,WAAY;AAClC,iBAAO;AAAA,YACH,eAAe,KAAK;AAAA,YACpB,MAAM,KAAK;AAAA,YACX,MAAM,KAAK;AAAA,YACX,KAAK,KAAK;AAAA,YACV,QAAQ,KAAK,OAAO,IAAI,SAAUtR,GAAG;AACjC,qBAAO;AAAA,gBACH,KAAKA,EAAE;AAAA,gBACP,OAAOA,EAAE;AAAA;YAE7B,CAAa;AAAA,YACD,gBAAgB,KAAK;AAAA;QAEjC,GAIIsR,EAAO,UAAU,WAAW,SAAUe,GAAM;AACxC,eAAK,OAAOA,EAAK,MAEjB,KAAK,SAASA,EAAK,OAAO,IAAI,SAAUrS,GAAG;AAAE,mBAAO,OAAO,OAAO,CAAA,GAAIA,CAAC;AAAA,UAAE,CAAE,GAC3E,KAAK,iBAAiBqS,EAAK,eAAe,IAAI,SAAUrS,GAAG;AACvD,mBAAO,OAAO,OAAO,CAAA,GAAIA,CAAC;AAAA,UACtC,CAAS,GACD,KAAK,gBAAgBqS,EAAK,cAAc,IAAI,SAAUrS,GAAG;AACrD,mBAAO,OAAO,OAAO,CAAA,GAAIA,CAAC;AAAA,UACtC,CAAS,GACD,KAAK,OAAOqS,EAAK,KAAK,IAAI,SAAUrS,GAAG;AAAE,mBAAO,OAAO,OAAO,CAAA,GAAIA,CAAC;AAAA,UAAE,CAAE,GACvEqR,EAAc,IAAI,MAAMgB,EAAK,GAAG,GAChC,KAAK,OAAM;AAAA,QACnB,GAMIf,EAAO,UAAU,WAAW,SAAU5W,GAAK;AACvC,eAAK,SAAS;AAAA,YACV;AAAA,cACI,KAAKA;AAAA,cACL,OAAO;AAAA;aAGf,KAAK,OAAM;AAAA,QACnB,GACW4W;AAAA,MACX;;AACAH,IAAAA,EAAA,SAAiBG;AAAA;;;;;AC7PjB,WAAO,eAAcH,GAAU,cAAc,EAAE,OAAO,IAAM,GAC5DA,EAAA,gBAAwBA,EAAA,mBAA2BA,EAAA,qBAA6B,QAKhFA,EAAA,qBAA6B;AAAA,MACzB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,OAMRA,EAAA,mBAA2B,OAAO,KAAKA,EAAQ,kBAAkB,EAAE,OAAO,SAAUmB,GAAKC,GAAK;AAC1F,aAAAD,EAAInB,EAAQ,mBAAmBoB,CAAG,CAAC,IAAIA,GAChCD;AAAA,IACX,GAAG,CAAA,CAAE;AACL,QAAIE,IAAmB,oBAAI,QAAO,GAC9BC,IAAqB,oBAAI,QAAO,GAIhCC;AAAA;AAAA,OAA+B,WAAY;AAK3C,iBAASA,EAAcrR,GAAO8I,GAAQ;AAClC,UAAAqI,EAAiB,IAAI,MAAMrI,CAAM,GACjCsI,EAAmB,IAAI,MAAMpR,EAAM,cAAc,GACjD,KAAK,QAAQA,EAAM,cACnB,KAAK,QAAQA,EAAM;AAAA,QAC3B;AACI,sBAAO,eAAeqR,EAAc,WAAW,UAAU;AAAA;AAAA;AAAA;AAAA,UAIrD,KAAK,WAAY;AACb,mBAAOD,EAAmB,IAAI,IAAI;AAAA,UAC9C;AAAA,UACQ,YAAY;AAAA,UACZ,cAAc;AAAA,QACtB,CAAK,GACD,OAAO,eAAeC,EAAc,WAAW,QAAQ;AAAA;AAAA;AAAA;AAAA,UAInD,KAAK,WAAY;AACb,mBAAIvB,EAAQ,mBAAmB,KAAK,MAAM,IAC/BA,EAAQ,mBAAmB,KAAK,MAAM,IAGtC;AAAA,UAEvB;AAAA,UACQ,YAAY;AAAA,UACZ,cAAc;AAAA,QACtB,CAAK,GACD,OAAO,eAAeuB,EAAc,WAAW,QAAQ;AAAA;AAAA;AAAA;AAAA,UAInD,KAAK,WAAY;AACb,gBAAIvI,IAASqI,EAAiB,IAAI,IAAI;AACtC,mBAAOrI,EAAO,eAAe,KAAK,KAAK;AAAA,UACnD;AAAA,UACQ,KAAK,SAAUnK,GAAG;AACd,gBAAImK,IAASqI,EAAiB,IAAI,IAAI;AACtC,iBAAK,QAAQrI,EAAO,eAAenK,CAAC;AAAA,UAChD;AAAA,UACQ,YAAY;AAAA,UACZ,cAAc;AAAA,QACtB,CAAK,GACD0S,EAAc,UAAU,SAAS,WAAY;AACzC,iBAAO;AAAA,YACH,QAAQ,KAAK;AAAA,YACb,OAAO,KAAK;AAAA,YACZ,MAAM,KAAK;AAAA,YACX,OAAO,KAAK;AAAA;QAExB,GACWA;AAAA,MACX;;AACAvB,IAAAA,EAAA,gBAAwBuB;AAAA;;;;;UC/FxB,OAAO,eAAeC,GAAS,cAAc,EAAE,OAAO,IAAM,GAC5DA,EAAA,uBAA+B;AAC/B,MAAIC,IAAkBrC,GAAA;AAKtB,WAASsC,IAAuB;AAC5B,WAAO,IAAI,MAAM,IAAI;AAAA;AAAA,MAEjB,KAAK,SAAUC,GAAQC,GAAS;AAC5B,YAAID,EAAOC,CAAO;AACd,iBAAOD,EAAOC,CAAO;AAEpB,YAAIH,EAAgB,iBAAiB,eAAeG,CAAO;AAC5D,iBAAOD,EAAOF,EAAgB,iBAAiBG,CAAO,CAAC;AAAA,MAEvE;AAAA;AAAA,MAEQ,KAAK,SAAUD,GAAQC,GAAStN,GAAO;AACnC,eAAImN,EAAgB,iBAAiB,eAAeG,CAAO,IACvDD,EAAOF,EAAgB,iBAAiBG,CAAO,CAAC,IAAItN,IAGpDqN,EAAOC,CAAO,IAAItN,GAEf;AAAA,MACnB;AAAA,IACA,CAAK;AAAA,EACL;AACA,SAAAkN,EAAA,uBAA+BE;;;;;UC9B/B,OAAO,eAAeG,GAAS,cAAc,EAAE,OAAO,IAAM,GAC5DA,EAAA,YAAoB;AACpB,MAAIR,IAAmB,oBAAI,QAAO,GAI9BS;AAAAA;AAAAA,KAA2B,WAAY;AAKvC,eAASA,EAAU5R,GAAO8I,GAAQ;AAC9B,QAAAqI,EAAiB,IAAI,MAAMrI,CAAM,GACjC,KAAK,QAAQ9I,EAAM,cACnB,KAAK,QAAQA,EAAM;AAAA,MAC3B;AACI,oBAAO,eAAe4R,EAAU,WAAW,QAAQ;AAAA;AAAA;AAAA;AAAA,QAI/C,KAAK,WAAY;AACb,cAAI9I,IAASqI,EAAiB,IAAI,IAAI;AACtC,iBAAOrI,EAAO,eAAe,KAAK,KAAK;AAAA,QACnD;AAAA,QACQ,KAAK,SAAUnK,GAAG;AACd,cAAImK,IAASqI,EAAiB,IAAI,IAAI;AACtC,eAAK,QAAQrI,EAAO,eAAenK,CAAC;AAAA,QAChD;AAAA,QACQ,YAAY;AAAA,QACZ,cAAc;AAAA,MACtB,CAAK,GACDiT,EAAU,UAAU,SAAS,WAAY;AACrC,eAAO;AAAA,UACH,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,OAAO,KAAK;AAAA;MAExB,GACWA;AAAA,IACX;;AACAD,SAAAA,EAAA,YAAoBC;;;;wBCxCpB,OAAO,eAAeC,GAAS,cAAc,EAAE,OAAO,IAAM,GAC5DA,EAAA,mBAA2BA,EAAA,uBAA+BA,EAAA,sBAA8B,QACxFA,EAAA,sBAA8B;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,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","x_google_ignoreList":[20,21,22,23,24,25,26,27,28,29,30,31,32,33,34]}