## GoldenPond FL Studio Script
## Copyright (C) 2025 Phil Jones

## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU Affero General Public License as
## published by the Free Software Foundation, either version 3 of the
## License, or (at your option) any later version.

## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU Affero General Public License for more details.

## To understand the GNU Affero General Public License see <https://www.gnu.org/licenses/>.


import flpianoroll as flp
from flpianoroll import *

import time
# Generated by Haxe 4.3.6
# coding: utf-8
import sys

import math as python_lib_Math
import math as Math
import inspect as python_lib_Inspect
import sys as python_lib_Sys
import functools as python_lib_Functools
import json as python_lib_Json
import random as python_lib_Random
import re as python_lib_Re
import traceback as python_lib_Traceback
from datetime import datetime as python_lib_datetime_Datetime
from datetime import timezone as python_lib_datetime_Timezone
from io import StringIO as python_lib_io_StringIO


class _hx_AnonObject:
    _hx_disable_getattr = False
    def __init__(self, fields):
        self.__dict__ = fields
    def __repr__(self):
        return repr(self.__dict__)
    def __contains__(self, item):
        return item in self.__dict__
    def __getitem__(self, item):
        return self.__dict__[item]
    def __getattr__(self, name):
        if (self._hx_disable_getattr):
            raise AttributeError('field does not exist')
        else:
            return None
    def _hx_hasattr(self,field):
        self._hx_disable_getattr = True
        try:
            getattr(self, field)
            self._hx_disable_getattr = False
            return True
        except AttributeError:
            self._hx_disable_getattr = False
            return False



class Enum:
    _hx_class_name = "Enum"
    __slots__ = ("tag", "index", "params")
    _hx_fields = ["tag", "index", "params"]
    _hx_methods = ["__str__"]

    def __init__(self,tag,index,params):
        self.tag = tag
        self.index = index
        self.params = params

    def __str__(self):
        if (self.params is None):
            return self.tag
        else:
            return self.tag + '(' + (', '.join(str(v) for v in self.params)) + ')'

Enum._hx_class = Enum


class Tuple2:
    _hx_class_name = "Tuple2"
    __slots__ = ("_0", "_1")
    _hx_fields = ["_0", "_1"]

    def __init__(self,_0,_1):
        self._0 = _0
        self._1 = _1

Tuple2._hx_class = Tuple2


class ChordParser:
    _hx_class_name = "ChordParser"
    __slots__ = ("key", "mode")
    _hx_fields = ["key", "mode"]
    _hx_methods = ["parseSeparator", "parseTranspose", "parseItem", "countOccurrences", "parseBracket", "interpretItem", "parseMode", "parse"]

    def __init__(self,key,mode):
        self.key = key
        self.mode = mode

    def parseSeparator(self,inputString):
        separators = ["|", ",", "&"]
        if ((len(inputString) > 0) and ((python_internal_ArrayImpl.indexOf(separators,("" if ((0 >= len(inputString))) else inputString[0]),None) != -1))):
            return Tuple2(("" if ((0 >= len(inputString))) else inputString[0]),HxString.substr(inputString,1,None))
        else:
            return Tuple2(None,inputString)

    def parseTranspose(self,inputString):
        transposeChars_b = python_lib_io_StringIO()
        while ((len(inputString) > 0) and ((python_internal_ArrayImpl.indexOf([",", "|"],("" if ((0 >= len(inputString))) else inputString[0]),None) == -1))):
            transposeChars_b.write(Std.string(("" if ((0 >= len(inputString))) else inputString[0])))
            inputString = HxString.substr(inputString,1,None)
        transposeString = StringTools.trim(transposeChars_b.getvalue())
        if (((("" if ((0 >= len(transposeString))) else transposeString[0])) != ">") and (((("" if ((0 >= len(transposeString))) else transposeString[0])) != "<"))):
            raise haxe_Exception.thrown((("Expected '>' or '<' at the start of '" + ("null" if transposeString is None else transposeString)) + "'"))
        transposeValue = Std.parseInt(HxString.substr(transposeString,1,None))
        if ((("" if ((0 >= len(transposeString))) else transposeString[0])) == ">"):
            _hx_local_0 = self
            _hx_local_1 = _hx_local_0.key
            _hx_local_0.key = (_hx_local_1 + transposeValue)
            _hx_local_0.key
        else:
            _hx_local_2 = self
            _hx_local_3 = _hx_local_2.key
            _hx_local_2.key = (_hx_local_3 - transposeValue)
            _hx_local_2.key
        return inputString

    def parseItem(self,inputString):
        itemChars_b = python_lib_io_StringIO()
        insideParentheses = False
        while ((len(inputString) > 0) and ((insideParentheses or ((python_internal_ArrayImpl.indexOf([",", "|", "&", ">", "<"],("" if ((0 >= len(inputString))) else inputString[0]),None) == -1))))):
            char = ("" if ((0 >= len(inputString))) else inputString[0])
            if (char == "("):
                insideParentheses = True
            elif (char == ")"):
                insideParentheses = False
            itemChars_b.write(Std.string(char))
            inputString = HxString.substr(inputString,1,None)
        return Tuple2(StringTools.trim(itemChars_b.getvalue()),inputString)

    def countOccurrences(self,_hx_str,char):
        count = 0
        _g = 0
        _g1 = len(_hx_str)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            if ((("" if (((i < 0) or ((i >= len(_hx_str))))) else _hx_str[i])) == char):
                count = (count + 1)
        return count

    def parseBracket(self,itemString):
        extension = None
        parts = itemString.split("(")
        if (len((parts[0] if 0 < len(parts) else None)) > 0):
            extension = Std.parseInt((parts[0] if 0 < len(parts) else None))
        bracketContent = HxString.substr((parts[1] if 1 < len(parts) else None),0,(len((parts[1] if 1 < len(parts) else None)) - 1))
        startIndex = None
        if (((bracketContent.find("!") if ((startIndex is None)) else HxString.indexOfImpl(bracketContent,"!",startIndex))) != -1):
            modeParts = bracketContent.split("!")
            degree = Std.parseInt((modeParts[0] if 0 < len(modeParts) else None))
            modeNumber = Std.parseInt((modeParts[1] if 1 < len(modeParts) else None))
            chord = ChordThing(self.key,self.mode,degree)
            newMode = None
            if (self.mode == Mode.getMajorMode()):
                newMode = Mode.constructNthMajorMode(modeNumber)
            elif (self.mode == Mode.getHarmonicMinorMode()):
                newMode = Mode.constructNthHarmonicMinorMode(modeNumber)
            elif (self.mode == Mode.getMelodicMinorMode()):
                newMode = Mode.constructNthMelodicMinorMode(modeNumber)
            elif (self.mode == Mode.getMinorMode()):
                newMode = Mode.constructNthMinorMode(modeNumber)
            else:
                raise haxe_Exception.thrown("Cannot get nth mode of unknown scale")
            chord.set_mode(newMode)
            if (extension is not None):
                if (extension == 7):
                    chord.seventh()
                elif (extension == 9):
                    chord.ninth()
            return chord
        else:
            secondaryParts = bracketContent.split("/")
            secondaryDegree = Std.parseInt((secondaryParts[0] if 0 < len(secondaryParts) else None))
            degree = Std.parseInt((secondaryParts[1] if 1 < len(secondaryParts) else None))
            chord = ChordThing(self.key,self.mode,degree)
            chord.set_as_secondary(secondaryDegree)
            if (extension is not None):
                if (extension == 7):
                    chord.seventh()
                elif (extension == 9):
                    chord.ninth()
            return chord

    def interpretItem(self,itemString):
        isModalInterchange = False
        if ((("" if ((0 >= len(itemString))) else itemString[0])) == "-"):
            isModalInterchange = True
            itemString = HxString.substr(itemString,1,None)
        inversion = 0
        startIndex = None
        if (((itemString.find("i") if ((startIndex is None)) else HxString.indexOfImpl(itemString,"i",startIndex))) != -1):
            inversion = self.countOccurrences(itemString,"i")
            _this = itemString.split("i")
            itemString = "".join([python_Boot.toString1(x1,'') for x1 in _this])
        tmp = None
        startIndex = None
        if (((itemString.find("(") if ((startIndex is None)) else HxString.indexOfImpl(itemString,"(",startIndex))) != -1):
            startIndex = None
            tmp = (((itemString.find(")") if ((startIndex is None)) else HxString.indexOfImpl(itemString,")",startIndex))) != -1)
        else:
            tmp = False
        if tmp:
            chord = self.parseBracket(itemString)
            chord.set_inversion(inversion)
            return chord
        itemValue = Std.parseInt(itemString)
        modeToUse = ((Mode.getMinorMode() if ((self.mode == Mode.getMajorMode())) else Mode.getMajorMode()) if isModalInterchange else self.mode)
        chord = None
        if ((1 <= itemValue) and ((itemValue <= 7))):
            chord = ChordThing(self.key,modeToUse,itemValue)
        elif ((61 <= itemValue) and ((itemValue <= 67))):
            chord = ChordThing(self.key,modeToUse,(itemValue - 60)).sixth()
        elif ((71 <= itemValue) and ((itemValue <= 77))):
            chord = ChordThing(self.key,modeToUse,(itemValue - 70)).seventh()
        elif ((91 <= itemValue) and ((itemValue <= 97))):
            chord = ChordThing(self.key,modeToUse,(itemValue - 90)).ninth()
        else:
            raise haxe_Exception.thrown(("Unexpected item value: " + ("null" if itemString is None else itemString)))
        chord.set_inversion(inversion)
        return chord

    def parseMode(self,inputString):
        modeChars_b = python_lib_io_StringIO()
        while ((len(inputString) > 0) and ((python_internal_ArrayImpl.indexOf([",", "|"],("" if ((0 >= len(inputString))) else inputString[0]),None) == -1))):
            modeChars_b.write(Std.string(("" if ((0 >= len(inputString))) else inputString[0])))
            inputString = HxString.substr(inputString,1,None)
        modeString = StringTools.trim(modeChars_b.getvalue())
        if (len(modeString) < 2):
            raise haxe_Exception.thrown("Expected mode specifier after '!'. Use !M, !m, !hm, or !mm")
        modeSpec = ("" if ((1 >= len(modeString))) else modeString[1])
        modeSpec1 = modeSpec
        if (modeSpec1 == "M"):
            self.mode = Mode.getMajorMode()
        elif (modeSpec1 == "h"):
            if ((len(modeString) < 3) or (((("" if ((2 >= len(modeString))) else modeString[2])) != "m"))):
                raise haxe_Exception.thrown("Expected 'hm' for harmonic minor mode")
            self.mode = Mode.getHarmonicMinorMode()
        elif (modeSpec1 == "m"):
            if ((len(modeString) >= 3) and (((("" if ((2 >= len(modeString))) else modeString[2])) == "m"))):
                self.mode = Mode.getMelodicMinorMode()
            else:
                self.mode = Mode.getMinorMode()
        else:
            raise haxe_Exception.thrown((("Invalid mode specifier: " + ("null" if modeSpec is None else modeSpec)) + ". Use !M, !m, !hm, or !mm"))
        return inputString

    def parse(self,inputString):
        chords = []
        voiceLeadNext = False
        while (len(inputString) > 0):
            sepResult = self.parseSeparator(inputString)
            separator = sepResult._0
            inputString = sepResult._1
            if (separator == "&"):
                voiceLeadNext = True
            if (len(inputString) > 0):
                if ((("" if ((0 >= len(inputString))) else inputString[0])) == "!"):
                    inputString = self.parseMode(inputString)
                elif (((("" if ((0 >= len(inputString))) else inputString[0])) == ">") or (((("" if ((0 >= len(inputString))) else inputString[0])) == "<"))):
                    inputString = self.parseTranspose(inputString)
                else:
                    itemResult = self.parseItem(inputString)
                    itemString = itemResult._0
                    inputString = itemResult._1
                    chord = self.interpretItem(itemString)
                    if voiceLeadNext:
                        chord.set_voice_leading()
                    chords.append(chord)
        return chords

ChordParser._hx_class = ChordParser


class IChordProgression:
    _hx_class_name = "IChordProgression"
    __slots__ = ()
    _hx_methods = ["toChordThings", "toNotes", "getChordNames"]
IChordProgression._hx_class = IChordProgression


class ChordProgression:
    _hx_class_name = "ChordProgression"
    __slots__ = ("key", "mode", "scoreString", "chordThings")
    _hx_fields = ["key", "mode", "scoreString", "chordThings"]
    _hx_methods = ["recalc", "toChordThings", "toNotes", "voice_lead", "getChordNames"]
    _hx_interfaces = [IChordProgression]

    def __init__(self,key,mode,scoreString):
        self.chordThings = None
        self.key = key
        self.mode = mode
        self.scoreString = scoreString
        self.recalc()

    def recalc(self):
        self.chordThings = self.toChordThings()

    def toChordThings(self):
        return ChordParser(self.key,self.mode).parse(self.scoreString)

    def toNotes(self):
        chords = []
        prev_chord = None
        _g = 0
        _g1 = self.chordThings
        while (_g < len(_g1)):
            ct = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
            _g = (_g + 1)
            chord = ct.generateChordNotes()
            if ((prev_chord is not None) and ((python_internal_ArrayImpl.indexOf(ct.modifiers,Modifier.VOICE_LEADING,None) != -1))):
                chord = self.voice_lead(prev_chord,chord)
            chords.append(chord)
            prev_chord = chord
        return chords

    def voice_lead(self,prevChord,nextChord):
        return nextChord

    def getChordNames(self):
        names = []
        _g = 0
        _g1 = self.chordThings
        while (_g < len(_g1)):
            ct = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
            _g = (_g + 1)
            x = ct.getChordName()
            names.append(x)
        return names

ChordProgression._hx_class = ChordProgression


class StutteredChordProgression:
    _hx_class_name = "StutteredChordProgression"
    __slots__ = ("progression", "stutterCount")
    _hx_fields = ["progression", "stutterCount"]
    _hx_methods = ["setStutterCount", "getStutterCount", "stutterArray", "toChordThings", "toNotes", "getChordNames"]
    _hx_interfaces = [IChordProgression]

    def __init__(self,progression,stutterCount):
        self.progression = progression
        self.stutterCount = stutterCount

    def setStutterCount(self,count):
        self.stutterCount = count
        return self

    def getStutterCount(self):
        return self.stutterCount

    def stutterArray(self,items):
        if ((self.stutterCount <= 0) or ((len(items) <= 0))):
            return items
        a = self.stutterCount
        b = len(items)
        x = (a if (python_lib_Math.isnan(a)) else (b if (python_lib_Math.isnan(b)) else min(a,b)))
        count = None
        try:
            count = int(x)
        except BaseException as _g:
            None
            count = None
        fragment = items[0:count]
        result = []
        while (len(result) < len(items)):
            result = (result + fragment)
        return result[0:len(items)]

    def toChordThings(self):
        return self.stutterArray(self.progression.toChordThings())

    def toNotes(self):
        return self.stutterArray(self.progression.toNotes())

    def getChordNames(self):
        return self.stutterArray(self.progression.getChordNames())

StutteredChordProgression._hx_class = StutteredChordProgression


