guitarpro-parser 1.0.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,"sources":["../src/pitch.ts","../src/dom.ts","../src/gpx-parser.ts","../src/gp5-parser.ts","../src/tab-parser.ts"],"sourcesContent":["/**\n * Copyright 2026 Emilien Bevierre\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Minimal pitch utilities — inlined from GuitarWeaver's pitch.ts to make\n * this package fully self-contained with zero external dependencies.\n */\n\n/** Chromatic pitch class: 0 = C, 1 = C#/Db, ..., 11 = B */\nexport type PitchClass = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;\n\nexport type Accidental = 'sharp' | 'flat' | 'natural';\n\nexport interface Note {\n\tpitchClass: PitchClass;\n\tname: string;\n\taccidental: Accidental;\n\toctave?: number;\n}\n\nconst SHARP_NAMES: Record<PitchClass, string> = {\n\t0: 'C',\n\t1: 'C#',\n\t2: 'D',\n\t3: 'D#',\n\t4: 'E',\n\t5: 'F',\n\t6: 'F#',\n\t7: 'G',\n\t8: 'G#',\n\t9: 'A',\n\t10: 'A#',\n\t11: 'B'\n};\n\nconst FLAT_NAMES: Record<PitchClass, string> = {\n\t0: 'C',\n\t1: 'Db',\n\t2: 'D',\n\t3: 'Eb',\n\t4: 'E',\n\t5: 'F',\n\t6: 'Gb',\n\t7: 'G',\n\t8: 'Ab',\n\t9: 'A',\n\t10: 'Bb',\n\t11: 'B'\n};\n\nconst NATURAL_PITCH_CLASSES = new Set<PitchClass>([0, 2, 4, 5, 7, 9, 11]);\n\nfunction resolveAccidental(pc: PitchClass, preferFlats: boolean): Accidental {\n\tif (NATURAL_PITCH_CLASSES.has(pc)) return 'natural';\n\treturn preferFlats ? 'flat' : 'sharp';\n}\n\n/** Builds a Note from a pitch class, with optional octave and flat preference. */\nexport function noteFromPitchClass(\n\tpc: PitchClass,\n\tpreferFlats = false,\n\toctave?: number\n): Note {\n\tconst name = preferFlats ? FLAT_NAMES[pc] : SHARP_NAMES[pc];\n\treturn {\n\t\tpitchClass: pc,\n\t\tname,\n\t\taccidental: resolveAccidental(pc, preferFlats),\n\t\toctave\n\t};\n}\n\n/** Converts MIDI note number to PitchClass. */\nexport function midiToPitchClass(midi: number): PitchClass {\n\treturn (((midi % 12) + 12) % 12) as PitchClass;\n}\n","/**\n * Copyright 2026 Emilien Bevierre\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * DOMParser abstraction — uses browser-native DOMParser when available,\n * falls back to linkedom for Node.js environments.\n */\n\ntype DOMParserConstructor = new () => DOMParser;\n\n/** Returns a DOMParser constructor that works in both browser and Node.js. */\nexport function getDOMParser(): DOMParserConstructor {\n\tif (typeof globalThis.DOMParser !== 'undefined') {\n\t\treturn globalThis.DOMParser;\n\t}\n\n\t// Node.js: use linkedom (provides full DOM with querySelector support)\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports\n\t\tconst linkedom = require('linkedom');\n\t\treturn linkedom.DOMParser as DOMParserConstructor;\n\t} catch {\n\t\tthrow new Error(\n\t\t\t'DOMParser is not available. In Node.js, install linkedom: npm install linkedom'\n\t\t);\n\t}\n}\n","/**\n * Copyright 2026 Emilien Bevierre\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * GPX parser : decodes Guitar Pro (.gpx) binary files and transforms them\n * directly into TabSong structures. Pure, zero native dependencies.\n *\n * Pipeline: Uint8Array → BCFZ/BCFS decode → extract score.gpif XML → DOMParser → TabSong\n */\n\nimport type { PitchClass, Note } from './pitch.js';\nimport { noteFromPitchClass, midiToPitchClass } from './pitch.js';\nimport type {\n\tDuration,\n\tTabNote,\n\tTabBeat,\n\tTabBar,\n\tTabTrack,\n\tTabSong\n} from './types.js';\nimport { getDOMParser } from './dom.js';\n\n// ---------------------------------------------------------------------------\n// Duration helpers (public — used by playback engine)\n// ---------------------------------------------------------------------------\n\n/** Maps Duration enum to beat fraction (quarter note = 1.0). */\nconst DURATION_BEATS: Record<string, number> = {\n\twhole: 4,\n\thalf: 2,\n\tquarter: 1,\n\teighth: 0.5,\n\t'16th': 0.25,\n\t'32nd': 0.125,\n\t'64th': 0.0625,\n\t'128th': 0.03125\n};\n\n/** Converts a rhythm value to a beat fraction accounting for dots and tuplets. */\nexport function durationToBeats(\n\tduration: Duration,\n\tdotCount: number,\n\ttuplet: { num: number; den: number } | null\n): number {\n\tlet beats = DURATION_BEATS[duration] ?? 1;\n\n\t// Augmentation dots: each dot adds half of the previous value\n\tlet dotValue = beats;\n\tfor (let i = 0; i < dotCount; i++) {\n\t\tdotValue /= 2;\n\t\tbeats += dotValue;\n\t}\n\n\t// Tuplet: e.g. triplet = 3 notes in the space of 2 → multiply by den/num\n\tif (tuplet && tuplet.num > 0) {\n\t\tbeats *= tuplet.den / tuplet.num;\n\t}\n\n\treturn beats;\n}\n\n/** Computes the duration in milliseconds for a beat at its tempo. */\nexport function beatDurationMs(beat: TabBeat): number {\n\tconst beatFraction = durationToBeats(beat.duration, beat.dotted, beat.tuplet);\n\tconst quarterNoteMs = 60000 / beat.tempo;\n\treturn beatFraction * quarterNoteMs;\n}\n\n// ---------------------------------------------------------------------------\n// BCFZ / BCFS binary decoder — pure DataView, no jDataView / Node deps\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps a DataView with a position cursor and jDataView-compatible bit-level reading.\n * Bit reads are MSB-first with a persistent bit offset that carries across calls,\n * matching jDataView.getUnsigned() semantics exactly.\n */\nclass BinaryReader {\n\tprivate view: DataView;\n\tprivate bytes: Uint8Array;\n\tprivate pos: number;\n\tprivate bitOffset: number;\n\treadonly byteLength: number;\n\n\tconstructor(buffer: ArrayBuffer) {\n\t\tthis.view = new DataView(buffer);\n\t\tthis.bytes = new Uint8Array(buffer);\n\t\tthis.pos = 0;\n\t\tthis.bitOffset = 0;\n\t\tthis.byteLength = buffer.byteLength;\n\t}\n\n\tseek(offset: number): void {\n\t\tthis.pos = offset;\n\t\tthis.bitOffset = 0;\n\t}\n\n\tgetPosition(): number {\n\t\treturn this.pos;\n\t}\n\n\tgetUint8(): number {\n\t\tthis.bitOffset = 0;\n\t\tconst v = this.view.getUint8(this.pos);\n\t\tthis.pos += 1;\n\t\treturn v;\n\t}\n\n\tgetUint32LE(offset?: number): number {\n\t\tthis.bitOffset = 0;\n\t\tif (offset !== undefined) {\n\t\t\treturn this.view.getUint32(offset, true);\n\t\t}\n\t\tconst v = this.view.getUint32(this.pos, true);\n\t\tthis.pos += 4;\n\t\treturn v;\n\t}\n\n\tgetString(length: number): string {\n\t\tthis.bitOffset = 0;\n\t\tconst chars: number[] = [];\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tchars.push(this.view.getUint8(this.pos + i));\n\t\t}\n\t\tthis.pos += length;\n\t\treturn String.fromCharCode(...chars);\n\t}\n\n\tgetZeroTerminatedString(offset: number, maxLength: number): string {\n\t\tconst chars: number[] = [];\n\t\tfor (let i = 0; i < maxLength; i++) {\n\t\t\tconst code = this.view.getUint8(offset + i) & 0xff;\n\t\t\tif (code === 0) break;\n\t\t\tchars.push(code);\n\t\t}\n\t\treturn String.fromCharCode(...chars);\n\t}\n\n\tgetBytes(length: number, offset?: number): Uint8Array {\n\t\tthis.bitOffset = 0;\n\t\tconst start = offset !== undefined ? offset : this.pos;\n\t\tif (offset === undefined) this.pos += length;\n\t\treturn new Uint8Array(this.view.buffer, start, length);\n\t}\n\n\t/**\n\t * Reads `bitLength` bits as an unsigned integer (MSB-first), matching\n\t * jDataView.getUnsigned() semantics: a persistent bitOffset carries across\n\t * calls, and bits are read big-endian from the byte stream.\n\t */\n\tgetUnsigned(bitLength: number): number {\n\t\tconst startBit = (this.pos << 3) + this.bitOffset;\n\t\tconst endBit = startBit + bitLength;\n\n\t\t// Byte range we need to read\n\t\tconst startByte = startBit >>> 3;\n\t\tconst endByte = (endBit + 7) >>> 3;\n\n\t\t// Update position: advance to the byte containing the last bit\n\t\tthis.bitOffset = endBit & 7;\n\t\tif (this.bitOffset !== 0) {\n\t\t\tthis.pos = (endBit >>> 3);\n\t\t} else {\n\t\t\tthis.pos = endBit >>> 3;\n\t\t}\n\n\t\t// Build wide value from the spanning bytes (MSB-first)\n\t\tlet wideValue = 0;\n\t\tfor (let i = startByte; i < endByte; i++) {\n\t\t\twideValue = (wideValue << 8) | (this.bytes[i] ?? 0);\n\t\t}\n\n\t\t// Right-shift to discard trailing bits we don't need\n\t\tconst trailingBits = (endByte << 3) - endBit;\n\t\twideValue = wideValue >>> trailingBits;\n\n\t\t// Mask to the requested bit length\n\t\tif (bitLength < 32) {\n\t\t\twideValue = wideValue & ((1 << bitLength) - 1);\n\t\t}\n\n\t\treturn wideValue;\n\t}\n}\n\n/** Reads `count` bits in reversed order (LSB first). */\nfunction readBitsReversed(reader: BinaryReader, count: number): number {\n\tlet bits = 0;\n\tfor (let i = 0; i < count; i++) {\n\t\tbits |= reader.getUnsigned(1) << i;\n\t}\n\treturn bits;\n}\n\ninterface InternalFile {\n\tname: string;\n\tsize: number;\n\tdata: Uint8Array | null;\n}\n\n/** Determines if a file from the BCFS container should be extracted. */\nfunction isFileToStore(name: string): boolean {\n\treturn name === 'score.gpif' || name === 'misc.xml';\n}\n\n/** Decompresses BCFZ block data using the custom LZ-style algorithm. */\nfunction decompressBlock(reader: BinaryReader, skipHeader: boolean): ArrayBuffer {\n\tconst expectedLength = reader.getUint32LE();\n\tconst temp = new Uint8Array(expectedLength);\n\tlet pos = 0;\n\n\ttry {\n\t\twhile (pos < expectedLength) {\n\t\t\tconst flag = reader.getUnsigned(1);\n\n\t\t\tif (flag === 1) {\n\t\t\t\tconst wordSize = reader.getUnsigned(4);\n\t\t\t\tconst offset = readBitsReversed(reader, wordSize);\n\t\t\t\tconst size = readBitsReversed(reader, wordSize);\n\n\t\t\t\tconst sourcePosition = pos - offset;\n\t\t\t\tconst readSize = Math.min(offset, size);\n\n\t\t\t\tfor (let i = 0; i < readSize; i++) {\n\t\t\t\t\ttemp[pos + i] = temp[sourcePosition + i];\n\t\t\t\t}\n\t\t\t\tpos += readSize;\n\t\t\t} else {\n\t\t\t\tconst size = readBitsReversed(reader, 2);\n\n\t\t\t\tfor (let i = 0; i < size; i++) {\n\t\t\t\t\ttemp[pos++] = reader.getUnsigned(8);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// End-of-block reached — partial decompression is acceptable\n\t}\n\n\tif (skipHeader) {\n\t\treturn temp.buffer.slice(4, temp.byteLength);\n\t}\n\treturn temp.buffer;\n}\n\n/** Parses the sector-based block filesystem from a BCFS/BCFZ container. */\nfunction parseBlockFilesystem(buffer: ArrayBuffer): InternalFile[] {\n\tconst SECTOR_SIZE = 0x1000;\n\tconst reader = new BinaryReader(buffer);\n\tlet offset = SECTOR_SIZE;\n\tconst files: InternalFile[] = [];\n\n\twhile (offset + SECTOR_SIZE + 3 < reader.byteLength) {\n\t\tconst entryType = reader.getUint32LE(offset);\n\n\t\tif (entryType === 2) {\n\t\t\tconst name = reader.getZeroTerminatedString(offset + 0x04, 127);\n\t\t\tconst size = reader.getUint32LE(offset + 0x8c);\n\n\t\t\tconst file: InternalFile = { name, size, data: null };\n\t\t\tfiles.push(file);\n\n\t\t\tconst store = isFileToStore(name);\n\t\t\tconst blocksOffset = offset + 0x94;\n\n\t\t\tconst dataChunks: Uint8Array[] = [];\n\t\t\tlet blockCount = 0;\n\t\t\tlet blockId: number;\n\n\t\t\twhile ((blockId = reader.getUint32LE(blocksOffset + 4 * blockCount)) !== 0) {\n\t\t\t\tconst blockOffset = blockId * SECTOR_SIZE;\n\n\t\t\t\tif (store) {\n\t\t\t\t\tconst max = blockOffset + SECTOR_SIZE;\n\t\t\t\t\tconst blockSize =\n\t\t\t\t\t\tmax > reader.byteLength\n\t\t\t\t\t\t\t? SECTOR_SIZE - (max - reader.byteLength)\n\t\t\t\t\t\t\t: SECTOR_SIZE;\n\t\t\t\t\tdataChunks.push(reader.getBytes(blockSize, blockOffset));\n\t\t\t\t}\n\n\t\t\t\tblockCount++;\n\t\t\t}\n\n\t\t\tif (store && dataChunks.length > 0) {\n\t\t\t\tconst totalSize = dataChunks.reduce((s, c) => s + c.length, 0);\n\t\t\t\tconst combined = new Uint8Array(Math.max(size, totalSize));\n\t\t\t\tlet writePos = 0;\n\t\t\t\tfor (const chunk of dataChunks) {\n\t\t\t\t\tcombined.set(chunk, writePos);\n\t\t\t\t\twritePos += chunk.length;\n\t\t\t\t}\n\t\t\t\tfile.data = combined.subarray(0, Math.min(size, totalSize));\n\t\t\t}\n\t\t}\n\n\t\toffset += SECTOR_SIZE;\n\t}\n\n\treturn files;\n}\n\n/** Top-level decoder: reads header, decompresses if needed, extracts files. */\nfunction decodeGpxBinary(data: Uint8Array): Map<string, string> {\n\t// Copy into a fresh ArrayBuffer to avoid SharedArrayBuffer issues\n\tconst buf = new ArrayBuffer(data.byteLength);\n\tnew Uint8Array(buf).set(data);\n\tconst reader = new BinaryReader(buf);\n\tconst header = reader.getString(4);\n\n\tlet filesystemBuffer: ArrayBuffer;\n\n\tswitch (header) {\n\t\tcase 'BCFZ':\n\t\t\tfilesystemBuffer = decompressBlock(reader, true);\n\t\t\tbreak;\n\t\tcase 'BCFS': {\n\t\t\tconst raw = reader.getBytes(reader.byteLength - 4);\n\t\t\tconst copy = new ArrayBuffer(raw.byteLength);\n\t\t\tnew Uint8Array(copy).set(raw);\n\t\t\tfilesystemBuffer = copy;\n\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tthrow new Error(`Bad GPX header: \"${header}\" (unsupported format)`);\n\t}\n\n\tconst files = parseBlockFilesystem(filesystemBuffer);\n\tconst result = new Map<string, string>();\n\n\tfor (const file of files) {\n\t\tif (file.data && isFileToStore(file.name)) {\n\t\t\tconst decoder = new TextDecoder('utf-8');\n\t\t\tresult.set(file.name, decoder.decode(file.data));\n\t\t}\n\t}\n\n\treturn result;\n}\n\n// ---------------------------------------------------------------------------\n// XML → TabSong transformer (replaces both gpifReducer + gpx-adapter)\n// ---------------------------------------------------------------------------\n\n/** Safely reads text content of a child element by tag name. */\nfunction childText(el: Element, tag: string): string | null {\n\tconst child = el.querySelector(`:scope > ${tag}`);\n\treturn child?.textContent?.trim() ?? null;\n}\n\n/** Parses a time signature string like \"4/4\" into { numerator, denominator }. */\nfunction parseTimeSignature(time: string | null): { numerator: number; denominator: number } {\n\tif (!time) return { numerator: 4, denominator: 4 };\n\tconst parts = time.split('/');\n\treturn {\n\t\tnumerator: parseInt(parts[0], 10) || 4,\n\t\tdenominator: parseInt(parts[1], 10) || 4\n\t};\n}\n\n/** Computes pitch class from string tuning + fret. */\nfunction pitchClassFromStringFret(tuningPitches: number[], stringIndex: number, fret: number): PitchClass {\n\tconst openPitch = tuningPitches[stringIndex] ?? 0;\n\treturn (((openPitch + fret) % 12 + 12) % 12) as PitchClass;\n}\n\n/** Parses tuning pitches string (e.g. \"40 45 50 55 59 64\") into MIDI note numbers. */\nfunction parseTuningPitches(pitchesStr: string): number[] {\n\treturn pitchesStr\n\t\t.split(/\\s+/)\n\t\t.filter((s) => s.length > 0)\n\t\t.map(Number);\n}\n\n// ---------------------------------------------------------------------------\n// Note property extraction from XML\n// ---------------------------------------------------------------------------\n\n/** Finds a <Property name=\"X\"> child element and returns its first child element. */\nfunction findProperty(propertiesEl: Element | null, name: string): Element | null {\n\tif (!propertiesEl) return null;\n\tconst props = propertiesEl.querySelectorAll(':scope > Property');\n\tfor (const prop of props) {\n\t\tif (prop.getAttribute('name') === name) return prop;\n\t}\n\treturn null;\n}\n\n/** Reads the text of the first child element of a property element. */\nfunction propValue(propertiesEl: Element | null, name: string): string | null {\n\tconst prop = findProperty(propertiesEl, name);\n\tif (!prop) return null;\n\tconst firstChild = prop.firstElementChild;\n\treturn firstChild?.textContent?.trim() ?? null;\n}\n\n/** Reads a boolean-enable property (e.g. <Enable /> present means true). */\nfunction propEnabled(propertiesEl: Element | null, name: string): boolean {\n\tconst prop = findProperty(propertiesEl, name);\n\tif (!prop) return null as unknown as boolean;\n\treturn prop.querySelector('Enable') !== null;\n}\n\n/** Reads numeric flags from a property (e.g. Slide flags). */\nfunction propFlags(propertiesEl: Element | null, name: string): number | null {\n\tconst prop = findProperty(propertiesEl, name);\n\tif (!prop) return null;\n\tconst flagsEl = prop.querySelector('Flags');\n\tif (!flagsEl) return null;\n\tconst val = parseInt(flagsEl.textContent?.trim() ?? '', 10);\n\treturn isNaN(val) ? null : val;\n}\n\n/** Reads a float value from a property child element. */\nfunction propFloat(propertiesEl: Element | null, name: string): number | null {\n\tconst prop = findProperty(propertiesEl, name);\n\tif (!prop) return null;\n\tconst floatEl = prop.querySelector('Float');\n\tif (!floatEl) return null;\n\tconst val = parseFloat(floatEl.textContent?.trim() ?? '');\n\treturn isNaN(val) ? null : val;\n}\n\n/** Reads the HType value from a HarmonicType property. */\nfunction propHType(propertiesEl: Element | null, name: string): string | null {\n\tconst prop = findProperty(propertiesEl, name);\n\tif (!prop) return null;\n\tconst htypeEl = prop.querySelector('HType');\n\treturn htypeEl?.textContent?.trim() ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Note transformation from XML element\n// ---------------------------------------------------------------------------\n\n/** Transforms a <Note> XML element into a TabNote. */\nfunction transformNoteElement(noteEl: Element, tuningPitches: number[]): TabNote {\n\tconst propsEl = noteEl.querySelector(':scope > Properties');\n\n\tconst stringIndex = parseInt(propValue(propsEl, 'String') ?? '0', 10);\n\tconst fret = parseInt(propValue(propsEl, 'Fret') ?? '0', 10);\n\n\tconst pc = pitchClassFromStringFret(tuningPitches, stringIndex, fret);\n\tconst note = noteFromPitchClass(pc, false);\n\n\tconst isBended = propEnabled(propsEl, 'Bended');\n\tconst bend = isBended\n\t\t? {\n\t\t\t\torigin: propFloat(propsEl, 'BendOriginValue') ?? 0,\n\t\t\t\tdestination: propFloat(propsEl, 'BendDestinationValue') ?? 0,\n\t\t\t\tmiddle: propFloat(propsEl, 'BendMiddleValue') ?? 0\n\t\t\t}\n\t\t: null;\n\n\tconst tieEl = noteEl.querySelector(':scope > Tie');\n\tconst letRingEl = noteEl.querySelector(':scope > LetRing');\n\tconst vibratoEl = noteEl.querySelector(':scope > Vibrato');\n\tconst accentEl = noteEl.querySelector(':scope > Accent');\n\n\treturn {\n\t\tstring: stringIndex,\n\t\tfret,\n\t\tpitchClass: pc,\n\t\tnoteName: note.name,\n\t\tslide: propFlags(propsEl, 'Slide'),\n\t\tharmonic: propHType(propsEl, 'HarmonicType'),\n\t\tpalmMute: propEnabled(propsEl, 'PalmMuted') ?? false,\n\t\tmuted: propEnabled(propsEl, 'Muted') ?? false,\n\t\tletRing: letRingEl !== null,\n\t\tbend,\n\t\ttie: {\n\t\t\torigin: tieEl ? tieEl.getAttribute('origin') === 'true' : false,\n\t\t\tdestination: tieEl ? tieEl.getAttribute('destination') === 'true' : false\n\t\t},\n\t\tvibrato: vibratoEl?.textContent?.trim() ?? null,\n\t\thammerOn: propEnabled(propsEl, 'HopoOrigin') ?? false,\n\t\tpullOff: propEnabled(propsEl, 'HopoDestination') ?? false,\n\t\ttapped: propEnabled(propsEl, 'Tapped') ?? false,\n\t\taccent: accentEl ? parseInt(accentEl.textContent?.trim() ?? '', 10) || null : null\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Main parser : XML DOM → TabSong\n// ---------------------------------------------------------------------------\n\n/** Builds a Map from id attribute to Element for all children of a container. */\nfunction indexElements(container: Element | null, childTag: string): Map<string, Element> {\n\tconst map = new Map<string, Element>();\n\tif (!container) return map;\n\tconst children = container.querySelectorAll(`:scope > ${childTag}`);\n\tfor (const child of children) {\n\t\tconst id = child.getAttribute('id');\n\t\tif (id) map.set(id, child);\n\t}\n\treturn map;\n}\n\n/** Splits a space-separated ID string into an array of trimmed strings. */\nfunction splitIds(text: string | null): string[] {\n\tif (!text) return [];\n\treturn text.split(/\\s+/).filter((s) => s.length > 0);\n}\n\n/** Builds a bar-index → tempo map from MasterTrack Automations. */\nfunction buildTempoMap(masterTrackEl: Element | null): Map<number, number> {\n\tconst tempoMap = new Map<number, number>();\n\tif (!masterTrackEl) return tempoMap;\n\n\tconst automationsEl = masterTrackEl.querySelector(':scope > Automations');\n\tif (!automationsEl) return tempoMap;\n\n\tconst autos = automationsEl.querySelectorAll(':scope > Automation');\n\tfor (const auto of autos) {\n\t\tconst type = childText(auto, 'Type');\n\t\tif (type?.toLowerCase() !== 'tempo') continue;\n\n\t\tconst barText = childText(auto, 'Bar');\n\t\tconst valueText = childText(auto, 'Value');\n\t\tif (barText === null || valueText === null) continue;\n\n\t\tconst barIndex = parseInt(barText, 10);\n\t\tconst value = parseFloat(valueText);\n\t\tif (!isNaN(barIndex) && !isNaN(value)) {\n\t\t\ttempoMap.set(barIndex, value);\n\t\t}\n\t}\n\treturn tempoMap;\n}\n\n/** Resolves the tempo at a given bar index by walking backwards through the tempo map. */\nfunction tempoAtBar(barIndex: number, tempoMap: Map<number, number>, defaultTempo: number): number {\n\tfor (let i = barIndex; i >= 0; i--) {\n\t\tconst t = tempoMap.get(i);\n\t\tif (t !== undefined) return t;\n\t}\n\treturn defaultTempo;\n}\n\n/** Transforms GPIF XML DOM into a TabSong. Exported for reuse by GP7+ ZIP parser. */\nexport function gpifToTabSong(doc: Document): TabSong {\n\tconst gpif = doc.querySelector('GPIF');\n\tif (!gpif) throw new Error('Invalid GPIF XML: no <GPIF> root element');\n\n\t// Score metadata\n\tconst scoreEl = gpif.querySelector(':scope > Score');\n\tconst title = scoreEl ? childText(scoreEl, 'Title') ?? '' : '';\n\tconst artist = scoreEl ? childText(scoreEl, 'Artist') ?? '' : '';\n\tconst album = scoreEl ? childText(scoreEl, 'Album') ?? '' : '';\n\n\t// Build lookup maps for all ID-referenced entities\n\tconst noteMap = indexElements(gpif.querySelector(':scope > Notes'), 'Note');\n\tconst beatMap = indexElements(gpif.querySelector(':scope > Beats'), 'Beat');\n\tconst voiceMap = indexElements(gpif.querySelector(':scope > Voices'), 'Voice');\n\tconst barMap = indexElements(gpif.querySelector(':scope > Bars'), 'Bar');\n\tconst rhythmMap = indexElements(gpif.querySelector(':scope > Rhythms'), 'Rhythm');\n\n\t// MasterBars\n\tconst masterBarsEl = gpif.querySelector(':scope > MasterBars');\n\tconst masterBarEls = masterBarsEl\n\t\t? Array.from(masterBarsEl.querySelectorAll(':scope > MasterBar'))\n\t\t: [];\n\n\t// Tempo map from MasterTrack automations\n\tconst masterTrackEl = gpif.querySelector(':scope > MasterTrack');\n\tconst tempoMap = buildTempoMap(masterTrackEl);\n\n\tlet initialTempo = 120;\n\tif (tempoMap.size > 0) {\n\t\tinitialTempo = tempoMap.get(0) ?? 120;\n\t}\n\n\t// Tracks\n\tconst tracksEl = gpif.querySelector(':scope > Tracks');\n\tconst trackEls = tracksEl ? Array.from(tracksEl.querySelectorAll(':scope > Track')) : [];\n\n\tconst tracks: TabTrack[] = trackEls.map((trackEl) =>\n\t\ttransformTrackElement(\n\t\t\ttrackEl,\n\t\t\tmasterBarEls,\n\t\t\tbarMap,\n\t\t\tvoiceMap,\n\t\t\tbeatMap,\n\t\t\tnoteMap,\n\t\t\trhythmMap,\n\t\t\ttempoMap,\n\t\t\tinitialTempo\n\t\t)\n\t);\n\n\treturn { title, artist, album, tempo: initialTempo, tracks };\n}\n\n/** Transforms a single <Track> element into a TabTrack. */\nfunction transformTrackElement(\n\ttrackEl: Element,\n\tmasterBarEls: Element[],\n\tbarMap: Map<string, Element>,\n\tvoiceMap: Map<string, Element>,\n\tbeatMap: Map<string, Element>,\n\tnoteMap: Map<string, Element>,\n\trhythmMap: Map<string, Element>,\n\ttempoMap: Map<number, number>,\n\tdefaultTempo: number\n): TabTrack {\n\tconst trackId = trackEl.getAttribute('id') ?? '0';\n\n\t// Extract tuning from track Properties\n\tconst propsEl = trackEl.querySelector(':scope > Properties');\n\tlet tuningPitches = [40, 45, 50, 55, 59, 64]; // Standard guitar tuning MIDI values\n\tlet capoFret = 0;\n\n\tif (propsEl) {\n\t\tconst tuningProp = findProperty(propsEl, 'Tuning');\n\t\tif (tuningProp) {\n\t\t\tconst pitchesEl = tuningProp.querySelector('Pitches');\n\t\t\tif (pitchesEl?.textContent) {\n\t\t\t\ttuningPitches = parseTuningPitches(pitchesEl.textContent.trim());\n\t\t\t}\n\t\t}\n\n\t\tconst capoProp = findProperty(propsEl, 'CapoFret');\n\t\tif (capoProp) {\n\t\t\tconst fretEl = capoProp.querySelector('Fret');\n\t\t\tif (fretEl?.textContent) {\n\t\t\t\tconst parsed = parseInt(fretEl.textContent.trim(), 10);\n\t\t\t\tif (!isNaN(parsed)) capoFret = parsed;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Convert MIDI pitches to Note[] (reversed: GPX stores high-to-low, we want low-to-high)\n\tconst tuning: Note[] = tuningPitches\n\t\t.map((midi) => noteFromPitchClass(midiToPitchClass(midi)))\n\t\t.reverse();\n\n\t// Determine track index for bar resolution\n\tconst trackIndex = parseInt(trackId, 10);\n\tlet globalBeatIndex = 0;\n\tconst bars: TabBar[] = [];\n\n\tfor (let mbIdx = 0; mbIdx < masterBarEls.length; mbIdx++) {\n\t\tconst masterBarEl = masterBarEls[mbIdx];\n\n\t\t// Bars element contains space-separated bar IDs\n\t\tconst barsText = childText(masterBarEl, 'Bars');\n\t\tconst barIds = splitIds(barsText);\n\n\t\tconst barId = barIds[trackIndex] ?? barIds[0];\n\t\tconst barEl = barId ? barMap.get(barId) : undefined;\n\n\t\tif (!barEl) {\n\t\t\tbars.push(makeEmptyBar(mbIdx, masterBarEl));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Parse time signature\n\t\tconst timeText = childText(masterBarEl, 'Time');\n\t\tconst timeSig = parseTimeSignature(timeText);\n\n\t\t// Parse key signature\n\t\tconst keyEl = masterBarEl.querySelector(':scope > Key');\n\t\tconst keySig = keyEl\n\t\t\t? {\n\t\t\t\t\taccidentalCount: parseInt(childText(keyEl, 'AccidentalCount') ?? '0', 10),\n\t\t\t\t\tmode: (childText(keyEl, 'Mode')?.toLowerCase() ?? 'major') as 'major' | 'minor'\n\t\t\t\t}\n\t\t\t: null;\n\n\t\t// Parse section\n\t\tconst sectionEl = masterBarEl.querySelector(':scope > Section');\n\t\tconst section = sectionEl\n\t\t\t? {\n\t\t\t\t\tletter: sectionEl.getAttribute('letter') ?? undefined,\n\t\t\t\t\ttext: sectionEl.getAttribute('text') ?? undefined\n\t\t\t\t}\n\t\t\t: null;\n\n\t\t// Parse repeat\n\t\tconst repeatEl = masterBarEl.querySelector(':scope > Repeat');\n\t\tconst repeatStart = repeatEl ? repeatEl.getAttribute('start') === 'true' : false;\n\t\tconst repeatEnd = repeatEl ? repeatEl.getAttribute('end') === 'true' : false;\n\t\tconst repeatCount = repeatEl ? parseInt(repeatEl.getAttribute('count') ?? '0', 10) || 0 : 0;\n\n\t\t// Resolve beats from the bar's voices\n\t\tconst voicesText = childText(barEl, 'Voices');\n\t\tconst voiceIds = splitIds(voicesText);\n\t\tconst tabBeats: TabBeat[] = [];\n\t\tconst currentTempo = tempoAtBar(mbIdx, tempoMap, defaultTempo);\n\n\t\t// Use first voice (primary voice)\n\t\tif (voiceIds.length > 0) {\n\t\t\tconst voiceEl = voiceMap.get(voiceIds[0]);\n\t\t\tif (voiceEl) {\n\t\t\t\tconst voiceBeatsText = childText(voiceEl, 'Beats');\n\t\t\t\tconst voiceBeatIds = splitIds(voiceBeatsText);\n\n\t\t\t\tfor (const beatId of voiceBeatIds) {\n\t\t\t\t\tconst beatEl = beatMap.get(beatId);\n\t\t\t\t\tif (!beatEl) continue;\n\n\t\t\t\t\t// Resolve rhythm\n\t\t\t\t\tconst rhythmRef = beatEl.querySelector(':scope > Rhythm')?.getAttribute('ref');\n\t\t\t\t\tconst rhythmEl = rhythmRef ? rhythmMap.get(rhythmRef) : undefined;\n\n\t\t\t\t\t// Resolve notes\n\t\t\t\t\tconst notesText = childText(beatEl, 'Notes');\n\t\t\t\t\tconst noteIds = splitIds(notesText);\n\t\t\t\t\tconst stringCount = tuningPitches.length;\n\t\t\t\t\tconst tabNotes: TabNote[] = noteIds\n\t\t\t\t\t\t.map((nid) => noteMap.get(nid))\n\t\t\t\t\t\t.filter((n): n is Element => n !== undefined)\n\t\t\t\t\t\t.map((n) => transformNoteElement(n, tuningPitches))\n\t\t\t\t\t\t.map((n) => ({ ...n, string: stringCount - 1 - n.string }));\n\n\t\t\t\t\t// Extract duration from rhythm\n\t\t\t\t\tconst noteValueText = rhythmEl\n\t\t\t\t\t\t? childText(rhythmEl, 'NoteValue')\n\t\t\t\t\t\t: null;\n\t\t\t\t\tconst duration = (noteValueText?.toLowerCase() ?? 'quarter') as Duration;\n\n\t\t\t\t\t// Extract tuplet\n\t\t\t\t\tconst tupletEl = rhythmEl?.querySelector(':scope > PrimaryTuplet');\n\t\t\t\t\tconst tuplet = tupletEl\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tnum: parseInt(tupletEl.getAttribute('num') ?? '1', 10) || 1,\n\t\t\t\t\t\t\t\tden: parseInt(tupletEl.getAttribute('den') ?? '1', 10) || 1\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null;\n\n\t\t\t\t\t// Extract dot count\n\t\t\t\t\tconst dotEl = rhythmEl?.querySelector(':scope > AugmentationDot');\n\t\t\t\t\tconst dotCount = dotEl\n\t\t\t\t\t\t? parseInt(dotEl.getAttribute('count') ?? '0', 10) || 0\n\t\t\t\t\t\t: 0;\n\n\t\t\t\t\tconst isRest = tabNotes.length === 0;\n\n\t\t\t\t\t// Extract dynamic\n\t\t\t\t\tconst dynamicText = childText(beatEl, 'Dynamic');\n\n\t\t\t\t\ttabBeats.push({\n\t\t\t\t\t\tindex: globalBeatIndex++,\n\t\t\t\t\t\tbarIndex: mbIdx,\n\t\t\t\t\t\tnotes: tabNotes,\n\t\t\t\t\t\tduration,\n\t\t\t\t\t\ttuplet: tuplet && (tuplet.num !== 1 || tuplet.den !== 1) ? tuplet : null,\n\t\t\t\t\t\tdotted: dotCount,\n\t\t\t\t\t\tisRest,\n\t\t\t\t\t\tdynamic: dynamicText,\n\t\t\t\t\t\ttempo: currentTempo\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbars.push({\n\t\t\tindex: mbIdx,\n\t\t\ttimeSignature: timeSig,\n\t\t\tkeySignature: keySig,\n\t\t\tsection,\n\t\t\tbeats: tabBeats,\n\t\t\trepeatStart,\n\t\t\trepeatEnd,\n\t\t\trepeatCount\n\t\t});\n\t}\n\n\treturn {\n\t\tid: trackId,\n\t\tname: childText(trackEl, 'Name') ?? 'Track',\n\t\tshortName: childText(trackEl, 'ShortName') ?? '',\n\t\tinstrument: trackEl.querySelector(':scope > Instrument')?.getAttribute('ref') ?? null,\n\t\ttuning,\n\t\tcapoFret,\n\t\tbars\n\t};\n}\n\n/** Creates an empty bar placeholder when a bar can't be resolved. */\nfunction makeEmptyBar(index: number, masterBarEl: Element): TabBar {\n\tconst timeText = childText(masterBarEl, 'Time');\n\treturn {\n\t\tindex,\n\t\ttimeSignature: parseTimeSignature(timeText),\n\t\tkeySignature: null,\n\t\tsection: null,\n\t\tbeats: [],\n\t\trepeatStart: false,\n\t\trepeatEnd: false,\n\t\trepeatCount: 0\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Parses a Guitar Pro .gpx file from raw bytes into a TabSong.\n * Pipeline: Uint8Array → BCFZ/BCFS decode → extract score.gpif → DOMParser → TabSong\n */\nexport function parseGpxFile(data: Uint8Array): TabSong {\n\t// Step 1: Decode the binary container\n\tconst files = decodeGpxBinary(data);\n\tconst gpifXml = files.get('score.gpif');\n\tif (!gpifXml) {\n\t\tthrow new Error('No score.gpif found in GPX archive');\n\t}\n\n\t// Step 2: Parse XML using DOMParser (browser-native or @xmldom/xmldom)\n\tconst DOMParserImpl = getDOMParser();\n\tconst parser = new DOMParserImpl();\n\tconst doc = parser.parseFromString(gpifXml, 'text/xml');\n\n\tconst parseError = doc.querySelector('parsererror');\n\tif (parseError) {\n\t\tthrow new Error(`Failed to parse GPIF XML: ${parseError.textContent}`);\n\t}\n\n\t// Step 3: Transform DOM into TabSong\n\treturn gpifToTabSong(doc);\n}\n","/**\n * Copyright 2026 Emilien Bevierre\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * GP5 parser : decodes Guitar Pro 5 (.gp5) binary files and transforms them\n * into TabSong structures. Pure, zero native dependencies.\n *\n * Pipeline: Uint8Array → sequential binary read → TabSong\n *\n * Based on the PyGuitarPro format specification (GP3→GP4→GP5 inheritance chain).\n */\n\nimport type { PitchClass, Note } from './pitch.js';\nimport { noteFromPitchClass, midiToPitchClass } from './pitch.js';\nimport type {\n\tDuration,\n\tTabNote,\n\tTabBeat,\n\tTabBar,\n\tTabTrack,\n\tTabSong\n} from './types.js';\n\n// ---------------------------------------------------------------------------\n// Binary reader — sequential LE reader with position tracking\n// ---------------------------------------------------------------------------\n\nclass GP5Reader {\n\tprivate view: DataView;\n\tprivate buf: Uint8Array;\n\tprivate pos: number;\n\treadonly byteLength: number;\n\n\tconstructor(buffer: ArrayBuffer) {\n\t\tthis.view = new DataView(buffer);\n\t\tthis.buf = new Uint8Array(buffer);\n\t\tthis.pos = 0;\n\t\tthis.byteLength = buffer.byteLength;\n\t}\n\n\tgetPosition(): number {\n\t\treturn this.pos;\n\t}\n\n\tskip(n: number): void {\n\t\tthis.pos += n;\n\t}\n\n\treadByte(): number {\n\t\tconst v = this.buf[this.pos];\n\t\tthis.pos += 1;\n\t\treturn v;\n\t}\n\n\treadSignedByte(): number {\n\t\tconst v = this.view.getInt8(this.pos);\n\t\tthis.pos += 1;\n\t\treturn v;\n\t}\n\n\treadBool(): boolean {\n\t\treturn this.readByte() !== 0;\n\t}\n\n\treadShort(): number {\n\t\tconst v = this.view.getInt16(this.pos, true);\n\t\tthis.pos += 2;\n\t\treturn v;\n\t}\n\n\treadInt(): number {\n\t\tconst v = this.view.getInt32(this.pos, true);\n\t\tthis.pos += 4;\n\t\treturn v;\n\t}\n\n\treadDouble(): number {\n\t\tconst v = this.view.getFloat64(this.pos, true);\n\t\tthis.pos += 8;\n\t\treturn v;\n\t}\n\n\t/** Reads IntByteSizeString: int(strLen+1) + byte(strLen) + chars. */\n\treadIntByteSizeString(): string {\n\t\tconst totalSize = this.readInt();\n\t\tconst strLen = this.readByte();\n\t\tconst str = this.readChars(strLen);\n\t\tconst padding = Math.max(0, totalSize - 1 - strLen);\n\t\tthis.skip(padding);\n\t\treturn str;\n\t}\n\n\t/** Reads IntSizeString: int(len) + chars. */\n\treadIntString(): string {\n\t\tconst len = this.readInt();\n\t\tif (len <= 0) return '';\n\t\treturn this.readChars(len);\n\t}\n\n\t/** Reads ByteSizeString with fixed buffer length. */\n\treadByteSizeString(fixedLen: number): string {\n\t\tconst strLen = this.readByte();\n\t\tconst str = this.readChars(Math.min(strLen, fixedLen));\n\t\tconst remaining = fixedLen - Math.min(strLen, fixedLen);\n\t\tthis.skip(remaining);\n\t\treturn str;\n\t}\n\n\tprivate readChars(length: number): string {\n\t\tconst chars: number[] = [];\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tchars.push(this.buf[this.pos + i]);\n\t\t}\n\t\tthis.pos += length;\n\t\treturn String.fromCharCode(...chars);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// GP version detection\n// ---------------------------------------------------------------------------\n\ninterface GP5Version {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n}\n\nfunction parseVersionString(versionStr: string): GP5Version {\n\tconst match = versionStr.match(/v(\\d+)\\.(\\d+)/);\n\tif (!match) return { major: 5, minor: 10, patch: 0 };\n\treturn {\n\t\tmajor: parseInt(match[1], 10),\n\t\tminor: parseInt(match[2], 10),\n\t\tpatch: 0\n\t};\n}\n\nfunction versionGreaterThan(v: GP5Version, major: number, minor: number, patch: number): boolean {\n\tif (v.major !== major) return v.major > major;\n\tif (v.minor !== minor) return v.minor > minor;\n\treturn v.patch > patch;\n}\n\n// ---------------------------------------------------------------------------\n// Duration mapping\n// ---------------------------------------------------------------------------\n\nconst GP_DURATION_MAP: Record<number, Duration> = {\n\t[-2]: 'whole',\n\t[-1]: 'half',\n\t[0]: 'quarter',\n\t[1]: 'eighth',\n\t[2]: '16th',\n\t[3]: '32nd',\n\t[4]: '64th',\n\t[5]: '128th'\n};\n\nfunction gpDurationToDuration(value: number): Duration {\n\treturn GP_DURATION_MAP[value] ?? 'quarter';\n}\n\n// ---------------------------------------------------------------------------\n// Tuplet mapping\n// ---------------------------------------------------------------------------\n\nconst TUPLET_MAP: Record<number, { num: number; den: number }> = {\n\t3: { num: 3, den: 2 },\n\t5: { num: 5, den: 4 },\n\t6: { num: 6, den: 4 },\n\t7: { num: 7, den: 4 },\n\t9: { num: 9, den: 8 },\n\t10: { num: 10, den: 8 },\n\t11: { num: 11, den: 8 },\n\t12: { num: 12, den: 8 },\n\t13: { num: 13, den: 8 }\n};\n\n// ---------------------------------------------------------------------------\n// Harmonic type mapping\n// ---------------------------------------------------------------------------\n\nconst HARMONIC_TYPE_MAP: Record<number, string> = {\n\t1: 'Natural',\n\t2: 'Artificial',\n\t3: 'Tapped',\n\t4: 'Pinch',\n\t5: 'Semi'\n};\n\n// ---------------------------------------------------------------------------\n// MIDI channel info\n// ---------------------------------------------------------------------------\n\ninterface MidiChannel {\n\tinstrument: number;\n\tvolume: number;\n\tbalance: number;\n\tchorus: number;\n\treverb: number;\n\tphaser: number;\n\ttremolo: number;\n}\n\n// ---------------------------------------------------------------------------\n// Measure header (parsed from the measure header block)\n// ---------------------------------------------------------------------------\n\ninterface MeasureHeader {\n\tnumerator: number;\n\tdenominator: number;\n\trepeatOpen: boolean;\n\trepeatClose: number;\n\trepeatAlternative: number;\n\tmarker: { name: string; color: [number, number, number] } | null;\n\tkeySignature: number;\n\tkeyMode: number;\n\thasDoubleBar: boolean;\n\ttripletFeel: number;\n}\n\n// ---------------------------------------------------------------------------\n// Track header\n// ---------------------------------------------------------------------------\n\ninterface TrackHeader {\n\tname: string;\n\tisPercussion: boolean;\n\tnumStrings: number;\n\ttuning: number[];\n\tport: number;\n\tchannelIndex: number;\n\teffectChannel: number;\n\tfretCount: number;\n\tcapoFret: number;\n}\n\n// ---------------------------------------------------------------------------\n// Internal beat/note structures used during parsing\n// ---------------------------------------------------------------------------\n\ninterface GP5ParsedNote {\n\tstring: number;\n\tfret: number;\n\tisTied: boolean;\n\tisDead: boolean;\n\tvelocity: number;\n\thammerOn: boolean;\n\tletRing: boolean;\n\tslide: number | null;\n\tharmonic: string | null;\n\tpalmMute: boolean;\n\tvibrato: boolean;\n\tbend: { type: number; value: number; points: { position: number; value: number; vibrato: boolean }[] } | null;\n\tstaccato: boolean;\n\theavyAccent: boolean;\n\taccent: boolean;\n\ttrill: { fret: number; period: number } | null;\n\ttremoloPicking: number | null;\n}\n\ninterface GP5ParsedBeat {\n\tduration: Duration;\n\tdotted: boolean;\n\ttuplet: { num: number; den: number } | null;\n\tisRest: boolean;\n\tisEmpty: boolean;\n\tnotes: GP5ParsedNote[];\n}\n\n// ---------------------------------------------------------------------------\n// Read helpers — individual GP binary sections\n// ---------------------------------------------------------------------------\n\nfunction readInfo(r: GP5Reader): { title: string; subtitle: string; artist: string; album: string } {\n\tconst title = r.readIntByteSizeString();\n\tconst subtitle = r.readIntByteSizeString();\n\tconst artist = r.readIntByteSizeString();\n\tconst album = r.readIntByteSizeString();\n\tr.readIntByteSizeString(); // words\n\tr.readIntByteSizeString(); // music\n\tr.readIntByteSizeString(); // copyright\n\tr.readIntByteSizeString(); // tab\n\tr.readIntByteSizeString(); // instructions\n\n\tconst noticeCount = r.readInt();\n\tfor (let i = 0; i < noticeCount; i++) {\n\t\tr.readIntByteSizeString();\n\t}\n\n\treturn { title, subtitle, artist, album };\n}\n\nfunction readLyrics(r: GP5Reader): void {\n\tr.readInt(); // lyric track\n\tfor (let i = 0; i < 5; i++) {\n\t\tr.readInt(); // start bar\n\t\tr.readIntString(); // text\n\t}\n}\n\nfunction readRSEMasterEffect(r: GP5Reader, version: GP5Version): void {\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.readInt(); // master volume\n\t\tr.readInt(); // unknown\n\t\treadEqualizer(r, 11);\n\t}\n}\n\nfunction readEqualizer(r: GP5Reader, bands: number): void {\n\tfor (let i = 0; i < bands; i++) {\n\t\tr.readSignedByte();\n\t}\n}\n\nfunction readPageSetup(r: GP5Reader): void {\n\tr.readInt(); // width\n\tr.readInt(); // height\n\tr.readInt(); // margin left\n\tr.readInt(); // margin right\n\tr.readInt(); // margin top\n\tr.readInt(); // margin bottom\n\tr.readInt(); // score size proportion\n\tr.readShort(); // header/footer flags\n\tfor (let i = 0; i < 10; i++) {\n\t\tr.readIntByteSizeString(); // template strings\n\t}\n}\n\nfunction readDirections(r: GP5Reader): void {\n\tfor (let i = 0; i < 19; i++) {\n\t\tr.readShort();\n\t}\n}\n\nfunction readMidiChannels(r: GP5Reader): MidiChannel[] {\n\tconst channels: MidiChannel[] = [];\n\tfor (let i = 0; i < 64; i++) {\n\t\tconst instrument = r.readInt();\n\t\tconst volume = r.readByte();\n\t\tconst balance = r.readByte();\n\t\tconst chorus = r.readByte();\n\t\tconst reverb = r.readByte();\n\t\tconst phaser = r.readByte();\n\t\tconst tremolo = r.readByte();\n\t\tr.skip(2); // padding\n\t\tchannels.push({ instrument, volume, balance, chorus, reverb, phaser, tremolo });\n\t}\n\treturn channels;\n}\n\nfunction readMeasureHeaders(r: GP5Reader, count: number, _version: GP5Version): MeasureHeader[] {\n\tconst headers: MeasureHeader[] = [];\n\tlet prevNumerator = 4;\n\tlet prevDenominator = 4;\n\n\tfor (let i = 0; i < count; i++) {\n\t\tif (i > 0) {\n\t\t\tr.skip(1); // blank byte before each header except first\n\t\t}\n\n\t\tconst flags = r.readByte();\n\n\t\tlet numerator = prevNumerator;\n\t\tlet denominator = prevDenominator;\n\n\t\tif (flags & 0x01) {\n\t\t\tnumerator = r.readSignedByte();\n\t\t}\n\t\tif (flags & 0x02) {\n\t\t\tdenominator = r.readSignedByte();\n\t\t}\n\n\t\tconst repeatOpen = (flags & 0x04) !== 0;\n\n\t\tlet repeatClose = -1;\n\t\tif (flags & 0x08) {\n\t\t\trepeatClose = r.readSignedByte();\n\t\t\tif (repeatClose > 0) repeatClose -= 1;\n\t\t}\n\n\t\tlet marker: MeasureHeader['marker'] = null;\n\t\tif (flags & 0x20) {\n\t\t\tconst name = r.readIntByteSizeString();\n\t\t\tconst colorR = r.readByte();\n\t\t\tconst colorG = r.readByte();\n\t\t\tconst colorB = r.readByte();\n\t\t\tr.skip(1); // padding\n\t\t\tmarker = { name, color: [colorR, colorG, colorB] };\n\t\t}\n\n\t\tlet keySignature = 0;\n\t\tlet keyMode = 0;\n\t\tif (flags & 0x40) {\n\t\t\tkeySignature = r.readSignedByte();\n\t\t\tkeyMode = r.readSignedByte();\n\t\t}\n\n\t\tconst hasDoubleBar = (flags & 0x80) !== 0;\n\n\t\tlet repeatAlternative = 0;\n\t\tif (flags & 0x10) {\n\t\t\trepeatAlternative = r.readByte();\n\t\t}\n\n\t\t// GP5: beam groups if time sig was set (both bits 0x01 and 0x02)\n\t\tif (flags & 0x03) {\n\t\t\tr.skip(4); // beam groups\n\t\t}\n\n\t\t// Blank byte if not alternate ending\n\t\tif (!(flags & 0x10)) {\n\t\t\tr.skip(1);\n\t\t}\n\n\t\tconst tripletFeel = r.readByte();\n\n\t\theaders.push({\n\t\t\tnumerator,\n\t\t\tdenominator,\n\t\t\trepeatOpen,\n\t\t\trepeatClose,\n\t\t\trepeatAlternative,\n\t\t\tmarker,\n\t\t\tkeySignature,\n\t\t\tkeyMode,\n\t\t\thasDoubleBar,\n\t\t\ttripletFeel\n\t\t});\n\n\t\tprevNumerator = numerator;\n\t\tprevDenominator = denominator;\n\t}\n\n\treturn headers;\n}\n\nfunction readTrackHeaders(r: GP5Reader, count: number, version: GP5Version): TrackHeader[] {\n\tconst tracks: TrackHeader[] = [];\n\n\tfor (let i = 0; i < count; i++) {\n\t\t// GP5.10: blank byte before first track; GP5.0: blank byte before every track\n\t\tif (i === 0 || versionGreaterThan(version, 5, 0, 0) === false) {\n\t\t\tr.skip(1);\n\t\t}\n\n\t\tconst flags1 = r.readByte();\n\t\tconst isPercussion = (flags1 & 0x01) !== 0;\n\n\t\tconst name = r.readByteSizeString(40);\n\t\tconst numStrings = r.readInt();\n\n\t\tconst tuning: number[] = [];\n\t\tfor (let s = 0; s < 7; s++) {\n\t\t\tconst val = r.readInt();\n\t\t\tif (s < numStrings) tuning.push(val);\n\t\t}\n\n\t\tconst port = r.readInt();\n\t\tconst channelIndex = r.readInt() - 1; // 1-based → 0-based\n\t\tconst effectChannel = r.readInt() - 1;\n\t\tconst fretCount = r.readInt();\n\t\tconst capoFret = r.readInt();\n\t\tr.skip(4); // color (3 bytes + padding)\n\n\t\ttracks.push({ name, isPercussion, numStrings, tuning, port, channelIndex, effectChannel, fretCount, capoFret });\n\n\t\t// GP5 track flags2 (display settings)\n\t\tr.readShort();\n\n\t\t// Auto accentuation + MIDI bank\n\t\tr.readByte(); // auto accentuation\n\t\tr.readByte(); // MIDI bank\n\n\t\t// Track RSE\n\t\treadTrackRSE(r, version);\n\t}\n\n\t// Trailing bytes after all tracks\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.skip(1);\n\t} else {\n\t\tr.skip(2);\n\t}\n\n\treturn tracks;\n}\n\nfunction readTrackRSE(r: GP5Reader, version: GP5Version): void {\n\tr.readByte(); // humanize\n\tr.skip(12); // 3 ints unknown\n\tr.skip(12); // additional unknown\n\treadRSEInstrument(r, version);\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\treadEqualizer(r, 4); // 3-band + gain\n\t\treadRSEInstrumentEffect(r, version);\n\t}\n}\n\nfunction readRSEInstrument(r: GP5Reader, version: GP5Version): void {\n\tr.readInt(); // MIDI instrument number\n\tr.readInt(); // unknown\n\tr.readInt(); // sound bank\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.readInt(); // effect number\n\t} else {\n\t\tr.readShort(); // effect number (GP5.0)\n\t\tr.skip(1);\n\t}\n}\n\nfunction readRSEInstrumentEffect(r: GP5Reader, version: GP5Version): void {\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.readIntByteSizeString(); // effect name\n\t\tr.readIntByteSizeString(); // effect category\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Measure / Beat / Note reading — the per-measure data block\n// ---------------------------------------------------------------------------\n\nfunction readMeasures(\n\tr: GP5Reader,\n\tmeasureCount: number,\n\ttrackCount: number,\n\tversion: GP5Version\n): GP5ParsedBeat[][][] {\n\t// Result: measures[trackIdx][measureIdx] = beats[]\n\tconst allMeasures: GP5ParsedBeat[][][] = [];\n\tfor (let t = 0; t < trackCount; t++) {\n\t\tallMeasures.push([]);\n\t}\n\n\t// GP5 stores measures in order: measure1/track1, measure1/track2, ..., measure2/track1, ...\n\t// GP5 has 2 voices per measure\n\tfor (let m = 0; m < measureCount; m++) {\n\t\tfor (let t = 0; t < trackCount; t++) {\n\t\t\tconst voice1Beats = readVoice(r, version);\n\t\t\tconst voice2Beats = readVoice(r, version);\n\t\t\tr.readByte(); // line break\n\n\t\t\t// Use voice 1 as primary; include voice 2 beats if voice 1 is empty\n\t\t\tconst beats = voice1Beats.length > 0 ? voice1Beats : voice2Beats;\n\t\t\tallMeasures[t].push(beats);\n\t\t}\n\t}\n\n\treturn allMeasures;\n}\n\nfunction readVoice(r: GP5Reader, version: GP5Version): GP5ParsedBeat[] {\n\tconst beatCount = r.readInt();\n\tconst beats: GP5ParsedBeat[] = [];\n\n\tfor (let b = 0; b < beatCount; b++) {\n\t\tbeats.push(readBeat(r, version));\n\t}\n\n\treturn beats;\n}\n\nfunction readBeat(r: GP5Reader, version: GP5Version): GP5ParsedBeat {\n\tconst flags = r.readByte();\n\n\tlet isRest = false;\n\tlet isEmpty = false;\n\tif (flags & 0x40) {\n\t\tconst status = r.readByte();\n\t\tisEmpty = status === 0x00;\n\t\tisRest = status === 0x02;\n\t}\n\n\t// Duration\n\tconst durationValue = r.readSignedByte();\n\tconst duration = gpDurationToDuration(durationValue);\n\tconst dotted = (flags & 0x01) !== 0;\n\n\tlet tuplet: { num: number; den: number } | null = null;\n\tif (flags & 0x20) {\n\t\tconst tupletValue = r.readInt();\n\t\ttuplet = TUPLET_MAP[tupletValue] ?? null;\n\t}\n\n\t// Chord diagram\n\tif (flags & 0x02) {\n\t\treadChord(r, version);\n\t}\n\n\t// Text\n\tif (flags & 0x04) {\n\t\tr.readIntByteSizeString();\n\t}\n\n\t// Beat effects\n\tif (flags & 0x08) {\n\t\treadBeatEffects(r, version);\n\t}\n\n\t// Mix table change\n\tif (flags & 0x10) {\n\t\treadMixTableChange(r, version);\n\t}\n\n\t// Notes\n\tconst stringFlags = r.readByte();\n\tconst notes: GP5ParsedNote[] = [];\n\n\tfor (let i = 6; i >= 0; i--) {\n\t\tif (stringFlags & (1 << i)) {\n\t\t\tnotes.push(readNote(r, version));\n\t\t}\n\t}\n\n\t// GP5 beat flags2\n\tconst flags2 = r.readShort();\n\tif (flags2 & 0x0800) {\n\t\tr.readByte(); // break secondary beams\n\t}\n\n\treturn { duration, dotted, tuplet, isRest: isRest || isEmpty, isEmpty, notes };\n}\n\nfunction readChord(r: GP5Reader, _version: GP5Version): void {\n\tconst header = r.readByte();\n\tif (header === 0) {\n\t\t// Old GP3 chord format: name + firstFret + (6 ints if firstFret != 0)\n\t\tr.readIntByteSizeString();\n\t\tconst firstFret = r.readInt();\n\t\tif (firstFret !== 0) {\n\t\t\tfor (let i = 0; i < 6; i++) r.readInt();\n\t\t}\n\t} else {\n\t\t// GP4+ format chord — large fixed structure\n\t\tr.skip(16); // sharp(1) + blank(3) + root(1) + type(1) + extension(1) + bassNote(4) + tonality(4) + add(1)\n\t\tr.readByteSizeString(22);\n\t\tr.readByte(); // fifth\n\t\tr.readByte(); // ninth\n\t\tr.readByte(); // eleventh\n\t\tfor (let i = 0; i < 6; i++) r.readInt(); // frets\n\t\tr.readByte(); // barreCount\n\t\tr.skip(5); // barre frets\n\t\tr.skip(5); // barre start strings\n\t\tr.skip(5); // barre end strings\n\t\tr.skip(7); // omissions\n\t\tr.skip(1); // blank\n\t\tr.skip(7); // fingering\n\t\tr.readBool(); // show diagrams fingering\n\t}\n}\n\nfunction readBeatEffects(r: GP5Reader, _version: GP5Version): void {\n\t// GP4+ uses 2 bytes of flags\n\tconst flags1 = r.readByte();\n\tconst flags2 = r.readByte();\n\n\tif (flags1 & 0x20) {\n\t\tconst slapEffect = r.readSignedByte();\n\t\tif (slapEffect === 0) {\n\t\t\t// Tremolo bar\n\t\t\treadBend(r);\n\t\t}\n\t}\n\n\tif (flags2 & 0x04) {\n\t\t// Tremolo bar\n\t\treadBend(r);\n\t}\n\n\tif (flags1 & 0x40) {\n\t\t// Beat stroke\n\t\tr.readByte(); // stroke down\n\t\tr.readByte(); // stroke up\n\t}\n\n\tif (flags2 & 0x02) {\n\t\t// Pick stroke\n\t\tr.readSignedByte();\n\t}\n}\n\nfunction readBend(r: GP5Reader): { type: number; value: number; points: { position: number; value: number; vibrato: boolean }[] } {\n\tconst type = r.readSignedByte();\n\tconst value = r.readInt();\n\tconst pointCount = r.readInt();\n\tconst points: { position: number; value: number; vibrato: boolean }[] = [];\n\tfor (let i = 0; i < pointCount; i++) {\n\t\tconst position = r.readInt();\n\t\tconst pointValue = r.readInt();\n\t\tconst vibrato = r.readBool();\n\t\tpoints.push({ position, value: pointValue, vibrato });\n\t}\n\treturn { type, value, points };\n}\n\nfunction readMixTableChange(r: GP5Reader, version: GP5Version): void {\n\tr.readSignedByte(); // instrument\n\n\t// RSE instrument (GP5)\n\treadRSEInstrument(r, version);\n\tif (!versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.skip(1); // GP5.0 extra byte\n\t}\n\n\tconst volume = r.readSignedByte();\n\tconst balance = r.readSignedByte();\n\tconst chorus = r.readSignedByte();\n\tconst reverb = r.readSignedByte();\n\tconst phaser = r.readSignedByte();\n\tconst tremolo = r.readSignedByte();\n\n\tr.readIntByteSizeString(); // tempo name\n\tconst tempo = r.readInt();\n\n\t// Durations for changed values\n\tif (volume >= 0) r.readSignedByte();\n\tif (balance >= 0) r.readSignedByte();\n\tif (chorus >= 0) r.readSignedByte();\n\tif (reverb >= 0) r.readSignedByte();\n\tif (phaser >= 0) r.readSignedByte();\n\tif (tremolo >= 0) r.readSignedByte();\n\tif (tempo >= 0) {\n\t\tr.readSignedByte(); // duration\n\t\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\t\tr.readBool(); // hide tempo\n\t\t}\n\t}\n\n\t// Mix table change flags (GP4+)\n\tr.readByte();\n\n\t// Wah effect (GP5)\n\tr.readSignedByte();\n\n\t// RSE instrument effect (GP5.1+)\n\treadRSEInstrumentEffect(r, version);\n}\n\nfunction readNote(r: GP5Reader, version: GP5Version): GP5ParsedNote {\n\tconst flags = r.readByte();\n\n\tconst heavyAccent = (flags & 0x02) !== 0;\n\tconst accent = (flags & 0x40) !== 0;\n\n\tlet isTied = false;\n\tlet isDead = false;\n\tif (flags & 0x20) {\n\t\tconst noteType = r.readByte();\n\t\tisTied = noteType === 2;\n\t\tisDead = noteType === 3;\n\t}\n\n\tlet velocity = 8; // default mf\n\tif (flags & 0x10) {\n\t\tvelocity = r.readSignedByte();\n\t}\n\n\tlet fret = 0;\n\tif (flags & 0x20) {\n\t\tfret = r.readSignedByte();\n\t\tif (fret < 0 || fret > 99) fret = 0;\n\t}\n\n\tif (flags & 0x80) {\n\t\tr.readSignedByte(); // left hand finger\n\t\tr.readSignedByte(); // right hand finger\n\t}\n\n\tif (flags & 0x01) {\n\t\tr.readDouble(); // duration percent\n\t}\n\n\t// GP5: second flags byte\n\tr.readByte();\n\n\t// Note effects\n\tlet hammerOn = false;\n\tlet letRing = false;\n\tlet slide: number | null = null;\n\tlet harmonic: string | null = null;\n\tlet palmMute = false;\n\tlet vibrato = false;\n\tlet bend: GP5ParsedNote['bend'] = null;\n\tlet staccato = false;\n\tlet trill: GP5ParsedNote['trill'] = null;\n\tlet tremoloPicking: number | null = null;\n\n\tif (flags & 0x08) {\n\t\tconst result = readNoteEffects(r, version);\n\t\thammerOn = result.hammerOn;\n\t\tletRing = result.letRing;\n\t\tslide = result.slide;\n\t\tharmonic = result.harmonic;\n\t\tpalmMute = result.palmMute;\n\t\tvibrato = result.vibrato;\n\t\tbend = result.bend;\n\t\tstaccato = result.staccato;\n\t\ttrill = result.trill;\n\t\ttremoloPicking = result.tremoloPicking;\n\t}\n\n\treturn {\n\t\tstring: 0, // Will be set by caller based on string index\n\t\tfret,\n\t\tisTied,\n\t\tisDead,\n\t\tvelocity,\n\t\thammerOn,\n\t\tletRing,\n\t\tslide,\n\t\tharmonic,\n\t\tpalmMute,\n\t\tvibrato,\n\t\tbend,\n\t\tstaccato,\n\t\theavyAccent,\n\t\taccent,\n\t\ttrill,\n\t\ttremoloPicking\n\t};\n}\n\ninterface NoteEffectsResult {\n\thammerOn: boolean;\n\tletRing: boolean;\n\tslide: number | null;\n\tharmonic: string | null;\n\tpalmMute: boolean;\n\tvibrato: boolean;\n\tbend: GP5ParsedNote['bend'];\n\tstaccato: boolean;\n\ttrill: GP5ParsedNote['trill'];\n\ttremoloPicking: number | null;\n}\n\nfunction readNoteEffects(r: GP5Reader, version: GP5Version): NoteEffectsResult {\n\t// GP4+ uses 2 bytes of flags\n\tconst flags1 = r.readByte();\n\tconst flags2 = r.readByte();\n\n\tlet bend: GP5ParsedNote['bend'] = null;\n\tlet hammerOn = false;\n\tlet letRing = false;\n\tlet slide: number | null = null;\n\tlet harmonic: string | null = null;\n\tlet palmMute = false;\n\tlet vibrato = false;\n\tlet staccato = false;\n\tlet trill: GP5ParsedNote['trill'] = null;\n\tlet tremoloPicking: number | null = null;\n\n\tif (flags1 & 0x01) {\n\t\tbend = readBend(r);\n\t}\n\thammerOn = (flags1 & 0x02) !== 0;\n\tletRing = (flags1 & 0x08) !== 0;\n\n\tif (flags1 & 0x10) {\n\t\treadGraceNote(r, version);\n\t}\n\n\tstaccato = (flags2 & 0x01) !== 0;\n\tpalmMute = (flags2 & 0x02) !== 0;\n\n\tif (flags2 & 0x04) {\n\t\ttremoloPicking = r.readSignedByte();\n\t}\n\n\tif (flags2 & 0x08) {\n\t\t// GP5 slides: byte with flags\n\t\tslide = r.readByte();\n\t}\n\n\tif (flags2 & 0x10) {\n\t\tconst harmonicType = r.readSignedByte();\n\t\tharmonic = HARMONIC_TYPE_MAP[harmonicType] ?? null;\n\t\tif (harmonicType === 2) {\n\t\t\t// Artificial harmonic extra data\n\t\t\tr.readByte(); // note\n\t\t\tr.readSignedByte(); // accidental\n\t\t\tr.readByte(); // octave\n\t\t} else if (harmonicType === 3) {\n\t\t\tr.readByte(); // fret\n\t\t}\n\t}\n\n\tif (flags2 & 0x20) {\n\t\tconst trillFret = r.readSignedByte();\n\t\tconst trillPeriod = r.readSignedByte();\n\t\ttrill = { fret: trillFret, period: trillPeriod };\n\t}\n\n\tvibrato = (flags2 & 0x40) !== 0;\n\n\treturn { hammerOn, letRing, slide, harmonic, palmMute, vibrato, bend, staccato, trill, tremoloPicking };\n}\n\nfunction readGraceNote(r: GP5Reader, version: GP5Version): void {\n\tr.readByte(); // fret\n\tr.readByte(); // velocity\n\tr.readByte(); // transition\n\tr.readByte(); // duration\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.readByte(); // flags (dead, on beat)\n\t} else {\n\t\tr.readByte();\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Transform parsed GP5 data → TabSong\n// ---------------------------------------------------------------------------\n\nfunction transformToTabSong(\n\tinfo: { title: string; subtitle: string; artist: string; album: string },\n\ttempo: number,\n\tmeasureHeaders: MeasureHeader[],\n\ttrackHeaders: TrackHeader[],\n\tparsedMeasures: GP5ParsedBeat[][][],\n\tchannels: MidiChannel[]\n): TabSong {\n\tconst tracks: TabTrack[] = trackHeaders.map((th, trackIdx) => {\n\t\tconst tuningPitches = th.tuning;\n\t\tconst tuning: Note[] = tuningPitches\n\t\t\t.map((midi) => noteFromPitchClass(midiToPitchClass(midi)))\n\t\t\t.reverse();\n\n\t\tlet globalBeatIndex = 0;\n\t\tconst bars: TabBar[] = [];\n\n\t\tfor (let mIdx = 0; mIdx < measureHeaders.length; mIdx++) {\n\t\t\tconst mh = measureHeaders[mIdx];\n\t\t\tconst beatsData = parsedMeasures[trackIdx]?.[mIdx] ?? [];\n\n\t\t\tconst tabBeats: TabBeat[] = [];\n\n\t\t\tfor (const beatData of beatsData) {\n\t\t\t\tif (beatData.isEmpty) continue;\n\n\t\t\t\tconst stringCount = th.numStrings;\n\t\t\t\tconst tabNotes: TabNote[] = [];\n\n\t\t\t\t// Notes in a GP5 beat are ordered from highest string to lowest\n\t\t\t\t// The string index is determined by the bit position in the string flags\n\t\t\t\tlet noteStringIndex = 0;\n\t\t\t\tfor (const noteData of beatData.notes) {\n\t\t\t\t\tconst stringIdx = stringCount - 1 - noteStringIndex;\n\t\t\t\t\tconst fret = noteData.fret;\n\t\t\t\t\tconst openPitch = tuningPitches[noteStringIndex] ?? 0;\n\t\t\t\t\tconst pc = (((openPitch + fret) % 12 + 12) % 12) as PitchClass;\n\t\t\t\t\tconst note = noteFromPitchClass(pc, false);\n\n\t\t\t\t\tlet bendResult: TabNote['bend'] = null;\n\t\t\t\t\tif (noteData.bend) {\n\t\t\t\t\t\tconst points = noteData.bend.points;\n\t\t\t\t\t\tconst origin = points.length > 0 ? points[0].value / 100 : 0;\n\t\t\t\t\t\tconst destination = points.length > 1 ? points[points.length - 1].value / 100 : 0;\n\t\t\t\t\t\tconst middle = points.length > 2 ? points[Math.floor(points.length / 2)].value / 100 : 0;\n\t\t\t\t\t\tbendResult = { origin, destination, middle };\n\t\t\t\t\t}\n\n\t\t\t\t\ttabNotes.push({\n\t\t\t\t\t\tstring: stringIdx,\n\t\t\t\t\t\tfret,\n\t\t\t\t\t\tpitchClass: pc,\n\t\t\t\t\t\tnoteName: note.name,\n\t\t\t\t\t\tslide: noteData.slide,\n\t\t\t\t\t\tharmonic: noteData.harmonic,\n\t\t\t\t\t\tpalmMute: noteData.palmMute,\n\t\t\t\t\t\tmuted: noteData.isDead,\n\t\t\t\t\t\tletRing: noteData.letRing,\n\t\t\t\t\t\tbend: bendResult,\n\t\t\t\t\t\ttie: {\n\t\t\t\t\t\t\torigin: false,\n\t\t\t\t\t\t\tdestination: noteData.isTied\n\t\t\t\t\t\t},\n\t\t\t\t\t\tvibrato: noteData.vibrato ? 'slight' : null,\n\t\t\t\t\t\thammerOn: noteData.hammerOn,\n\t\t\t\t\t\tpullOff: false, // GP5 uses hammerOn for both — context determines direction\n\t\t\t\t\t\ttapped: false,\n\t\t\t\t\t\taccent: noteData.accent ? 1 : noteData.heavyAccent ? 2 : null\n\t\t\t\t\t});\n\n\t\t\t\t\tnoteStringIndex++;\n\t\t\t\t}\n\n\t\t\t\ttabBeats.push({\n\t\t\t\t\tindex: globalBeatIndex++,\n\t\t\t\t\tbarIndex: mIdx,\n\t\t\t\t\tnotes: tabNotes,\n\t\t\t\t\tduration: beatData.duration,\n\t\t\t\t\ttuplet: beatData.tuplet,\n\t\t\t\t\tdotted: beatData.dotted ? 1 : 0,\n\t\t\t\t\tisRest: beatData.isRest && tabNotes.length === 0,\n\t\t\t\t\tdynamic: null,\n\t\t\t\t\ttempo\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst section = mh.marker\n\t\t\t\t? { text: mh.marker.name }\n\t\t\t\t: null;\n\n\t\t\tbars.push({\n\t\t\t\tindex: mIdx,\n\t\t\t\ttimeSignature: { numerator: mh.numerator, denominator: mh.denominator },\n\t\t\t\tkeySignature: mh.keySignature !== 0\n\t\t\t\t\t? { accidentalCount: mh.keySignature, mode: mh.keyMode === 1 ? 'minor' : 'major' }\n\t\t\t\t\t: null,\n\t\t\t\tsection,\n\t\t\t\tbeats: tabBeats,\n\t\t\t\trepeatStart: mh.repeatOpen,\n\t\t\t\trepeatEnd: mh.repeatClose >= 0,\n\t\t\t\trepeatCount: mh.repeatClose >= 0 ? mh.repeatClose : 0\n\t\t\t});\n\t\t}\n\n\t\tconst ch = channels[th.channelIndex];\n\t\tconst instrumentName = ch ? `MIDI ${ch.instrument}` : null;\n\n\t\treturn {\n\t\t\tid: String(trackIdx),\n\t\t\tname: th.name,\n\t\t\tshortName: th.name.substring(0, 4),\n\t\t\tinstrument: instrumentName,\n\t\t\ttuning,\n\t\t\tcapoFret: th.capoFret,\n\t\t\tbars\n\t\t};\n\t});\n\n\treturn {\n\t\ttitle: info.title || info.subtitle || '',\n\t\tartist: info.artist,\n\t\talbum: info.album,\n\t\ttempo,\n\t\ttracks\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Parses a Guitar Pro 5 (.gp5) file from raw bytes into a TabSong. */\nexport function parseGp5File(data: Uint8Array): TabSong {\n\tconst buf = new ArrayBuffer(data.byteLength);\n\tnew Uint8Array(buf).set(data);\n\tconst r = new GP5Reader(buf);\n\n\t// Version string: ByteSizeString of size 30 (1 byte len + 30 chars)\n\tconst versionStr = r.readByteSizeString(30);\n\tconst version = parseVersionString(versionStr);\n\n\t// Validate it's a GP5 file\n\tif (version.major !== 5) {\n\t\tthrow new Error(`Unsupported Guitar Pro version: ${versionStr} (expected GP5)`);\n\t}\n\n\t// Score information\n\tconst info = readInfo(r);\n\n\t// Lyrics\n\treadLyrics(r);\n\n\t// RSE master effect\n\treadRSEMasterEffect(r, version);\n\n\t// Page setup\n\treadPageSetup(r);\n\n\t// Tempo\n\tr.readIntByteSizeString(); // tempo name\n\tconst tempo = r.readInt();\n\n\t// Hide tempo (GP5.1+)\n\tif (versionGreaterThan(version, 5, 0, 0)) {\n\t\tr.readBool();\n\t}\n\n\t// Key signature + octave\n\tr.readSignedByte(); // key\n\tr.readInt(); // octave\n\n\t// MIDI channels\n\tconst channels = readMidiChannels(r);\n\n\t// Directions (GP5)\n\treadDirections(r);\n\n\t// Master reverb\n\tr.readInt();\n\n\t// Measure count + track count\n\tconst measureCount = r.readInt();\n\tconst trackCount = r.readInt();\n\n\t// Measure headers\n\tconst measureHeaders = readMeasureHeaders(r, measureCount, version);\n\n\t// Tracks\n\tconst trackHeaders = readTrackHeaders(r, trackCount, version);\n\n\t// Measures (the actual beat/note data)\n\tconst parsedMeasures = readMeasures(r, measureCount, trackCount, version);\n\n\treturn transformToTabSong(info, tempo, measureHeaders, trackHeaders, parsedMeasures, channels);\n}\n","/**\n * Copyright 2026 Emilien Bevierre\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Unified Guitar Pro file parser — dispatches to format-specific parsers\n * based on file header detection.\n *\n * Supported formats:\n * - .gpx → BCFZ/BCFS container (Guitar Pro 6)\n * - .gp → ZIP container with Content/score.gpif (Guitar Pro 7+)\n * - .gp5 → Legacy sequential binary (Guitar Pro 5)\n *\n * Pure, zero native dependencies.\n */\n\nimport type { TabSong } from './types.js';\nimport { parseGpxFile, gpifToTabSong } from './gpx-parser.js';\nimport { parseGp5File } from './gp5-parser.js';\nimport { getDOMParser } from './dom.js';\n\n// ---------------------------------------------------------------------------\n// Minimal ZIP extractor — handles STORE and DEFLATE methods\n// ---------------------------------------------------------------------------\n\n/** Central Directory entry with resolved sizes for files using data descriptors. */\ninterface ZipCentralEntry {\n\tfileName: string;\n\tcompressionMethod: number;\n\tcompressedSize: number;\n\tuncompressedSize: number;\n\tlocalHeaderOffset: number;\n}\n\n/** Finds the End of Central Directory record and reads all central entries. */\nfunction readCentralDirectory(data: Uint8Array, view: DataView): ZipCentralEntry[] {\n\t// Scan backwards for End of Central Directory signature (0x06054b50)\n\tlet eocdOffset = -1;\n\tfor (let i = data.byteLength - 22; i >= 0; i--) {\n\t\tif (view.getUint32(i, true) === 0x06054b50) {\n\t\t\teocdOffset = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (eocdOffset === -1) return [];\n\n\tconst cdOffset = view.getUint32(eocdOffset + 16, true);\n\tconst cdEntryCount = view.getUint16(eocdOffset + 10, true);\n\n\tconst entries: ZipCentralEntry[] = [];\n\tlet pos = cdOffset;\n\n\tfor (let i = 0; i < cdEntryCount; i++) {\n\t\tif (pos + 46 > data.byteLength) break;\n\t\tif (view.getUint32(pos, true) !== 0x02014b50) break;\n\n\t\tconst compressionMethod = view.getUint16(pos + 10, true);\n\t\tconst compressedSize = view.getUint32(pos + 20, true);\n\t\tconst uncompressedSize = view.getUint32(pos + 24, true);\n\t\tconst nameLength = view.getUint16(pos + 28, true);\n\t\tconst extraLength = view.getUint16(pos + 30, true);\n\t\tconst commentLength = view.getUint16(pos + 32, true);\n\t\tconst localHeaderOffset = view.getUint32(pos + 42, true);\n\n\t\tconst nameBytes = data.subarray(pos + 46, pos + 46 + nameLength);\n\t\tconst fileName = String.fromCharCode(...nameBytes);\n\n\t\tentries.push({ fileName, compressionMethod, compressedSize, uncompressedSize, localHeaderOffset });\n\t\tpos += 46 + nameLength + extraLength + commentLength;\n\t}\n\n\treturn entries;\n}\n\n/**\n * Extracts a single file from a ZIP archive by name.\n * Uses the Central Directory for reliable size info (handles data descriptors).\n * Supports compression methods 0 (STORE) and 8 (DEFLATE).\n */\nfunction extractFileFromZip(data: Uint8Array, targetName: string): Uint8Array | null {\n\tconst view = new DataView(data.buffer, data.byteOffset, data.byteLength);\n\tconst entries = readCentralDirectory(data, view);\n\n\tconst entry = entries.find((e) => e.fileName === targetName);\n\tif (!entry) return null;\n\n\t// Read past the local file header to find the data\n\tconst localOffset = entry.localHeaderOffset;\n\tif (view.getUint32(localOffset, true) !== 0x04034b50) return null;\n\n\tconst localNameLength = view.getUint16(localOffset + 26, true);\n\tconst localExtraLength = view.getUint16(localOffset + 28, true);\n\tconst dataOffset = localOffset + 30 + localNameLength + localExtraLength;\n\n\tconst compressedData = data.subarray(dataOffset, dataOffset + entry.compressedSize);\n\n\tif (entry.compressionMethod === 0) {\n\t\treturn compressedData;\n\t} else if (entry.compressionMethod === 8) {\n\t\treturn decompressDeflateSync(compressedData, entry.uncompressedSize);\n\t} else {\n\t\tthrow new Error(`Unsupported ZIP compression method: ${entry.compressionMethod}`);\n\t}\n}\n\n/** Decompresses raw DEFLATE data using a synchronous inflate implementation. */\nfunction decompressDeflateSync(compressed: Uint8Array, expectedSize: number): Uint8Array {\n\treturn inflate(compressed, expectedSize);\n}\n\n// ---------------------------------------------------------------------------\n// Minimal INFLATE implementation — pure JS, handles raw DEFLATE (no zlib header)\n// ---------------------------------------------------------------------------\n\n/** Fixed Huffman code length tables per RFC 1951 */\nfunction buildFixedLitLenTree(): { codes: Uint16Array; lengths: Uint8Array } {\n\tconst lengths = new Uint8Array(288);\n\tfor (let i = 0; i <= 143; i++) lengths[i] = 8;\n\tfor (let i = 144; i <= 255; i++) lengths[i] = 9;\n\tfor (let i = 256; i <= 279; i++) lengths[i] = 7;\n\tfor (let i = 280; i <= 287; i++) lengths[i] = 8;\n\treturn buildHuffmanTable(lengths);\n}\n\nfunction buildFixedDistTree(): { codes: Uint16Array; lengths: Uint8Array } {\n\tconst lengths = new Uint8Array(32);\n\tlengths.fill(5);\n\treturn buildHuffmanTable(lengths);\n}\n\n/** Builds a Huffman decoding table from code lengths. */\nfunction buildHuffmanTable(codeLengths: Uint8Array): { codes: Uint16Array; lengths: Uint8Array } {\n\tconst maxBits = Math.max(...codeLengths);\n\tconst count = new Uint16Array(maxBits + 1);\n\tfor (const len of codeLengths) {\n\t\tif (len > 0) count[len]++;\n\t}\n\n\tconst nextCode = new Uint16Array(maxBits + 1);\n\tlet code = 0;\n\tfor (let bits = 1; bits <= maxBits; bits++) {\n\t\tcode = (code + count[bits - 1]) << 1;\n\t\tnextCode[bits] = code;\n\t}\n\n\tconst codes = new Uint16Array(codeLengths.length);\n\tconst lengths = new Uint8Array(codeLengths.length);\n\tfor (let i = 0; i < codeLengths.length; i++) {\n\t\tconst len = codeLengths[i];\n\t\tif (len > 0) {\n\t\t\tcodes[i] = nextCode[len]++;\n\t\t\tlengths[i] = len;\n\t\t}\n\t}\n\n\treturn { codes, lengths };\n}\n\n/** Bit reader for DEFLATE streams. */\nclass BitReader {\n\tprivate data: Uint8Array;\n\tprivate bytePos: number;\n\tprivate bitPos: number;\n\n\tconstructor(data: Uint8Array) {\n\t\tthis.data = data;\n\t\tthis.bytePos = 0;\n\t\tthis.bitPos = 0;\n\t}\n\n\treadBits(n: number): number {\n\t\tlet result = 0;\n\t\tfor (let i = 0; i < n; i++) {\n\t\t\tif (this.bytePos >= this.data.length) return result;\n\t\t\tresult |= ((this.data[this.bytePos] >> this.bitPos) & 1) << i;\n\t\t\tthis.bitPos++;\n\t\t\tif (this.bitPos === 8) {\n\t\t\t\tthis.bitPos = 0;\n\t\t\t\tthis.bytePos++;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\talignToByte(): void {\n\t\tif (this.bitPos > 0) {\n\t\t\tthis.bitPos = 0;\n\t\t\tthis.bytePos++;\n\t\t}\n\t}\n\n\treadByte(): number {\n\t\treturn this.data[this.bytePos++];\n\t}\n\n\treadBytes(n: number): Uint8Array {\n\t\tconst result = this.data.subarray(this.bytePos, this.bytePos + n);\n\t\tthis.bytePos += n;\n\t\treturn result;\n\t}\n}\n\n/** Decodes a Huffman symbol from the bit stream. */\nfunction decodeSymbol(bits: BitReader, table: { codes: Uint16Array; lengths: Uint8Array }): number {\n\tlet code = 0;\n\n\tfor (let len = 1; len <= 15; len++) {\n\t\tcode = (code << 1) | bits.readBits(1);\n\t\tfor (let i = 0; i < table.codes.length; i++) {\n\t\t\tif (table.lengths[i] === len && table.codes[i] === code) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t}\n\n\tthrow new Error('Invalid Huffman code');\n}\n\nconst LENGTH_BASE = [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258];\nconst LENGTH_EXTRA = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];\nconst DIST_BASE = [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577];\nconst DIST_EXTRA = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];\nconst CL_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];\n\n/** Inflates a raw DEFLATE stream (no zlib/gzip header). */\nfunction inflate(compressed: Uint8Array, expectedSize: number): Uint8Array {\n\tconst bits = new BitReader(compressed);\n\tconst output = new Uint8Array(expectedSize);\n\tlet outPos = 0;\n\n\tlet bfinal = 0;\n\twhile (bfinal === 0) {\n\t\tbfinal = bits.readBits(1);\n\t\tconst btype = bits.readBits(2);\n\n\t\tif (btype === 0) {\n\t\t\t// No compression\n\t\t\tbits.alignToByte();\n\t\t\tconst len = bits.readByte() | (bits.readByte() << 8);\n\t\t\tbits.readByte(); bits.readByte(); // nlen\n\t\t\tconst block = bits.readBytes(len);\n\t\t\toutput.set(block, outPos);\n\t\t\toutPos += len;\n\t\t} else {\n\t\t\tlet litLenTree: { codes: Uint16Array; lengths: Uint8Array };\n\t\t\tlet distTree: { codes: Uint16Array; lengths: Uint8Array };\n\n\t\t\tif (btype === 1) {\n\t\t\t\tlitLenTree = buildFixedLitLenTree();\n\t\t\t\tdistTree = buildFixedDistTree();\n\t\t\t} else if (btype === 2) {\n\t\t\t\tconst hlit = bits.readBits(5) + 257;\n\t\t\t\tconst hdist = bits.readBits(5) + 1;\n\t\t\t\tconst hclen = bits.readBits(4) + 4;\n\n\t\t\t\tconst clLengths = new Uint8Array(19);\n\t\t\t\tfor (let i = 0; i < hclen; i++) {\n\t\t\t\t\tclLengths[CL_ORDER[i]] = bits.readBits(3);\n\t\t\t\t}\n\t\t\t\tconst clTree = buildHuffmanTable(clLengths);\n\n\t\t\t\tconst allLengths = new Uint8Array(hlit + hdist);\n\t\t\t\tlet idx = 0;\n\t\t\t\twhile (idx < hlit + hdist) {\n\t\t\t\t\tconst sym = decodeSymbol(bits, clTree);\n\t\t\t\t\tif (sym < 16) {\n\t\t\t\t\t\tallLengths[idx++] = sym;\n\t\t\t\t\t} else if (sym === 16) {\n\t\t\t\t\t\tconst repeat = bits.readBits(2) + 3;\n\t\t\t\t\t\tconst prev = allLengths[idx - 1];\n\t\t\t\t\t\tfor (let i = 0; i < repeat; i++) allLengths[idx++] = prev;\n\t\t\t\t\t} else if (sym === 17) {\n\t\t\t\t\t\tconst repeat = bits.readBits(3) + 3;\n\t\t\t\t\t\tfor (let i = 0; i < repeat; i++) allLengths[idx++] = 0;\n\t\t\t\t\t} else if (sym === 18) {\n\t\t\t\t\t\tconst repeat = bits.readBits(7) + 11;\n\t\t\t\t\t\tfor (let i = 0; i < repeat; i++) allLengths[idx++] = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlitLenTree = buildHuffmanTable(allLengths.subarray(0, hlit));\n\t\t\t\tdistTree = buildHuffmanTable(allLengths.subarray(hlit));\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Invalid DEFLATE block type: ${btype}`);\n\t\t\t}\n\n\t\t\t// Decode compressed data\n\t\t\twhile (true) {\n\t\t\t\tconst sym = decodeSymbol(bits, litLenTree);\n\n\t\t\t\tif (sym < 256) {\n\t\t\t\t\toutput[outPos++] = sym;\n\t\t\t\t} else if (sym === 256) {\n\t\t\t\t\tbreak; // End of block\n\t\t\t\t} else {\n\t\t\t\t\tconst lengthIdx = sym - 257;\n\t\t\t\t\tconst length = LENGTH_BASE[lengthIdx] + bits.readBits(LENGTH_EXTRA[lengthIdx]);\n\n\t\t\t\t\tconst distSym = decodeSymbol(bits, distTree);\n\t\t\t\t\tconst distance = DIST_BASE[distSym] + bits.readBits(DIST_EXTRA[distSym]);\n\n\t\t\t\t\tfor (let i = 0; i < length; i++) {\n\t\t\t\t\t\toutput[outPos] = output[outPos - distance];\n\t\t\t\t\t\toutPos++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn output.subarray(0, outPos);\n}\n\n// ---------------------------------------------------------------------------\n// GP7+ ZIP parser — extracts score.gpif and delegates to GPIF transformer\n// ---------------------------------------------------------------------------\n\n/** Parses a Guitar Pro 7+ (.gp) ZIP file into a TabSong. */\nfunction parseGp7File(data: Uint8Array): TabSong {\n\tconst gpifData = extractFileFromZip(data, 'Content/score.gpif');\n\tif (!gpifData) {\n\t\tthrow new Error('No Content/score.gpif found in GP7+ archive');\n\t}\n\n\tconst decoder = new TextDecoder('utf-8');\n\tconst gpifXml = decoder.decode(gpifData);\n\n\tconst DOMParserImpl = getDOMParser();\n\tconst parser = new DOMParserImpl();\n\tconst doc = parser.parseFromString(gpifXml, 'text/xml');\n\n\tconst parseError = doc.querySelector('parsererror');\n\tif (parseError) {\n\t\tthrow new Error(`Failed to parse GPIF XML: ${parseError.textContent}`);\n\t}\n\n\treturn gpifToTabSong(doc);\n}\n\n// ---------------------------------------------------------------------------\n// Format detection\n// ---------------------------------------------------------------------------\n\n/** Detects file format from header bytes and filename. */\nfunction detectFormat(data: Uint8Array, fileName?: string): 'gpx' | 'gp7' | 'gp5' {\n\tif (data.length < 4) {\n\t\tthrow new Error('File too small to be a valid Guitar Pro file');\n\t}\n\n\tconst header = String.fromCharCode(data[0], data[1], data[2], data[3]);\n\n\t// BCFZ or BCFS → GPX format (Guitar Pro 6)\n\tif (header === 'BCFZ' || header === 'BCFS') {\n\t\treturn 'gpx';\n\t}\n\n\t// PK (ZIP signature) → GP7+ format\n\tif (data[0] === 0x50 && data[1] === 0x4B) {\n\t\treturn 'gp7';\n\t}\n\n\t// Check for GP5 version string: first byte is string length, followed by \"FICHIER GUITAR PRO\"\n\tconst strLen = data[0];\n\tif (strLen > 10 && strLen < 50 && data.byteLength > strLen + 1) {\n\t\tconst versionStr = String.fromCharCode(...Array.from(data.subarray(1, 1 + Math.min(strLen, 40))));\n\t\tif (versionStr.includes('GUITAR PRO')) {\n\t\t\treturn 'gp5';\n\t\t}\n\t}\n\n\t// Fall back to file extension\n\tif (fileName) {\n\t\tconst ext = fileName.toLowerCase();\n\t\tif (ext.endsWith('.gpx')) return 'gpx';\n\t\tif (ext.endsWith('.gp5') || ext.endsWith('.gp4') || ext.endsWith('.gp3')) return 'gp5';\n\t\tif (ext.endsWith('.gp')) return 'gp7';\n\t}\n\n\tthrow new Error('Unrecognized Guitar Pro file format');\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Parses any supported Guitar Pro file format into a TabSong.\n * Detects format automatically from file header bytes.\n *\n * Supported: .gpx (GP6), .gp (GP7+), .gp5 (GP5)\n */\nexport function parseTabFile(data: Uint8Array, fileName?: string): TabSong {\n\tconst format = detectFormat(data, fileName);\n\n\tswitch (format) {\n\t\tcase 'gpx':\n\t\t\treturn parseGpxFile(data);\n\t\tcase 'gp7':\n\t\t\treturn parseGp7File(data);\n\t\tcase 'gp5':\n\t\t\treturn parseGp5File(data);\n\t}\n}\n\nexport { detectFormat };\n"],"mappings":";;;;;;;;AAiCA,IAAM,cAA0C;AAAA,EAC/C,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AACL;AAEA,IAAM,aAAyC;AAAA,EAC9C,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AACL;AAEA,IAAM,wBAAwB,oBAAI,IAAgB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC;AAExE,SAAS,kBAAkB,IAAgB,aAAkC;AAC5E,MAAI,sBAAsB,IAAI,EAAE,EAAG,QAAO;AAC1C,SAAO,cAAc,SAAS;AAC/B;AAGO,SAAS,mBACf,IACA,cAAc,OACd,QACO;AACP,QAAM,OAAO,cAAc,WAAW,EAAE,IAAI,YAAY,EAAE;AAC1D,SAAO;AAAA,IACN,YAAY;AAAA,IACZ;AAAA,IACA,YAAY,kBAAkB,IAAI,WAAW;AAAA,IAC7C;AAAA,EACD;AACD;AAGO,SAAS,iBAAiB,MAA0B;AAC1D,UAAU,OAAO,KAAM,MAAM;AAC9B;;;AChEO,SAAS,eAAqC;AACpD,MAAI,OAAO,WAAW,cAAc,aAAa;AAChD,WAAO,WAAW;AAAA,EACnB;AAGA,MAAI;AAEH,UAAM,WAAW,UAAQ,UAAU;AACnC,WAAO,SAAS;AAAA,EACjB,QAAQ;AACP,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACD;;;ACCA,IAAM,iBAAyC;AAAA,EAC9C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACV;AAGO,SAAS,gBACf,UACA,UACA,QACS;AACT,MAAI,QAAQ,eAAe,QAAQ,KAAK;AAGxC,MAAI,WAAW;AACf,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AAClC,gBAAY;AACZ,aAAS;AAAA,EACV;AAGA,MAAI,UAAU,OAAO,MAAM,GAAG;AAC7B,aAAS,OAAO,MAAM,OAAO;AAAA,EAC9B;AAEA,SAAO;AACR;AAGO,SAAS,eAAe,MAAuB;AACrD,QAAM,eAAe,gBAAgB,KAAK,UAAU,KAAK,QAAQ,KAAK,MAAM;AAC5E,QAAM,gBAAgB,MAAQ,KAAK;AACnC,SAAO,eAAe;AACvB;AAWA,IAAM,eAAN,MAAmB;AAAA,EAOlB,YAAY,QAAqB;AAChC,SAAK,OAAO,IAAI,SAAS,MAAM;AAC/B,SAAK,QAAQ,IAAI,WAAW,MAAM;AAClC,SAAK,MAAM;AACX,SAAK,YAAY;AACjB,SAAK,aAAa,OAAO;AAAA,EAC1B;AAAA,EAEA,KAAK,QAAsB;AAC1B,SAAK,MAAM;AACX,SAAK,YAAY;AAAA,EAClB;AAAA,EAEA,cAAsB;AACrB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,WAAmB;AAClB,SAAK,YAAY;AACjB,UAAM,IAAI,KAAK,KAAK,SAAS,KAAK,GAAG;AACrC,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,YAAY,QAAyB;AACpC,SAAK,YAAY;AACjB,QAAI,WAAW,QAAW;AACzB,aAAO,KAAK,KAAK,UAAU,QAAQ,IAAI;AAAA,IACxC;AACA,UAAM,IAAI,KAAK,KAAK,UAAU,KAAK,KAAK,IAAI;AAC5C,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,UAAU,QAAwB;AACjC,SAAK,YAAY;AACjB,UAAM,QAAkB,CAAC;AACzB,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAChC,YAAM,KAAK,KAAK,KAAK,SAAS,KAAK,MAAM,CAAC,CAAC;AAAA,IAC5C;AACA,SAAK,OAAO;AACZ,WAAO,OAAO,aAAa,GAAG,KAAK;AAAA,EACpC;AAAA,EAEA,wBAAwB,QAAgB,WAA2B;AAClE,UAAM,QAAkB,CAAC;AACzB,aAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AACnC,YAAM,OAAO,KAAK,KAAK,SAAS,SAAS,CAAC,IAAI;AAC9C,UAAI,SAAS,EAAG;AAChB,YAAM,KAAK,IAAI;AAAA,IAChB;AACA,WAAO,OAAO,aAAa,GAAG,KAAK;AAAA,EACpC;AAAA,EAEA,SAAS,QAAgB,QAA6B;AACrD,SAAK,YAAY;AACjB,UAAM,QAAQ,WAAW,SAAY,SAAS,KAAK;AACnD,QAAI,WAAW,OAAW,MAAK,OAAO;AACtC,WAAO,IAAI,WAAW,KAAK,KAAK,QAAQ,OAAO,MAAM;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,WAA2B;AACtC,UAAM,YAAY,KAAK,OAAO,KAAK,KAAK;AACxC,UAAM,SAAS,WAAW;AAG1B,UAAM,YAAY,aAAa;AAC/B,UAAM,UAAW,SAAS,MAAO;AAGjC,SAAK,YAAY,SAAS;AAC1B,QAAI,KAAK,cAAc,GAAG;AACzB,WAAK,MAAO,WAAW;AAAA,IACxB,OAAO;AACN,WAAK,MAAM,WAAW;AAAA,IACvB;AAGA,QAAI,YAAY;AAChB,aAAS,IAAI,WAAW,IAAI,SAAS,KAAK;AACzC,kBAAa,aAAa,KAAM,KAAK,MAAM,CAAC,KAAK;AAAA,IAClD;AAGA,UAAM,gBAAgB,WAAW,KAAK;AACtC,gBAAY,cAAc;AAG1B,QAAI,YAAY,IAAI;AACnB,kBAAY,aAAc,KAAK,aAAa;AAAA,IAC7C;AAEA,WAAO;AAAA,EACR;AACD;AAGA,SAAS,iBAAiB,QAAsB,OAAuB;AACtE,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC/B,YAAQ,OAAO,YAAY,CAAC,KAAK;AAAA,EAClC;AACA,SAAO;AACR;AASA,SAAS,cAAc,MAAuB;AAC7C,SAAO,SAAS,gBAAgB,SAAS;AAC1C;AAGA,SAAS,gBAAgB,QAAsB,YAAkC;AAChF,QAAM,iBAAiB,OAAO,YAAY;AAC1C,QAAM,OAAO,IAAI,WAAW,cAAc;AAC1C,MAAI,MAAM;AAEV,MAAI;AACH,WAAO,MAAM,gBAAgB;AAC5B,YAAM,OAAO,OAAO,YAAY,CAAC;AAEjC,UAAI,SAAS,GAAG;AACf,cAAM,WAAW,OAAO,YAAY,CAAC;AACrC,cAAM,SAAS,iBAAiB,QAAQ,QAAQ;AAChD,cAAM,OAAO,iBAAiB,QAAQ,QAAQ;AAE9C,cAAM,iBAAiB,MAAM;AAC7B,cAAM,WAAW,KAAK,IAAI,QAAQ,IAAI;AAEtC,iBAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AAClC,eAAK,MAAM,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAAA,QACxC;AACA,eAAO;AAAA,MACR,OAAO;AACN,cAAM,OAAO,iBAAiB,QAAQ,CAAC;AAEvC,iBAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC9B,eAAK,KAAK,IAAI,OAAO,YAAY,CAAC;AAAA,QACnC;AAAA,MACD;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AAEA,MAAI,YAAY;AACf,WAAO,KAAK,OAAO,MAAM,GAAG,KAAK,UAAU;AAAA,EAC5C;AACA,SAAO,KAAK;AACb;AAGA,SAAS,qBAAqB,QAAqC;AAClE,QAAM,cAAc;AACpB,QAAM,SAAS,IAAI,aAAa,MAAM;AACtC,MAAI,SAAS;AACb,QAAM,QAAwB,CAAC;AAE/B,SAAO,SAAS,cAAc,IAAI,OAAO,YAAY;AACpD,UAAM,YAAY,OAAO,YAAY,MAAM;AAE3C,QAAI,cAAc,GAAG;AACpB,YAAM,OAAO,OAAO,wBAAwB,SAAS,GAAM,GAAG;AAC9D,YAAM,OAAO,OAAO,YAAY,SAAS,GAAI;AAE7C,YAAM,OAAqB,EAAE,MAAM,MAAM,MAAM,KAAK;AACpD,YAAM,KAAK,IAAI;AAEf,YAAM,QAAQ,cAAc,IAAI;AAChC,YAAM,eAAe,SAAS;AAE9B,YAAM,aAA2B,CAAC;AAClC,UAAI,aAAa;AACjB,UAAI;AAEJ,cAAQ,UAAU,OAAO,YAAY,eAAe,IAAI,UAAU,OAAO,GAAG;AAC3E,cAAM,cAAc,UAAU;AAE9B,YAAI,OAAO;AACV,gBAAM,MAAM,cAAc;AAC1B,gBAAM,YACL,MAAM,OAAO,aACV,eAAe,MAAM,OAAO,cAC5B;AACJ,qBAAW,KAAK,OAAO,SAAS,WAAW,WAAW,CAAC;AAAA,QACxD;AAEA;AAAA,MACD;AAEA,UAAI,SAAS,WAAW,SAAS,GAAG;AACnC,cAAM,YAAY,WAAW,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,QAAQ,CAAC;AAC7D,cAAM,WAAW,IAAI,WAAW,KAAK,IAAI,MAAM,SAAS,CAAC;AACzD,YAAI,WAAW;AACf,mBAAW,SAAS,YAAY;AAC/B,mBAAS,IAAI,OAAO,QAAQ;AAC5B,sBAAY,MAAM;AAAA,QACnB;AACA,aAAK,OAAO,SAAS,SAAS,GAAG,KAAK,IAAI,MAAM,SAAS,CAAC;AAAA,MAC3D;AAAA,IACD;AAEA,cAAU;AAAA,EACX;AAEA,SAAO;AACR;AAGA,SAAS,gBAAgB,MAAuC;AAE/D,QAAM,MAAM,IAAI,YAAY,KAAK,UAAU;AAC3C,MAAI,WAAW,GAAG,EAAE,IAAI,IAAI;AAC5B,QAAM,SAAS,IAAI,aAAa,GAAG;AACnC,QAAM,SAAS,OAAO,UAAU,CAAC;AAEjC,MAAI;AAEJ,UAAQ,QAAQ;AAAA,IACf,KAAK;AACJ,yBAAmB,gBAAgB,QAAQ,IAAI;AAC/C;AAAA,IACD,KAAK;AAAQ;AACZ,cAAM,MAAM,OAAO,SAAS,OAAO,aAAa,CAAC;AACjD,cAAM,OAAO,IAAI,YAAY,IAAI,UAAU;AAC3C,YAAI,WAAW,IAAI,EAAE,IAAI,GAAG;AAC5B,2BAAmB;AAAA,MACpB;AACC;AAAA,IACD;AACC,YAAM,IAAI,MAAM,oBAAoB,MAAM,wBAAwB;AAAA,EACpE;AAEA,QAAM,QAAQ,qBAAqB,gBAAgB;AACnD,QAAM,SAAS,oBAAI,IAAoB;AAEvC,aAAW,QAAQ,OAAO;AACzB,QAAI,KAAK,QAAQ,cAAc,KAAK,IAAI,GAAG;AAC1C,YAAM,UAAU,IAAI,YAAY,OAAO;AACvC,aAAO,IAAI,KAAK,MAAM,QAAQ,OAAO,KAAK,IAAI,CAAC;AAAA,IAChD;AAAA,EACD;AAEA,SAAO;AACR;AAOA,SAAS,UAAU,IAAa,KAA4B;AAC3D,QAAM,QAAQ,GAAG,cAAc,YAAY,GAAG,EAAE;AAChD,SAAO,OAAO,aAAa,KAAK,KAAK;AACtC;AAGA,SAAS,mBAAmB,MAAiE;AAC5F,MAAI,CAAC,KAAM,QAAO,EAAE,WAAW,GAAG,aAAa,EAAE;AACjD,QAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,SAAO;AAAA,IACN,WAAW,SAAS,MAAM,CAAC,GAAG,EAAE,KAAK;AAAA,IACrC,aAAa,SAAS,MAAM,CAAC,GAAG,EAAE,KAAK;AAAA,EACxC;AACD;AAGA,SAAS,yBAAyB,eAAyB,aAAqB,MAA0B;AACzG,QAAM,YAAY,cAAc,WAAW,KAAK;AAChD,WAAU,YAAY,QAAQ,KAAK,MAAM;AAC1C;AAGA,SAAS,mBAAmB,YAA8B;AACzD,SAAO,WACL,MAAM,KAAK,EACX,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAC1B,IAAI,MAAM;AACb;AAOA,SAAS,aAAa,cAA8B,MAA8B;AACjF,MAAI,CAAC,aAAc,QAAO;AAC1B,QAAM,QAAQ,aAAa,iBAAiB,mBAAmB;AAC/D,aAAW,QAAQ,OAAO;AACzB,QAAI,KAAK,aAAa,MAAM,MAAM,KAAM,QAAO;AAAA,EAChD;AACA,SAAO;AACR;AAGA,SAAS,UAAU,cAA8B,MAA6B;AAC7E,QAAM,OAAO,aAAa,cAAc,IAAI;AAC5C,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,aAAa,KAAK;AACxB,SAAO,YAAY,aAAa,KAAK,KAAK;AAC3C;AAGA,SAAS,YAAY,cAA8B,MAAuB;AACzE,QAAM,OAAO,aAAa,cAAc,IAAI;AAC5C,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,cAAc,QAAQ,MAAM;AACzC;AAGA,SAAS,UAAU,cAA8B,MAA6B;AAC7E,QAAM,OAAO,aAAa,cAAc,IAAI;AAC5C,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,KAAK,cAAc,OAAO;AAC1C,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,MAAM,SAAS,QAAQ,aAAa,KAAK,KAAK,IAAI,EAAE;AAC1D,SAAO,MAAM,GAAG,IAAI,OAAO;AAC5B;AAGA,SAAS,UAAU,cAA8B,MAA6B;AAC7E,QAAM,OAAO,aAAa,cAAc,IAAI;AAC5C,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,KAAK,cAAc,OAAO;AAC1C,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,MAAM,WAAW,QAAQ,aAAa,KAAK,KAAK,EAAE;AACxD,SAAO,MAAM,GAAG,IAAI,OAAO;AAC5B;AAGA,SAAS,UAAU,cAA8B,MAA6B;AAC7E,QAAM,OAAO,aAAa,cAAc,IAAI;AAC5C,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,KAAK,cAAc,OAAO;AAC1C,SAAO,SAAS,aAAa,KAAK,KAAK;AACxC;AAOA,SAAS,qBAAqB,QAAiB,eAAkC;AAChF,QAAM,UAAU,OAAO,cAAc,qBAAqB;AAE1D,QAAM,cAAc,SAAS,UAAU,SAAS,QAAQ,KAAK,KAAK,EAAE;AACpE,QAAM,OAAO,SAAS,UAAU,SAAS,MAAM,KAAK,KAAK,EAAE;AAE3D,QAAM,KAAK,yBAAyB,eAAe,aAAa,IAAI;AACpE,QAAM,OAAO,mBAAmB,IAAI,KAAK;AAEzC,QAAM,WAAW,YAAY,SAAS,QAAQ;AAC9C,QAAM,OAAO,WACV;AAAA,IACA,QAAQ,UAAU,SAAS,iBAAiB,KAAK;AAAA,IACjD,aAAa,UAAU,SAAS,sBAAsB,KAAK;AAAA,IAC3D,QAAQ,UAAU,SAAS,iBAAiB,KAAK;AAAA,EAClD,IACC;AAEH,QAAM,QAAQ,OAAO,cAAc,cAAc;AACjD,QAAM,YAAY,OAAO,cAAc,kBAAkB;AACzD,QAAM,YAAY,OAAO,cAAc,kBAAkB;AACzD,QAAM,WAAW,OAAO,cAAc,iBAAiB;AAEvD,SAAO;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,IACA,YAAY;AAAA,IACZ,UAAU,KAAK;AAAA,IACf,OAAO,UAAU,SAAS,OAAO;AAAA,IACjC,UAAU,UAAU,SAAS,cAAc;AAAA,IAC3C,UAAU,YAAY,SAAS,WAAW,KAAK;AAAA,IAC/C,OAAO,YAAY,SAAS,OAAO,KAAK;AAAA,IACxC,SAAS,cAAc;AAAA,IACvB;AAAA,IACA,KAAK;AAAA,MACJ,QAAQ,QAAQ,MAAM,aAAa,QAAQ,MAAM,SAAS;AAAA,MAC1D,aAAa,QAAQ,MAAM,aAAa,aAAa,MAAM,SAAS;AAAA,IACrE;AAAA,IACA,SAAS,WAAW,aAAa,KAAK,KAAK;AAAA,IAC3C,UAAU,YAAY,SAAS,YAAY,KAAK;AAAA,IAChD,SAAS,YAAY,SAAS,iBAAiB,KAAK;AAAA,IACpD,QAAQ,YAAY,SAAS,QAAQ,KAAK;AAAA,IAC1C,QAAQ,WAAW,SAAS,SAAS,aAAa,KAAK,KAAK,IAAI,EAAE,KAAK,OAAO;AAAA,EAC/E;AACD;AAOA,SAAS,cAAc,WAA2B,UAAwC;AACzF,QAAM,MAAM,oBAAI,IAAqB;AACrC,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,WAAW,UAAU,iBAAiB,YAAY,QAAQ,EAAE;AAClE,aAAW,SAAS,UAAU;AAC7B,UAAM,KAAK,MAAM,aAAa,IAAI;AAClC,QAAI,GAAI,KAAI,IAAI,IAAI,KAAK;AAAA,EAC1B;AACA,SAAO;AACR;AAGA,SAAS,SAAS,MAA+B;AAChD,MAAI,CAAC,KAAM,QAAO,CAAC;AACnB,SAAO,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AACpD;AAGA,SAAS,cAAc,eAAoD;AAC1E,QAAM,WAAW,oBAAI,IAAoB;AACzC,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,gBAAgB,cAAc,cAAc,sBAAsB;AACxE,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,QAAQ,cAAc,iBAAiB,qBAAqB;AAClE,aAAW,QAAQ,OAAO;AACzB,UAAM,OAAO,UAAU,MAAM,MAAM;AACnC,QAAI,MAAM,YAAY,MAAM,QAAS;AAErC,UAAM,UAAU,UAAU,MAAM,KAAK;AACrC,UAAM,YAAY,UAAU,MAAM,OAAO;AACzC,QAAI,YAAY,QAAQ,cAAc,KAAM;AAE5C,UAAM,WAAW,SAAS,SAAS,EAAE;AACrC,UAAM,QAAQ,WAAW,SAAS;AAClC,QAAI,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,GAAG;AACtC,eAAS,IAAI,UAAU,KAAK;AAAA,IAC7B;AAAA,EACD;AACA,SAAO;AACR;AAGA,SAAS,WAAW,UAAkB,UAA+B,cAA8B;AAClG,WAAS,IAAI,UAAU,KAAK,GAAG,KAAK;AACnC,UAAM,IAAI,SAAS,IAAI,CAAC;AACxB,QAAI,MAAM,OAAW,QAAO;AAAA,EAC7B;AACA,SAAO;AACR;AAGO,SAAS,cAAc,KAAwB;AACrD,QAAM,OAAO,IAAI,cAAc,MAAM;AACrC,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,0CAA0C;AAGrE,QAAM,UAAU,KAAK,cAAc,gBAAgB;AACnD,QAAM,QAAQ,UAAU,UAAU,SAAS,OAAO,KAAK,KAAK;AAC5D,QAAM,SAAS,UAAU,UAAU,SAAS,QAAQ,KAAK,KAAK;AAC9D,QAAM,QAAQ,UAAU,UAAU,SAAS,OAAO,KAAK,KAAK;AAG5D,QAAM,UAAU,cAAc,KAAK,cAAc,gBAAgB,GAAG,MAAM;AAC1E,QAAM,UAAU,cAAc,KAAK,cAAc,gBAAgB,GAAG,MAAM;AAC1E,QAAM,WAAW,cAAc,KAAK,cAAc,iBAAiB,GAAG,OAAO;AAC7E,QAAM,SAAS,cAAc,KAAK,cAAc,eAAe,GAAG,KAAK;AACvE,QAAM,YAAY,cAAc,KAAK,cAAc,kBAAkB,GAAG,QAAQ;AAGhF,QAAM,eAAe,KAAK,cAAc,qBAAqB;AAC7D,QAAM,eAAe,eAClB,MAAM,KAAK,aAAa,iBAAiB,oBAAoB,CAAC,IAC9D,CAAC;AAGJ,QAAM,gBAAgB,KAAK,cAAc,sBAAsB;AAC/D,QAAM,WAAW,cAAc,aAAa;AAE5C,MAAI,eAAe;AACnB,MAAI,SAAS,OAAO,GAAG;AACtB,mBAAe,SAAS,IAAI,CAAC,KAAK;AAAA,EACnC;AAGA,QAAM,WAAW,KAAK,cAAc,iBAAiB;AACrD,QAAM,WAAW,WAAW,MAAM,KAAK,SAAS,iBAAiB,gBAAgB,CAAC,IAAI,CAAC;AAEvF,QAAM,SAAqB,SAAS;AAAA,IAAI,CAAC,YACxC;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAEA,SAAO,EAAE,OAAO,QAAQ,OAAO,OAAO,cAAc,OAAO;AAC5D;AAGA,SAAS,sBACR,SACA,cACA,QACA,UACA,SACA,SACA,WACA,UACA,cACW;AACX,QAAM,UAAU,QAAQ,aAAa,IAAI,KAAK;AAG9C,QAAM,UAAU,QAAQ,cAAc,qBAAqB;AAC3D,MAAI,gBAAgB,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;AAC3C,MAAI,WAAW;AAEf,MAAI,SAAS;AACZ,UAAM,aAAa,aAAa,SAAS,QAAQ;AACjD,QAAI,YAAY;AACf,YAAM,YAAY,WAAW,cAAc,SAAS;AACpD,UAAI,WAAW,aAAa;AAC3B,wBAAgB,mBAAmB,UAAU,YAAY,KAAK,CAAC;AAAA,MAChE;AAAA,IACD;AAEA,UAAM,WAAW,aAAa,SAAS,UAAU;AACjD,QAAI,UAAU;AACb,YAAM,SAAS,SAAS,cAAc,MAAM;AAC5C,UAAI,QAAQ,aAAa;AACxB,cAAM,SAAS,SAAS,OAAO,YAAY,KAAK,GAAG,EAAE;AACrD,YAAI,CAAC,MAAM,MAAM,EAAG,YAAW;AAAA,MAChC;AAAA,IACD;AAAA,EACD;AAGA,QAAM,SAAiB,cACrB,IAAI,CAAC,SAAS,mBAAmB,iBAAiB,IAAI,CAAC,CAAC,EACxD,QAAQ;AAGV,QAAM,aAAa,SAAS,SAAS,EAAE;AACvC,MAAI,kBAAkB;AACtB,QAAM,OAAiB,CAAC;AAExB,WAAS,QAAQ,GAAG,QAAQ,aAAa,QAAQ,SAAS;AACzD,UAAM,cAAc,aAAa,KAAK;AAGtC,UAAM,WAAW,UAAU,aAAa,MAAM;AAC9C,UAAM,SAAS,SAAS,QAAQ;AAEhC,UAAM,QAAQ,OAAO,UAAU,KAAK,OAAO,CAAC;AAC5C,UAAM,QAAQ,QAAQ,OAAO,IAAI,KAAK,IAAI;AAE1C,QAAI,CAAC,OAAO;AACX,WAAK,KAAK,aAAa,OAAO,WAAW,CAAC;AAC1C;AAAA,IACD;AAGA,UAAM,WAAW,UAAU,aAAa,MAAM;AAC9C,UAAM,UAAU,mBAAmB,QAAQ;AAG3C,UAAM,QAAQ,YAAY,cAAc,cAAc;AACtD,UAAM,SAAS,QACZ;AAAA,MACA,iBAAiB,SAAS,UAAU,OAAO,iBAAiB,KAAK,KAAK,EAAE;AAAA,MACxE,MAAO,UAAU,OAAO,MAAM,GAAG,YAAY,KAAK;AAAA,IACnD,IACC;AAGH,UAAM,YAAY,YAAY,cAAc,kBAAkB;AAC9D,UAAM,UAAU,YACb;AAAA,MACA,QAAQ,UAAU,aAAa,QAAQ,KAAK;AAAA,MAC5C,MAAM,UAAU,aAAa,MAAM,KAAK;AAAA,IACzC,IACC;AAGH,UAAM,WAAW,YAAY,cAAc,iBAAiB;AAC5D,UAAM,cAAc,WAAW,SAAS,aAAa,OAAO,MAAM,SAAS;AAC3E,UAAM,YAAY,WAAW,SAAS,aAAa,KAAK,MAAM,SAAS;AACvE,UAAM,cAAc,WAAW,SAAS,SAAS,aAAa,OAAO,KAAK,KAAK,EAAE,KAAK,IAAI;AAG1F,UAAM,aAAa,UAAU,OAAO,QAAQ;AAC5C,UAAM,WAAW,SAAS,UAAU;AACpC,UAAM,WAAsB,CAAC;AAC7B,UAAM,eAAe,WAAW,OAAO,UAAU,YAAY;AAG7D,QAAI,SAAS,SAAS,GAAG;AACxB,YAAM,UAAU,SAAS,IAAI,SAAS,CAAC,CAAC;AACxC,UAAI,SAAS;AACZ,cAAM,iBAAiB,UAAU,SAAS,OAAO;AACjD,cAAM,eAAe,SAAS,cAAc;AAE5C,mBAAW,UAAU,cAAc;AAClC,gBAAM,SAAS,QAAQ,IAAI,MAAM;AACjC,cAAI,CAAC,OAAQ;AAGb,gBAAM,YAAY,OAAO,cAAc,iBAAiB,GAAG,aAAa,KAAK;AAC7E,gBAAM,WAAW,YAAY,UAAU,IAAI,SAAS,IAAI;AAGxD,gBAAM,YAAY,UAAU,QAAQ,OAAO;AAC3C,gBAAM,UAAU,SAAS,SAAS;AAClC,gBAAM,cAAc,cAAc;AAClC,gBAAM,WAAsB,QAC1B,IAAI,CAAC,QAAQ,QAAQ,IAAI,GAAG,CAAC,EAC7B,OAAO,CAAC,MAAoB,MAAM,MAAS,EAC3C,IAAI,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC,EACjD,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,QAAQ,cAAc,IAAI,EAAE,OAAO,EAAE;AAG3D,gBAAM,gBAAgB,WACnB,UAAU,UAAU,WAAW,IAC/B;AACH,gBAAM,WAAY,eAAe,YAAY,KAAK;AAGlD,gBAAM,WAAW,UAAU,cAAc,wBAAwB;AACjE,gBAAM,SAAS,WACZ;AAAA,YACA,KAAK,SAAS,SAAS,aAAa,KAAK,KAAK,KAAK,EAAE,KAAK;AAAA,YAC1D,KAAK,SAAS,SAAS,aAAa,KAAK,KAAK,KAAK,EAAE,KAAK;AAAA,UAC3D,IACC;AAGH,gBAAM,QAAQ,UAAU,cAAc,0BAA0B;AAChE,gBAAM,WAAW,QACd,SAAS,MAAM,aAAa,OAAO,KAAK,KAAK,EAAE,KAAK,IACpD;AAEH,gBAAM,SAAS,SAAS,WAAW;AAGnC,gBAAM,cAAc,UAAU,QAAQ,SAAS;AAE/C,mBAAS,KAAK;AAAA,YACb,OAAO;AAAA,YACP,UAAU;AAAA,YACV,OAAO;AAAA,YACP;AAAA,YACA,QAAQ,WAAW,OAAO,QAAQ,KAAK,OAAO,QAAQ,KAAK,SAAS;AAAA,YACpE,QAAQ;AAAA,YACR;AAAA,YACA,SAAS;AAAA,YACT,OAAO;AAAA,UACR,CAAC;AAAA,QACF;AAAA,MACD;AAAA,IACD;AAEA,SAAK,KAAK;AAAA,MACT,OAAO;AAAA,MACP,eAAe;AAAA,MACf,cAAc;AAAA,MACd;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC;AAAA,EACF;AAEA,SAAO;AAAA,IACN,IAAI;AAAA,IACJ,MAAM,UAAU,SAAS,MAAM,KAAK;AAAA,IACpC,WAAW,UAAU,SAAS,WAAW,KAAK;AAAA,IAC9C,YAAY,QAAQ,cAAc,qBAAqB,GAAG,aAAa,KAAK,KAAK;AAAA,IACjF;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAGA,SAAS,aAAa,OAAe,aAA8B;AAClE,QAAM,WAAW,UAAU,aAAa,MAAM;AAC9C,SAAO;AAAA,IACN;AAAA,IACA,eAAe,mBAAmB,QAAQ;AAAA,IAC1C,cAAc;AAAA,IACd,SAAS;AAAA,IACT,OAAO,CAAC;AAAA,IACR,aAAa;AAAA,IACb,WAAW;AAAA,IACX,aAAa;AAAA,EACd;AACD;AASO,SAAS,aAAa,MAA2B;AAEvD,QAAM,QAAQ,gBAAgB,IAAI;AAClC,QAAM,UAAU,MAAM,IAAI,YAAY;AACtC,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,MAAM,oCAAoC;AAAA,EACrD;AAGA,QAAM,gBAAgB,aAAa;AACnC,QAAM,SAAS,IAAI,cAAc;AACjC,QAAM,MAAM,OAAO,gBAAgB,SAAS,UAAU;AAEtD,QAAM,aAAa,IAAI,cAAc,aAAa;AAClD,MAAI,YAAY;AACf,UAAM,IAAI,MAAM,6BAA6B,WAAW,WAAW,EAAE;AAAA,EACtE;AAGA,SAAO,cAAc,GAAG;AACzB;;;AC1xBA,IAAM,YAAN,MAAgB;AAAA,EAMf,YAAY,QAAqB;AAChC,SAAK,OAAO,IAAI,SAAS,MAAM;AAC/B,SAAK,MAAM,IAAI,WAAW,MAAM;AAChC,SAAK,MAAM;AACX,SAAK,aAAa,OAAO;AAAA,EAC1B;AAAA,EAEA,cAAsB;AACrB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,KAAK,GAAiB;AACrB,SAAK,OAAO;AAAA,EACb;AAAA,EAEA,WAAmB;AAClB,UAAM,IAAI,KAAK,IAAI,KAAK,GAAG;AAC3B,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,iBAAyB;AACxB,UAAM,IAAI,KAAK,KAAK,QAAQ,KAAK,GAAG;AACpC,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,WAAoB;AACnB,WAAO,KAAK,SAAS,MAAM;AAAA,EAC5B;AAAA,EAEA,YAAoB;AACnB,UAAM,IAAI,KAAK,KAAK,SAAS,KAAK,KAAK,IAAI;AAC3C,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,UAAkB;AACjB,UAAM,IAAI,KAAK,KAAK,SAAS,KAAK,KAAK,IAAI;AAC3C,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,aAAqB;AACpB,UAAM,IAAI,KAAK,KAAK,WAAW,KAAK,KAAK,IAAI;AAC7C,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,wBAAgC;AAC/B,UAAM,YAAY,KAAK,QAAQ;AAC/B,UAAM,SAAS,KAAK,SAAS;AAC7B,UAAM,MAAM,KAAK,UAAU,MAAM;AACjC,UAAM,UAAU,KAAK,IAAI,GAAG,YAAY,IAAI,MAAM;AAClD,SAAK,KAAK,OAAO;AACjB,WAAO;AAAA,EACR;AAAA;AAAA,EAGA,gBAAwB;AACvB,UAAM,MAAM,KAAK,QAAQ;AACzB,QAAI,OAAO,EAAG,QAAO;AACrB,WAAO,KAAK,UAAU,GAAG;AAAA,EAC1B;AAAA;AAAA,EAGA,mBAAmB,UAA0B;AAC5C,UAAM,SAAS,KAAK,SAAS;AAC7B,UAAM,MAAM,KAAK,UAAU,KAAK,IAAI,QAAQ,QAAQ,CAAC;AACrD,UAAM,YAAY,WAAW,KAAK,IAAI,QAAQ,QAAQ;AACtD,SAAK,KAAK,SAAS;AACnB,WAAO;AAAA,EACR;AAAA,EAEQ,UAAU,QAAwB;AACzC,UAAM,QAAkB,CAAC;AACzB,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAChC,YAAM,KAAK,KAAK,IAAI,KAAK,MAAM,CAAC,CAAC;AAAA,IAClC;AACA,SAAK,OAAO;AACZ,WAAO,OAAO,aAAa,GAAG,KAAK;AAAA,EACpC;AACD;AAYA,SAAS,mBAAmB,YAAgC;AAC3D,QAAM,QAAQ,WAAW,MAAM,eAAe;AAC9C,MAAI,CAAC,MAAO,QAAO,EAAE,OAAO,GAAG,OAAO,IAAI,OAAO,EAAE;AACnD,SAAO;AAAA,IACN,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC5B,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC5B,OAAO;AAAA,EACR;AACD;AAEA,SAAS,mBAAmB,GAAe,OAAe,OAAe,OAAwB;AAChG,MAAI,EAAE,UAAU,MAAO,QAAO,EAAE,QAAQ;AACxC,MAAI,EAAE,UAAU,MAAO,QAAO,EAAE,QAAQ;AACxC,SAAO,EAAE,QAAQ;AAClB;AAMA,IAAM,kBAA4C;AAAA,EACjD,CAAC,EAAE,GAAG;AAAA,EACN,CAAC,EAAE,GAAG;AAAA,EACN,CAAC,CAAC,GAAG;AAAA,EACL,CAAC,CAAC,GAAG;AAAA,EACL,CAAC,CAAC,GAAG;AAAA,EACL,CAAC,CAAC,GAAG;AAAA,EACL,CAAC,CAAC,GAAG;AAAA,EACL,CAAC,CAAC,GAAG;AACN;AAEA,SAAS,qBAAqB,OAAyB;AACtD,SAAO,gBAAgB,KAAK,KAAK;AAClC;AAMA,IAAM,aAA2D;AAAA,EAChE,GAAG,EAAE,KAAK,GAAG,KAAK,EAAE;AAAA,EACpB,GAAG,EAAE,KAAK,GAAG,KAAK,EAAE;AAAA,EACpB,GAAG,EAAE,KAAK,GAAG,KAAK,EAAE;AAAA,EACpB,GAAG,EAAE,KAAK,GAAG,KAAK,EAAE;AAAA,EACpB,GAAG,EAAE,KAAK,GAAG,KAAK,EAAE;AAAA,EACpB,IAAI,EAAE,KAAK,IAAI,KAAK,EAAE;AAAA,EACtB,IAAI,EAAE,KAAK,IAAI,KAAK,EAAE;AAAA,EACtB,IAAI,EAAE,KAAK,IAAI,KAAK,EAAE;AAAA,EACtB,IAAI,EAAE,KAAK,IAAI,KAAK,EAAE;AACvB;AAMA,IAAM,oBAA4C;AAAA,EACjD,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACJ;AAsFA,SAAS,SAAS,GAAkF;AACnG,QAAM,QAAQ,EAAE,sBAAsB;AACtC,QAAM,WAAW,EAAE,sBAAsB;AACzC,QAAM,SAAS,EAAE,sBAAsB;AACvC,QAAM,QAAQ,EAAE,sBAAsB;AACtC,IAAE,sBAAsB;AACxB,IAAE,sBAAsB;AACxB,IAAE,sBAAsB;AACxB,IAAE,sBAAsB;AACxB,IAAE,sBAAsB;AAExB,QAAM,cAAc,EAAE,QAAQ;AAC9B,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACrC,MAAE,sBAAsB;AAAA,EACzB;AAEA,SAAO,EAAE,OAAO,UAAU,QAAQ,MAAM;AACzC;AAEA,SAAS,WAAW,GAAoB;AACvC,IAAE,QAAQ;AACV,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC3B,MAAE,QAAQ;AACV,MAAE,cAAc;AAAA,EACjB;AACD;AAEA,SAAS,oBAAoB,GAAc,SAA2B;AACrE,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,MAAE,QAAQ;AACV,MAAE,QAAQ;AACV,kBAAc,GAAG,EAAE;AAAA,EACpB;AACD;AAEA,SAAS,cAAc,GAAc,OAAqB;AACzD,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC/B,MAAE,eAAe;AAAA,EAClB;AACD;AAEA,SAAS,cAAc,GAAoB;AAC1C,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,UAAU;AACZ,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC5B,MAAE,sBAAsB;AAAA,EACzB;AACD;AAEA,SAAS,eAAe,GAAoB;AAC3C,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC5B,MAAE,UAAU;AAAA,EACb;AACD;AAEA,SAAS,iBAAiB,GAA6B;AACtD,QAAM,WAA0B,CAAC;AACjC,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC5B,UAAM,aAAa,EAAE,QAAQ;AAC7B,UAAM,SAAS,EAAE,SAAS;AAC1B,UAAM,UAAU,EAAE,SAAS;AAC3B,UAAM,SAAS,EAAE,SAAS;AAC1B,UAAM,SAAS,EAAE,SAAS;AAC1B,UAAM,SAAS,EAAE,SAAS;AAC1B,UAAM,UAAU,EAAE,SAAS;AAC3B,MAAE,KAAK,CAAC;AACR,aAAS,KAAK,EAAE,YAAY,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EAC/E;AACA,SAAO;AACR;AAEA,SAAS,mBAAmB,GAAc,OAAe,UAAuC;AAC/F,QAAM,UAA2B,CAAC;AAClC,MAAI,gBAAgB;AACpB,MAAI,kBAAkB;AAEtB,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC/B,QAAI,IAAI,GAAG;AACV,QAAE,KAAK,CAAC;AAAA,IACT;AAEA,UAAM,QAAQ,EAAE,SAAS;AAEzB,QAAI,YAAY;AAChB,QAAI,cAAc;AAElB,QAAI,QAAQ,GAAM;AACjB,kBAAY,EAAE,eAAe;AAAA,IAC9B;AACA,QAAI,QAAQ,GAAM;AACjB,oBAAc,EAAE,eAAe;AAAA,IAChC;AAEA,UAAM,cAAc,QAAQ,OAAU;AAEtC,QAAI,cAAc;AAClB,QAAI,QAAQ,GAAM;AACjB,oBAAc,EAAE,eAAe;AAC/B,UAAI,cAAc,EAAG,gBAAe;AAAA,IACrC;AAEA,QAAI,SAAkC;AACtC,QAAI,QAAQ,IAAM;AACjB,YAAM,OAAO,EAAE,sBAAsB;AACrC,YAAM,SAAS,EAAE,SAAS;AAC1B,YAAM,SAAS,EAAE,SAAS;AAC1B,YAAM,SAAS,EAAE,SAAS;AAC1B,QAAE,KAAK,CAAC;AACR,eAAS,EAAE,MAAM,OAAO,CAAC,QAAQ,QAAQ,MAAM,EAAE;AAAA,IAClD;AAEA,QAAI,eAAe;AACnB,QAAI,UAAU;AACd,QAAI,QAAQ,IAAM;AACjB,qBAAe,EAAE,eAAe;AAChC,gBAAU,EAAE,eAAe;AAAA,IAC5B;AAEA,UAAM,gBAAgB,QAAQ,SAAU;AAExC,QAAI,oBAAoB;AACxB,QAAI,QAAQ,IAAM;AACjB,0BAAoB,EAAE,SAAS;AAAA,IAChC;AAGA,QAAI,QAAQ,GAAM;AACjB,QAAE,KAAK,CAAC;AAAA,IACT;AAGA,QAAI,EAAE,QAAQ,KAAO;AACpB,QAAE,KAAK,CAAC;AAAA,IACT;AAEA,UAAM,cAAc,EAAE,SAAS;AAE/B,YAAQ,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD,CAAC;AAED,oBAAgB;AAChB,sBAAkB;AAAA,EACnB;AAEA,SAAO;AACR;AAEA,SAAS,iBAAiB,GAAc,OAAe,SAAoC;AAC1F,QAAM,SAAwB,CAAC;AAE/B,WAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAE/B,QAAI,MAAM,KAAK,mBAAmB,SAAS,GAAG,GAAG,CAAC,MAAM,OAAO;AAC9D,QAAE,KAAK,CAAC;AAAA,IACT;AAEA,UAAM,SAAS,EAAE,SAAS;AAC1B,UAAM,gBAAgB,SAAS,OAAU;AAEzC,UAAM,OAAO,EAAE,mBAAmB,EAAE;AACpC,UAAM,aAAa,EAAE,QAAQ;AAE7B,UAAM,SAAmB,CAAC;AAC1B,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC3B,YAAM,MAAM,EAAE,QAAQ;AACtB,UAAI,IAAI,WAAY,QAAO,KAAK,GAAG;AAAA,IACpC;AAEA,UAAM,OAAO,EAAE,QAAQ;AACvB,UAAM,eAAe,EAAE,QAAQ,IAAI;AACnC,UAAM,gBAAgB,EAAE,QAAQ,IAAI;AACpC,UAAM,YAAY,EAAE,QAAQ;AAC5B,UAAM,WAAW,EAAE,QAAQ;AAC3B,MAAE,KAAK,CAAC;AAER,WAAO,KAAK,EAAE,MAAM,cAAc,YAAY,QAAQ,MAAM,cAAc,eAAe,WAAW,SAAS,CAAC;AAG9G,MAAE,UAAU;AAGZ,MAAE,SAAS;AACX,MAAE,SAAS;AAGX,iBAAa,GAAG,OAAO;AAAA,EACxB;AAGA,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,MAAE,KAAK,CAAC;AAAA,EACT,OAAO;AACN,MAAE,KAAK,CAAC;AAAA,EACT;AAEA,SAAO;AACR;AAEA,SAAS,aAAa,GAAc,SAA2B;AAC9D,IAAE,SAAS;AACX,IAAE,KAAK,EAAE;AACT,IAAE,KAAK,EAAE;AACT,oBAAkB,GAAG,OAAO;AAC5B,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,kBAAc,GAAG,CAAC;AAClB,4BAAwB,GAAG,OAAO;AAAA,EACnC;AACD;AAEA,SAAS,kBAAkB,GAAc,SAA2B;AACnE,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,IAAE,QAAQ;AACV,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,MAAE,QAAQ;AAAA,EACX,OAAO;AACN,MAAE,UAAU;AACZ,MAAE,KAAK,CAAC;AAAA,EACT;AACD;AAEA,SAAS,wBAAwB,GAAc,SAA2B;AACzE,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,MAAE,sBAAsB;AACxB,MAAE,sBAAsB;AAAA,EACzB;AACD;AAMA,SAAS,aACR,GACA,cACA,YACA,SACsB;AAEtB,QAAM,cAAmC,CAAC;AAC1C,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACpC,gBAAY,KAAK,CAAC,CAAC;AAAA,EACpB;AAIA,WAAS,IAAI,GAAG,IAAI,cAAc,KAAK;AACtC,aAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACpC,YAAM,cAAc,UAAU,GAAG,OAAO;AACxC,YAAM,cAAc,UAAU,GAAG,OAAO;AACxC,QAAE,SAAS;AAGX,YAAM,QAAQ,YAAY,SAAS,IAAI,cAAc;AACrD,kBAAY,CAAC,EAAE,KAAK,KAAK;AAAA,IAC1B;AAAA,EACD;AAEA,SAAO;AACR;AAEA,SAAS,UAAU,GAAc,SAAsC;AACtE,QAAM,YAAY,EAAE,QAAQ;AAC5B,QAAM,QAAyB,CAAC;AAEhC,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AACnC,UAAM,KAAK,SAAS,GAAG,OAAO,CAAC;AAAA,EAChC;AAEA,SAAO;AACR;AAEA,SAAS,SAAS,GAAc,SAAoC;AACnE,QAAM,QAAQ,EAAE,SAAS;AAEzB,MAAI,SAAS;AACb,MAAI,UAAU;AACd,MAAI,QAAQ,IAAM;AACjB,UAAM,SAAS,EAAE,SAAS;AAC1B,cAAU,WAAW;AACrB,aAAS,WAAW;AAAA,EACrB;AAGA,QAAM,gBAAgB,EAAE,eAAe;AACvC,QAAM,WAAW,qBAAqB,aAAa;AACnD,QAAM,UAAU,QAAQ,OAAU;AAElC,MAAI,SAA8C;AAClD,MAAI,QAAQ,IAAM;AACjB,UAAM,cAAc,EAAE,QAAQ;AAC9B,aAAS,WAAW,WAAW,KAAK;AAAA,EACrC;AAGA,MAAI,QAAQ,GAAM;AACjB,cAAU,GAAG,OAAO;AAAA,EACrB;AAGA,MAAI,QAAQ,GAAM;AACjB,MAAE,sBAAsB;AAAA,EACzB;AAGA,MAAI,QAAQ,GAAM;AACjB,oBAAgB,GAAG,OAAO;AAAA,EAC3B;AAGA,MAAI,QAAQ,IAAM;AACjB,uBAAmB,GAAG,OAAO;AAAA,EAC9B;AAGA,QAAM,cAAc,EAAE,SAAS;AAC/B,QAAM,QAAyB,CAAC;AAEhC,WAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC5B,QAAI,cAAe,KAAK,GAAI;AAC3B,YAAM,KAAK,SAAS,GAAG,OAAO,CAAC;AAAA,IAChC;AAAA,EACD;AAGA,QAAM,SAAS,EAAE,UAAU;AAC3B,MAAI,SAAS,MAAQ;AACpB,MAAE,SAAS;AAAA,EACZ;AAEA,SAAO,EAAE,UAAU,QAAQ,QAAQ,QAAQ,UAAU,SAAS,SAAS,MAAM;AAC9E;AAEA,SAAS,UAAU,GAAc,UAA4B;AAC5D,QAAM,SAAS,EAAE,SAAS;AAC1B,MAAI,WAAW,GAAG;AAEjB,MAAE,sBAAsB;AACxB,UAAM,YAAY,EAAE,QAAQ;AAC5B,QAAI,cAAc,GAAG;AACpB,eAAS,IAAI,GAAG,IAAI,GAAG,IAAK,GAAE,QAAQ;AAAA,IACvC;AAAA,EACD,OAAO;AAEN,MAAE,KAAK,EAAE;AACT,MAAE,mBAAmB,EAAE;AACvB,MAAE,SAAS;AACX,MAAE,SAAS;AACX,MAAE,SAAS;AACX,aAAS,IAAI,GAAG,IAAI,GAAG,IAAK,GAAE,QAAQ;AACtC,MAAE,SAAS;AACX,MAAE,KAAK,CAAC;AACR,MAAE,KAAK,CAAC;AACR,MAAE,KAAK,CAAC;AACR,MAAE,KAAK,CAAC;AACR,MAAE,KAAK,CAAC;AACR,MAAE,KAAK,CAAC;AACR,MAAE,SAAS;AAAA,EACZ;AACD;AAEA,SAAS,gBAAgB,GAAc,UAA4B;AAElE,QAAM,SAAS,EAAE,SAAS;AAC1B,QAAM,SAAS,EAAE,SAAS;AAE1B,MAAI,SAAS,IAAM;AAClB,UAAM,aAAa,EAAE,eAAe;AACpC,QAAI,eAAe,GAAG;AAErB,eAAS,CAAC;AAAA,IACX;AAAA,EACD;AAEA,MAAI,SAAS,GAAM;AAElB,aAAS,CAAC;AAAA,EACX;AAEA,MAAI,SAAS,IAAM;AAElB,MAAE,SAAS;AACX,MAAE,SAAS;AAAA,EACZ;AAEA,MAAI,SAAS,GAAM;AAElB,MAAE,eAAe;AAAA,EAClB;AACD;AAEA,SAAS,SAAS,GAAgH;AACjI,QAAM,OAAO,EAAE,eAAe;AAC9B,QAAM,QAAQ,EAAE,QAAQ;AACxB,QAAM,aAAa,EAAE,QAAQ;AAC7B,QAAM,SAAkE,CAAC;AACzE,WAAS,IAAI,GAAG,IAAI,YAAY,KAAK;AACpC,UAAM,WAAW,EAAE,QAAQ;AAC3B,UAAM,aAAa,EAAE,QAAQ;AAC7B,UAAM,UAAU,EAAE,SAAS;AAC3B,WAAO,KAAK,EAAE,UAAU,OAAO,YAAY,QAAQ,CAAC;AAAA,EACrD;AACA,SAAO,EAAE,MAAM,OAAO,OAAO;AAC9B;AAEA,SAAS,mBAAmB,GAAc,SAA2B;AACpE,IAAE,eAAe;AAGjB,oBAAkB,GAAG,OAAO;AAC5B,MAAI,CAAC,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AAC1C,MAAE,KAAK,CAAC;AAAA,EACT;AAEA,QAAM,SAAS,EAAE,eAAe;AAChC,QAAM,UAAU,EAAE,eAAe;AACjC,QAAM,SAAS,EAAE,eAAe;AAChC,QAAM,SAAS,EAAE,eAAe;AAChC,QAAM,SAAS,EAAE,eAAe;AAChC,QAAM,UAAU,EAAE,eAAe;AAEjC,IAAE,sBAAsB;AACxB,QAAM,QAAQ,EAAE,QAAQ;AAGxB,MAAI,UAAU,EAAG,GAAE,eAAe;AAClC,MAAI,WAAW,EAAG,GAAE,eAAe;AACnC,MAAI,UAAU,EAAG,GAAE,eAAe;AAClC,MAAI,UAAU,EAAG,GAAE,eAAe;AAClC,MAAI,UAAU,EAAG,GAAE,eAAe;AAClC,MAAI,WAAW,EAAG,GAAE,eAAe;AACnC,MAAI,SAAS,GAAG;AACf,MAAE,eAAe;AACjB,QAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,QAAE,SAAS;AAAA,IACZ;AAAA,EACD;AAGA,IAAE,SAAS;AAGX,IAAE,eAAe;AAGjB,0BAAwB,GAAG,OAAO;AACnC;AAEA,SAAS,SAAS,GAAc,SAAoC;AACnE,QAAM,QAAQ,EAAE,SAAS;AAEzB,QAAM,eAAe,QAAQ,OAAU;AACvC,QAAM,UAAU,QAAQ,QAAU;AAElC,MAAI,SAAS;AACb,MAAI,SAAS;AACb,MAAI,QAAQ,IAAM;AACjB,UAAM,WAAW,EAAE,SAAS;AAC5B,aAAS,aAAa;AACtB,aAAS,aAAa;AAAA,EACvB;AAEA,MAAI,WAAW;AACf,MAAI,QAAQ,IAAM;AACjB,eAAW,EAAE,eAAe;AAAA,EAC7B;AAEA,MAAI,OAAO;AACX,MAAI,QAAQ,IAAM;AACjB,WAAO,EAAE,eAAe;AACxB,QAAI,OAAO,KAAK,OAAO,GAAI,QAAO;AAAA,EACnC;AAEA,MAAI,QAAQ,KAAM;AACjB,MAAE,eAAe;AACjB,MAAE,eAAe;AAAA,EAClB;AAEA,MAAI,QAAQ,GAAM;AACjB,MAAE,WAAW;AAAA,EACd;AAGA,IAAE,SAAS;AAGX,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,QAAuB;AAC3B,MAAI,WAA0B;AAC9B,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,OAA8B;AAClC,MAAI,WAAW;AACf,MAAI,QAAgC;AACpC,MAAI,iBAAgC;AAEpC,MAAI,QAAQ,GAAM;AACjB,UAAM,SAAS,gBAAgB,GAAG,OAAO;AACzC,eAAW,OAAO;AAClB,cAAU,OAAO;AACjB,YAAQ,OAAO;AACf,eAAW,OAAO;AAClB,eAAW,OAAO;AAClB,cAAU,OAAO;AACjB,WAAO,OAAO;AACd,eAAW,OAAO;AAClB,YAAQ,OAAO;AACf,qBAAiB,OAAO;AAAA,EACzB;AAEA,SAAO;AAAA,IACN,QAAQ;AAAA;AAAA,IACR;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,EACD;AACD;AAeA,SAAS,gBAAgB,GAAc,SAAwC;AAE9E,QAAM,SAAS,EAAE,SAAS;AAC1B,QAAM,SAAS,EAAE,SAAS;AAE1B,MAAI,OAA8B;AAClC,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,QAAuB;AAC3B,MAAI,WAA0B;AAC9B,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,QAAgC;AACpC,MAAI,iBAAgC;AAEpC,MAAI,SAAS,GAAM;AAClB,WAAO,SAAS,CAAC;AAAA,EAClB;AACA,cAAY,SAAS,OAAU;AAC/B,aAAW,SAAS,OAAU;AAE9B,MAAI,SAAS,IAAM;AAClB,kBAAc,GAAG,OAAO;AAAA,EACzB;AAEA,cAAY,SAAS,OAAU;AAC/B,cAAY,SAAS,OAAU;AAE/B,MAAI,SAAS,GAAM;AAClB,qBAAiB,EAAE,eAAe;AAAA,EACnC;AAEA,MAAI,SAAS,GAAM;AAElB,YAAQ,EAAE,SAAS;AAAA,EACpB;AAEA,MAAI,SAAS,IAAM;AAClB,UAAM,eAAe,EAAE,eAAe;AACtC,eAAW,kBAAkB,YAAY,KAAK;AAC9C,QAAI,iBAAiB,GAAG;AAEvB,QAAE,SAAS;AACX,QAAE,eAAe;AACjB,QAAE,SAAS;AAAA,IACZ,WAAW,iBAAiB,GAAG;AAC9B,QAAE,SAAS;AAAA,IACZ;AAAA,EACD;AAEA,MAAI,SAAS,IAAM;AAClB,UAAM,YAAY,EAAE,eAAe;AACnC,UAAM,cAAc,EAAE,eAAe;AACrC,YAAQ,EAAE,MAAM,WAAW,QAAQ,YAAY;AAAA,EAChD;AAEA,aAAW,SAAS,QAAU;AAE9B,SAAO,EAAE,UAAU,SAAS,OAAO,UAAU,UAAU,SAAS,MAAM,UAAU,OAAO,eAAe;AACvG;AAEA,SAAS,cAAc,GAAc,SAA2B;AAC/D,IAAE,SAAS;AACX,IAAE,SAAS;AACX,IAAE,SAAS;AACX,IAAE,SAAS;AACX,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,MAAE,SAAS;AAAA,EACZ,OAAO;AACN,MAAE,SAAS;AAAA,EACZ;AACD;AAMA,SAAS,mBACR,MACA,OACA,gBACA,cACA,gBACA,UACU;AACV,QAAM,SAAqB,aAAa,IAAI,CAAC,IAAI,aAAa;AAC7D,UAAM,gBAAgB,GAAG;AACzB,UAAM,SAAiB,cACrB,IAAI,CAAC,SAAS,mBAAmB,iBAAiB,IAAI,CAAC,CAAC,EACxD,QAAQ;AAEV,QAAI,kBAAkB;AACtB,UAAM,OAAiB,CAAC;AAExB,aAAS,OAAO,GAAG,OAAO,eAAe,QAAQ,QAAQ;AACxD,YAAM,KAAK,eAAe,IAAI;AAC9B,YAAM,YAAY,eAAe,QAAQ,IAAI,IAAI,KAAK,CAAC;AAEvD,YAAM,WAAsB,CAAC;AAE7B,iBAAW,YAAY,WAAW;AACjC,YAAI,SAAS,QAAS;AAEtB,cAAM,cAAc,GAAG;AACvB,cAAM,WAAsB,CAAC;AAI7B,YAAI,kBAAkB;AACtB,mBAAW,YAAY,SAAS,OAAO;AACtC,gBAAM,YAAY,cAAc,IAAI;AACpC,gBAAM,OAAO,SAAS;AACtB,gBAAM,YAAY,cAAc,eAAe,KAAK;AACpD,gBAAM,OAAQ,YAAY,QAAQ,KAAK,MAAM;AAC7C,gBAAM,OAAO,mBAAmB,IAAI,KAAK;AAEzC,cAAI,aAA8B;AAClC,cAAI,SAAS,MAAM;AAClB,kBAAM,SAAS,SAAS,KAAK;AAC7B,kBAAM,SAAS,OAAO,SAAS,IAAI,OAAO,CAAC,EAAE,QAAQ,MAAM;AAC3D,kBAAM,cAAc,OAAO,SAAS,IAAI,OAAO,OAAO,SAAS,CAAC,EAAE,QAAQ,MAAM;AAChF,kBAAM,SAAS,OAAO,SAAS,IAAI,OAAO,KAAK,MAAM,OAAO,SAAS,CAAC,CAAC,EAAE,QAAQ,MAAM;AACvF,yBAAa,EAAE,QAAQ,aAAa,OAAO;AAAA,UAC5C;AAEA,mBAAS,KAAK;AAAA,YACb,QAAQ;AAAA,YACR;AAAA,YACA,YAAY;AAAA,YACZ,UAAU,KAAK;AAAA,YACf,OAAO,SAAS;AAAA,YAChB,UAAU,SAAS;AAAA,YACnB,UAAU,SAAS;AAAA,YACnB,OAAO,SAAS;AAAA,YAChB,SAAS,SAAS;AAAA,YAClB,MAAM;AAAA,YACN,KAAK;AAAA,cACJ,QAAQ;AAAA,cACR,aAAa,SAAS;AAAA,YACvB;AAAA,YACA,SAAS,SAAS,UAAU,WAAW;AAAA,YACvC,UAAU,SAAS;AAAA,YACnB,SAAS;AAAA;AAAA,YACT,QAAQ;AAAA,YACR,QAAQ,SAAS,SAAS,IAAI,SAAS,cAAc,IAAI;AAAA,UAC1D,CAAC;AAED;AAAA,QACD;AAEA,iBAAS,KAAK;AAAA,UACb,OAAO;AAAA,UACP,UAAU;AAAA,UACV,OAAO;AAAA,UACP,UAAU,SAAS;AAAA,UACnB,QAAQ,SAAS;AAAA,UACjB,QAAQ,SAAS,SAAS,IAAI;AAAA,UAC9B,QAAQ,SAAS,UAAU,SAAS,WAAW;AAAA,UAC/C,SAAS;AAAA,UACT;AAAA,QACD,CAAC;AAAA,MACF;AAEA,YAAM,UAAU,GAAG,SAChB,EAAE,MAAM,GAAG,OAAO,KAAK,IACvB;AAEH,WAAK,KAAK;AAAA,QACT,OAAO;AAAA,QACP,eAAe,EAAE,WAAW,GAAG,WAAW,aAAa,GAAG,YAAY;AAAA,QACtE,cAAc,GAAG,iBAAiB,IAC/B,EAAE,iBAAiB,GAAG,cAAc,MAAM,GAAG,YAAY,IAAI,UAAU,QAAQ,IAC/E;AAAA,QACH;AAAA,QACA,OAAO;AAAA,QACP,aAAa,GAAG;AAAA,QAChB,WAAW,GAAG,eAAe;AAAA,QAC7B,aAAa,GAAG,eAAe,IAAI,GAAG,cAAc;AAAA,MACrD,CAAC;AAAA,IACF;AAEA,UAAM,KAAK,SAAS,GAAG,YAAY;AACnC,UAAM,iBAAiB,KAAK,QAAQ,GAAG,UAAU,KAAK;AAEtD,WAAO;AAAA,MACN,IAAI,OAAO,QAAQ;AAAA,MACnB,MAAM,GAAG;AAAA,MACT,WAAW,GAAG,KAAK,UAAU,GAAG,CAAC;AAAA,MACjC,YAAY;AAAA,MACZ;AAAA,MACA,UAAU,GAAG;AAAA,MACb;AAAA,IACD;AAAA,EACD,CAAC;AAED,SAAO;AAAA,IACN,OAAO,KAAK,SAAS,KAAK,YAAY;AAAA,IACtC,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,IACZ;AAAA,IACA;AAAA,EACD;AACD;AAOO,SAAS,aAAa,MAA2B;AACvD,QAAM,MAAM,IAAI,YAAY,KAAK,UAAU;AAC3C,MAAI,WAAW,GAAG,EAAE,IAAI,IAAI;AAC5B,QAAM,IAAI,IAAI,UAAU,GAAG;AAG3B,QAAM,aAAa,EAAE,mBAAmB,EAAE;AAC1C,QAAM,UAAU,mBAAmB,UAAU;AAG7C,MAAI,QAAQ,UAAU,GAAG;AACxB,UAAM,IAAI,MAAM,mCAAmC,UAAU,iBAAiB;AAAA,EAC/E;AAGA,QAAM,OAAO,SAAS,CAAC;AAGvB,aAAW,CAAC;AAGZ,sBAAoB,GAAG,OAAO;AAG9B,gBAAc,CAAC;AAGf,IAAE,sBAAsB;AACxB,QAAM,QAAQ,EAAE,QAAQ;AAGxB,MAAI,mBAAmB,SAAS,GAAG,GAAG,CAAC,GAAG;AACzC,MAAE,SAAS;AAAA,EACZ;AAGA,IAAE,eAAe;AACjB,IAAE,QAAQ;AAGV,QAAM,WAAW,iBAAiB,CAAC;AAGnC,iBAAe,CAAC;AAGhB,IAAE,QAAQ;AAGV,QAAM,eAAe,EAAE,QAAQ;AAC/B,QAAM,aAAa,EAAE,QAAQ;AAG7B,QAAM,iBAAiB,mBAAmB,GAAG,cAAc,OAAO;AAGlE,QAAM,eAAe,iBAAiB,GAAG,YAAY,OAAO;AAG5D,QAAM,iBAAiB,aAAa,GAAG,cAAc,YAAY,OAAO;AAExE,SAAO,mBAAmB,MAAM,OAAO,gBAAgB,cAAc,gBAAgB,QAAQ;AAC9F;;;ACljCA,SAAS,qBAAqB,MAAkB,MAAmC;AAElF,MAAI,aAAa;AACjB,WAAS,IAAI,KAAK,aAAa,IAAI,KAAK,GAAG,KAAK;AAC/C,QAAI,KAAK,UAAU,GAAG,IAAI,MAAM,WAAY;AAC3C,mBAAa;AACb;AAAA,IACD;AAAA,EACD;AACA,MAAI,eAAe,GAAI,QAAO,CAAC;AAE/B,QAAM,WAAW,KAAK,UAAU,aAAa,IAAI,IAAI;AACrD,QAAM,eAAe,KAAK,UAAU,aAAa,IAAI,IAAI;AAEzD,QAAM,UAA6B,CAAC;AACpC,MAAI,MAAM;AAEV,WAAS,IAAI,GAAG,IAAI,cAAc,KAAK;AACtC,QAAI,MAAM,KAAK,KAAK,WAAY;AAChC,QAAI,KAAK,UAAU,KAAK,IAAI,MAAM,SAAY;AAE9C,UAAM,oBAAoB,KAAK,UAAU,MAAM,IAAI,IAAI;AACvD,UAAM,iBAAiB,KAAK,UAAU,MAAM,IAAI,IAAI;AACpD,UAAM,mBAAmB,KAAK,UAAU,MAAM,IAAI,IAAI;AACtD,UAAM,aAAa,KAAK,UAAU,MAAM,IAAI,IAAI;AAChD,UAAM,cAAc,KAAK,UAAU,MAAM,IAAI,IAAI;AACjD,UAAM,gBAAgB,KAAK,UAAU,MAAM,IAAI,IAAI;AACnD,UAAM,oBAAoB,KAAK,UAAU,MAAM,IAAI,IAAI;AAEvD,UAAM,YAAY,KAAK,SAAS,MAAM,IAAI,MAAM,KAAK,UAAU;AAC/D,UAAM,WAAW,OAAO,aAAa,GAAG,SAAS;AAEjD,YAAQ,KAAK,EAAE,UAAU,mBAAmB,gBAAgB,kBAAkB,kBAAkB,CAAC;AACjG,WAAO,KAAK,aAAa,cAAc;AAAA,EACxC;AAEA,SAAO;AACR;AAOA,SAAS,mBAAmB,MAAkB,YAAuC;AACpF,QAAM,OAAO,IAAI,SAAS,KAAK,QAAQ,KAAK,YAAY,KAAK,UAAU;AACvE,QAAM,UAAU,qBAAqB,MAAM,IAAI;AAE/C,QAAM,QAAQ,QAAQ,KAAK,CAAC,MAAM,EAAE,aAAa,UAAU;AAC3D,MAAI,CAAC,MAAO,QAAO;AAGnB,QAAM,cAAc,MAAM;AAC1B,MAAI,KAAK,UAAU,aAAa,IAAI,MAAM,SAAY,QAAO;AAE7D,QAAM,kBAAkB,KAAK,UAAU,cAAc,IAAI,IAAI;AAC7D,QAAM,mBAAmB,KAAK,UAAU,cAAc,IAAI,IAAI;AAC9D,QAAM,aAAa,cAAc,KAAK,kBAAkB;AAExD,QAAM,iBAAiB,KAAK,SAAS,YAAY,aAAa,MAAM,cAAc;AAElF,MAAI,MAAM,sBAAsB,GAAG;AAClC,WAAO;AAAA,EACR,WAAW,MAAM,sBAAsB,GAAG;AACzC,WAAO,sBAAsB,gBAAgB,MAAM,gBAAgB;AAAA,EACpE,OAAO;AACN,UAAM,IAAI,MAAM,uCAAuC,MAAM,iBAAiB,EAAE;AAAA,EACjF;AACD;AAGA,SAAS,sBAAsB,YAAwB,cAAkC;AACxF,SAAO,QAAQ,YAAY,YAAY;AACxC;AAOA,SAAS,uBAAoE;AAC5E,QAAM,UAAU,IAAI,WAAW,GAAG;AAClC,WAAS,IAAI,GAAG,KAAK,KAAK,IAAK,SAAQ,CAAC,IAAI;AAC5C,WAAS,IAAI,KAAK,KAAK,KAAK,IAAK,SAAQ,CAAC,IAAI;AAC9C,WAAS,IAAI,KAAK,KAAK,KAAK,IAAK,SAAQ,CAAC,IAAI;AAC9C,WAAS,IAAI,KAAK,KAAK,KAAK,IAAK,SAAQ,CAAC,IAAI;AAC9C,SAAO,kBAAkB,OAAO;AACjC;AAEA,SAAS,qBAAkE;AAC1E,QAAM,UAAU,IAAI,WAAW,EAAE;AACjC,UAAQ,KAAK,CAAC;AACd,SAAO,kBAAkB,OAAO;AACjC;AAGA,SAAS,kBAAkB,aAAsE;AAChG,QAAM,UAAU,KAAK,IAAI,GAAG,WAAW;AACvC,QAAM,QAAQ,IAAI,YAAY,UAAU,CAAC;AACzC,aAAW,OAAO,aAAa;AAC9B,QAAI,MAAM,EAAG,OAAM,GAAG;AAAA,EACvB;AAEA,QAAM,WAAW,IAAI,YAAY,UAAU,CAAC;AAC5C,MAAI,OAAO;AACX,WAAS,OAAO,GAAG,QAAQ,SAAS,QAAQ;AAC3C,WAAQ,OAAO,MAAM,OAAO,CAAC,KAAM;AACnC,aAAS,IAAI,IAAI;AAAA,EAClB;AAEA,QAAM,QAAQ,IAAI,YAAY,YAAY,MAAM;AAChD,QAAM,UAAU,IAAI,WAAW,YAAY,MAAM;AACjD,WAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC5C,UAAM,MAAM,YAAY,CAAC;AACzB,QAAI,MAAM,GAAG;AACZ,YAAM,CAAC,IAAI,SAAS,GAAG;AACvB,cAAQ,CAAC,IAAI;AAAA,IACd;AAAA,EACD;AAEA,SAAO,EAAE,OAAO,QAAQ;AACzB;AAGA,IAAM,YAAN,MAAgB;AAAA,EAKf,YAAY,MAAkB;AAC7B,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EACf;AAAA,EAEA,SAAS,GAAmB;AAC3B,QAAI,SAAS;AACb,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC3B,UAAI,KAAK,WAAW,KAAK,KAAK,OAAQ,QAAO;AAC7C,iBAAY,KAAK,KAAK,KAAK,OAAO,KAAK,KAAK,SAAU,MAAM;AAC5D,WAAK;AACL,UAAI,KAAK,WAAW,GAAG;AACtB,aAAK,SAAS;AACd,aAAK;AAAA,MACN;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAEA,cAAoB;AACnB,QAAI,KAAK,SAAS,GAAG;AACpB,WAAK,SAAS;AACd,WAAK;AAAA,IACN;AAAA,EACD;AAAA,EAEA,WAAmB;AAClB,WAAO,KAAK,KAAK,KAAK,SAAS;AAAA,EAChC;AAAA,EAEA,UAAU,GAAuB;AAChC,UAAM,SAAS,KAAK,KAAK,SAAS,KAAK,SAAS,KAAK,UAAU,CAAC;AAChE,SAAK,WAAW;AAChB,WAAO;AAAA,EACR;AACD;AAGA,SAAS,aAAa,MAAiB,OAA4D;AAClG,MAAI,OAAO;AAEX,WAAS,MAAM,GAAG,OAAO,IAAI,OAAO;AACnC,WAAQ,QAAQ,IAAK,KAAK,SAAS,CAAC;AACpC,aAAS,IAAI,GAAG,IAAI,MAAM,MAAM,QAAQ,KAAK;AAC5C,UAAI,MAAM,QAAQ,CAAC,MAAM,OAAO,MAAM,MAAM,CAAC,MAAM,MAAM;AACxD,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD;AAEA,QAAM,IAAI,MAAM,sBAAsB;AACvC;AAEA,IAAM,cAAc,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACtI,IAAM,eAAe,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAC3G,IAAM,YAAY,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,OAAO,OAAO,KAAK;AAC/J,IAAM,aAAa,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;AACpH,IAAM,WAAW,CAAC,IAAI,IAAI,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,EAAE;AAGlF,SAAS,QAAQ,YAAwB,cAAkC;AAC1E,QAAM,OAAO,IAAI,UAAU,UAAU;AACrC,QAAM,SAAS,IAAI,WAAW,YAAY;AAC1C,MAAI,SAAS;AAEb,MAAI,SAAS;AACb,SAAO,WAAW,GAAG;AACpB,aAAS,KAAK,SAAS,CAAC;AACxB,UAAM,QAAQ,KAAK,SAAS,CAAC;AAE7B,QAAI,UAAU,GAAG;AAEhB,WAAK,YAAY;AACjB,YAAM,MAAM,KAAK,SAAS,IAAK,KAAK,SAAS,KAAK;AAClD,WAAK,SAAS;AAAG,WAAK,SAAS;AAC/B,YAAM,QAAQ,KAAK,UAAU,GAAG;AAChC,aAAO,IAAI,OAAO,MAAM;AACxB,gBAAU;AAAA,IACX,OAAO;AACN,UAAI;AACJ,UAAI;AAEJ,UAAI,UAAU,GAAG;AAChB,qBAAa,qBAAqB;AAClC,mBAAW,mBAAmB;AAAA,MAC/B,WAAW,UAAU,GAAG;AACvB,cAAM,OAAO,KAAK,SAAS,CAAC,IAAI;AAChC,cAAM,QAAQ,KAAK,SAAS,CAAC,IAAI;AACjC,cAAM,QAAQ,KAAK,SAAS,CAAC,IAAI;AAEjC,cAAM,YAAY,IAAI,WAAW,EAAE;AACnC,iBAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC/B,oBAAU,SAAS,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;AAAA,QACzC;AACA,cAAM,SAAS,kBAAkB,SAAS;AAE1C,cAAM,aAAa,IAAI,WAAW,OAAO,KAAK;AAC9C,YAAI,MAAM;AACV,eAAO,MAAM,OAAO,OAAO;AAC1B,gBAAM,MAAM,aAAa,MAAM,MAAM;AACrC,cAAI,MAAM,IAAI;AACb,uBAAW,KAAK,IAAI;AAAA,UACrB,WAAW,QAAQ,IAAI;AACtB,kBAAM,SAAS,KAAK,SAAS,CAAC,IAAI;AAClC,kBAAM,OAAO,WAAW,MAAM,CAAC;AAC/B,qBAAS,IAAI,GAAG,IAAI,QAAQ,IAAK,YAAW,KAAK,IAAI;AAAA,UACtD,WAAW,QAAQ,IAAI;AACtB,kBAAM,SAAS,KAAK,SAAS,CAAC,IAAI;AAClC,qBAAS,IAAI,GAAG,IAAI,QAAQ,IAAK,YAAW,KAAK,IAAI;AAAA,UACtD,WAAW,QAAQ,IAAI;AACtB,kBAAM,SAAS,KAAK,SAAS,CAAC,IAAI;AAClC,qBAAS,IAAI,GAAG,IAAI,QAAQ,IAAK,YAAW,KAAK,IAAI;AAAA,UACtD;AAAA,QACD;AAEA,qBAAa,kBAAkB,WAAW,SAAS,GAAG,IAAI,CAAC;AAC3D,mBAAW,kBAAkB,WAAW,SAAS,IAAI,CAAC;AAAA,MACvD,OAAO;AACN,cAAM,IAAI,MAAM,+BAA+B,KAAK,EAAE;AAAA,MACvD;AAGA,aAAO,MAAM;AACZ,cAAM,MAAM,aAAa,MAAM,UAAU;AAEzC,YAAI,MAAM,KAAK;AACd,iBAAO,QAAQ,IAAI;AAAA,QACpB,WAAW,QAAQ,KAAK;AACvB;AAAA,QACD,OAAO;AACN,gBAAM,YAAY,MAAM;AACxB,gBAAM,SAAS,YAAY,SAAS,IAAI,KAAK,SAAS,aAAa,SAAS,CAAC;AAE7E,gBAAM,UAAU,aAAa,MAAM,QAAQ;AAC3C,gBAAM,WAAW,UAAU,OAAO,IAAI,KAAK,SAAS,WAAW,OAAO,CAAC;AAEvE,mBAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAChC,mBAAO,MAAM,IAAI,OAAO,SAAS,QAAQ;AACzC;AAAA,UACD;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,SAAO,OAAO,SAAS,GAAG,MAAM;AACjC;AAOA,SAAS,aAAa,MAA2B;AAChD,QAAM,WAAW,mBAAmB,MAAM,oBAAoB;AAC9D,MAAI,CAAC,UAAU;AACd,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC9D;AAEA,QAAM,UAAU,IAAI,YAAY,OAAO;AACvC,QAAM,UAAU,QAAQ,OAAO,QAAQ;AAEvC,QAAM,gBAAgB,aAAa;AACnC,QAAM,SAAS,IAAI,cAAc;AACjC,QAAM,MAAM,OAAO,gBAAgB,SAAS,UAAU;AAEtD,QAAM,aAAa,IAAI,cAAc,aAAa;AAClD,MAAI,YAAY;AACf,UAAM,IAAI,MAAM,6BAA6B,WAAW,WAAW,EAAE;AAAA,EACtE;AAEA,SAAO,cAAc,GAAG;AACzB;AAOA,SAAS,aAAa,MAAkB,UAA0C;AACjF,MAAI,KAAK,SAAS,GAAG;AACpB,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAC/D;AAEA,QAAM,SAAS,OAAO,aAAa,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC;AAGrE,MAAI,WAAW,UAAU,WAAW,QAAQ;AAC3C,WAAO;AAAA,EACR;AAGA,MAAI,KAAK,CAAC,MAAM,MAAQ,KAAK,CAAC,MAAM,IAAM;AACzC,WAAO;AAAA,EACR;AAGA,QAAM,SAAS,KAAK,CAAC;AACrB,MAAI,SAAS,MAAM,SAAS,MAAM,KAAK,aAAa,SAAS,GAAG;AAC/D,UAAM,aAAa,OAAO,aAAa,GAAG,MAAM,KAAK,KAAK,SAAS,GAAG,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC;AAChG,QAAI,WAAW,SAAS,YAAY,GAAG;AACtC,aAAO;AAAA,IACR;AAAA,EACD;AAGA,MAAI,UAAU;AACb,UAAM,MAAM,SAAS,YAAY;AACjC,QAAI,IAAI,SAAS,MAAM,EAAG,QAAO;AACjC,QAAI,IAAI,SAAS,MAAM,KAAK,IAAI,SAAS,MAAM,KAAK,IAAI,SAAS,MAAM,EAAG,QAAO;AACjF,QAAI,IAAI,SAAS,KAAK,EAAG,QAAO;AAAA,EACjC;AAEA,QAAM,IAAI,MAAM,qCAAqC;AACtD;AAYO,SAAS,aAAa,MAAkB,UAA4B;AAC1E,QAAM,SAAS,aAAa,MAAM,QAAQ;AAE1C,UAAQ,QAAQ;AAAA,IACf,KAAK;AACJ,aAAO,aAAa,IAAI;AAAA,IACzB,KAAK;AACJ,aAAO,aAAa,IAAI;AAAA,IACzB,KAAK;AACJ,aAAO,aAAa,IAAI;AAAA,EAC1B;AACD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "guitarpro-parser",
3
+ "version": "1.0.0",
4
+ "author": "Emilien Bevierre",
5
+ "description": "Pure JavaScript parser for Guitar Pro files (.gp, .gpx, .gp5). Zero native dependencies, works in browser and Node.js.",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
20
+ }
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "sideEffects": false,
26
+ "scripts": {
27
+ "build": "tsup",
28
+ "test": "vitest run",
29
+ "test:watch": "vitest",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "keywords": [
33
+ "guitar-pro",
34
+ "gpx",
35
+ "gp5",
36
+ "gp7",
37
+ "tablature",
38
+ "tab",
39
+ "parser",
40
+ "music",
41
+ "guitar"
42
+ ],
43
+ "license": "Apache-2.0",
44
+ "devDependencies": {
45
+ "tsup": "^8.4.0",
46
+ "typescript": "^5.7.0",
47
+ "vitest": "^3.0.0"
48
+ },
49
+ "dependencies": {
50
+ "linkedom": "^0.18.9"
51
+ }
52
+ }