class ChordThing:
    _hx_class_name = "ChordThing"
    __slots__ = ("key", "mode", "degree", "length", "modifiers", "inversion", "secondary_degree")
    _hx_fields = ["key", "mode", "degree", "length", "modifiers", "inversion", "secondary_degree"]
    _hx_methods = ["valueEquals", "set_as_secondary", "swap_mode", "seventh", "ninth", "sixth", "set_inversion", "set_voice_leading", "toString", "clone", "has_extensions", "get_mode", "calculateAsSecondaryChord", "generateChordNotes", "midiToNoteName", "calculateRootNote", "getBassNote", "determineChordQuality", "determineExtension", "getChordName", "set_mode"]

    def __init__(self,key,mode,degree,length = None):
        if (length is None):
            length = 1
        self.key = key
        self.mode = mode
        self.degree = degree
        self.length = length
        self.modifiers = []
        self.inversion = 0
        self.secondary_degree = None

    def valueEquals(self,other):
        if (not Std.isOfType(other,ChordThing)):
            return False
        def _hx_local_1():
            _hx_local_0 = other
            if (Std.isOfType(_hx_local_0,ChordThing) or ((_hx_local_0 is None))):
                _hx_local_0
            else:
                raise "Class cast error"
            return _hx_local_0
        otherChord = _hx_local_1()
        if (((((self.key != otherChord.key) or (not self.mode.valueEquals(otherChord.mode))) or ((self.degree != otherChord.degree))) or ((self.length != otherChord.length))) or ((self.inversion != otherChord.inversion))):
            return False
        if (len(self.modifiers) != len(otherChord.modifiers)):
            return False
        _g = 0
        _g1 = len(self.modifiers)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            if ((self.modifiers[i] if i >= 0 and i < len(self.modifiers) else None) != (otherChord.modifiers[i] if i >= 0 and i < len(otherChord.modifiers) else None)):
                return False
        return True

    def set_as_secondary(self,secondary_degree):
        _this = self.modifiers
        _this.append(Modifier.SECONDARY)
        self.secondary_degree = secondary_degree
        return self

    def swap_mode(self):
        if self.mode.valueEquals(Mode.getMajorMode()):
            self.mode = Mode.getMinorMode()
        else:
            self.mode = Mode.getMajorMode()
        return self

    def seventh(self):
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None) != -1):
            _this = self.modifiers
            pos = python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None)
            if (pos < 0):
                pos = (len(_this) + pos)
            if (pos < 0):
                pos = 0
            res = _this[pos:(pos + 1)]
            del _this[pos:(pos + 1)]
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SIXTH,None) != -1):
            _this = self.modifiers
            pos = python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SIXTH,None)
            if (pos < 0):
                pos = (len(_this) + pos)
            if (pos < 0):
                pos = 0
            res = _this[pos:(pos + 1)]
            del _this[pos:(pos + 1)]
        _this = self.modifiers
        _this.append(Modifier.SEVENTH)
        return self

    def ninth(self):
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None) != -1):
            _this = self.modifiers
            pos = python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None)
            if (pos < 0):
                pos = (len(_this) + pos)
            if (pos < 0):
                pos = 0
            res = _this[pos:(pos + 1)]
            del _this[pos:(pos + 1)]
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SIXTH,None) != -1):
            _this = self.modifiers
            pos = python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SIXTH,None)
            if (pos < 0):
                pos = (len(_this) + pos)
            if (pos < 0):
                pos = 0
            res = _this[pos:(pos + 1)]
            del _this[pos:(pos + 1)]
        _this = self.modifiers
        _this.append(Modifier.NINTH)
        return self

    def sixth(self):
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None) != -1):
            _this = self.modifiers
            pos = python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None)
            if (pos < 0):
                pos = (len(_this) + pos)
            if (pos < 0):
                pos = 0
            res = _this[pos:(pos + 1)]
            del _this[pos:(pos + 1)]
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None) != -1):
            _this = self.modifiers
            pos = python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None)
            if (pos < 0):
                pos = (len(_this) + pos)
            if (pos < 0):
                pos = 0
            res = _this[pos:(pos + 1)]
            del _this[pos:(pos + 1)]
        _this = self.modifiers
        _this.append(Modifier.SIXTH)
        return self

    def set_inversion(self,inversion):
        self.inversion = inversion
        return self

    def set_voice_leading(self):
        _this = self.modifiers
        _this.append(Modifier.VOICE_LEADING)
        return self

    def toString(self):
        modeStr = ("MAJOR" if (self.mode.valueEquals(Mode.getMajorMode())) else "MINOR")
        degree_repr = ((((("(" + Std.string(self.secondary_degree)) + "/") + Std.string(self.degree)) + ")") if ((python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SECONDARY,None) != -1)) else ("" + Std.string(self.degree)))
        _this = self.modifiers
        return ((((((((((("ChordThing(" + Std.string(self.key)) + ",") + ("null" if modeStr is None else modeStr)) + ",") + ("null" if degree_repr is None else degree_repr)) + ",") + Std.string(self.inversion)) + ",") + Std.string(self.length)) + ") + ") + HxOverrides.stringOrNull(((("[" + HxOverrides.stringOrNull(",".join([python_Boot.toString1(x1,'') for x1 in _this]))) + "]"))))

    def clone(self):
        ct = ChordThing(self.key,self.mode,self.degree,self.length)
        ct.modifiers = list(self.modifiers)
        ct.inversion = self.inversion
        ct.secondary_degree = self.secondary_degree
        return ct

    def has_extensions(self):
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None) == -1):
            return (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None) != -1)
        else:
            return True

    def get_mode(self):
        return self.mode

    def calculateAsSecondaryChord(self):
        new_tonic = self.mode.nth_from(self.key,self.degree)
        ct = ChordThing(new_tonic,Mode.getMajorMode(),self.secondary_degree,self.length)
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None) != -1):
            ct.seventh()
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None) != -1):
            ct.ninth()
        ct.set_inversion(self.inversion)
        return ct

    def generateChordNotes(self):
        if ((python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SECONDARY,None) != -1) and ((self.secondary_degree is not None))):
            return self.calculateAsSecondaryChord().generateChordNotes()
        chord = None
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None) != -1):
            chord = self.mode.make_ninth(self.key,self.degree)
        elif (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None) != -1):
            chord = self.mode.make_seventh(self.key,self.degree)
        elif (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SIXTH,None) != -1):
            chord = self.mode.make_sixth(self.key,self.degree)
        else:
            chord = self.mode.make_triad(self.key,self.degree)
        _g = 0
        _g1 = self.inversion
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            x = (None if ((len(chord) == 0)) else chord.pop(0))
            chord.append((x + 12))
        return chord

    def midiToNoteName(self,midiNote,includeOctave = None):
        if (includeOctave is None):
            includeOctave = False
        noteNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
        noteName = python_internal_ArrayImpl._get(noteNames, HxOverrides.mod(midiNote, 12))
        if includeOctave:
            octave = (Math.floor((midiNote / 12)) - 1)
            return (("null" if noteName is None else noteName) + Std.string(octave))
        return noteName

    def calculateRootNote(self):
        intervals = ([0, 2, 4, 5, 7, 9, 11] if (self.mode.valueEquals(Mode.getMajorMode())) else [0, 2, 3, 5, 7, 8, 10])
        degreeIndex = HxOverrides.mod(((self.degree - 1)), 7)
        semitoneOffset = (intervals[degreeIndex] if degreeIndex >= 0 and degreeIndex < len(intervals) else None)
        return (self.key + semitoneOffset)

    def getBassNote(self):
        if (self.inversion == 0):
            return self.calculateRootNote()
        originalChord = self.clone()
        originalChord.inversion = 0
        chordNotes = originalChord.generateChordNotes()
        a = self.inversion
        b = (len(chordNotes) - 1)
        x = (a if (python_lib_Math.isnan(a)) else (b if (python_lib_Math.isnan(b)) else min(a,b)))
        inversionIndex = None
        try:
            inversionIndex = int(x)
        except BaseException as _g:
            None
            inversionIndex = None
        return (chordNotes[inversionIndex] if inversionIndex >= 0 and inversionIndex < len(chordNotes) else None)

    def determineChordQuality(self):
        originalChord = self.clone()
        originalChord.inversion = 0
        chordNotes = originalChord.generateChordNotes()
        if (len(chordNotes) < 3):
            return ""
        root = (chordNotes[0] if 0 < len(chordNotes) else None)
        third = (chordNotes[1] if 1 < len(chordNotes) else None)
        fifth = (chordNotes[2] if 2 < len(chordNotes) else None)
        thirdInterval = (third - root)
        fifthInterval = (fifth - root)
        if ((thirdInterval == 4) and ((fifthInterval == 7))):
            return ""
        elif ((thirdInterval == 3) and ((fifthInterval == 7))):
            return "m"
        elif ((thirdInterval == 3) and ((fifthInterval == 6))):
            return "dim"
        elif ((thirdInterval == 4) and ((fifthInterval == 8))):
            return "aug"
        elif (thirdInterval == 4):
            return ""
        else:
            return "m"

    def determineExtension(self):
        if (not self.has_extensions()):
            return ""
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SEVENTH,None) != -1):
            return "7"
        if (python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.NINTH,None) != -1):
            return "9"
        return ""

    def getChordName(self):
        if ((python_internal_ArrayImpl.indexOf(self.modifiers,Modifier.SECONDARY,None) != -1) and ((self.secondary_degree is not None))):
            secondaryChord = self.calculateAsSecondaryChord()
            return secondaryChord.getChordName()
        rootNote = self.calculateRootNote()
        rootName = self.midiToNoteName(rootNote)
        quality = self.determineChordQuality()
        chordName = (("null" if rootName is None else rootName) + ("null" if quality is None else quality))
        extension = self.determineExtension()
        chordName = (("null" if chordName is None else chordName) + ("null" if extension is None else extension))
        if (self.inversion > 0):
            bassNote = self.getBassNote()
            bassName = self.midiToNoteName(bassNote)
            chordName = (("null" if chordName is None else chordName) + HxOverrides.stringOrNull((("/" + ("null" if bassName is None else bassName)))))
        return chordName

    def set_mode(self,newMode):
        self.mode = newMode

ChordThing._hx_class = ChordThing


class Class: pass


class Date:
    _hx_class_name = "Date"
    __slots__ = ("date", "dateUTC")
    _hx_fields = ["date", "dateUTC"]
    _hx_methods = ["toString"]
    _hx_statics = ["makeLocal"]

    def __init__(self,year,month,day,hour,_hx_min,sec):
        self.dateUTC = None
        if (year < python_lib_datetime_Datetime.min.year):
            year = python_lib_datetime_Datetime.min.year
        if (day == 0):
            day = 1
        self.date = Date.makeLocal(python_lib_datetime_Datetime(year,(month + 1),day,hour,_hx_min,sec,0))
        self.dateUTC = self.date.astimezone(python_lib_datetime_Timezone.utc)

    def toString(self):
        return self.date.strftime("%Y-%m-%d %H:%M:%S")

    @staticmethod
    def makeLocal(date):
        try:
            return date.astimezone()
        except BaseException as _g:
            None
            tzinfo = python_lib_datetime_Datetime.now(python_lib_datetime_Timezone.utc).astimezone().tzinfo
            return date.replace(**python__KwArgs_KwArgs_Impl_.fromT(_hx_AnonObject({'tzinfo': tzinfo})))

Date._hx_class = Date


class EReg:
    _hx_class_name = "EReg"
    __slots__ = ("pattern", "matchObj", "_hx_global")
    _hx_fields = ["pattern", "matchObj", "global"]

    def __init__(self,r,opt):
        self.matchObj = None
        self._hx_global = False
        options = 0
        _g = 0
        _g1 = len(opt)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            c = (-1 if ((i >= len(opt))) else ord(opt[i]))
            if (c == 109):
                options = (options | python_lib_Re.M)
            if (c == 105):
                options = (options | python_lib_Re.I)
            if (c == 115):
                options = (options | python_lib_Re.S)
            if (c == 117):
                options = (options | python_lib_Re.U)
            if (c == 103):
                self._hx_global = True
        self.pattern = python_lib_Re.compile(r,options)

EReg._hx_class = EReg


class GoldenData:
    _hx_class_name = "GoldenData"
    __slots__ = ("root", "mode", "chordSequence", "stutter", "bpm", "chordDuration", "lines", "lastSerializedString")
    _hx_fields = ["root", "mode", "chordSequence", "stutter", "bpm", "chordDuration", "lines", "lastSerializedString"]
    _hx_methods = ["addLine", "setMode", "makeMode", "makeChordProgression", "makeTimeManipulator", "makeLineGenerator", "hasChanged", "toString", "toJSON"]
    _hx_statics = ["makeFromJSON"]

    def __init__(self):
        self.root = 60
        self.mode = 0
        self.chordSequence = "1,4,5,1"
        self.stutter = 0
        self.bpm = 120
        self.chordDuration = 4
        self.lines = []
        self.lastSerializedString = ""

    def addLine(self,pattern,instrumentContext):
        _this = self.lines
        x = LineData(pattern,instrumentContext)
        _this.append(x)
        return self

    def setMode(self,modeIndex):
        self.mode = modeIndex
        return self

    def makeMode(self):
        _g = self.mode
        if (_g == 0):
            return Mode.getMajorMode()
        elif (_g == 1):
            return Mode.getMinorMode()
        elif (_g == 2):
            return Mode.getHarmonicMinorMode()
        elif (_g == 3):
            return Mode.getMelodicMinorMode()
        else:
            return Mode.getMajorMode()

    def makeChordProgression(self):
        baseProgression = ChordProgression(self.root,self.makeMode(),self.chordSequence)
        if (self.stutter > 0):
            return StutteredChordProgression(baseProgression,self.stutter)
        return baseProgression

    def makeTimeManipulator(self):
        return TimeManipulator().setPPQ(96).setChordDuration(self.chordDuration).setBPM(self.bpm)

    def makeLineGenerator(self,lineIndex):
        if ((lineIndex < 0) or ((lineIndex >= len(self.lines)))):
            raise haxe_Exception.thrown(("Invalid line index: " + Std.string(lineIndex)))
        line = (self.lines[lineIndex] if lineIndex >= 0 and lineIndex < len(self.lines) else None)
        timeManipulator = self.makeTimeManipulator()
        progression = self.makeChordProgression()
        return LineGenerator.createFromPattern(timeManipulator,progression,line.pattern,line.instrumentContext)

    def hasChanged(self):
        currentString = self.toJSON()
        changed = (currentString != self.lastSerializedString)
        self.lastSerializedString = currentString
        return changed

    def toString(self):
        modeNames = ["major", "minor", "harmonic minor", "melodic minor"]
        modeName = python_internal_ArrayImpl._get(modeNames, self.mode)
        result = "GoldenPond Project\n"
        result = (("null" if result is None else result) + "-------------------------------------------\n")
        result = (("null" if result is None else result) + HxOverrides.stringOrNull(((("Root: " + Std.string(self.root)) + "\n"))))
        result = (("null" if result is None else result) + HxOverrides.stringOrNull(((((("Mode: " + ("null" if modeName is None else modeName)) + " (") + Std.string(self.mode)) + ")\n"))))
        result = (("null" if result is None else result) + HxOverrides.stringOrNull(((("Chord Sequence: " + HxOverrides.stringOrNull(self.chordSequence)) + "\n"))))
        result = (("null" if result is None else result) + HxOverrides.stringOrNull(((("Stutter: " + Std.string(self.stutter)) + "\n"))))
        result = (("null" if result is None else result) + HxOverrides.stringOrNull(((("BPM: " + Std.string(self.bpm)) + "\n"))))
        result = (("null" if result is None else result) + HxOverrides.stringOrNull(((("Chord Duration: " + Std.string(self.chordDuration)) + "\n"))))
        result = (("null" if result is None else result) + "Lines:\n")
        _g = 0
        _g1 = len(self.lines)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            line = (self.lines[i] if i >= 0 and i < len(self.lines) else None)
            result = (("null" if result is None else result) + HxOverrides.stringOrNull(((((((("  Line " + Std.string(((i + 1)))) + ": Pattern=\"") + HxOverrides.stringOrNull(line.pattern)) + "\", InstrumentContext=") + HxOverrides.stringOrNull(line.instrumentContext.toString())) + "\n"))))
        result = (("null" if result is None else result) + "-------------------------------------------\n")
        return result

    def toJSON(self):
        def _hx_local_0(line):
            return _hx_AnonObject({'pattern': line.pattern, 'instrumentContextCode': line.instrumentContext.getCode(), 'instrumentContextData': line.instrumentContext.toJSON()})
        data = _hx_AnonObject({'root': self.root, 'mode': self.mode, 'chordSequence': self.chordSequence, 'stutter': self.stutter, 'bpm': self.bpm, 'chordDuration': self.chordDuration, 'lines': list(map(_hx_local_0,self.lines))})
        return haxe_format_JsonPrinter.print(data,None,None)

    @staticmethod
    def makeFromJSON(json,deserializationHelper):
        data = python_lib_Json.loads(json,**python__KwArgs_KwArgs_Impl_.fromT(_hx_AnonObject({'object_hook': python_Lib.dictToAnon})))
        result = GoldenData()
        result.root = data.root
        result.mode = data.mode
        result.chordSequence = data.chordSequence
        result.stutter = data.stutter
        result.bpm = data.bpm
        result.chordDuration = data.chordDuration
        result.lines = []
        _g = 0
        _g1 = data.lines
        while (_g < len(_g1)):
            lineData = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
            _g = (_g + 1)
            try:
                line = deserializationHelper.helpMake("LineData",haxe_format_JsonPrinter.print(lineData,None,None))
                _this = result.lines
                _this.append(line)
            except BaseException as _g2:
                None
                _g3 = haxe_Exception.caught(_g2).unwrap()
                if Std.isOfType(_g3,str):
                    e = _g3
                    print(str(("Error deserializing line: " + ("null" if e is None else e))))
                    continue
                else:
                    raise _g2
        return result

GoldenData._hx_class = GoldenData


class ISerializable:
    _hx_class_name = "ISerializable"
    __slots__ = ()
    _hx_methods = ["toString", "toJSON", "getCode"]
ISerializable._hx_class = ISerializable


class LineData:
    _hx_class_name = "LineData"
    __slots__ = ("pattern", "instrumentContext")
    _hx_fields = ["pattern", "instrumentContext"]
    _hx_methods = ["toString", "toJSON", "getCode"]
    _hx_interfaces = [ISerializable]

    def __init__(self,pattern,instrumentContext):
        self.pattern = pattern
        self.instrumentContext = instrumentContext

    def toString(self):
        return (((("LineData[pattern: " + HxOverrides.stringOrNull(self.pattern)) + ", instrumentContext: ") + HxOverrides.stringOrNull(self.instrumentContext.toString())) + "]")

    def toJSON(self):
        return haxe_format_JsonPrinter.print(_hx_AnonObject({'pattern': self.pattern, 'instrumentContextCode': self.instrumentContext.getCode(), 'instrumentContextData': self.instrumentContext.toJSON()}),None,None)

    def getCode(self):
        return "LineData"

LineData._hx_class = LineData

class Modifier(Enum):
    __slots__ = ()
    _hx_class_name = "Modifier"
    _hx_constructs = ["SEVENTH", "NINTH", "SIXTH", "SECONDARY", "VOICE_LEADING"]
Modifier.SEVENTH = Modifier("SEVENTH", 0, ())
Modifier.NINTH = Modifier("NINTH", 1, ())
Modifier.SIXTH = Modifier("SIXTH", 2, ())
Modifier.SECONDARY = Modifier("SECONDARY", 3, ())
Modifier.VOICE_LEADING = Modifier("VOICE_LEADING", 4, ())
Modifier._hx_class = Modifier

class _Mode_BaseScale(Enum):
    __slots__ = ()
    _hx_class_name = "_Mode.BaseScale"
    _hx_constructs = ["MAJOR", "MELODIC_MINOR", "HARMONIC_MINOR"]
_Mode_BaseScale.MAJOR = _Mode_BaseScale("MAJOR", 0, ())
_Mode_BaseScale.MELODIC_MINOR = _Mode_BaseScale("MELODIC_MINOR", 1, ())
_Mode_BaseScale.HARMONIC_MINOR = _Mode_BaseScale("HARMONIC_MINOR", 2, ())
_Mode_BaseScale._hx_class = _Mode_BaseScale


class Mode:
    _hx_class_name = "Mode"
    __slots__ = ("intervals",)
    _hx_fields = ["intervals"]
    _hx_methods = ["nth_from", "make_chord_from_pattern", "make_triad", "make_sixth", "make_seventh", "make_ninth", "valueEquals", "hashCode"]
    _hx_statics = ["major_intervals", "minor_intervals", "harmonic_minor_intervals", "melodic_minor_intervals", "modeMap", "constructMajorMode", "constructMelodicMinorMode", "constructHarmonicMinorMode", "initializeModeMap", "getMode", "getMajorMode", "getMinorMode", "getHarmonicMinorMode", "getMelodicMinorMode", "getDorianMode", "getPhrygianMode", "getLydianMode", "getMixolydianMode", "getAeolianMode", "getLocrianMode", "constructNthMajorMode", "constructNthHarmonicMinorMode", "constructNthMelodicMinorMode", "constructNthMinorMode"]

    def __init__(self,intervals):
        self.intervals = intervals

    def nth_from(self,root,n):
        if (n == 1):
            return root
        note = root
        _g = 0
        _g1 = (n - 1)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            note = (note + python_internal_ArrayImpl._get(self.intervals, HxOverrides.mod(i, len(self.intervals))))
        return note

    def make_chord_from_pattern(self,root,n,pat):
        _gthis = self
        def _hx_local_1():
            def _hx_local_0(x):
                return _gthis.nth_from(root,((n + x) - 1))
            return list(map(_hx_local_0,pat))
        return _hx_local_1()

    def make_triad(self,root,n):
        return self.make_chord_from_pattern(root,n,[1, 3, 5])

    def make_sixth(self,root,n):
        return self.make_chord_from_pattern(root,n,[1, 3, 5, 6])

    def make_seventh(self,root,n):
        return self.make_chord_from_pattern(root,n,[1, 3, 5, 7])

    def make_ninth(self,root,n):
        return self.make_chord_from_pattern(root,n,[1, 3, 5, 7, 9])

    def valueEquals(self,other):
        if (not Std.isOfType(other,Mode)):
            return False
        def _hx_local_1():
            _hx_local_0 = other
            if (Std.isOfType(_hx_local_0,Mode) or ((_hx_local_0 is None))):
                _hx_local_0
            else:
                raise "Class cast error"
            return _hx_local_0
        otherMode = _hx_local_1()
        if (otherMode is None):
            return False
        if (len(self.intervals) != len(otherMode.intervals)):
            return False
        _g = 0
        _g1 = len(self.intervals)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            if ((self.intervals[i] if i >= 0 and i < len(self.intervals) else None) != (otherMode.intervals[i] if i >= 0 and i < len(otherMode.intervals) else None)):
                return False
        return True

    def hashCode(self):
        hash = 17
        _g = 0
        _g1 = self.intervals
        while (_g < len(_g1)):
            interval = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
            _g = (_g + 1)
            hash = ((hash * 31) + interval)
        return hash
    modeMap = None

    @staticmethod
    def constructMajorMode(offset):
        intervals = []
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod(((offset - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod((((1 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod((((2 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod((((3 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod((((4 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod((((5 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.major_intervals, HxOverrides.mod((((6 + offset) - 1)), 7))
        intervals.append(x)
        return Mode(intervals)

    @staticmethod
    def constructMelodicMinorMode(offset):
        intervals = []
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod(((offset - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod((((1 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod((((2 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod((((3 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod((((4 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod((((5 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.melodic_minor_intervals, HxOverrides.mod((((6 + offset) - 1)), 7))
        intervals.append(x)
        return Mode(intervals)

    @staticmethod
    def constructHarmonicMinorMode(offset):
        intervals = []
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod(((offset - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod((((1 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod((((2 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod((((3 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod((((4 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod((((5 + offset) - 1)), 7))
        intervals.append(x)
        x = python_internal_ArrayImpl._get(Mode.harmonic_minor_intervals, HxOverrides.mod((((6 + offset) - 1)), 7))
        intervals.append(x)
        return Mode(intervals)

    @staticmethod
    def initializeModeMap():
        if (Mode.modeMap is None):
            Mode.modeMap = haxe_ds_EnumValueMap()
            majorModes = []
            x = Mode.constructMajorMode(1)
            majorModes.append(x)
            x = Mode.constructMajorMode(2)
            majorModes.append(x)
            x = Mode.constructMajorMode(3)
            majorModes.append(x)
            x = Mode.constructMajorMode(4)
            majorModes.append(x)
            x = Mode.constructMajorMode(5)
            majorModes.append(x)
            x = Mode.constructMajorMode(6)
            majorModes.append(x)
            x = Mode.constructMajorMode(7)
            majorModes.append(x)
            Mode.modeMap.set(_Mode_BaseScale.MAJOR,majorModes)
            melodicMinorModes = []
            x = Mode.constructMelodicMinorMode(1)
            melodicMinorModes.append(x)
            x = Mode.constructMelodicMinorMode(2)
            melodicMinorModes.append(x)
            x = Mode.constructMelodicMinorMode(3)
            melodicMinorModes.append(x)
            x = Mode.constructMelodicMinorMode(4)
            melodicMinorModes.append(x)
            x = Mode.constructMelodicMinorMode(5)
            melodicMinorModes.append(x)
            x = Mode.constructMelodicMinorMode(6)
            melodicMinorModes.append(x)
            x = Mode.constructMelodicMinorMode(7)
            melodicMinorModes.append(x)
            Mode.modeMap.set(_Mode_BaseScale.MELODIC_MINOR,melodicMinorModes)
            harmonicMinorModes = []
            x = Mode.constructHarmonicMinorMode(1)
            harmonicMinorModes.append(x)
            x = Mode.constructHarmonicMinorMode(2)
            harmonicMinorModes.append(x)
            x = Mode.constructHarmonicMinorMode(3)
            harmonicMinorModes.append(x)
            x = Mode.constructHarmonicMinorMode(4)
            harmonicMinorModes.append(x)
            x = Mode.constructHarmonicMinorMode(5)
            harmonicMinorModes.append(x)
            x = Mode.constructHarmonicMinorMode(6)
            harmonicMinorModes.append(x)
            x = Mode.constructHarmonicMinorMode(7)
            harmonicMinorModes.append(x)
            Mode.modeMap.set(_Mode_BaseScale.HARMONIC_MINOR,harmonicMinorModes)

    @staticmethod
    def getMode(baseScale,modeNumber):
        Mode.initializeModeMap()
        if ((modeNumber < 1) or ((modeNumber > 7))):
            raise haxe_Exception.thrown("Mode number must be between 1 and 7")
        return python_internal_ArrayImpl._get(Mode.modeMap.get(baseScale), (modeNumber - 1))

    @staticmethod
    def getMajorMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,1)

    @staticmethod
    def getMinorMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,6)

    @staticmethod
    def getHarmonicMinorMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.HARMONIC_MINOR,1)

    @staticmethod
    def getMelodicMinorMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MELODIC_MINOR,1)

    @staticmethod
    def getDorianMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,2)

    @staticmethod
    def getPhrygianMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,3)

    @staticmethod
    def getLydianMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,4)

    @staticmethod
    def getMixolydianMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,5)

    @staticmethod
    def getAeolianMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,6)

    @staticmethod
    def getLocrianMode():
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,7)

    @staticmethod
    def constructNthMajorMode(offset):
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MAJOR,offset)

    @staticmethod
    def constructNthHarmonicMinorMode(offset):
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.HARMONIC_MINOR,offset)

    @staticmethod
    def constructNthMelodicMinorMode(offset):
        Mode.initializeModeMap()
        return Mode.getMode(_Mode_BaseScale.MELODIC_MINOR,offset)

    @staticmethod
    def constructNthMinorMode(n):
        return Mode.constructNthMajorMode(n)

Mode._hx_class = Mode


class _Mode_Mode_Fields_:
    _hx_class_name = "_Mode.Mode_Fields_"
    __slots__ = ()
    _hx_statics = ["MAJOR", "MINOR", "HARMONIC_MINOR", "MELODIC_MINOR"]
_Mode_Mode_Fields_._hx_class = _Mode_Mode_Fields_


class Reflect:
    _hx_class_name = "Reflect"
    __slots__ = ()
    _hx_statics = ["field", "isFunction", "compare", "isEnumValue"]

    @staticmethod
    def field(o,field):
        return python_Boot.field(o,field)

    @staticmethod
    def isFunction(f):
        if (not ((python_lib_Inspect.isfunction(f) or python_lib_Inspect.ismethod(f)))):
            return python_Boot.hasField(f,"func_code")
        else:
            return True

    @staticmethod
    def compare(a,b):
        if ((a is None) and ((b is None))):
            return 0
        if (a is None):
            return 1
        elif (b is None):
            return -1
        elif HxOverrides.eq(a,b):
            return 0
        elif (a > b):
            return 1
        else:
            return -1

    @staticmethod
    def isEnumValue(v):
        if not HxOverrides.eq(v,Enum):
            return isinstance(v,Enum)
        else:
            return False
Reflect._hx_class = Reflect

class SelectorType(Enum):
    __slots__ = ()
    _hx_class_name = "SelectorType"
    _hx_constructs = ["Ascending", "Descending", "Repeat", "FullChord", "Random", "RandomFromScale", "SpecificNote", "Rest", "TopNote", "ScaleDegree"]

    @staticmethod
    def SpecificNote(n):
        return SelectorType("SpecificNote", 6, (n,))

    @staticmethod
    def ScaleDegree(n):
        return SelectorType("ScaleDegree", 9, (n,))
SelectorType.Ascending = SelectorType("Ascending", 0, ())
SelectorType.Descending = SelectorType("Descending", 1, ())
SelectorType.Repeat = SelectorType("Repeat", 2, ())
SelectorType.FullChord = SelectorType("FullChord", 3, ())
SelectorType.Random = SelectorType("Random", 4, ())
SelectorType.RandomFromScale = SelectorType("RandomFromScale", 5, ())
SelectorType.Rest = SelectorType("Rest", 7, ())
SelectorType.TopNote = SelectorType("TopNote", 8, ())
SelectorType._hx_class = SelectorType


class IRhythmGenerator:
    _hx_class_name = "IRhythmGenerator"
    __slots__ = ()
    _hx_methods = ["hasNext", "next", "reset", "getPatternLength", "getTotalSteps", "parseFailed", "getSteps"]
IRhythmGenerator._hx_class = IRhythmGenerator


class ExplicitRhythmGenerator:
    _hx_class_name = "ExplicitRhythmGenerator"
    __slots__ = ("steps", "index", "density", "totalSteps")
    _hx_fields = ["steps", "index", "density", "totalSteps"]
    _hx_methods = ["hasNext", "next", "reset", "getPatternLength", "getTotalSteps", "parseFailed", "getSteps"]
    _hx_interfaces = [IRhythmGenerator]

    def __init__(self,steps,density):
        self.steps = steps
        self.index = 0
        self.density = density
        self.totalSteps = (len(steps) * density)

    def hasNext(self):
        return True

    def next(self):
        selector = python_internal_ArrayImpl._get(self.steps, HxOverrides.mod(self.index, len(self.steps)))
        self.index = HxOverrides.mod(((self.index + 1)), self.totalSteps)
        return selector

    def reset(self):
        self.index = 0

    def getPatternLength(self):
        return len(self.steps)

    def getTotalSteps(self):
        return self.totalSteps

    def parseFailed(self):
        return False

    def getSteps(self):
        return self.steps

ExplicitRhythmGenerator._hx_class = ExplicitRhythmGenerator


class SimpleRhythmGenerator(ExplicitRhythmGenerator):
    _hx_class_name = "SimpleRhythmGenerator"
    __slots__ = ()
    _hx_fields = []
    _hx_methods = []
    _hx_statics = []
    _hx_interfaces = []
    _hx_super = ExplicitRhythmGenerator


    def __init__(self,k,n,selector,density,offset = None):
        if (offset is None):
            offset = 0
        steps = []
        _g = 0
        _g1 = n
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            steps.append(SelectorType.Rest)
        if (k >= n):
            _g = 0
            _g1 = n
            while (_g < _g1):
                i = _g
                _g = (_g + 1)
                python_internal_ArrayImpl._set(steps, i, selector)
        else:
            stepSize = (n / k)
            currentStep = 0.0
            _g = 0
            _g1 = k
            while (_g < _g1):
                i = _g
                _g = (_g + 1)
                pos = Math.floor((currentStep + 0.5))
                pos = HxOverrides.mod(((pos + offset)), n)
                python_internal_ArrayImpl._set(steps, pos, selector)
                currentStep = (currentStep + stepSize)
        super().__init__(steps,density)
SimpleRhythmGenerator._hx_class = SimpleRhythmGenerator


class BjorklundRhythmGenerator(ExplicitRhythmGenerator):
    _hx_class_name = "BjorklundRhythmGenerator"
    __slots__ = ()
    _hx_fields = []
    _hx_methods = ["bjorklund", "standardBjorklund", "buildPatternRecursive"]
    _hx_statics = []
    _hx_interfaces = []
    _hx_super = ExplicitRhythmGenerator


    def __init__(self,k,n,selector,density,offset = None):
        if (offset is None):
            offset = 0
        b = (k if (python_lib_Math.isnan(k)) else (n if (python_lib_Math.isnan(n)) else min(k,n)))
        x = (0 if (python_lib_Math.isnan(0)) else (b if (python_lib_Math.isnan(b)) else max(0,b)))
        try:
            k = int(x)
        except BaseException as _g:
            None
            k = None
        x = (1 if (python_lib_Math.isnan(1)) else (n if (python_lib_Math.isnan(n)) else max(1,n)))
        try:
            n = int(x)
        except BaseException as _g:
            None
            n = None
        pattern = []
        if (k <= 0):
            _g = []
            _g1 = 0
            _g2 = n
            while (_g1 < _g2):
                i = _g1
                _g1 = (_g1 + 1)
                _g.append(SelectorType.Rest)
            pattern = _g
        elif (k >= n):
            _g = []
            _g1 = 0
            _g2 = n
            while (_g1 < _g2):
                i = _g1
                _g1 = (_g1 + 1)
                _g.append(selector)
            pattern = _g
        else:
            bits = self.bjorklund(k,n)
            if (offset > 0):
                _g = []
                _g1 = 0
                _g2 = n
                while (_g1 < _g2):
                    i = _g1
                    _g1 = (_g1 + 1)
                    _g.append(False)
                rotated = _g
                _g = 0
                _g1 = n
                while (_g < _g1):
                    i = _g
                    _g = (_g + 1)
                    newPos = HxOverrides.mod((((i - offset) + n)), n)
                    python_internal_ArrayImpl._set(rotated, i, (bits[newPos] if newPos >= 0 and newPos < len(bits) else None))
                bits = rotated
            def _hx_local_0(bit):
                if bit:
                    return selector
                else:
                    return SelectorType.Rest
            pattern = list(map(_hx_local_0,bits))
        super().__init__(pattern,density)

    def bjorklund(self,k,n):
        if (k <= 0):
            _g = []
            _g1 = 0
            _g2 = n
            while (_g1 < _g2):
                i = _g1
                _g1 = (_g1 + 1)
                _g.append(False)
            return _g
        if (k >= n):
            _g = []
            _g1 = 0
            _g2 = n
            while (_g1 < _g2):
                i = _g1
                _g1 = (_g1 + 1)
                _g.append(True)
            return _g
        return self.standardBjorklund(k,n)

    def standardBjorklund(self,k,n):
        pattern = []
        counts = []
        remainders = []
        divisor = (n - k)
        remainders.append(k)
        level = 0
        while True:
            x = Math.floor((divisor / (remainders[level] if level >= 0 and level < len(remainders) else None)))
            counts.append(x)
            remainders.append(HxOverrides.mod(divisor, (remainders[level] if level >= 0 and level < len(remainders) else None)))
            divisor = (remainders[level] if level >= 0 and level < len(remainders) else None)
            level = (level + 1)
            if (not (((remainders[level] if level >= 0 and level < len(remainders) else None) > 1))):
                break
        counts.append(divisor)
        self.buildPatternRecursive(level,counts,remainders,pattern)
        firstOneIndex = python_internal_ArrayImpl.indexOf(pattern,1,None)
        if (firstOneIndex > 0):
            pattern = (pattern[firstOneIndex:None] + pattern[0:firstOneIndex])
        def _hx_local_2():
            def _hx_local_1(val):
                return (val == 1)
            return list(map(_hx_local_1,pattern))
        return _hx_local_2()

    def buildPatternRecursive(self,level,counts,remainders,pattern):
        if (level == -1):
            pattern.append(0)
        elif (level == -2):
            pattern.append(1)
        else:
            _g = 0
            _g1 = (counts[level] if level >= 0 and level < len(counts) else None)
            while (_g < _g1):
                i = _g
                _g = (_g + 1)
                self.buildPatternRecursive((level - 1),counts,remainders,pattern)
            if ((remainders[level] if level >= 0 and level < len(remainders) else None) != 0):
                self.buildPatternRecursive((level - 2),counts,remainders,pattern)

BjorklundRhythmGenerator._hx_class = BjorklundRhythmGenerator


class ParseFailedRhythmGenerator:
    _hx_class_name = "ParseFailedRhythmGenerator"
    __slots__ = ("patternLength",)
    _hx_fields = ["patternLength"]
    _hx_methods = ["hasNext", "next", "reset", "getPatternLength", "getTotalSteps", "parseFailed", "getSteps"]
    _hx_interfaces = [IRhythmGenerator]

    def __init__(self,patternLength = None):
        if (patternLength is None):
            patternLength = 1
        self.patternLength = patternLength

    def hasNext(self):
        return True

    def next(self):
        return SelectorType.Rest

    def reset(self):
        pass

    def getPatternLength(self):
        return self.patternLength

    def getTotalSteps(self):
        return self.patternLength

    def parseFailed(self):
        return True

    def getSteps(self):
        return []

ParseFailedRhythmGenerator._hx_class = ParseFailedRhythmGenerator


class RhythmLanguage:
    _hx_class_name = "RhythmLanguage"
    __slots__ = ()
    _hx_statics = ["makeRhythmGenerator", "parse", "parseEuclidean", "parseExplicit", "parseSelectorType"]

    @staticmethod
    def makeRhythmGenerator(pattern):
        return RhythmLanguage.parse(pattern)

    @staticmethod
    def parse(input):
        input = StringTools.trim(input)
        euclidean = RhythmLanguage.parseEuclidean(input)
        if (not euclidean.parseFailed()):
            return euclidean
        explicit = RhythmLanguage.parseExplicit(input)
        if (not explicit.parseFailed()):
            return explicit
        return ParseFailedRhythmGenerator()

    @staticmethod
    def parseEuclidean(input):
        regex = EReg("^([0-9]+)([/%])([0-9]+)(\\+([0-9]+))?\\s+([><rc=tR]|[0-9])\\s+([0-9]+)$","")
        regex.matchObj = python_lib_Re.search(regex.pattern,input)
        if (regex.matchObj is None):
            return ParseFailedRhythmGenerator()
        k = Std.parseInt(regex.matchObj.group(1))
        separator = regex.matchObj.group(2)
        n = Std.parseInt(regex.matchObj.group(3))
        offsetStr = regex.matchObj.group(5)
        offset = (Std.parseInt(offsetStr) if ((offsetStr is not None)) else 0)
        selector = RhythmLanguage.parseSelectorType(regex.matchObj.group(6))
        density = Std.parseInt(regex.matchObj.group(7))
        if ((((k is None) or ((n is None))) or ((selector is None))) or ((density is None))):
            return ParseFailedRhythmGenerator()
        if (((k <= 0) or ((n <= 0))) or ((density <= 0))):
            return ParseFailedRhythmGenerator()
        if (separator == "%"):
            return BjorklundRhythmGenerator(k,n,selector,density,offset)
        else:
            return SimpleRhythmGenerator(k,n,selector,density,offset)

    @staticmethod
    def parseExplicit(input):
        parts = input.split(" ")
        if (len(parts) != 2):
            return ParseFailedRhythmGenerator()
        stepsStr = (parts[0] if 0 < len(parts) else None)
        density = Std.parseInt((parts[1] if 1 < len(parts) else None))
        if ((density is None) or ((density <= 0))):
            return ParseFailedRhythmGenerator()
        steps = list()
        _g = 0
        _g1 = len(stepsStr)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            char = ("" if (((i < 0) or ((i >= len(stepsStr))))) else stepsStr[i])
            if (char == "."):
                steps.append(SelectorType.Rest)
            else:
                selector = RhythmLanguage.parseSelectorType(char)
                if (selector is None):
                    return ParseFailedRhythmGenerator()
                steps.append(selector)
        return ExplicitRhythmGenerator(steps,density)

    @staticmethod
    def parseSelectorType(input):
        input1 = input
        if (input1 == "<"):
            return SelectorType.Descending
        elif (input1 == "="):
            return SelectorType.Repeat
        elif (input1 == ">"):
            return SelectorType.Ascending
        elif (input1 == "R"):
            return SelectorType.RandomFromScale
        elif (input1 == "c"):
            return SelectorType.FullChord
        elif (input1 == "r"):
            return SelectorType.Random
        elif (input1 == "t"):
            return SelectorType.TopNote
        else:
            n = input
            _this = EReg("^[1-9]$","")
            _this.matchObj = python_lib_Re.search(_this.pattern,n)
            if (_this.matchObj is not None):
                return SelectorType.SpecificNote(Std.parseInt(n))
            else:
                return None
RhythmLanguage._hx_class = RhythmLanguage


class INote:
    _hx_class_name = "INote"
    __slots__ = ()
    _hx_methods = ["getMidiNoteValue", "getStartTime", "getLength"]
INote._hx_class = INote


class IDeserializationHelper:
    _hx_class_name = "IDeserializationHelper"
    __slots__ = ()
    _hx_methods = ["helpMake"]
IDeserializationHelper._hx_class = IDeserializationHelper


class IInstrumentContext:
    _hx_class_name = "IInstrumentContext"
    __slots__ = ()
    _hx_methods = ["makeNote"]
    _hx_interfaces = [ISerializable]
IInstrumentContext._hx_class = IInstrumentContext


class Note:
    _hx_class_name = "Note"
    __slots__ = ("chan", "note", "startTime", "length", "velocity")
    _hx_fields = ["chan", "note", "startTime", "length", "velocity"]
    _hx_methods = ["toString", "toStruct", "valueEquals", "transpose", "getMidiNoteValue", "getStartTime", "getLength"]
    _hx_interfaces = [INote]

    def __init__(self,chan,note,velocity,startTime,length):
        self.chan = chan
        self.note = note
        self.startTime = startTime
        self.length = length
        self.velocity = velocity

    def toString(self):
        return (((((((((("Note[chan: " + Std.string(self.chan)) + ", note: ") + Std.string(self.note)) + ", vel: ") + Std.string(self.velocity)) + ", startTime: ") + Std.string(self.startTime)) + ", length: ") + Std.string(self.length)) + "]")

    def toStruct(self):
        return _hx_AnonObject({'chan': self.chan, 'note': self.note, 'velocity': self.velocity, 'startTime': self.startTime, 'length': self.length})

    def valueEquals(self,other):
        if (not Std.isOfType(other,Note)):
            return False
        def _hx_local_1():
            _hx_local_0 = other
            if (Std.isOfType(_hx_local_0,Note) or ((_hx_local_0 is None))):
                _hx_local_0
            else:
                raise "Class cast error"
            return _hx_local_0
        otherNote = _hx_local_1()
        if ((((self.chan == otherNote.chan) and ((self.note == otherNote.note))) and ((self.velocity == otherNote.velocity))) and ((self.startTime == otherNote.startTime))):
            return (self.length == otherNote.length)
        else:
            return False

    def transpose(self,offset):
        return Note(self.chan,(self.note + offset),self.velocity,self.startTime,self.length)

    def getMidiNoteValue(self):
        return self.note

    def getStartTime(self):
        return self.startTime

    def getLength(self):
        return self.length

Note._hx_class = Note


class ScoreUtilities:
    _hx_class_name = "ScoreUtilities"
    __slots__ = ()
    _hx_statics = ["transposeNotes", "makePianoRollSVG"]

    @staticmethod
    def transposeNotes(notes,offset,instrumentContext):
        _g = []
        _g1 = 0
        while (_g1 < len(notes)):
            n = (notes[_g1] if _g1 >= 0 and _g1 < len(notes) else None)
            _g1 = (_g1 + 1)
            x = instrumentContext.makeNote((n.getMidiNoteValue() + offset),n.getStartTime(),n.getLength())
            _g.append(x)
        return _g

    @staticmethod
    def makePianoRollSVG(notes,svgWidth,svgHeight):
        noteHeight = (svgHeight / 100)
        maxTime = 0.0
        _g = 0
        while (_g < len(notes)):
            note = (notes[_g] if _g >= 0 and _g < len(notes) else None)
            _g = (_g + 1)
            b = (note.getStartTime() + note.getLength())
            if (not python_lib_Math.isnan(maxTime)):
                maxTime = (b if (python_lib_Math.isnan(b)) else max(maxTime,b))
        timeScale = ((svgWidth / maxTime) if ((maxTime > 0)) else 0.1)
        pitchOffset = 20
        svg_b = python_lib_io_StringIO()
        svg_b.write(Std.string((((((((("<svg width=\"" + Std.string(svgWidth)) + "\" height=\"") + Std.string(svgHeight)) + "\" viewBox=\"0 0 ") + Std.string(svgWidth)) + " ") + Std.string(svgHeight)) + "\" xmlns=\"http://www.w3.org/2000/svg\">\n")))
        _g = 0
        _g1 = None
        try:
            _g1 = int((svgHeight / noteHeight))
        except BaseException as _g2:
            None
            _g1 = None
        _g2 = _g1
        while (_g < _g2):
            i = _g
            _g = (_g + 1)
            y = (i * noteHeight)
            svg_b.write(Std.string((((((("<line x1=\"0\" y1=\"" + Std.string(y)) + "\" x2=\"") + Std.string(svgWidth)) + "\" y2=\"") + Std.string(y)) + "\" stroke=\"#ddd\" />\n")))
        _g = 0
        while (_g < len(notes)):
            note = (notes[_g] if _g >= 0 and _g < len(notes) else None)
            _g = (_g + 1)
            x = (note.getStartTime() * timeScale)
            y = ((svgHeight - ((((note.getMidiNoteValue() - pitchOffset)) * noteHeight))) - noteHeight)
            width = (note.getLength() * timeScale)
            height = noteHeight
            if (((python_lib_Math.isnan(x) or python_lib_Math.isnan(y)) or python_lib_Math.isnan(width)) or python_lib_Math.isnan(height)):
                print(str(((((((((("Invalid note values: note=" + Std.string(note)) + ", x=") + Std.string(x)) + ", y=") + Std.string(y)) + ", width=") + Std.string(width)) + ", height=") + Std.string(height))))
                continue
            svg_b.write(Std.string((((((((("<rect x=\"" + Std.string(x)) + "\" y=\"") + Std.string(y)) + "\" width=\"") + Std.string(width)) + "\" height=\"") + Std.string(height)) + "\" fill=\"black\" />\n")))
        svg_b.write("</svg>")
        return svg_b.getvalue()
ScoreUtilities._hx_class = ScoreUtilities


class Std:
    _hx_class_name = "Std"
    __slots__ = ()
    _hx_statics = ["is", "isOfType", "string", "parseInt"]

    @staticmethod
    def _hx_is(v,t):
        return Std.isOfType(v,t)

    @staticmethod
    def isOfType(v,t):
        if ((v is None) and ((t is None))):
            return False
        if (t is None):
            return False
        if ((type(t) == type) and (t == Dynamic)):
            return (v is not None)
        isBool = isinstance(v,bool)
        if (((type(t) == type) and (t == Bool)) and isBool):
            return True
        if ((((not isBool) and (not ((type(t) == type) and (t == Bool)))) and ((type(t) == type) and (t == Int))) and isinstance(v,int)):
            return True
        vIsFloat = isinstance(v,float)
        tmp = None
        tmp1 = None
        if (((not isBool) and vIsFloat) and ((type(t) == type) and (t == Int))):
            f = v
            tmp1 = (((f != Math.POSITIVE_INFINITY) and ((f != Math.NEGATIVE_INFINITY))) and (not python_lib_Math.isnan(f)))
        else:
            tmp1 = False
        if tmp1:
            tmp1 = None
            try:
                tmp1 = int(v)
            except BaseException as _g:
                None
                tmp1 = None
            tmp = (v == tmp1)
        else:
            tmp = False
        if ((tmp and ((v <= 2147483647))) and ((v >= -2147483648))):
            return True
        if (((not isBool) and ((type(t) == type) and (t == Float))) and isinstance(v,(float, int))):
            return True
        if ((type(t) == type) and (t == str)):
            return isinstance(v,str)
        isEnumType = ((type(t) == type) and (t == Enum))
        if ((isEnumType and python_lib_Inspect.isclass(v)) and hasattr(v,"_hx_constructs")):
            return True
        if isEnumType:
            return False
        isClassType = ((type(t) == type) and (t == Class))
        if ((((isClassType and (not isinstance(v,Enum))) and python_lib_Inspect.isclass(v)) and hasattr(v,"_hx_class_name")) and (not hasattr(v,"_hx_constructs"))):
            return True
        if isClassType:
            return False
        tmp = None
        try:
            tmp = isinstance(v,t)
        except BaseException as _g:
            None
            tmp = False
        if tmp:
            return True
        if python_lib_Inspect.isclass(t):
            cls = t
            loop = None
            def _hx_local_1(intf):
                f = (intf._hx_interfaces if (hasattr(intf,"_hx_interfaces")) else [])
                if (f is not None):
                    _g = 0
                    while (_g < len(f)):
                        i = (f[_g] if _g >= 0 and _g < len(f) else None)
                        _g = (_g + 1)
                        if (i == cls):
                            return True
                        else:
                            l = loop(i)
                            if l:
                                return True
                    return False
                else:
                    return False
            loop = _hx_local_1
            currentClass = v.__class__
            result = False
            while (currentClass is not None):
                if loop(currentClass):
                    result = True
                    break
                currentClass = python_Boot.getSuperClass(currentClass)
            return result
        else:
            return False

    @staticmethod
    def string(s):
        return python_Boot.toString1(s,"")

    @staticmethod
    def parseInt(x):
        if (x is None):
            return None
        _hx_len = len(x)
        index = 0
        while (index < _hx_len):
            if (not (x[index] in " \n\r\t\x0B\x0C")):
                break
            index = (index + 1)
        isNegative = None
        if (index < _hx_len):
            sign = x[index]
            if ((sign == "-") or ((sign == "+"))):
                index = (index + 1)
            isNegative = (sign == "-")
        else:
            isNegative = False
        isHexadecimal = None
        if ((index + 1) < _hx_len):
            cur = x[index]
            next = x[(index + 1)]
            isHexadecimal = ((cur == "0") and (((next == "x") or ((next == "X")))))
        else:
            isHexadecimal = False
        if isHexadecimal:
            index = (index + 2)
        cur = index
        if isHexadecimal:
            while (cur < _hx_len):
                if (not (x[cur] in "0123456789abcdefABCDEF")):
                    break
                cur = (cur + 1)
        else:
            while (cur < _hx_len):
                if (not (x[cur] in "0123456789")):
                    break
                cur = (cur + 1)
        firstInvalidIndex = cur
        if (index == firstInvalidIndex):
            return None
        result = int(HxString.substring(x,index,firstInvalidIndex),(16 if isHexadecimal else 10))
        if isNegative:
            return -result
        else:
            return result
Std._hx_class = Std


class Float: pass


class Int: pass


class Bool: pass


class Dynamic: pass


class StringBuf:
    _hx_class_name = "StringBuf"
    __slots__ = ("b",)
    _hx_fields = ["b"]
    _hx_methods = ["get_length"]

    def __init__(self):
        self.b = python_lib_io_StringIO()

    def get_length(self):
        pos = self.b.tell()
        self.b.seek(0,2)
        _hx_len = self.b.tell()
        self.b.seek(pos,0)
        return _hx_len

StringBuf._hx_class = StringBuf


class StringTools:
    _hx_class_name = "StringTools"
    __slots__ = ()
    _hx_statics = ["isSpace", "ltrim", "rtrim", "trim", "lpad"]

    @staticmethod
    def isSpace(s,pos):
        if (((len(s) == 0) or ((pos < 0))) or ((pos >= len(s)))):
            return False
        c = HxString.charCodeAt(s,pos)
        if (not (((c > 8) and ((c < 14))))):
            return (c == 32)
        else:
            return True

    @staticmethod
    def ltrim(s):
        l = len(s)
        r = 0
        while ((r < l) and StringTools.isSpace(s,r)):
            r = (r + 1)
        if (r > 0):
            return HxString.substr(s,r,(l - r))
        else:
            return s

    @staticmethod
    def rtrim(s):
        l = len(s)
        r = 0
        while ((r < l) and StringTools.isSpace(s,((l - r) - 1))):
            r = (r + 1)
        if (r > 0):
            return HxString.substr(s,0,(l - r))
        else:
            return s

    @staticmethod
    def trim(s):
        return StringTools.ltrim(StringTools.rtrim(s))

    @staticmethod
    def lpad(s,c,l):
        if (len(c) <= 0):
            return s
        buf = StringBuf()
        l = (l - len(s))
        while (buf.get_length() < l):
            s1 = Std.string(c)
            buf.b.write(s1)
        s1 = Std.string(s)
        buf.b.write(s1)
        return buf.b.getvalue()
StringTools._hx_class = StringTools

class SeqTypes(Enum):
    __slots__ = ()
    _hx_class_name = "SeqTypes"
    _hx_constructs = ["CHORDS", "ARPUP", "ARPDOWN", "BASS", "TOP", "RANDOM", "SCALE"]
SeqTypes.CHORDS = SeqTypes("CHORDS", 0, ())
SeqTypes.ARPUP = SeqTypes("ARPUP", 1, ())
SeqTypes.ARPDOWN = SeqTypes("ARPDOWN", 2, ())
SeqTypes.BASS = SeqTypes("BASS", 3, ())
SeqTypes.TOP = SeqTypes("TOP", 4, ())
SeqTypes.RANDOM = SeqTypes("RANDOM", 5, ())
SeqTypes.SCALE = SeqTypes("SCALE", 6, ())
SeqTypes._hx_class = SeqTypes

class DivisionValue(Enum):
    __slots__ = ()
    _hx_class_name = "DivisionValue"
    _hx_constructs = ["SIXTEENTH", "TWELFTH", "EIGHTH", "SIXTH", "QUARTER", "THIRD", "HALF", "WHOLE"]
DivisionValue.SIXTEENTH = DivisionValue("SIXTEENTH", 0, ())
DivisionValue.TWELFTH = DivisionValue("TWELFTH", 1, ())
DivisionValue.EIGHTH = DivisionValue("EIGHTH", 2, ())
DivisionValue.SIXTH = DivisionValue("SIXTH", 3, ())
DivisionValue.QUARTER = DivisionValue("QUARTER", 4, ())
DivisionValue.THIRD = DivisionValue("THIRD", 5, ())
DivisionValue.HALF = DivisionValue("HALF", 6, ())
DivisionValue.WHOLE = DivisionValue("WHOLE", 7, ())
DivisionValue._hx_class = DivisionValue

class RhythmicDensity(Enum):
    __slots__ = ()
    _hx_class_name = "RhythmicDensity"
    _hx_constructs = ["SIXTEEN", "TWELVE", "EIGHT", "SIX", "FOUR", "THREE", "TWO", "ONE"]
RhythmicDensity.SIXTEEN = RhythmicDensity("SIXTEEN", 0, ())
RhythmicDensity.TWELVE = RhythmicDensity("TWELVE", 1, ())
RhythmicDensity.EIGHT = RhythmicDensity("EIGHT", 2, ())
RhythmicDensity.SIX = RhythmicDensity("SIX", 3, ())
RhythmicDensity.FOUR = RhythmicDensity("FOUR", 4, ())
RhythmicDensity.THREE = RhythmicDensity("THREE", 5, ())
RhythmicDensity.TWO = RhythmicDensity("TWO", 6, ())
RhythmicDensity.ONE = RhythmicDensity("ONE", 7, ())
RhythmicDensity._hx_class = RhythmicDensity


class ILineGenerator:
    _hx_class_name = "ILineGenerator"
    __slots__ = ()
    _hx_methods = ["generateNotes", "getPitches", "getDurations"]
ILineGenerator._hx_class = ILineGenerator


class ArpIterator:
    _hx_class_name = "ArpIterator"
    __slots__ = ("chord", "noteIndex", "step")
    _hx_fields = ["chord", "noteIndex", "step"]
    _hx_methods = ["hasNext", "next"]

    def __init__(self,chord,step = None):
        if (step is None):
            step = 1
        self.chord = chord
        self.noteIndex = 0
        self.step = step

    def hasNext(self):
        return True

    def next(self):
        note = python_internal_ArrayImpl._get(self.chord, HxOverrides.mod(self.noteIndex, len(self.chord)))
        self.noteIndex = HxOverrides.mod(((self.noteIndex + self.step)), len(self.chord))
        return note

ArpIterator._hx_class = ArpIterator


class NoteSelectorIterator:
    _hx_class_name = "NoteSelectorIterator"
    __slots__ = ("chords", "chordIndex", "noteSelector")
    _hx_fields = ["chords", "chordIndex", "noteSelector"]
    _hx_methods = ["hasNext", "next"]

    def __init__(self,chords,noteSelector):
        self.chords = chords.toNotes()
        self.chordIndex = 0
        self.noteSelector = noteSelector

    def hasNext(self):
        return (self.chordIndex < len(self.chords))

    def next(self):
        note = self.noteSelector(python_internal_ArrayImpl._get(self.chords, self.chordIndex))
        _hx_local_0 = self
        _hx_local_1 = _hx_local_0.chordIndex
        _hx_local_0.chordIndex = (_hx_local_1 + 1)
        _hx_local_1
        return note

NoteSelectorIterator._hx_class = NoteSelectorIterator


class MenuHelper:
    _hx_class_name = "MenuHelper"
    __slots__ = ()
    _hx_statics = ["getDivisionNames", "getDivisionValues", "getDivisionFor", "divisionValue2Numeric", "getRhythmicDensityNames", "getRhythmicDensityValues", "getRhythmicDensityFor", "rhythmicDensityToNumeric"]

    @staticmethod
    def getDivisionNames():
        return ["1/16", "1/12", "1/8", "1/6", "1/4", "1/3", "1/2", "1"]

    @staticmethod
    def getDivisionValues():
        return [DivisionValue.SIXTEENTH, DivisionValue.TWELFTH, DivisionValue.EIGHTH, DivisionValue.SIXTH, DivisionValue.QUARTER, DivisionValue.THIRD, DivisionValue.HALF, DivisionValue.WHOLE]

    @staticmethod
    def getDivisionFor(i):
        return python_internal_ArrayImpl._get(MenuHelper.getDivisionValues(), i)

    @staticmethod
    def divisionValue2Numeric(dv):
        _g = haxe_ds_EnumValueMap()
        _g.set(DivisionValue.SIXTEENTH,0.0625)
        _g.set(DivisionValue.TWELFTH,0.0833333333333333287)
        _g.set(DivisionValue.EIGHTH,0.125)
        _g.set(DivisionValue.SIXTH,0.166666666666666657)
        _g.set(DivisionValue.QUARTER,0.25)
        _g.set(DivisionValue.THIRD,0.333333333333333315)
        _g.set(DivisionValue.HALF,0.5)
        _g.set(DivisionValue.WHOLE,1)
        return _g.get(dv)

    @staticmethod
    def getRhythmicDensityNames():
        return ["16 patterns/chord", "12 patterns/chord", "8 patterns/chord", "6 patterns/chord", "4 patterns/chord", "3 patterns/chord", "2 patterns/chord", "1 pattern/chord"]

    @staticmethod
    def getRhythmicDensityValues():
        return [RhythmicDensity.SIXTEEN, RhythmicDensity.TWELVE, RhythmicDensity.EIGHT, RhythmicDensity.SIX, RhythmicDensity.FOUR, RhythmicDensity.THREE, RhythmicDensity.TWO, RhythmicDensity.ONE]

    @staticmethod
    def getRhythmicDensityFor(i):
        return python_internal_ArrayImpl._get(MenuHelper.getRhythmicDensityValues(), i)

    @staticmethod
    def rhythmicDensityToNumeric(rd):
        _g = haxe_ds_EnumValueMap()
        _g.set(RhythmicDensity.SIXTEEN,0.0625)
        _g.set(RhythmicDensity.TWELVE,0.0833333333333333287)
        _g.set(RhythmicDensity.EIGHT,0.125)
        _g.set(RhythmicDensity.SIX,0.166666666666666657)
        _g.set(RhythmicDensity.FOUR,0.25)
        _g.set(RhythmicDensity.THREE,0.333333333333333315)
        _g.set(RhythmicDensity.TWO,0.5)
        _g.set(RhythmicDensity.ONE,1)
        result = _g.get(rd)
        return result
MenuHelper._hx_class = MenuHelper


class TimeManipulator:
    _hx_class_name = "TimeManipulator"
    __slots__ = ("ppq", "chordDuration", "chordTicks", "bpm")
    _hx_fields = ["ppq", "chordDuration", "chordTicks", "bpm"]
    _hx_methods = ["recalc", "setChordDuration", "setPPQ", "setBPM", "toString", "quarterToMS", "getBPM", "getPPQ"]

    def __init__(self):
        self.chordTicks = None
        self.ppq = 1000
        self.chordDuration = 16
        self.bpm = 120
        self.recalc()

    def recalc(self):
        self.chordTicks = (self.ppq * self.chordDuration)

    def setChordDuration(self,cl):
        self.chordDuration = cl
        self.recalc()
        return self

    def setPPQ(self,p):
        self.ppq = p
        self.recalc()
        return self

    def setBPM(self,b):
        self.bpm = b
        self.recalc()
        return self

    def toString(self):
        return ((((((("\nTimeManipulator\n  PPQ: " + Std.string(self.ppq)) + "\n  Chord Length Multiplier: ") + Std.string(self.chordDuration)) + "\n  quarterToMS: ") + Std.string(self.quarterToMS())) + "\n  chordTicks:") + Std.string(self.chordTicks))

    def quarterToMS(self):
        return (60 / self.bpm)

    def getBPM(self):
        return self.bpm

    def getPPQ(self):
        return self.ppq

TimeManipulator._hx_class = TimeManipulator


class MidiInstrumentContext:
    _hx_class_name = "MidiInstrumentContext"
    __slots__ = ("chan", "velocity", "gateLength", "transpose")
    _hx_fields = ["chan", "velocity", "gateLength", "transpose"]
    _hx_methods = ["getChannel", "makeNote", "toString", "toJSON", "getCode"]
    _hx_interfaces = [IInstrumentContext]

    def __init__(self,chan,velocity,gateLength,transpose):
        self.chan = chan
        self.velocity = velocity
        self.gateLength = gateLength
        self.transpose = transpose

    def getChannel(self):
        return self.chan

    def makeNote(self,note,startTime,length):
        return Note(self.chan,(note + self.transpose),self.velocity,startTime,(length * self.gateLength))

    def toString(self):
        return (((((((("MidiInstrumentContext[chan: " + Std.string(self.chan)) + ", velocity: ") + Std.string(self.velocity)) + ", gateLength: ") + Std.string(self.gateLength)) + ", transpose: ") + Std.string(self.transpose)) + "]")

    def toJSON(self):
        return haxe_format_JsonPrinter.print(_hx_AnonObject({'chan': self.chan, 'velocity': self.velocity, 'gateLength': self.gateLength, 'transpose': self.transpose}),None,None)

    def getCode(self):
        return "MidiInstrumentContext"

MidiInstrumentContext._hx_class = MidiInstrumentContext


class DeserializationHelper:
    _hx_class_name = "DeserializationHelper"
    __slots__ = ()
    _hx_methods = ["helpMake"]
    _hx_interfaces = [IDeserializationHelper]

    def __init__(self):
        pass

    def helpMake(self,code,json):
        code1 = code
        _hx_local_0 = len(code1)
        if (_hx_local_0 == 8):
            if (code1 == "LineData"):
                lineData = python_lib_Json.loads(json,**python__KwArgs_KwArgs_Impl_.fromT(_hx_AnonObject({'object_hook': python_Lib.dictToAnon})))
                instrumentContext = self.helpMake(lineData.instrumentContextCode,lineData.instrumentContextData)
                return LineData(lineData.pattern,instrumentContext)
            else:
                raise haxe_Exception.thrown(("Unknown code: " + ("null" if code is None else code)))
        elif (_hx_local_0 == 21):
            if (code1 == "MidiInstrumentContext"):
                contextData = python_lib_Json.loads(json,**python__KwArgs_KwArgs_Impl_.fromT(_hx_AnonObject({'object_hook': python_Lib.dictToAnon})))
                return MidiInstrumentContext(contextData.chan,contextData.velocity,contextData.gateLength,contextData.transpose)
            else:
                raise haxe_Exception.thrown(("Unknown code: " + ("null" if code is None else code)))
        else:
            raise haxe_Exception.thrown(("Unknown code: " + ("null" if code is None else code)))

DeserializationHelper._hx_class = DeserializationHelper


class LineGenerator:
    _hx_class_name = "LineGenerator"
    __slots__ = ("timeManipulator", "seq", "rhythmGenerator", "instrumentContext", "cachedNotes", "lastNoteIndex", "lastNoteValue")
    _hx_fields = ["timeManipulator", "seq", "rhythmGenerator", "instrumentContext", "cachedNotes", "lastNoteIndex", "lastNoteValue"]
    _hx_methods = ["selectNotesFromChord", "generateCachedNotes", "getPitches", "getDurations", "generateNotes", "notesInSeconds"]
    _hx_statics = ["create", "createFromPattern"]
    _hx_interfaces = [ILineGenerator]

    def __init__(self,timeManipulator,seq,rhythmGenerator,instrumentContext):
        self.timeManipulator = timeManipulator
        self.seq = seq
        self.rhythmGenerator = rhythmGenerator
        self.instrumentContext = instrumentContext
        self.cachedNotes = None
        self.lastNoteIndex = -1
        self.lastNoteValue = -1

    def selectNotesFromChord(self,selector,chordThing):
        tmp = selector.index
        if (tmp == 0):
            chord = chordThing.generateChordNotes()
            self.lastNoteIndex = (0 if ((self.lastNoteIndex == -1)) else HxOverrides.mod(((self.lastNoteIndex + 1)), len(chord)))
            self.lastNoteValue = python_internal_ArrayImpl._get(chord, self.lastNoteIndex)
            return [self.lastNoteValue]
        elif (tmp == 1):
            chord = chordThing.generateChordNotes()
            self.lastNoteIndex = ((len(chord) - 1) if ((self.lastNoteIndex == -1)) else HxOverrides.mod((((self.lastNoteIndex - 1) + len(chord))), len(chord)))
            self.lastNoteValue = python_internal_ArrayImpl._get(chord, self.lastNoteIndex)
            return [self.lastNoteValue]
        elif (tmp == 2):
            if (self.lastNoteValue == -1):
                chord = chordThing.generateChordNotes()
                self.lastNoteIndex = 0
                self.lastNoteValue = (chord[0] if 0 < len(chord) else None)
            return [self.lastNoteValue]
        elif (tmp == 3):
            return chordThing.generateChordNotes()
        elif (tmp == 4):
            chord = chordThing.generateChordNotes()
            x = Math.floor((python_lib_Random.random() * len(chord)))
            tmp = None
            try:
                tmp = int(x)
            except BaseException as _g:
                None
                tmp = None
            self.lastNoteIndex = tmp
            self.lastNoteValue = python_internal_ArrayImpl._get(chord, self.lastNoteIndex)
            return [self.lastNoteValue]
        elif (tmp == 5):
            mode = chordThing.get_mode()
            x = (Math.floor((python_lib_Random.random() * 7)) + 1)
            degree = None
            try:
                degree = int(x)
            except BaseException as _g:
                None
                degree = None
            self.lastNoteValue = mode.nth_from(chordThing.key,degree)
            return [self.lastNoteValue]
        elif (tmp == 6):
            n = selector.params[0]
            chord = chordThing.generateChordNotes()
            a = (n - 1)
            b = (len(chord) - 1)
            x = (a if (python_lib_Math.isnan(a)) else (b if (python_lib_Math.isnan(b)) else min(a,b)))
            tmp = None
            try:
                tmp = int(x)
            except BaseException as _g:
                None
                tmp = None
            self.lastNoteIndex = tmp
            self.lastNoteValue = python_internal_ArrayImpl._get(chord, self.lastNoteIndex)
            return [self.lastNoteValue]
        elif (tmp == 7):
            return []
        elif (tmp == 8):
            chord = chordThing.generateChordNotes()
            self.lastNoteIndex = (len(chord) - 1)
            self.lastNoteValue = python_internal_ArrayImpl._get(chord, self.lastNoteIndex)
            return [self.lastNoteValue]
        elif (tmp == 9):
            n = selector.params[0]
            if ((n < 1) or ((n > 7))):
                return []
            else:
                mode = chordThing.get_mode()
                self.lastNoteValue = mode.nth_from(chordThing.key,n)
                return [self.lastNoteValue]
        else:
            pass

    def generateCachedNotes(self):
        notes = list()
        currentTime = 0.0
        totalSteps = self.rhythmGenerator.getTotalSteps()
        stepSize = (self.timeManipulator.chordTicks / totalSteps)
        _g = 0
        _g1 = self.seq.toChordThings()
        while (_g < len(_g1)):
            ct = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
            _g = (_g + 1)
            self.lastNoteIndex = -1
            self.lastNoteValue = -1
            self.rhythmGenerator.reset()
            _g2 = 0
            _g3 = totalSteps
            while (_g2 < _g3):
                step = _g2
                _g2 = (_g2 + 1)
                selector = self.rhythmGenerator.next()
                if (selector != SelectorType.Rest):
                    notesToAdd = self.selectNotesFromChord(selector,ct)
                    _g4 = 0
                    while (_g4 < len(notesToAdd)):
                        note = (notesToAdd[_g4] if _g4 >= 0 and _g4 < len(notesToAdd) else None)
                        _g4 = (_g4 + 1)
                        x = self.instrumentContext.makeNote(note,currentTime,stepSize)
                        notes.append(x)
                currentTime = (currentTime + stepSize)
        return notes

    def getPitches(self):
        pitches = list()
        _g = 0
        _g1 = self.cachedNotes
        while (_g < len(_g1)):
            note = (_g1[_g] if _g >= 0 and _g < len(_g1) else None)
            _g = (_g + 1)
            x = note.getMidiNoteValue()
            pitches.append(x)
        return pitches

    def getDurations(self):
        durations = list()
        if (len(self.cachedNotes) == 0):
            return durations
        _g = 0
        _g1 = (len(self.cachedNotes) - 1)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            currentNote = (self.cachedNotes[i] if i >= 0 and i < len(self.cachedNotes) else None)
            nextNote = python_internal_ArrayImpl._get(self.cachedNotes, (i + 1))
            duration = (nextNote.getStartTime() - currentNote.getStartTime())
            durations.append(duration)
        x = python_internal_ArrayImpl._get(self.cachedNotes, (len(self.cachedNotes) - 1)).getLength()
        durations.append(x)
        return durations

    def generateNotes(self,startTime):
        if (self.cachedNotes is None):
            self.cachedNotes = self.generateCachedNotes()
        return self.cachedNotes

    def notesInSeconds(self,startTime):
        tickNotes = self.generateNotes(startTime)
        secondsPerTick = (60.0 / ((self.timeManipulator.getBPM() * self.timeManipulator.getPPQ())))
        result = list()
        _g = 0
        while (_g < len(tickNotes)):
            n = (tickNotes[_g] if _g >= 0 and _g < len(tickNotes) else None)
            _g = (_g + 1)
            x = self.instrumentContext.makeNote(n.getMidiNoteValue(),(n.getStartTime() * secondsPerTick),(n.getLength() * secondsPerTick))
            result.append(x)
        return result

    @staticmethod
    def create(timeManipulator,seq,rhythmGenerator,instrumentContext):
        return LineGenerator(timeManipulator,seq,rhythmGenerator,instrumentContext)

    @staticmethod
    def createFromPattern(timeManipulator,seq,pattern,instrumentContext):
        rhythmGenerator = RhythmLanguage.makeRhythmGenerator(pattern)
        if rhythmGenerator.parseFailed():
            raise haxe_Exception.thrown((("Invalid rhythm pattern: \"" + ("null" if pattern is None else pattern)) + "\""))
        return LineGenerator.create(timeManipulator,seq,rhythmGenerator,instrumentContext)

LineGenerator._hx_class = LineGenerator

class ValueType(Enum):
    __slots__ = ()
    _hx_class_name = "ValueType"
    _hx_constructs = ["TNull", "TInt", "TFloat", "TBool", "TObject", "TFunction", "TClass", "TEnum", "TUnknown"]

    @staticmethod
    def TClass(c):
        return ValueType("TClass", 6, (c,))

    @staticmethod
    def TEnum(e):
        return ValueType("TEnum", 7, (e,))
ValueType.TNull = ValueType("TNull", 0, ())
ValueType.TInt = ValueType("TInt", 1, ())
ValueType.TFloat = ValueType("TFloat", 2, ())
ValueType.TBool = ValueType("TBool", 3, ())
ValueType.TObject = ValueType("TObject", 4, ())
ValueType.TFunction = ValueType("TFunction", 5, ())
ValueType.TUnknown = ValueType("TUnknown", 8, ())
ValueType._hx_class = ValueType


class Type:
    _hx_class_name = "Type"
    __slots__ = ()
    _hx_statics = ["getClass", "typeof"]

    @staticmethod
    def getClass(o):
        if (o is None):
            return None
        o1 = o
        if ((o1 is not None) and ((HxOverrides.eq(o1,str) or python_lib_Inspect.isclass(o1)))):
            return None
        if isinstance(o,_hx_AnonObject):
            return None
        if hasattr(o,"_hx_class"):
            return o._hx_class
        if hasattr(o,"__class__"):
            return o.__class__
        else:
            return None

    @staticmethod
    def typeof(v):
        if (v is None):
            return ValueType.TNull
        elif isinstance(v,bool):
            return ValueType.TBool
        elif isinstance(v,int):
            return ValueType.TInt
        elif isinstance(v,float):
            return ValueType.TFloat
        elif isinstance(v,str):
            return ValueType.TClass(str)
        elif isinstance(v,list):
            return ValueType.TClass(list)
        elif (isinstance(v,_hx_AnonObject) or python_lib_Inspect.isclass(v)):
            return ValueType.TObject
        elif isinstance(v,Enum):
            return ValueType.TEnum(v.__class__)
        elif (isinstance(v,type) or hasattr(v,"_hx_class")):
            return ValueType.TClass(v.__class__)
        elif callable(v):
            return ValueType.TFunction
        else:
            return ValueType.TUnknown
Type._hx_class = Type


class haxe_IMap:
    _hx_class_name = "haxe.IMap"
    __slots__ = ()
haxe_IMap._hx_class = haxe_IMap


class haxe_Exception(Exception):
    _hx_class_name = "haxe.Exception"
    __slots__ = ("_hx___nativeStack", "_hx___skipStack", "_hx___nativeException", "_hx___previousException")
    _hx_fields = ["__nativeStack", "__skipStack", "__nativeException", "__previousException"]
    _hx_methods = ["unwrap", "get_native"]
    _hx_statics = ["caught", "thrown"]
    _hx_interfaces = []
    _hx_super = Exception


    def __init__(self,message,previous = None,native = None):
        self._hx___previousException = None
        self._hx___nativeException = None
        self._hx___nativeStack = None
        self._hx___skipStack = 0
        super().__init__(message)
        self._hx___previousException = previous
        if ((native is not None) and Std.isOfType(native,BaseException)):
            self._hx___nativeException = native
            self._hx___nativeStack = haxe_NativeStackTrace.exceptionStack()
        else:
            self._hx___nativeException = self
            infos = python_lib_Traceback.extract_stack()
            if (len(infos) != 0):
                infos.pop()
            infos.reverse()
            self._hx___nativeStack = infos

    def unwrap(self):
        return self._hx___nativeException

    def get_native(self):
        return self._hx___nativeException

    @staticmethod
    def caught(value):
        if Std.isOfType(value,haxe_Exception):
            return value
        elif Std.isOfType(value,BaseException):
            return haxe_Exception(str(value),None,value)
        else:
            return haxe_ValueException(value,None,value)

    @staticmethod
    def thrown(value):
        if Std.isOfType(value,haxe_Exception):
            return value.get_native()
        elif Std.isOfType(value,BaseException):
            return value
        else:
            e = haxe_ValueException(value)
            e._hx___skipStack = (e._hx___skipStack + 1)
            return e

haxe_Exception._hx_class = haxe_Exception


class haxe_NativeStackTrace:
    _hx_class_name = "haxe.NativeStackTrace"
    __slots__ = ()
    _hx_statics = ["saveStack", "exceptionStack"]

    @staticmethod
    def saveStack(exception):
        pass

    @staticmethod
    def exceptionStack():
        exc = python_lib_Sys.exc_info()
        if (exc[2] is not None):
            infos = python_lib_Traceback.extract_tb(exc[2])
            infos.reverse()
            return infos
        else:
            return []
haxe_NativeStackTrace._hx_class = haxe_NativeStackTrace


class haxe_ValueException(haxe_Exception):
    _hx_class_name = "haxe.ValueException"
    __slots__ = ("value",)
    _hx_fields = ["value"]
    _hx_methods = ["unwrap"]
    _hx_statics = []
    _hx_interfaces = []
    _hx_super = haxe_Exception


    def __init__(self,value,previous = None,native = None):
        self.value = None
        super().__init__(("null" if ((value is None)) else Std.string(value)),previous,native)
        self.value = value

    def unwrap(self):
        return self.value

haxe_ValueException._hx_class = haxe_ValueException


class haxe_ds_BalancedTree:
    _hx_class_name = "haxe.ds.BalancedTree"
    __slots__ = ("root",)
    _hx_fields = ["root"]
    _hx_methods = ["set", "get", "setLoop", "balance", "compare"]
    _hx_interfaces = [haxe_IMap]

    def __init__(self):
        self.root = None

    def set(self,key,value):
        self.root = self.setLoop(key,value,self.root)

    def get(self,key):
        node = self.root
        while (node is not None):
            c = self.compare(key,node.key)
            if (c == 0):
                return node.value
            if (c < 0):
                node = node.left
            else:
                node = node.right
        return None

    def setLoop(self,k,v,node):
        if (node is None):
            return haxe_ds_TreeNode(None,k,v,None)
        c = self.compare(k,node.key)
        if (c == 0):
            return haxe_ds_TreeNode(node.left,k,v,node.right,(0 if ((node is None)) else node._height))
        elif (c < 0):
            nl = self.setLoop(k,v,node.left)
            return self.balance(nl,node.key,node.value,node.right)
        else:
            nr = self.setLoop(k,v,node.right)
            return self.balance(node.left,node.key,node.value,nr)

    def balance(self,l,k,v,r):
        hl = (0 if ((l is None)) else l._height)
        hr = (0 if ((r is None)) else r._height)
        if (hl > ((hr + 2))):
            _this = l.left
            _this1 = l.right
            if (((0 if ((_this is None)) else _this._height)) >= ((0 if ((_this1 is None)) else _this1._height))):
                return haxe_ds_TreeNode(l.left,l.key,l.value,haxe_ds_TreeNode(l.right,k,v,r))
            else:
                return haxe_ds_TreeNode(haxe_ds_TreeNode(l.left,l.key,l.value,l.right.left),l.right.key,l.right.value,haxe_ds_TreeNode(l.right.right,k,v,r))
        elif (hr > ((hl + 2))):
            _this = r.right
            _this1 = r.left
            if (((0 if ((_this is None)) else _this._height)) > ((0 if ((_this1 is None)) else _this1._height))):
                return haxe_ds_TreeNode(haxe_ds_TreeNode(l,k,v,r.left),r.key,r.value,r.right)
            else:
                return haxe_ds_TreeNode(haxe_ds_TreeNode(l,k,v,r.left.left),r.left.key,r.left.value,haxe_ds_TreeNode(r.left.right,r.key,r.value,r.right))
        else:
            return haxe_ds_TreeNode(l,k,v,r,(((hl if ((hl > hr)) else hr)) + 1))

    def compare(self,k1,k2):
        return Reflect.compare(k1,k2)

haxe_ds_BalancedTree._hx_class = haxe_ds_BalancedTree


class haxe_ds_TreeNode:
    _hx_class_name = "haxe.ds.TreeNode"
    __slots__ = ("left", "right", "key", "value", "_height")
    _hx_fields = ["left", "right", "key", "value", "_height"]

    def __init__(self,l,k,v,r,h = None):
        if (h is None):
            h = -1
        self._height = None
        self.left = l
        self.key = k
        self.value = v
        self.right = r
        if (h == -1):
            tmp = None
            _this = self.left
            _this1 = self.right
            if (((0 if ((_this is None)) else _this._height)) > ((0 if ((_this1 is None)) else _this1._height))):
                _this = self.left
                tmp = (0 if ((_this is None)) else _this._height)
            else:
                _this = self.right
                tmp = (0 if ((_this is None)) else _this._height)
            self._height = (tmp + 1)
        else:
            self._height = h

haxe_ds_TreeNode._hx_class = haxe_ds_TreeNode


class haxe_ds_EnumValueMap(haxe_ds_BalancedTree):
    _hx_class_name = "haxe.ds.EnumValueMap"
    __slots__ = ()
    _hx_fields = []
    _hx_methods = ["compare", "compareArgs", "compareArg"]
    _hx_statics = []
    _hx_interfaces = [haxe_IMap]
    _hx_super = haxe_ds_BalancedTree


    def __init__(self):
        super().__init__()

    def compare(self,k1,k2):
        d = (k1.index - k2.index)
        if (d != 0):
            return d
        p1 = list(k1.params)
        p2 = list(k2.params)
        if ((len(p1) == 0) and ((len(p2) == 0))):
            return 0
        return self.compareArgs(p1,p2)

    def compareArgs(self,a1,a2):
        ld = (len(a1) - len(a2))
        if (ld != 0):
            return ld
        _g = 0
        _g1 = len(a1)
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            d = self.compareArg((a1[i] if i >= 0 and i < len(a1) else None),(a2[i] if i >= 0 and i < len(a2) else None))
            if (d != 0):
                return d
        return 0

    def compareArg(self,v1,v2):
        if (Reflect.isEnumValue(v1) and Reflect.isEnumValue(v2)):
            return self.compare(v1,v2)
        elif (Std.isOfType(v1,list) and Std.isOfType(v2,list)):
            return self.compareArgs(v1,v2)
        else:
            return Reflect.compare(v1,v2)

haxe_ds_EnumValueMap._hx_class = haxe_ds_EnumValueMap


class haxe_ds_StringMap:
    _hx_class_name = "haxe.ds.StringMap"
    __slots__ = ("h",)
    _hx_fields = ["h"]
    _hx_methods = ["keys"]
    _hx_interfaces = [haxe_IMap]

    def __init__(self):
        self.h = dict()

    def keys(self):
        return python_HaxeIterator(iter(self.h.keys()))

haxe_ds_StringMap._hx_class = haxe_ds_StringMap


class haxe_format_JsonPrinter:
    _hx_class_name = "haxe.format.JsonPrinter"
    __slots__ = ("buf", "replacer", "indent", "pretty", "nind")
    _hx_fields = ["buf", "replacer", "indent", "pretty", "nind"]
    _hx_methods = ["write", "classString", "fieldsString", "quote"]
    _hx_statics = ["print"]

    def __init__(self,replacer,space):
        self.replacer = replacer
        self.indent = space
        self.pretty = (space is not None)
        self.nind = 0
        self.buf = StringBuf()

    def write(self,k,v):
        if (self.replacer is not None):
            v = self.replacer(k,v)
        _g = Type.typeof(v)
        tmp = _g.index
        if (tmp == 0):
            self.buf.b.write("null")
        elif (tmp == 1):
            _this = self.buf
            s = Std.string(v)
            _this.b.write(s)
        elif (tmp == 2):
            f = v
            v1 = (Std.string(v) if ((((f != Math.POSITIVE_INFINITY) and ((f != Math.NEGATIVE_INFINITY))) and (not python_lib_Math.isnan(f)))) else "null")
            _this = self.buf
            s = Std.string(v1)
            _this.b.write(s)
        elif (tmp == 3):
            _this = self.buf
            s = Std.string(v)
            _this.b.write(s)
        elif (tmp == 4):
            self.fieldsString(v,python_Boot.fields(v))
        elif (tmp == 5):
            self.buf.b.write("\"<fun>\"")
        elif (tmp == 6):
            c = _g.params[0]
            if (c == str):
                self.quote(v)
            elif (c == list):
                v1 = v
                _this = self.buf
                s = "".join(map(chr,[91]))
                _this.b.write(s)
                _hx_len = len(v1)
                last = (_hx_len - 1)
                _g1 = 0
                _g2 = _hx_len
                while (_g1 < _g2):
                    i = _g1
                    _g1 = (_g1 + 1)
                    if (i > 0):
                        _this = self.buf
                        s = "".join(map(chr,[44]))
                        _this.b.write(s)
                    else:
                        _hx_local_0 = self
                        _hx_local_1 = _hx_local_0.nind
                        _hx_local_0.nind = (_hx_local_1 + 1)
                        _hx_local_1
                    if self.pretty:
                        _this1 = self.buf
                        s1 = "".join(map(chr,[10]))
                        _this1.b.write(s1)
                    if self.pretty:
                        v2 = StringTools.lpad("",self.indent,(self.nind * len(self.indent)))
                        _this2 = self.buf
                        s2 = Std.string(v2)
                        _this2.b.write(s2)
                    self.write(i,(v1[i] if i >= 0 and i < len(v1) else None))
                    if (i == last):
                        _hx_local_2 = self
                        _hx_local_3 = _hx_local_2.nind
                        _hx_local_2.nind = (_hx_local_3 - 1)
                        _hx_local_3
                        if self.pretty:
                            _this3 = self.buf
                            s3 = "".join(map(chr,[10]))
                            _this3.b.write(s3)
                        if self.pretty:
                            v3 = StringTools.lpad("",self.indent,(self.nind * len(self.indent)))
                            _this4 = self.buf
                            s4 = Std.string(v3)
                            _this4.b.write(s4)
                _this = self.buf
                s = "".join(map(chr,[93]))
                _this.b.write(s)
            elif (c == haxe_ds_StringMap):
                v1 = v
                o = _hx_AnonObject({})
                k = v1.keys()
                while k.hasNext():
                    k1 = k.next()
                    value = v1.h.get(k1,None)
                    setattr(o,(("_hx_" + k1) if ((k1 in python_Boot.keywords)) else (("_hx_" + k1) if (((((len(k1) > 2) and ((ord(k1[0]) == 95))) and ((ord(k1[1]) == 95))) and ((ord(k1[(len(k1) - 1)]) != 95)))) else k1)),value)
                v1 = o
                self.fieldsString(v1,python_Boot.fields(v1))
            elif (c == Date):
                v1 = v
                self.quote(v1.toString())
            else:
                self.classString(v)
        elif (tmp == 7):
            _g1 = _g.params[0]
            i = v.index
            v = Std.string(i)
            _this = self.buf
            s = Std.string(v)
            _this.b.write(s)
        elif (tmp == 8):
            self.buf.b.write("\"???\"")
        else:
            pass

    def classString(self,v):
        self.fieldsString(v,python_Boot.getInstanceFields(Type.getClass(v)))

    def fieldsString(self,v,fields):
        _this = self.buf
        s = "".join(map(chr,[123]))
        _this.b.write(s)
        _hx_len = len(fields)
        empty = True
        _g = 0
        _g1 = _hx_len
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            f = (fields[i] if i >= 0 and i < len(fields) else None)
            value = Reflect.field(v,f)
            if Reflect.isFunction(value):
                continue
            if empty:
                _hx_local_0 = self
                _hx_local_1 = _hx_local_0.nind
                _hx_local_0.nind = (_hx_local_1 + 1)
                _hx_local_1
                empty = False
            else:
                _this = self.buf
                s = "".join(map(chr,[44]))
                _this.b.write(s)
            if self.pretty:
                _this1 = self.buf
                s1 = "".join(map(chr,[10]))
                _this1.b.write(s1)
            if self.pretty:
                v1 = StringTools.lpad("",self.indent,(self.nind * len(self.indent)))
                _this2 = self.buf
                s2 = Std.string(v1)
                _this2.b.write(s2)
            self.quote(f)
            _this3 = self.buf
            s3 = "".join(map(chr,[58]))
            _this3.b.write(s3)
            if self.pretty:
                _this4 = self.buf
                s4 = "".join(map(chr,[32]))
                _this4.b.write(s4)
            self.write(f,value)
        if (not empty):
            _hx_local_2 = self
            _hx_local_3 = _hx_local_2.nind
            _hx_local_2.nind = (_hx_local_3 - 1)
            _hx_local_3
            if self.pretty:
                _this = self.buf
                s = "".join(map(chr,[10]))
                _this.b.write(s)
            if self.pretty:
                v = StringTools.lpad("",self.indent,(self.nind * len(self.indent)))
                _this = self.buf
                s = Std.string(v)
                _this.b.write(s)
        _this = self.buf
        s = "".join(map(chr,[125]))
        _this.b.write(s)

    def quote(self,s):
        _this = self.buf
        s1 = "".join(map(chr,[34]))
        _this.b.write(s1)
        i = 0
        length = len(s)
        while (i < length):
            index = i
            i = (i + 1)
            c = ord(s[index])
            c1 = c
            if (c1 == 8):
                self.buf.b.write("\\b")
            elif (c1 == 9):
                self.buf.b.write("\\t")
            elif (c1 == 10):
                self.buf.b.write("\\n")
            elif (c1 == 12):
                self.buf.b.write("\\f")
            elif (c1 == 13):
                self.buf.b.write("\\r")
            elif (c1 == 34):
                self.buf.b.write("\\\"")
            elif (c1 == 92):
                self.buf.b.write("\\\\")
            else:
                _this = self.buf
                s1 = "".join(map(chr,[c]))
                _this.b.write(s1)
        _this = self.buf
        s = "".join(map(chr,[34]))
        _this.b.write(s)

    @staticmethod
    def print(o,replacer = None,space = None):
        printer = haxe_format_JsonPrinter(replacer,space)
        printer.write("",o)
        return printer.buf.b.getvalue()

haxe_format_JsonPrinter._hx_class = haxe_format_JsonPrinter


class haxe_iterators_ArrayIterator:
    _hx_class_name = "haxe.iterators.ArrayIterator"
    __slots__ = ("array", "current")
    _hx_fields = ["array", "current"]
    _hx_methods = ["hasNext", "next"]

    def __init__(self,array):
        self.current = 0
        self.array = array

    def hasNext(self):
        return (self.current < len(self.array))

    def next(self):
        def _hx_local_3():
            def _hx_local_2():
                _hx_local_0 = self
                _hx_local_1 = _hx_local_0.current
                _hx_local_0.current = (_hx_local_1 + 1)
                return _hx_local_1
            return python_internal_ArrayImpl._get(self.array, _hx_local_2())
        return _hx_local_3()

haxe_iterators_ArrayIterator._hx_class = haxe_iterators_ArrayIterator


class haxe_iterators_ArrayKeyValueIterator:
    _hx_class_name = "haxe.iterators.ArrayKeyValueIterator"
    __slots__ = ("current", "array")
    _hx_fields = ["current", "array"]
    _hx_methods = ["hasNext", "next"]

    def __init__(self,array):
        self.current = 0
        self.array = array

    def hasNext(self):
        return (self.current < len(self.array))

    def next(self):
        def _hx_local_3():
            def _hx_local_2():
                _hx_local_0 = self
                _hx_local_1 = _hx_local_0.current
                _hx_local_0.current = (_hx_local_1 + 1)
                return _hx_local_1
            return _hx_AnonObject({'value': python_internal_ArrayImpl._get(self.array, self.current), 'key': _hx_local_2()})
        return _hx_local_3()

haxe_iterators_ArrayKeyValueIterator._hx_class = haxe_iterators_ArrayKeyValueIterator


class python_Boot:
    _hx_class_name = "python.Boot"
    __slots__ = ()
    _hx_statics = ["keywords", "toString1", "fields", "simpleField", "hasField", "field", "getInstanceFields", "getSuperClass", "getClassFields", "prefixLength", "unhandleKeywords"]

    @staticmethod
    def toString1(o,s):
        if (o is None):
            return "null"
        if isinstance(o,str):
            return o
        if (s is None):
            s = ""
        if (len(s) >= 5):
            return "<...>"
        if isinstance(o,bool):
            if o:
                return "true"
            else:
                return "false"
        if (isinstance(o,int) and (not isinstance(o,bool))):
            return str(o)
        if isinstance(o,float):
            try:
                if (o == int(o)):
                    return str(Math.floor((o + 0.5)))
                else:
                    return str(o)
            except BaseException as _g:
                None
                return str(o)
        if isinstance(o,list):
            o1 = o
            l = len(o1)
            st = "["
            s = (("null" if s is None else s) + "\t")
            _g = 0
            _g1 = l
            while (_g < _g1):
                i = _g
                _g = (_g + 1)
                prefix = ""
                if (i > 0):
                    prefix = ","
                st = (("null" if st is None else st) + HxOverrides.stringOrNull(((("null" if prefix is None else prefix) + HxOverrides.stringOrNull(python_Boot.toString1((o1[i] if i >= 0 and i < len(o1) else None),s))))))
            st = (("null" if st is None else st) + "]")
            return st
        try:
            if hasattr(o,"toString"):
                return o.toString()
        except BaseException as _g:
            None
        if hasattr(o,"__class__"):
            if isinstance(o,_hx_AnonObject):
                toStr = None
                try:
                    fields = python_Boot.fields(o)
                    _g = []
                    _g1 = 0
                    while (_g1 < len(fields)):
                        f = (fields[_g1] if _g1 >= 0 and _g1 < len(fields) else None)
                        _g1 = (_g1 + 1)
                        x = ((("" + ("null" if f is None else f)) + " : ") + HxOverrides.stringOrNull(python_Boot.toString1(python_Boot.simpleField(o,f),(("null" if s is None else s) + "\t"))))
                        _g.append(x)
                    fieldsStr = _g
                    toStr = (("{ " + HxOverrides.stringOrNull(", ".join([x1 for x1 in fieldsStr]))) + " }")
                except BaseException as _g:
                    None
                    return "{ ... }"
                if (toStr is None):
                    return "{ ... }"
                else:
                    return toStr
            if isinstance(o,Enum):
                o1 = o
                l = len(o1.params)
                hasParams = (l > 0)
                if hasParams:
                    paramsStr = ""
                    _g = 0
                    _g1 = l
                    while (_g < _g1):
                        i = _g
                        _g = (_g + 1)
                        prefix = ""
                        if (i > 0):
                            prefix = ","
                        paramsStr = (("null" if paramsStr is None else paramsStr) + HxOverrides.stringOrNull(((("null" if prefix is None else prefix) + HxOverrides.stringOrNull(python_Boot.toString1(o1.params[i],s))))))
                    return (((HxOverrides.stringOrNull(o1.tag) + "(") + ("null" if paramsStr is None else paramsStr)) + ")")
                else:
                    return o1.tag
            if hasattr(o,"_hx_class_name"):
                if (o.__class__.__name__ != "type"):
                    fields = python_Boot.getInstanceFields(o)
                    _g = []
                    _g1 = 0
                    while (_g1 < len(fields)):
                        f = (fields[_g1] if _g1 >= 0 and _g1 < len(fields) else None)
                        _g1 = (_g1 + 1)
                        x = ((("" + ("null" if f is None else f)) + " : ") + HxOverrides.stringOrNull(python_Boot.toString1(python_Boot.simpleField(o,f),(("null" if s is None else s) + "\t"))))
                        _g.append(x)
                    fieldsStr = _g
                    toStr = (((HxOverrides.stringOrNull(o._hx_class_name) + "( ") + HxOverrides.stringOrNull(", ".join([x1 for x1 in fieldsStr]))) + " )")
                    return toStr
                else:
                    fields = python_Boot.getClassFields(o)
                    _g = []
                    _g1 = 0
                    while (_g1 < len(fields)):
                        f = (fields[_g1] if _g1 >= 0 and _g1 < len(fields) else None)
                        _g1 = (_g1 + 1)
                        x = ((("" + ("null" if f is None else f)) + " : ") + HxOverrides.stringOrNull(python_Boot.toString1(python_Boot.simpleField(o,f),(("null" if s is None else s) + "\t"))))
                        _g.append(x)
                    fieldsStr = _g
                    toStr = (((("#" + HxOverrides.stringOrNull(o._hx_class_name)) + "( ") + HxOverrides.stringOrNull(", ".join([x1 for x1 in fieldsStr]))) + " )")
                    return toStr
            if ((type(o) == type) and (o == str)):
                return "#String"
            if ((type(o) == type) and (o == list)):
                return "#Array"
            if callable(o):
                return "function"
            try:
                if hasattr(o,"__repr__"):
                    return o.__repr__()
            except BaseException as _g:
                None
            if hasattr(o,"__str__"):
                return o.__str__([])
            if hasattr(o,"__name__"):
                return o.__name__
            return "???"
        else:
            return str(o)

    @staticmethod
    def fields(o):
        a = []
        if (o is not None):
            if hasattr(o,"_hx_fields"):
                fields = o._hx_fields
                if (fields is not None):
                    return list(fields)
            if isinstance(o,_hx_AnonObject):
                d = o.__dict__
                keys = d.keys()
                handler = python_Boot.unhandleKeywords
                for k in keys:
                    if (k != '_hx_disable_getattr'):
                        a.append(handler(k))
            elif hasattr(o,"__dict__"):
                d = o.__dict__
                keys1 = d.keys()
                for k in keys1:
                    a.append(k)
        return a

    @staticmethod
    def simpleField(o,field):
        if (field is None):
            return None
        field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
        if hasattr(o,field1):
            return getattr(o,field1)
        else:
            return None

    @staticmethod
    def hasField(o,field):
        if isinstance(o,_hx_AnonObject):
            return o._hx_hasattr(field)
        return hasattr(o,(("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field)))

    @staticmethod
    def field(o,field):
        if (field is None):
            return None
        if isinstance(o,str):
            field1 = field
            _hx_local_0 = len(field1)
            if (_hx_local_0 == 10):
                if (field1 == "charCodeAt"):
                    return python_internal_MethodClosure(o,HxString.charCodeAt)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_0 == 11):
                if (field1 == "lastIndexOf"):
                    return python_internal_MethodClosure(o,HxString.lastIndexOf)
                elif (field1 == "toLowerCase"):
                    return python_internal_MethodClosure(o,HxString.toLowerCase)
                elif (field1 == "toUpperCase"):
                    return python_internal_MethodClosure(o,HxString.toUpperCase)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_0 == 9):
                if (field1 == "substring"):
                    return python_internal_MethodClosure(o,HxString.substring)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_0 == 5):
                if (field1 == "split"):
                    return python_internal_MethodClosure(o,HxString.split)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_0 == 7):
                if (field1 == "indexOf"):
                    return python_internal_MethodClosure(o,HxString.indexOf)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_0 == 8):
                if (field1 == "toString"):
                    return python_internal_MethodClosure(o,HxString.toString)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_0 == 6):
                if (field1 == "charAt"):
                    return python_internal_MethodClosure(o,HxString.charAt)
                elif (field1 == "length"):
                    return len(o)
                elif (field1 == "substr"):
                    return python_internal_MethodClosure(o,HxString.substr)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            else:
                field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                return (getattr(o,field1) if (hasattr(o,field1)) else None)
        elif isinstance(o,list):
            field1 = field
            _hx_local_1 = len(field1)
            if (_hx_local_1 == 11):
                if (field1 == "lastIndexOf"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.lastIndexOf)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 4):
                if (field1 == "copy"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.copy)
                elif (field1 == "join"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.join)
                elif (field1 == "push"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.push)
                elif (field1 == "sort"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.sort)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 5):
                if (field1 == "shift"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.shift)
                elif (field1 == "slice"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.slice)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 7):
                if (field1 == "indexOf"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.indexOf)
                elif (field1 == "reverse"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.reverse)
                elif (field1 == "unshift"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.unshift)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 3):
                if (field1 == "map"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.map)
                elif (field1 == "pop"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.pop)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 8):
                if (field1 == "contains"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.contains)
                elif (field1 == "iterator"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.iterator)
                elif (field1 == "toString"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.toString)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 16):
                if (field1 == "keyValueIterator"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.keyValueIterator)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            elif (_hx_local_1 == 6):
                if (field1 == "concat"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.concat)
                elif (field1 == "filter"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.filter)
                elif (field1 == "insert"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.insert)
                elif (field1 == "length"):
                    return len(o)
                elif (field1 == "remove"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.remove)
                elif (field1 == "splice"):
                    return python_internal_MethodClosure(o,python_internal_ArrayImpl.splice)
                else:
                    field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                    return (getattr(o,field1) if (hasattr(o,field1)) else None)
            else:
                field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
                return (getattr(o,field1) if (hasattr(o,field1)) else None)
        else:
            field1 = (("_hx_" + field) if ((field in python_Boot.keywords)) else (("_hx_" + field) if (((((len(field) > 2) and ((ord(field[0]) == 95))) and ((ord(field[1]) == 95))) and ((ord(field[(len(field) - 1)]) != 95)))) else field))
            return (getattr(o,field1) if (hasattr(o,field1)) else None)

    @staticmethod
    def getInstanceFields(c):
        f = (list(c._hx_fields) if (hasattr(c,"_hx_fields")) else [])
        if hasattr(c,"_hx_methods"):
            f = (f + c._hx_methods)
        sc = python_Boot.getSuperClass(c)
        if (sc is None):
            return f
        else:
            scArr = python_Boot.getInstanceFields(sc)
            scMap = set(scArr)
            _g = 0
            while (_g < len(f)):
                f1 = (f[_g] if _g >= 0 and _g < len(f) else None)
                _g = (_g + 1)
                if (not (f1 in scMap)):
                    scArr.append(f1)
            return scArr

    @staticmethod
    def getSuperClass(c):
        if (c is None):
            return None
        try:
            if hasattr(c,"_hx_super"):
                return c._hx_super
            return None
        except BaseException as _g:
            None
        return None

    @staticmethod
    def getClassFields(c):
        if hasattr(c,"_hx_statics"):
            x = c._hx_statics
            return list(x)
        else:
            return []

    @staticmethod
    def unhandleKeywords(name):
        if (HxString.substr(name,0,python_Boot.prefixLength) == "_hx_"):
            real = HxString.substr(name,python_Boot.prefixLength,None)
            if (real in python_Boot.keywords):
                return real
        return name
python_Boot._hx_class = python_Boot


class python_HaxeIterator:
    _hx_class_name = "python.HaxeIterator"
    __slots__ = ("it", "x", "has", "checked")
    _hx_fields = ["it", "x", "has", "checked"]
    _hx_methods = ["next", "hasNext"]

    def __init__(self,it):
        self.checked = False
        self.has = False
        self.x = None
        self.it = it

    def next(self):
        if (not self.checked):
            self.hasNext()
        self.checked = False
        return self.x

    def hasNext(self):
        if (not self.checked):
            try:
                self.x = self.it.__next__()
                self.has = True
            except BaseException as _g:
                None
                if Std.isOfType(haxe_Exception.caught(_g).unwrap(),StopIteration):
                    self.has = False
                    self.x = None
                else:
                    raise _g
            self.checked = True
        return self.has

python_HaxeIterator._hx_class = python_HaxeIterator


class python__KwArgs_KwArgs_Impl_:
    _hx_class_name = "python._KwArgs.KwArgs_Impl_"
    __slots__ = ()
    _hx_statics = ["fromT"]

    @staticmethod
    def fromT(d):
        return python_Lib.anonAsDict(d)
python__KwArgs_KwArgs_Impl_._hx_class = python__KwArgs_KwArgs_Impl_


class python_Lib:
    _hx_class_name = "python.Lib"
    __slots__ = ()
    _hx_statics = ["dictToAnon", "anonToDict", "anonAsDict"]

    @staticmethod
    def dictToAnon(v):
        return _hx_AnonObject(v.copy())

    @staticmethod
    def anonToDict(o):
        if isinstance(o,_hx_AnonObject):
            return o.__dict__.copy()
        else:
            return None

    @staticmethod
    def anonAsDict(o):
        if isinstance(o,_hx_AnonObject):
            return o.__dict__
        else:
            return None
python_Lib._hx_class = python_Lib


class python_internal_ArrayImpl:
    _hx_class_name = "python.internal.ArrayImpl"
    __slots__ = ()
    _hx_statics = ["concat", "copy", "iterator", "keyValueIterator", "indexOf", "lastIndexOf", "join", "toString", "pop", "push", "unshift", "remove", "contains", "shift", "slice", "sort", "splice", "map", "filter", "insert", "reverse", "_get", "_set"]

    @staticmethod
    def concat(a1,a2):
        return (a1 + a2)

    @staticmethod
    def copy(x):
        return list(x)

    @staticmethod
    def iterator(x):
        return python_HaxeIterator(x.__iter__())

    @staticmethod
    def keyValueIterator(x):
        return haxe_iterators_ArrayKeyValueIterator(x)

    @staticmethod
    def indexOf(a,x,fromIndex = None):
        _hx_len = len(a)
        l = (0 if ((fromIndex is None)) else ((_hx_len + fromIndex) if ((fromIndex < 0)) else fromIndex))
        if (l < 0):
            l = 0
        _g = l
        _g1 = _hx_len
        while (_g < _g1):
            i = _g
            _g = (_g + 1)
            if HxOverrides.eq(a[i],x):
                return i
        return -1

    @staticmethod
    def lastIndexOf(a,x,fromIndex = None):
        _hx_len = len(a)
        l = (_hx_len if ((fromIndex is None)) else (((_hx_len + fromIndex) + 1) if ((fromIndex < 0)) else (fromIndex + 1)))
        if (l > _hx_len):
            l = _hx_len
        while True:
            l = (l - 1)
            tmp = l
            if (not ((tmp > -1))):
                break
            if HxOverrides.eq(a[l],x):
                return l
        return -1

    @staticmethod
    def join(x,sep):
        return sep.join([python_Boot.toString1(x1,'') for x1 in x])

    @staticmethod
    def toString(x):
        return (("[" + HxOverrides.stringOrNull(",".join([python_Boot.toString1(x1,'') for x1 in x]))) + "]")

    @staticmethod
    def pop(x):
        if (len(x) == 0):
            return None
        else:
            return x.pop()

    @staticmethod
    def push(x,e):
        x.append(e)
        return len(x)

    @staticmethod
    def unshift(x,e):
        x.insert(0, e)

    @staticmethod
    def remove(x,e):
        try:
            x.remove(e)
            return True
        except BaseException as _g:
            None
            return False

    @staticmethod
    def contains(x,e):
        return (e in x)

    @staticmethod
    def shift(x):
        if (len(x) == 0):
            return None
        return x.pop(0)

    @staticmethod
    def slice(x,pos,end = None):
        return x[pos:end]

    @staticmethod
    def sort(x,f):
        x.sort(key= python_lib_Functools.cmp_to_key(f))

    @staticmethod
    def splice(x,pos,_hx_len):
        if (pos < 0):
            pos = (len(x) + pos)
        if (pos < 0):
            pos = 0
        res = x[pos:(pos + _hx_len)]
        del x[pos:(pos + _hx_len)]
        return res

    @staticmethod
    def map(x,f):
        return list(map(f,x))

    @staticmethod
    def filter(x,f):
        return list(filter(f,x))

    @staticmethod
    def insert(a,pos,x):
        a.insert(pos, x)

    @staticmethod
    def reverse(a):
        a.reverse()

    @staticmethod
    def _get(x,idx):
        if ((idx > -1) and ((idx < len(x)))):
            return x[idx]
        else:
            return None

    @staticmethod
    def _set(x,idx,v):
        l = len(x)
        while (l < idx):
            x.append(None)
            l = (l + 1)
        if (l == idx):
            x.append(v)
        else:
            x[idx] = v
        return v
python_internal_ArrayImpl._hx_class = python_internal_ArrayImpl


class HxOverrides:
    _hx_class_name = "HxOverrides"
    __slots__ = ()
    _hx_statics = ["eq", "stringOrNull", "modf", "mod", "mapKwArgs"]

    @staticmethod
    def eq(a,b):
        if (isinstance(a,list) or isinstance(b,list)):
            return a is b
        return (a == b)

    @staticmethod
    def stringOrNull(s):
        if (s is None):
            return "null"
        else:
            return s

    @staticmethod
    def modf(a,b):
        if (b == 0.0):
            return float('nan')
        elif (a < 0):
            if (b < 0):
                return -(-a % (-b))
            else:
                return -(-a % b)
        elif (b < 0):
            return a % (-b)
        else:
            return a % b

    @staticmethod
    def mod(a,b):
        if (a < 0):
            if (b < 0):
                return -(-a % (-b))
            else:
                return -(-a % b)
        elif (b < 0):
            return a % (-b)
        else:
            return a % b

    @staticmethod
    def mapKwArgs(a,v):
        a1 = _hx_AnonObject(python_Lib.anonToDict(a))
        k = python_HaxeIterator(iter(v.keys()))
        while k.hasNext():
            k1 = k.next()
            val = v.get(k1)
            if a1._hx_hasattr(k1):
                x = getattr(a1,k1)
                setattr(a1,val,x)
                delattr(a1,k1)
        return a1
HxOverrides._hx_class = HxOverrides


class python_internal_MethodClosure:
    _hx_class_name = "python.internal.MethodClosure"
    __slots__ = ("obj", "func")
    _hx_fields = ["obj", "func"]
    _hx_methods = ["__call__"]

    def __init__(self,obj,func):
        self.obj = obj
        self.func = func

    def __call__(self,*args):
        return self.func(self.obj,*args)

python_internal_MethodClosure._hx_class = python_internal_MethodClosure


class HxString:
    _hx_class_name = "HxString"
    __slots__ = ()
    _hx_statics = ["split", "charCodeAt", "charAt", "lastIndexOf", "toUpperCase", "toLowerCase", "indexOf", "indexOfImpl", "toString", "substring", "substr"]

    @staticmethod
    def split(s,d):
        if (d == ""):
            return list(s)
        else:
            return s.split(d)

    @staticmethod
    def charCodeAt(s,index):
        if ((((s is None) or ((len(s) == 0))) or ((index < 0))) or ((index >= len(s)))):
            return None
        else:
            return ord(s[index])

    @staticmethod
    def charAt(s,index):
        if ((index < 0) or ((index >= len(s)))):
            return ""
        else:
            return s[index]

    @staticmethod
    def lastIndexOf(s,_hx_str,startIndex = None):
        if (startIndex is None):
            return s.rfind(_hx_str, 0, len(s))
        elif (_hx_str == ""):
            length = len(s)
            if (startIndex < 0):
                startIndex = (length + startIndex)
                if (startIndex < 0):
                    startIndex = 0
            if (startIndex > length):
                return length
            else:
                return startIndex
        else:
            i = s.rfind(_hx_str, 0, (startIndex + 1))
            startLeft = (max(0,((startIndex + 1) - len(_hx_str))) if ((i == -1)) else (i + 1))
            check = s.find(_hx_str, startLeft, len(s))
            if ((check > i) and ((check <= startIndex))):
                return check
            else:
                return i

    @staticmethod
    def toUpperCase(s):
        return s.upper()

    @staticmethod
    def toLowerCase(s):
        return s.lower()

    @staticmethod
    def indexOf(s,_hx_str,startIndex = None):
        if (startIndex is None):
            return s.find(_hx_str)
        else:
            return HxString.indexOfImpl(s,_hx_str,startIndex)

    @staticmethod
    def indexOfImpl(s,_hx_str,startIndex):
        if (_hx_str == ""):
            length = len(s)
            if (startIndex < 0):
                startIndex = (length + startIndex)
                if (startIndex < 0):
                    startIndex = 0
            if (startIndex > length):
                return length
            else:
                return startIndex
        return s.find(_hx_str, startIndex)

    @staticmethod
    def toString(s):
        return s

    @staticmethod
    def substring(s,startIndex,endIndex = None):
        if (startIndex < 0):
            startIndex = 0
        if (endIndex is None):
            return s[startIndex:]
        else:
            if (endIndex < 0):
                endIndex = 0
            if (endIndex < startIndex):
                return s[endIndex:startIndex]
            else:
                return s[startIndex:endIndex]

    @staticmethod
    def substr(s,startIndex,_hx_len = None):
        if (_hx_len is None):
            return s[startIndex:]
        else:
            if (_hx_len == 0):
                return ""
            if (startIndex < 0):
                startIndex = (len(s) + startIndex)
                if (startIndex < 0):
                    startIndex = 0
            return s[startIndex:(startIndex + _hx_len)]
HxString._hx_class = HxString

Math.NEGATIVE_INFINITY = float("-inf")
Math.POSITIVE_INFINITY = float("inf")
Math.NaN = float("nan")
Math.PI = python_lib_Math.pi

Mode.major_intervals = [2, 2, 1, 2, 2, 2, 1]
Mode.minor_intervals = [2, 1, 2, 2, 1, 2, 2]
Mode.harmonic_minor_intervals = [2, 1, 2, 2, 1, 3, 1]
Mode.melodic_minor_intervals = [2, 1, 2, 2, 2, 2, 1]
_Mode_Mode_Fields_.MAJOR = Mode.getMajorMode()
_Mode_Mode_Fields_.MINOR = Mode.getMinorMode()
_Mode_Mode_Fields_.HARMONIC_MINOR = Mode.getHarmonicMinorMode()
_Mode_Mode_Fields_.MELODIC_MINOR = Mode.getMelodicMinorMode()
python_Boot.keywords = set(["and", "del", "from", "not", "with", "as", "elif", "global", "or", "yield", "assert", "else", "if", "pass", "None", "break", "except", "import", "raise", "True", "class", "exec", "in", "return", "False", "continue", "finally", "is", "try", "def", "for", "lambda", "while"])
python_Boot.prefixLength = len("_hx_")
# We need to leave a couple of blank lines at the top of this file

def makeNote(num, time, length, color=0, velocity=0.5):
    """
    make a new Note object

    num: pitch
    time: time in ticks
    length: duration in ticks
    color: int in [0: 16)
    """
    note = flp.Note()
    note.number = int(num)
    note.time = int(time)
    note.length = int(length)
    note.color = int(color)
    note.velocity = velocity
    return note
      
def createDialog():
    form = flp.ScriptDialog("GoldenPond",
    'GoldenPond is language for defining chord progressions.\r\nThis is the FL Studio version which also lets you create rhythmic patterns for arpeggios and melodies.\r\nSee http://gilbertlisterresearch.com/ for more information and documentation.')
    
    form.AddInputKnobInt('Root',65,32,96)
    form.AddInputCombo('Mode',["major","minor","harmonic minor","melodic minor"],0)
    form.AddInputText('ChordSeq', "1,6,4,5")
    
    form.AddInputCheckbox('Chords',False)
    form.AddInputCheckbox('Bass',False)
    form.AddInputCheckbox('Arp ↑',False)
    form.AddInputCheckbox('Arp ↓',False)
    form.AddInputCheckbox('Top',False)
    form.AddInputCheckbox('Random',False)
    
    form.AddInputKnobInt('Rhythm k',4,1,24)
    form.AddInputKnobInt('Rhythm n',8,1,24)
    form.AddInputKnobInt('Density',4,1,8)
    form.AddInputKnob('Note Proportion',0.8,0.1,1.5)
    form.AddInputKnobInt('Chord Duration',4,1,16)
    form.AddInputKnobInt("Stutter",0,0,16)
    form.AddInputCheckbox("Silent",False)
    
    return form


def post_notes_to_score(notes_list):
    for note_data in notes_list:
        note = makeNote(
            note_data.getMidiNoteValue(),
            note_data.getStartTime(),
            note_data.getLength(),
            color=note_data.chan,
            velocity=note_data.velocity/127.0
        )
        flp.score.addNote(note)


def transpose_all(all_notes, n):
    transposed = [{'note': note_entry['note'] + n, 
                   'start_time': note_entry['start_time'], 
                   'length': note_entry['length']} for note_entry in all_notes]
    return transposed
 

def makeALine(tm,seq,k,n,selectorType,density,note_prop,chan,all_notes) : 
    rgen = SimpleRhythmGenerator(k,n,selectorType,density)
    line = LineGenerator(tm, seq, rgen, note_prop)
    all_notes.extend(line.generateNotes(0, chan, 100))

        
def apply(form):
    # Create GoldenData instance
    data = GoldenData()
    
    # Set basic parameters
    data.root = form.GetInputValue('Root')
    data.mode = form.GetInputValue('Mode')
    data.chordSequence = form.GetInputValue('ChordSeq')
    data.stutter = form.GetInputValue("Stutter")
    data.chordDuration = form.GetInputValue('Chord Duration')
    data.bpm = 120  # FL Studio handles BPM separately
    
    # Get rhythm parameters
    k = form.GetInputValue('Rhythm k')
    n = form.GetInputValue('Rhythm n')
    density = form.GetInputValue('Density')
    note_prop = form.GetInputValue('Note Proportion')
    
    # Handle silent checkbox first
    if form.GetInputValue("Silent")==1:
        flp.score.clearNotes(False)
        return

    try:
        # Add lines based on checkboxes
        if form.GetInputValue("Chords")==1:
            pattern = f"{k}/{n} c {density}"
            data.addLine(pattern, MidiInstrumentContext(0, 100, note_prop, 0))

        if form.GetInputValue("Arp ↑")==1:
            pattern = f"{k}/{n} > {density}"
            data.addLine(pattern, MidiInstrumentContext(1, 100, note_prop, 0))

        if form.GetInputValue("Arp ↓")==1:
            pattern = f"{k}/{n} < {density}"
            data.addLine(pattern, MidiInstrumentContext(2, 100, note_prop, 0))

        if form.GetInputValue("Bass")==1:
            pattern = f"{k}/{n} 1 {density}"
            data.addLine(pattern, MidiInstrumentContext(3, 100, note_prop, -12))

        if form.GetInputValue("Top")==1:
            pattern = f"{k}/{n} t {density}"
            data.addLine(pattern, MidiInstrumentContext(4, 100, note_prop, 12))

        if form.GetInputValue("Random")==1:
            pattern = f"{k}%{n} r {density}"
            data.addLine(pattern, MidiInstrumentContext(5, 100, note_prop, 0))

        # Generate all lines using GoldenData
        all_notes = []
        for i in range(len(data.lines)):
            generator = data.makeLineGenerator(i)
            notes = generator.generateNotes(0)
            if notes:  # Only add if we got notes back
                all_notes.extend(notes)

        # Only clear and update if we successfully generated notes
        if all_notes:
            flp.score.clearNotes(False)
            post_notes_to_score(all_notes)
            
            if data.hasChanged():
                Utils.log("Project updated:\n%s" % data.toString())
            
    except Exception as e:
        Utils.log("Exception\n%s" % e)
        
