{ "version": 3, "sources": ["../../chronograph/src/class/Base.js", "../../chronograph/src/collection/Iterator.js", "../../chronograph/src/util/Helpers.js", "../../chronograph/src/chrono/Effect.js", "../../chronograph/src/class/Mixin.js", "../../chronograph/src/environment/Debug.js", "../../chronograph/src/primitives/Calculation.js", "../../chronograph/src/graph/WalkDepth.js", "../../chronograph/src/chrono/Quark.js", "../../chronograph/src/chrono/Identifier.js", "../../chronograph/src/chrono/Revision.js", "../../chronograph/src/util/LeveledQueue.js", "../../chronograph/src/chrono/TransactionCycleDetectionWalkContext.js", "../../chronograph/src/chrono/TransactionWalkDepth.js", "../../chronograph/src/chrono/Transaction.js", "../../chronograph/src/chrono/Graph.js", "../../chronograph/src/schema/EntityMeta.js", "../../chronograph/src/replica/Replica.js", "../../chronograph/src/replica/Identifier.js", "../../chronograph/src/schema/Field.js", "../../chronograph/src/replica/Entity.js", "../../Engine/lib/Engine/scheduling/Types.js", "../../Engine/lib/Engine/util/Constants.js", "../../chronograph/src/class/RequiredProperty.js", "../../chronograph/src/cycle_resolver/CycleResolver.js", "../../Core/lib/Core/helper/BrowserHelper.js", "../../Core/lib/Core/helper/StringHelper.js", "../../Core/lib/Core/helper/util/Objects.js", "../../Core/lib/Core/helper/VersionHelper.js", "../../Core/lib/Core/Config.js", "../../Core/lib/Core/Base.js", "../../Core/lib/Core/helper/AjaxHelper.js", "../../Core/lib/Core/helper/ArrayHelper.js", "../../Core/lib/Core/helper/FunctionHelper.js", "../../Core/lib/Core/mixin/Events.js", "../../Core/lib/Core/localization/LocaleHelper.js", "../../Core/lib/Core/localization/LocaleManager.js", "../../Core/lib/Core/localization/Localizable.js", "../../Core/lib/Core/localization/En.js", "../../Core/lib/Core/helper/DateHelper.js", "../../chronograph/src/replica/Reference.js", "../../chronograph/src/replica/ReferenceBucket.js", "../../Engine/lib/Engine/chrono/ModelFieldAtom.js", "../../Engine/lib/Engine/chrono/SchedulingIssueEffect.js", "../../Engine/lib/Engine/util/Functions.js", "../../Core/lib/Core/helper/ObjectHelper.js", "../../Core/lib/Core/data/stm/mixin/ModelStm.js", "../../Core/lib/Core/data/mixin/TreeNode.js", "../../Core/lib/Core/data/mixin/ModelLink.js", "../../Core/lib/Core/mixin/Factoryable.js", "../../Core/lib/Core/data/field/DataField.js", "../../Core/lib/Core/data/field/ArrayDataField.js", "../../Core/lib/Core/data/field/BooleanDataField.js", "../../Core/lib/Core/data/field/DateDataField.js", "../../Core/lib/Core/data/field/StringDataField.js", "../../Core/lib/Core/data/field/DurationUnitDataField.js", "../../Core/lib/Core/data/field/IntegerDataField.js", "../../Core/lib/Core/data/field/ModelDataField.js", "../../Core/lib/Core/data/field/NumberDataField.js", "../../Core/lib/Core/data/field/ObjectDataField.js", "../../Core/lib/Core/data/field/StoreDataField.js", "../../Core/lib/Core/data/Model.js", "../../Engine/lib/Engine/chrono/ChronoModelMixin.js", "../../Engine/lib/Engine/quark/AbstractPartOfProjectGenericMixin.js", "../../Engine/lib/Engine/quark/ChronoPartOfProjectGenericMixin.js", "../../Core/lib/Core/mixin/InstancePlugin.js", "../../Core/lib/Core/mixin/Pluggable.js", "../../Core/lib/Core/mixin/Delayable.js", "../../Core/lib/Core/state/StateStorage.js", "../../Core/lib/Core/state/StateProvider.js", "../../Core/lib/Core/mixin/State.js", "../../Core/lib/Core/mixin/Identifiable.js", "../../Core/lib/Core/data/Duration.js", "../../Core/lib/Core/util/CollectionFilter.js", "../../Core/lib/Core/helper/IdHelper.js", "../../Core/lib/Core/util/CollectionSorter.js", "../../Core/lib/Core/util/Collection.js", "../../Core/lib/Core/util/Bag.js", "../../Core/lib/Core/data/StoreBag.js", "../../Core/lib/Core/data/mixin/StoreCRUD.js", "../../Core/lib/Core/data/mixin/StoreChanges.js", "../../Core/lib/Core/data/mixin/StoreFilter.js", "../../Core/lib/Core/data/mixin/StoreGroup.js", "../../Core/lib/Core/data/mixin/StoreProxy.js", "../../Core/lib/Core/data/mixin/StoreRelation.js", "../../Core/lib/Core/data/mixin/StoreSum.js", "../../Core/lib/Core/data/mixin/StoreSearch.js", "../../Core/lib/Core/data/mixin/StoreSort.js", "../../Core/lib/Core/data/mixin/StoreChained.js", "../../Core/lib/Core/data/mixin/StoreState.js", "../../Core/lib/Core/data/Wbs.js", "../../Core/lib/Core/data/mixin/StoreTree.js", "../../Core/lib/Core/helper/WalkHelper.js", "../../Core/lib/Core/data/mixin/StoreSync.js", "../../Core/lib/Core/data/stm/mixin/StoreStm.js", "../../Core/lib/Core/data/Store.js", "../../Engine/lib/Engine/quark/store/mixin/ChronoStoreMixin.js", "../../Engine/lib/Engine/quark/store/mixin/AbstractPartOfProjectStoreMixin.js", "../../Engine/lib/Engine/quark/store/mixin/ChronoPartOfProjectStoreMixin.js", "../../Engine/lib/Engine/quark/model/mixin/AbstractPartOfProjectModelMixin.js", "../../Engine/lib/Engine/quark/model/mixin/ChronoPartOfProjectModelMixin.js", "../../Engine/lib/Engine/vendor/later/later.js", "../../Engine/lib/Engine/calendar/CalendarIntervalMixin.js", "../../Engine/lib/Engine/calendar/CalendarIntervalStore.js", "../../Engine/lib/Engine/util/Types.js", "../../Engine/lib/Engine/calendar/CalendarCache.js", "../../Engine/lib/Engine/util/StripDuplicates.js", "../../Engine/lib/Engine/calendar/CalendarCacheInterval.js", "../../Engine/lib/Engine/util/BinarySearch.js", "../../Engine/lib/Engine/calendar/SortedMap.js", "../../Engine/lib/Engine/calendar/IntervalCache.js", "../../Core/lib/Core/helper/TimeZoneHelper.js", "../../Engine/lib/Engine/calendar/CalendarCacheSingle.js", "../../Engine/lib/Engine/calendar/UnspecifiedTimeIntervalModel.js", "../../Engine/lib/Engine/quark/model/AbstractCalendarMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseCalendarMixin.js", "../../chronograph/src/chrono/CycleResolver.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseEventDispatcher.js", "../../Engine/lib/Engine/calendar/CalendarCacheIntervalMultiple.js", "../../Engine/lib/Engine/calendar/CalendarCacheMultiple.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/HasCalendarMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseEventMixin.js", "../../Engine/lib/Engine/quark/model/AbstractHasAssignmentsMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseHasAssignmentsMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/HasDependenciesMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/SchedulerBasicEvent.js", "../../Engine/lib/Engine/quark/store/AbstractEventStoreMixin.js", "../../Engine/lib/Engine/quark/store/ChronoEventStoreMixin.js", "../../Engine/lib/Engine/localization/En.js", "../../Engine/lib/Engine/scheduling/DateInterval.js", "../../Engine/lib/Engine/chrono/Conflict.js", "../../Engine/lib/Engine/chrono/Replica.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/HasSubEventsMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/HasChildrenMixin.js", "../../chronograph/src/schema/Schema.js", "../../Core/lib/Core/data/stm/state/StateBase.js", "../../Core/lib/Core/data/stm/Props.js", "../../Core/lib/Core/data/stm/state/Registry.js", "../../Core/lib/Core/data/stm/Helpers.js", "../../Core/lib/Core/data/stm/state/DisabledState.js", "../../Core/lib/Core/data/stm/Transaction.js", "../../Core/lib/Core/data/stm/state/ReadyState.js", "../../Core/lib/Core/data/stm/state/RecordingState.js", "../../Core/lib/Core/data/stm/state/RestoringState.js", "../../Core/lib/Core/data/stm/state/AutoReadyState.js", "../../Core/lib/Core/data/stm/state/AutoRecordingState.js", "../../Core/lib/Core/data/stm/action/ActionBase.js", "../../Core/lib/Core/data/stm/action/UpdateAction.js", "../../Core/lib/Core/data/stm/action/InsertChildAction.js", "../../Core/lib/Core/data/stm/action/RemoveChildAction.js", "../../Core/lib/Core/data/stm/action/AddAction.js", "../../Core/lib/Core/data/stm/action/InsertAction.js", "../../Core/lib/Core/data/stm/action/RemoveAction.js", "../../Core/lib/Core/data/stm/action/RemoveAllAction.js", "../../Core/lib/Core/data/stm/StateTrackingManager.js", "../../Engine/lib/Engine/scheduling/DurationConverterMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseAssignmentMixin.js", "../../Engine/lib/Engine/quark/store/AbstractAssignmentStoreMixin.js", "../../Engine/lib/Engine/quark/store/ChronoAssignmentStoreMixin.js", "../../Engine/lib/Engine/quark/store/AbstractCalendarManagerStoreMixin.js", "../../Engine/lib/Engine/quark/store/ChronoCalendarManagerStoreMixin.js", "../../Engine/lib/Engine/quark/store/AbstractDependencyStoreMixin.js", "../../Engine/lib/Engine/quark/store/ChronoDependencyStoreMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseResourceMixin.js", "../../Engine/lib/Engine/quark/store/AbstractResourceStoreMixin.js", "../../Engine/lib/Engine/quark/store/ChronoResourceStoreMixin.js", "../../Engine/lib/Engine/quark/model/AbstractProjectMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/ChronoAbstractProjectMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/BaseDependencyMixin.js", "../../Engine/lib/Engine/util/Queue.js", "../../Engine/lib/Engine/quark/model/scheduler_basic/SchedulerBasicProjectMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/ConstrainedEarlyEventMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/HasDateConstraintMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/ScheduledByDependenciesEarlyEventMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProAssignmentMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProDependencyMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/HasPercentDoneMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProHasAssignmentsMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProEventSegment.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SplitEventMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/HasEffortMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/HasEffortDispatcher.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/HasSchedulingModeMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/scheduling_modes/FixedDurationDispatcher.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/scheduling_modes/FixedDurationMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/DelayFromParentMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProEvent.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProResourceMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_pro/SchedulerProProjectMixin.js", "../../Engine/lib/Engine/quark/model/gantt/ConstrainedByParentMixin.js", "../../Engine/lib/Engine/quark/model/gantt/ConstrainedLateEventMixin.js", "../../Engine/lib/Engine/quark/model/gantt/ScheduledByDependenciesLateEventMixin.js", "../../Engine/lib/Engine/quark/model/gantt/InactiveEventMixin.js", "../../Engine/lib/Engine/quark/model/gantt/scheduling_modes/FixedEffortDispatcher.js", "../../Engine/lib/Engine/quark/model/gantt/scheduling_modes/FixedEffortMixin.js", "../../Engine/lib/Engine/quark/model/gantt/scheduling_modes/FixedUnitsDispatcher.js", "../../Engine/lib/Engine/quark/model/gantt/scheduling_modes/FixedUnitsMixin.js", "../../Engine/lib/Engine/quark/model/gantt/GanttEvent.js", "../../Engine/lib/Engine/quark/model/gantt/HasCriticalPathsMixin.js", "../../Engine/lib/Engine/quark/model/gantt/GanttProjectMixin.js", "../../Engine/lib/Engine/quark/CorePartOfProjectGenericMixin.js", "../../Engine/lib/Engine/quark/model/mixin/CorePartOfProjectModelMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreEventMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreResourceMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreAssignmentMixin.js", "../../Engine/lib/Engine/quark/store/mixin/CorePartOfProjectStoreMixin.js", "../../Engine/lib/Engine/quark/store/CoreAssignmentStoreMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreCalendarMixin.js", "../../Engine/lib/Engine/quark/store/CoreCalendarManagerStoreMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreDependencyMixin.js", "../../Engine/lib/Engine/quark/store/CoreDependencyStoreMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreHasAssignmentsMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/CoreHasDependenciesMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/SchedulerCoreEvent.js", "../../Engine/lib/Engine/quark/store/CoreEventStoreMixin.js", "../../Engine/lib/Engine/quark/store/CoreResourceStoreMixin.js", "../../Engine/lib/Engine/quark/model/scheduler_core/SchedulerCoreProjectMixin.js", "../../Core/lib/Core/helper/util/DomClassList.js", "../../Core/lib/Core/data/AjaxStore.js", "../../Core/lib/Core/data/DomDataStore.js", "../../SchedulerPro/lib/SchedulerPro/model/changelog/ChangeLogEntity.js", "../../Grid/lib/Grid/data/GridRowModel.js", "../../Scheduler/lib/Scheduler/crud/mixin/AbstractCrudManagerValidation.js", "../../Scheduler/lib/Scheduler/crud/AbstractCrudManagerMixin.js", "../../Scheduler/lib/Scheduler/crud/AbstractCrudManager.js", "../../Scheduler/lib/Scheduler/crud/transport/AjaxTransport.js", "../../Scheduler/lib/Scheduler/crud/encoder/JsonEncoder.js", "../../Scheduler/lib/Scheduler/model/mixin/TimeZonedDatesMixin.js", "../../Scheduler/lib/Scheduler/model/TimeSpan.js", "../../Scheduler/lib/Scheduler/data/util/recurrence/RecurrenceDayRuleEncoder.js", "../../Scheduler/lib/Scheduler/data/util/recurrence/AbstractRecurrenceIterator.js", "../../Scheduler/lib/Scheduler/data/util/recurrence/DailyRecurrenceIterator.js", "../../Scheduler/lib/Scheduler/data/util/recurrence/WeeklyRecurrenceIterator.js", "../../Scheduler/lib/Scheduler/data/util/recurrence/MonthlyRecurrenceIterator.js", "../../Scheduler/lib/Scheduler/data/util/recurrence/YearlyRecurrenceIterator.js", "../../Scheduler/lib/Scheduler/model/RecurrenceModel.js", "../../Scheduler/lib/Scheduler/model/mixin/RecurringTimeSpan.js", "../../Scheduler/lib/Scheduler/model/ResourceTimeRangeModel.js", "../../Scheduler/lib/Scheduler/data/mixin/RecurringTimeSpansMixin.js", "../../Scheduler/lib/Scheduler/data/ResourceTimeRangeStore.js", "../../Scheduler/lib/Scheduler/data/mixin/PartOfProject.js", "../../Scheduler/lib/Scheduler/model/mixin/AssignmentModelMixin.js", "../../Scheduler/lib/Scheduler/model/AssignmentModel.js", "../../Scheduler/lib/Scheduler/data/mixin/AssignmentStoreMixin.js", "../../Scheduler/lib/Scheduler/data/AssignmentStore.js", "../../Scheduler/lib/Scheduler/data/mixin/EventStoreMixin.js", "../../Scheduler/lib/Scheduler/data/mixin/GetEventsMixin.js", "../../Core/lib/Core/util/DayTime.js", "../../Scheduler/lib/Scheduler/data/util/EventDayIndex.js", "../../Scheduler/lib/Scheduler/data/mixin/DayIndexMixin.js", "../../Scheduler/lib/Scheduler/data/mixin/RecurringEventsMixin.js", "../../Scheduler/lib/Scheduler/model/mixin/EventModelMixin.js", "../../Scheduler/lib/Scheduler/model/EventModel.js", "../../Scheduler/lib/Scheduler/data/EventStore.js", "../../Scheduler/lib/Scheduler/data/mixin/ResourceStoreMixin.js", "../../Scheduler/lib/Scheduler/model/mixin/ResourceModelMixin.js", "../../Scheduler/lib/Scheduler/model/ResourceModel.js", "../../Scheduler/lib/Scheduler/data/ResourceStore.js", "../../Scheduler/lib/Scheduler/model/DependencyBaseModel.js", "../../Scheduler/lib/Scheduler/model/DependencyModel.js", "../../Scheduler/lib/Scheduler/data/mixin/DependencyStoreMixin.js", "../../Scheduler/lib/Scheduler/data/DependencyStore.js", "../../Scheduler/lib/Scheduler/model/TimeRangeModel.js", "../../Scheduler/lib/Scheduler/data/TimeRangeStore.js", "../../Scheduler/lib/Scheduler/data/mixin/ProjectCrudManager.js", "../../Scheduler/lib/Scheduler/model/mixin/ProjectModelCommon.js", "../../Scheduler/lib/Scheduler/data/plugin/StoreTimeZonePlugin.js", "../../Scheduler/lib/Scheduler/model/mixin/ProjectModelTimeZoneMixin.js", "../../Scheduler/lib/Scheduler/model/mixin/ProjectModelMixin.js", "../../Scheduler/lib/Scheduler/model/mixin/ProjectCurrentConfig.js", "../../Scheduler/lib/Scheduler/data/util/ModelPersistencyManager.js", "../../Scheduler/lib/Scheduler/model/ProjectModel.js", "../../SchedulerPro/lib/SchedulerPro/data/mixin/PartOfProject.js", "../../SchedulerPro/lib/SchedulerPro/model/AssignmentModel.js", "../../SchedulerPro/lib/SchedulerPro/data/AssignmentStore.js", "../../SchedulerPro/lib/SchedulerPro/model/CalendarIntervalModel.js", "../../SchedulerPro/lib/SchedulerPro/model/CalendarModel.js", "../../SchedulerPro/lib/SchedulerPro/data/CalendarManagerStore.js", "../../SchedulerPro/lib/SchedulerPro/model/DependencyModel.js", "../../SchedulerPro/lib/SchedulerPro/data/DependencyStore.js", "../../SchedulerPro/lib/SchedulerPro/model/mixin/PercentDoneMixin.js", "../../SchedulerPro/lib/SchedulerPro/model/EventSegmentModel.js", "../../SchedulerPro/lib/SchedulerPro/model/EventModel.js", "../../SchedulerPro/lib/SchedulerPro/data/EventStore.js", "../../SchedulerPro/lib/SchedulerPro/model/ResourceModel.js", "../../SchedulerPro/lib/SchedulerPro/data/ResourceStore.js", "../../SchedulerPro/lib/SchedulerPro/data/mixin/ProjectCrudManager.js", "../../SchedulerPro/lib/SchedulerPro/model/mixin/ProjectChangeHandlerMixin.js", "../../SchedulerPro/lib/SchedulerPro/data/stm/action/EventUpdateAction.js", "../../SchedulerPro/lib/SchedulerPro/data/stm/StateTrackingManager.js", "../../SchedulerPro/lib/SchedulerPro/model/ProjectModel.js", "../lib/Gantt/model/AssignmentModel.js", "../lib/Gantt/data/AssignmentStore.js", "../lib/Gantt/model/CalendarModel.js", "../lib/Gantt/data/CalendarManagerStore.js", "../lib/Gantt/model/DependencyModel.js", "../lib/Gantt/data/DependencyStore.js", "../lib/Gantt/model/ResourceModel.js", "../lib/Gantt/data/ResourceStore.js", "../lib/Gantt/model/Baseline.js", "../lib/Gantt/data/field/WbsField.js", "../lib/Gantt/model/TaskModel.js", "../lib/Gantt/data/TaskStore.js", "../lib/Gantt/model/CalendarIntervalModel.js", "../lib/Gantt/model/ProjectModel.js"], "sourcesContent": ["//---------------------------------------------------------------------------------------------------------------------\n/**\n * This is a base class, providing the type-safe static constructor [[new]]. This is very convenient when using\n * [[Mixin|mixins]], as mixins can not have types in the constructors.\n */\nexport class Base {\n /**\n * This method applies its 1st argument (if any) to the current instance using `Object.assign()`.\n *\n * Supposed to be overridden in the subclasses to customize the instance creation process.\n *\n * @param props\n */\n initialize(props) {\n props && Object.assign(this, props);\n }\n /**\n * This is a type-safe static constructor method, accepting a single argument, with the object, corresponding to the\n * class properties. It will generate a compilation error, if unknown property is provided.\n *\n * For example:\n *\n * ```ts\n * class MyClass extends Base {\n * prop : string\n * }\n *\n * const instance : MyClass = MyClass.new({ prop : 'prop', wrong : 11 })\n * ```\n *\n * will produce:\n *\n * ```plaintext\n * TS2345: Argument of type '{ prop: string; wrong: number; }' is not assignable to parameter of type 'Partial'.\n * Object literal may only specify known properties, and 'wrong' does not exist in type 'Partial'\n * ```\n *\n * The only thing this constructor does is create an instance and call the [[initialize]] method on it, forwarding\n * the first argument. The customization of instance is supposed to be performed in that method.\n *\n * @param props\n */\n static new(props) {\n const instance = new this();\n instance.initialize(props);\n return instance;\n }\n}\n", "//---------------------------------------------------------------------------------------------------------------------\n/**\n * Given a single `Iterable`, returns an array of 2 iterables, mirroring the original one (which should not be used anymore).\n *\n * For example:\n *\n * const gen = function* () { yield 1; yield 2; yield 3 }\n *\n * const [ iterable1, iterable2 ] = split(gen())\n * const [ iter1, iter2 ] = [\n * iterable1[ Symbol.iterator ](),\n * iterable2[ Symbol.iterator ]()\n * ]\n *\n * iter1.next() // 1\n * iter2.next() // 1\n * iter2.next() // 2\n * iter2.next() // 3\n * iter1.next() // 2\n * iter1.next() // 3\n * iter1.next() // done\n * iter2.next() // done\n *\n * @param iterable\n */\nexport function split(iterable) {\n const gen1Pending = [];\n const gen2Pending = [];\n let iterator;\n const gen1 = function* () {\n if (!iterator)\n iterator = iterable[Symbol.iterator]();\n while (true) {\n if (gen1Pending.length) {\n yield* gen1Pending;\n gen1Pending.length = 0;\n }\n if (!iterator)\n break;\n const { value, done } = iterator.next();\n if (done) {\n iterator = null;\n iterable = null;\n break;\n }\n gen2Pending.push(value);\n yield value;\n }\n };\n const gen2 = function* () {\n if (!iterator)\n iterator = iterable[Symbol.iterator]();\n while (true) {\n if (gen2Pending.length) {\n yield* gen2Pending;\n gen2Pending.length = 0;\n }\n if (!iterator)\n break;\n const { value, done } = iterator.next();\n if (done) {\n iterator = null;\n iterable = null;\n break;\n }\n gen1Pending.push(value);\n yield value;\n }\n };\n return [gen1(), gen2()];\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* inBatchesBySize(iterator, batchSize) {\n if (batchSize < 0)\n throw new Error(\"Batch size needs to a natural number\");\n batchSize = batchSize | 0;\n const runningBatch = [];\n for (const el of iterator) {\n if (runningBatch.length === batchSize) {\n yield runningBatch;\n runningBatch.length = 0;\n }\n runningBatch.push(el);\n }\n if (runningBatch.length > 0)\n yield runningBatch;\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* filter(iterator, func) {\n let i = 0;\n for (const el of iterator) {\n if (func(el, i++))\n yield el;\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* drop(iterator, howMany) {\n let i = 0;\n for (const el of iterator) {\n if (++i > howMany)\n yield el;\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function every(iterator, func) {\n let i = 0;\n for (const el of iterator) {\n if (!func(el, i++))\n return false;\n }\n return true;\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function some(iterator, func) {\n let i = 0;\n for (const el of iterator) {\n if (func(el, i++))\n return true;\n }\n return false;\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* map(iterator, func) {\n let i = 0;\n for (const el of iterator)\n yield func(el, i++);\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function reduce(iterator, func, initialAcc) {\n let i = 0;\n let acc = initialAcc;\n for (const el of iterator) {\n acc = func(acc, el, i++);\n }\n return acc;\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* uniqueOnly(iterator) {\n const seen = new Set();\n for (const el of iterator) {\n if (!seen.has(el)) {\n seen.add(el);\n yield el;\n }\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* uniqueOnlyBy(iterator, func) {\n const seen = new Set();\n for (const el of iterator) {\n const uniqueBy = func(el);\n if (!seen.has(uniqueBy)) {\n seen.add(uniqueBy);\n yield el;\n }\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* reverse(iterator) {\n const all = Array.from(iterator);\n for (let i = all.length - 1; i >= 0; i--)\n yield all[i];\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* takeWhile(iterator, func) {\n let i = 0;\n for (const el of iterator) {\n if (func(el, i++))\n yield el;\n else\n return;\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* takeUntilIncluding(iterator, func) {\n let i = 0;\n for (const el of iterator) {\n yield el;\n if (func(el, i++))\n return;\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* takeUntilExcluding(iterator, func) {\n let i = 0;\n for (const el of iterator) {\n if (func(el, i++))\n return;\n yield el;\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* concat(...iterators) {\n for (let i = 0; i < iterators.length; i++)\n yield* iterators[i];\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function* concatIterable(iteratorsProducer) {\n for (const iterator of iteratorsProducer)\n yield* iterator;\n}\n//---------------------------------------------------------------------------------------------------------------------\n// just a chained syntax sugar class\n// note, that we either use a combination of `this.derive()` + this.iterable (which will clear the `this.iterable`)\n// or, use just `this` as iterable, which will also clear the iterator\n//\nexport class ChainedIteratorClass {\n constructor(iterable) {\n this.iterable = undefined;\n if (!iterable)\n throw new Error(\"Require an iterable instance for chaining\");\n this.iterable = iterable;\n }\n derive(iterable) {\n this.iterable = undefined;\n return new ChainedIteratorClass(iterable);\n }\n copy() {\n const [iter1, iter2] = split(this.iterable);\n this.iterable = iter2;\n return new ChainedIteratorClass(iter1);\n }\n split() {\n const [iter1, iter2] = split(this.iterable);\n return [new ChainedIteratorClass(iter1), this.derive(iter2)];\n }\n inBatchesBySize(batchSize) {\n return this.derive(inBatchesBySize(this.iterable, batchSize));\n }\n filter(func) {\n return this.derive(filter(this.iterable, func));\n }\n drop(howMany) {\n return this.derive(drop(this.iterable, howMany));\n }\n map(func) {\n return this.derive(map(this.iterable, func));\n }\n reduce(func, initialAcc) {\n return reduce(this, func, initialAcc);\n }\n concat() {\n //@ts-ignore\n return this.derive(concatIterable(this.iterable));\n }\n uniqueOnly() {\n return this.derive(uniqueOnly(this.iterable));\n }\n uniqueOnlyBy(func) {\n return this.derive(uniqueOnlyBy(this.iterable, func));\n }\n every(func) {\n return every(this, func);\n }\n some(func) {\n return some(this, func);\n }\n takeWhile(func) {\n return this.derive(takeWhile(this.iterable, func));\n }\n *[Symbol.iterator]() {\n let iterable = this.iterable;\n if (!iterable)\n throw new Error(\"Chained iterator already exhausted or used to derive the new one\");\n // practice shows, that cleaning up the iterable after yourself helps garbage collector a lot\n this.iterable = undefined;\n yield* iterable;\n // yes, we really want to avoid memory leaks\n iterable = undefined;\n }\n toArray() {\n return Array.from(this);\n }\n sort(order) {\n return Array.from(this).sort(order);\n }\n toSet() {\n return new Set(this);\n }\n toMap() {\n //@ts-ignore\n return new Map(this);\n }\n // toMap () : T extends [ K, V ] ? Map : never {\n // return new Map(this.iterable as (T extends [ K, V ] ? Iterable : never)) as (T extends [ K, V ] ? Map : never)\n // }\n flush() {\n for (const element of this) { }\n }\n memoize() {\n return new MemoizedIteratorClass(this);\n }\n}\nexport const ChainedIterator = (iterator) => new ChainedIteratorClass(iterator);\nexport const CI = ChainedIterator;\n//---------------------------------------------------------------------------------------------------------------------\nexport class MemoizedIteratorClass extends ChainedIteratorClass {\n constructor() {\n super(...arguments);\n this.elements = [];\n this.$iterator = undefined;\n }\n set iterable(iterable) {\n this.$iterable = iterable;\n }\n get iterable() {\n return this;\n }\n derive(iterable) {\n return new ChainedIteratorClass(iterable);\n }\n *[Symbol.iterator]() {\n const elements = this.elements;\n if (this.$iterable) {\n if (!this.$iterator)\n this.$iterator = this.$iterable[Symbol.iterator]();\n let iterator = this.$iterator;\n let alreadyConsumed = elements.length;\n // yield the 1st batch \"efficiently\"\n if (alreadyConsumed > 0)\n yield* elements;\n while (true) {\n if (elements.length > alreadyConsumed) {\n // wonder if `yield* elements.slice(alreadyConsumed)` is more performant or not\n for (let i = alreadyConsumed; i < elements.length; i++)\n yield elements[i];\n alreadyConsumed = elements.length;\n }\n if (!iterator)\n break;\n const { value, done } = iterator.next();\n if (done) {\n iterator = this.$iterator = null;\n this.$iterable = null;\n }\n else {\n elements.push(value);\n alreadyConsumed++;\n yield value;\n }\n }\n }\n else {\n yield* elements;\n }\n }\n}\nexport const MemoizedIterator = (iterator) => new MemoizedIteratorClass(iterator);\nexport const MI = MemoizedIterator;\n", "//---------------------------------------------------------------------------------------------------------------------\n// assume 32-bit platform (https://v8.dev/blog/react-cliff)\nimport { CI } from \"../collection/Iterator.js\";\nexport const MIN_SMI = -Math.pow(2, 30);\nexport const MAX_SMI = Math.pow(2, 30) - 1;\n//---------------------------------------------------------------------------------------------------------------------\nexport const uppercaseFirst = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);\n//---------------------------------------------------------------------------------------------------------------------\nexport const isAtomicValue = (value) => Object(value) !== value;\n//---------------------------------------------------------------------------------------------------------------------\nexport const typeOf = (value) => Object.prototype.toString.call(value).slice(8, -1);\n//---------------------------------------------------------------------------------------------------------------------\nexport const defineProperty = (target, property, value) => {\n Object.defineProperty(target, property, { value, enumerable: true, configurable: true });\n return value;\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const prototypeValue = (value) => {\n return function (target, propertyKey) {\n target[propertyKey] = value;\n };\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const copyMapInto = (sourceMap, targetMap) => {\n for (const [key, value] of sourceMap)\n targetMap.set(key, value);\n return targetMap;\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const copySetInto = (sourceSet, targetSet) => {\n for (const value of sourceSet)\n targetSet.add(value);\n return targetSet;\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const delay = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));\n//---------------------------------------------------------------------------------------------------------------------\nexport const matchAll = function* (regexp, testStr) {\n let match;\n while ((match = regexp.exec(testStr)) !== null) {\n yield match;\n }\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const allMatches = function (regexp, testStr) {\n return CI(matchAll(regexp, testStr)).map(match => CI(match).drop(1)).concat().toArray();\n};\nlet isRegeneratorRuntime = null;\nexport const isGeneratorFunction = function (func) {\n if (isRegeneratorRuntime === null)\n isRegeneratorRuntime = typeof regeneratorRuntime !== 'undefined';\n if (isRegeneratorRuntime === true) {\n return regeneratorRuntime.isGeneratorFunction(func);\n }\n else {\n return func.constructor.name === 'GeneratorFunction';\n }\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const isPromise = function (obj) {\n return obj && typeof obj.then === 'function';\n};\n", "var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nimport { Base } from \"../class/Base.js\";\nimport { prototypeValue } from \"../util/Helpers.js\";\n//---------------------------------------------------------------------------------------------------------------------\nexport const BreakCurrentStackExecution = Symbol('BreakCurrentStackExecution');\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * The base class for effect. Effect is some value, that can be send to the \"outer\" calculation context, using the\n * effect handler function. Effect handler then will process an effect and return some resulting value.\n *\n * ```ts\n * const identifier = graph.identifier((Y : SyncEffectHandler) : number => {\n * const proposedValue : number = Y(ProposedOrPrevious)\n *\n * const maxValue : number = Y(max)\n *\n * return proposedValue <= maxValue ? proposedValue : maxValue\n * })\n * ```\n */\nexport class Effect extends Base {\n}\n__decorate([\n prototypeValue(true)\n], Effect.prototype, \"sync\", void 0);\n__decorate([\n prototypeValue(true)\n], Effect.prototype, \"pure\", void 0);\n//---------------------------------------------------------------------------------------------------------------------\nexport const ProposedOrPreviousSymbol = Symbol('ProposedOrPreviousSymbol');\n/**\n * The constant that represents a request for either user input (proposed value) or previous value of the\n * identifier, currently being calculated.\n *\n * Important note, is that if an identifier yields a `ProposedOrPrevious` effect and its computed value does not match the value of this effect,\n * it will be re-calculated (computation function called) again on the next read. This is because the value of its `ProposedOrPrevious` input changes.\n *\n * ```ts\n * const graph4 = ChronoGraph.new()\n *\n * const max = graph4.variable(100)\n *\n * const identifier15 = graph4.identifier((Y) : number => {\n * const proposedValue : number = Y(ProposedOrPrevious)\n *\n * const maxValue : number = Y(max)\n *\n * return proposedValue <= maxValue ? proposedValue : maxValue\n * })\n *\n * graph4.write(identifier15, 18)\n *\n * const value15_1 = graph4.read(identifier15) // 18\n *\n * graph4.write(identifier15, 180)\n *\n * const value15_2 = graph4.read(identifier15) // 100\n *\n * graph4.write(max, 50)\n *\n * const value15_3 = graph4.read(identifier15) // 50\n * ```\n */\nexport const ProposedOrPrevious = Effect.new({ handler: ProposedOrPreviousSymbol });\n//---------------------------------------------------------------------------------------------------------------------\nexport const RejectSymbol = Symbol('RejectSymbol');\n/**\n * Class for [[Reject]] effect.\n */\nexport class RejectEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = RejectSymbol;\n }\n}\n__decorate([\n prototypeValue(false)\n], RejectEffect.prototype, \"pure\", void 0);\n/**\n * This is constructor for `RejectEffect` class. If this effect will be yielded during computation the current transaction\n * will be [[ChronoGraph.reject|rejected]].\n *\n * @param reason\n * @constructor\n */\nexport const Reject = (reason) => RejectEffect.new({ reason });\n//---------------------------------------------------------------------------------------------------------------------\nexport const TransactionSymbol = Symbol('TransactionSymbol');\nexport const GetTransaction = Effect.new({ handler: TransactionSymbol });\n//---------------------------------------------------------------------------------------------------------------------\nexport const OwnQuarkSymbol = Symbol('OwnQuarkSymbol');\nexport const OwnQuark = Effect.new({ handler: OwnQuarkSymbol });\n//---------------------------------------------------------------------------------------------------------------------\nexport const OwnIdentifierSymbol = Symbol('OwnIdentifierSymbol');\nexport const OwnIdentifier = Effect.new({ handler: OwnIdentifierSymbol });\n//---------------------------------------------------------------------------------------------------------------------\nexport const WriteSymbol = Symbol('WriteSymbol');\nexport class WriteEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = WriteSymbol;\n }\n}\n__decorate([\n prototypeValue(false)\n], WriteEffect.prototype, \"pure\", void 0);\nexport const Write = (identifier, proposedValue, ...proposedArgs) => WriteEffect.new({ identifier, proposedArgs: [proposedValue, ...proposedArgs] });\nexport const WriteSeveralSymbol = Symbol('WriteSeveralSymbol');\nexport class WriteSeveralEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = WriteSeveralSymbol;\n }\n}\n__decorate([\n prototypeValue(false)\n], WriteSeveralEffect.prototype, \"pure\", void 0);\nexport const WriteSeveral = (writes) => WriteSeveralEffect.new({ writes });\n//---------------------------------------------------------------------------------------------------------------------\nexport const PreviousValueOfSymbol = Symbol('PreviousValueOfSymbol');\nexport class PreviousValueOfEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = PreviousValueOfSymbol;\n }\n}\nexport const PreviousValueOf = (identifier) => PreviousValueOfEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const ProposedValueOfSymbol = Symbol('ProposedValueOfSymbol');\nexport class ProposedValueOfEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = ProposedValueOfSymbol;\n }\n}\nexport const ProposedValueOf = (identifier) => ProposedValueOfEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const HasProposedValueSymbol = Symbol('HasProposedValueSymbol');\nexport class HasProposedValueEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = HasProposedValueSymbol;\n }\n}\nexport const HasProposedValue = (identifier) => HasProposedValueEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const HasProposedNotPreviousValueSymbol = Symbol('HasProposedNotPreviousValueSymbol');\nexport class HasProposedNotPreviousValueEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = HasProposedNotPreviousValueSymbol;\n }\n}\nexport const HasProposedNotPreviousValue = (identifier) => HasProposedNotPreviousValueEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const ProposedOrPreviousValueOfSymbol = Symbol('ProposedOrPreviousValueOfSymbol');\nexport class ProposedOrPreviousValueOfEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = ProposedOrPreviousValueOfSymbol;\n }\n}\nexport const ProposedOrPreviousValueOf = (identifier) => ProposedOrPreviousValueOfEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const ProposedArgumentsOfSymbol = Symbol('ProposedArgumentsOfSymbol');\nexport class ProposedArgumentsOfEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = ProposedArgumentsOfSymbol;\n }\n}\nexport const ProposedArgumentsOf = (identifier) => ProposedArgumentsOfEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const UnsafeProposedOrPreviousValueOfSymbol = Symbol('UnsafeProposedOrPreviousValueOfSymbol');\nexport class UnsafeProposedOrPreviousValueOfEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = UnsafeProposedOrPreviousValueOfSymbol;\n }\n}\nexport const UnsafeProposedOrPreviousValueOf = (identifier) => UnsafeProposedOrPreviousValueOfEffect.new({ identifier });\n//---------------------------------------------------------------------------------------------------------------------\nexport const UnsafePreviousValueOfSymbol = Symbol('UnsafePreviousValueOfSymbol');\nexport class UnsafePreviousValueOfEffect extends Effect {\n constructor() {\n super(...arguments);\n this.handler = UnsafePreviousValueOfSymbol;\n }\n}\nexport const UnsafePreviousValueOf = (identifier) => UnsafePreviousValueOfEffect.new({ identifier });\n", "import { CI, MI } from \"../collection/Iterator.js\";\n//---------------------------------------------------------------------------------------------------------------------\nconst MixinInstanceOfProperty = Symbol('MixinIdentity');\nconst MixinStateProperty = Symbol('MixinStateProperty');\n//---------------------------------------------------------------------------------------------------------------------\nclass MixinWalkDepthState {\n constructor() {\n this.baseEl = undefined;\n this.sourceEl = undefined;\n this.$elementsByTopoLevel = undefined;\n this.$topoLevels = undefined;\n this.linearizedByTopoLevelsSource = MI(this.linearizedByTopoLevels());\n }\n static new(props) {\n const me = new this();\n props && Object.assign(me, props);\n return me;\n }\n get topoLevels() {\n if (this.$topoLevels !== undefined)\n return this.$topoLevels;\n return this.$topoLevels = this.buildTopoLevels();\n }\n buildTopoLevels() {\n return Array.from(this.elementsByTopoLevel.keys()).sort((level1, level2) => level1 - level2);\n }\n get elementsByTopoLevel() {\n if (this.$elementsByTopoLevel !== undefined)\n return this.$elementsByTopoLevel;\n return this.$elementsByTopoLevel = this.buildElementsByTopoLevel();\n }\n getOrCreateLevel(map, topoLevel) {\n let elementsAtLevel = map.get(topoLevel);\n if (!elementsAtLevel) {\n elementsAtLevel = [];\n map.set(topoLevel, elementsAtLevel);\n }\n return elementsAtLevel;\n }\n buildElementsByTopoLevel() {\n let maxTopoLevel = 0;\n const baseElements = this.baseEl ? CI(this.baseEl.walkDepthState.elementsByTopoLevel.values()).concat().toSet() : new Set();\n const map = CI(this.sourceEl.requirements)\n .map(mixin => mixin.walkDepthState.elementsByTopoLevel)\n .concat()\n .reduce((elementsByTopoLevel, [topoLevel, mixins]) => {\n if (topoLevel > maxTopoLevel)\n maxTopoLevel = topoLevel;\n this.getOrCreateLevel(elementsByTopoLevel, topoLevel).push(mixins);\n return elementsByTopoLevel;\n }, new Map());\n this.getOrCreateLevel(map, maxTopoLevel + 1).push([this.sourceEl]);\n return CI(map).map(([level, elements]) => {\n return [level, CI(elements).concat().uniqueOnly().filter(mixin => !baseElements.has(mixin)).sort((mixin1, mixin2) => mixin1.id - mixin2.id)];\n }).toMap();\n }\n *linearizedByTopoLevels() {\n yield* CI(this.topoLevels).map(level => this.elementsByTopoLevel.get(level)).concat();\n }\n}\n// Note: 65535 mixins only, because of the hashing function implementation (String.fromCharCode)\nlet MIXIN_ID = 1;\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * @hidden\n */\nexport const identity = a => class extends a {\n};\n// export type IdentityMixin = < T extends AnyConstructor>(base : T) => T\n//\n// export const IdentityMixin = () : IdentityMixin => identity\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * @hidden\n */\nexport class ZeroBaseClass {\n}\n//---------------------------------------------------------------------------------------------------------------------\nclass MixinState {\n constructor() {\n this.id = MIXIN_ID++;\n this.requirements = [];\n this.baseClass = ZeroBaseClass;\n this.identitySymbol = undefined;\n this.mixinLambda = identity;\n this.walkDepthState = undefined;\n // private $hash : MixinHash = ''\n this.$minimalClass = undefined;\n this.name = '';\n }\n static new(props) {\n const me = new this();\n props && Object.assign(me, props);\n me.walkDepthState = MixinWalkDepthState.new({ sourceEl: me, baseEl: getMixinState(me.baseClass) });\n //------------------\n const mixinLambda = me.mixinLambda;\n const symbol = me.identitySymbol = Symbol(mixinLambda.name);\n const mixinLambdaWrapper = Object.assign(function (base) {\n const extendedClass = mixinLambda(base);\n extendedClass.prototype[symbol] = true;\n return extendedClass;\n }, {\n [MixinInstanceOfProperty]: symbol,\n [MixinStateProperty]: me\n });\n Object.defineProperty(mixinLambdaWrapper, Symbol.hasInstance, { value: isInstanceOfStatic });\n me.mixinLambda = mixinLambdaWrapper;\n return me;\n }\n get minimalClass() {\n if (this.$minimalClass !== undefined)\n return this.$minimalClass;\n return this.$minimalClass = this.buildMinimalClass();\n }\n // get hash () : MixinHash {\n // if (this.$hash !== '') return this.$hash\n //\n // return this.$hash = this.buildHash()\n // }\n // buildHash () : MixinHash {\n // return String.fromCharCode(...this.walkDepthState.linearizedByTopoLevelsSource.map(mixin => mixin.id))\n // }\n getBaseClassMixinId(baseClass) {\n const constructor = this.constructor;\n const mixinId = constructor.baseClassesIds.get(baseClass);\n if (mixinId !== undefined)\n return mixinId;\n const newId = MIXIN_ID++;\n constructor.baseClassesIds.set(baseClass, newId);\n return newId;\n }\n buildMinimalClass() {\n const self = this.constructor;\n let baseCls = this.baseClass;\n const minimalClassConstructor = this.walkDepthState.linearizedByTopoLevelsSource.reduce((acc, mixin) => {\n const { cls, hash } = acc;\n const nextHash = hash + String.fromCharCode(mixin.id);\n let wrapperCls = self.minimalClassesByLinearHash.get(nextHash);\n if (!wrapperCls) {\n wrapperCls = mixin.mixinLambda(cls);\n mixin.name = wrapperCls.name;\n self.minimalClassesByLinearHash.set(nextHash, wrapperCls);\n }\n acc.cls = wrapperCls;\n acc.hash = nextHash;\n return acc;\n }, { cls: baseCls, hash: String.fromCharCode(this.getBaseClassMixinId(baseCls)) }).cls;\n const minimalClass = Object.assign(minimalClassConstructor, {\n [MixinInstanceOfProperty]: this.identitySymbol,\n [MixinStateProperty]: this,\n mix: this.mixinLambda,\n derive: (base) => Mixin([minimalClass, base], base => class extends base {\n }),\n $: this,\n toString: this.toString.bind(this)\n });\n Object.defineProperty(minimalClass, Symbol.hasInstance, { value: isInstanceOfStatic });\n return minimalClass;\n }\n toString() {\n return this.walkDepthState.linearizedByTopoLevelsSource.reduce((acc, mixin) => `${mixin.name}(${acc})`, this.baseClass.name);\n }\n}\nMixinState.minimalClassesByLinearHash = new Map();\nMixinState.baseClassesIds = new Map();\n//endregion type helpers\n//---------------------------------------------------------------------------------------------------------------------\nconst isMixinClass = (func) => {\n return Object.getPrototypeOf(func.prototype).constructor.hasOwnProperty(MixinStateProperty);\n};\nconst getMixinState = (func) => {\n return Object.getPrototypeOf(func.prototype).constructor[MixinStateProperty];\n};\n//---------------------------------------------------------------------------------------------------------------------\nconst mixin = (required, mixinLambda) => {\n let baseClass;\n if (required.length > 0) {\n const lastRequirement = required[required.length - 1];\n // absence of `[ MixinStateProperty ]` indicates its a regular class and not a mixin class\n // avoid assigning ZeroBaseClass - it will be applied as default at the end\n if (!isMixinClass(lastRequirement) && lastRequirement !== ZeroBaseClass)\n baseClass = lastRequirement;\n }\n const requirements = [];\n required.forEach((requirement, index) => {\n const mixinState = requirement[MixinStateProperty];\n if (mixinState !== undefined) {\n const currentBaseClass = mixinState.baseClass;\n // ignore ZeroBaseClass - since those are compatible with any other base class\n if (currentBaseClass !== ZeroBaseClass) {\n if (baseClass) {\n // already found a base class from requirements earlier\n if (baseClass !== currentBaseClass) {\n const currentIsSub = currentBaseClass.prototype.isPrototypeOf(baseClass.prototype);\n const currentIsSuper = baseClass.prototype.isPrototypeOf(currentBaseClass.prototype);\n if (!currentIsSub && !currentIsSuper)\n throw new Error(\"Base class mismatch\");\n baseClass = currentIsSuper ? currentBaseClass : baseClass;\n }\n }\n else\n // first base class from requirements\n baseClass = currentBaseClass;\n }\n requirements.push(mixinState);\n }\n else {\n if (index !== required.length - 1)\n throw new Error(\"Base class should be provided as the last element of the requirements array\");\n }\n });\n //------------------\n const mixinState = MixinState.new({\n requirements,\n mixinLambda: mixinLambda,\n baseClass: baseClass || ZeroBaseClass\n });\n return mixinState.minimalClass;\n};\n//---------------------------------------------------------------------------------------------------------------------\n// this function works both with default mixin class and mixin application function\n// it supplied internally as [Symbol.hasInstance] for the default mixin class and mixin application function\nconst isInstanceOfStatic = function (instance) {\n return Boolean(instance && instance[this[MixinInstanceOfProperty]]);\n};\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * This is the `instanceof` analog for the classes created with [[Mixin]] helper. It also provides [typeguard](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards).\n *\n * There's no strict need to use it, as the native `instanceof` is also supported for the mixins created with the [[Mixin]] helper and also provides\n * typeguarding.\n *\n * @param instance Any value, normally an instance of the mixin class\n * @param func The constructor function of the class, created with [[Mixin]]\n */\nexport const isInstanceOf = (instance, func) => {\n return Boolean(instance && instance[func[MixinInstanceOfProperty]]);\n};\n//---------------------------------------------------------------------------------------\n/**\n * This function allows you to create mixin classes. Mixin classes solves the well-known problem with \"classical\" single-class inheritance,\n * in which class hierarchy must form a tree. When using mixins, class hierarchy becomes an arbitrary acyclic graph.\n *\n * Another view on mixins is that, if \"classical\" class is a point (a vertice of the graph), mixin class is an arrow between the points\n * (an edge in the graph, or rather, a description of the edge).\n *\n * Some background information about the mixin pattern can be found [here](https://mariusschulz.com/blog/typescript-2-2-mixin-classes)\n * and [here](https://www.bryntum.com/blog/the-mixin-pattern-in-typescript-all-you-need-to-know/).\n *\n * The pattern, being described here, is the evolution of the previous work, and main advantage is that it solves the compilation error\n * for circular references.\n *\n * Mixin definition. Requirements\n * ------------------------------\n *\n * The pattern looks like:\n *\n * class Mixin1 extends Mixin(\n * [],\n * (base : AnyConstructor) =>\n *\n * class Mixin1 extends base {\n * prop1 : string\n * method1 () : string {\n * return this.prop1\n * }\n * static static1 : number\n * }\n * ){}\n *\n * The core of the definition above is the mixin lambda - a function which receives a base class as its argument and returns a class,\n * extending the base class with additional properties.\n *\n * The example above creates a mixin `Mixin1` which has no requirements. Requirements are the other mixins,\n * which needs to be included in the base class of this mixin.\n *\n * There's also a special type of the requirement,\n * called \"base class requirement\". It is optional and can only appear as the last argument of the requirements\n * array. It does not have to be a mixin, created with the `Mixin` function, but can be any JS class. This requirement\n * specifies, that the base class of this mixin should be a subclass of the given class (or that class itself).\n *\n * The requirements of the mixin needs to be listed 3 times:\n * - as an array of constructor functions, in the 1st argument of the `Mixin` function\n * - as an instance type intersection, in the 1st type argument for the [[AnyConstructor]] type\n * - as an static type intersection, in the 2nd type argument for the [[AnyConstructor]] type\n *\n * For example, `Mixin2` requires `Mixin1`:\n *\n * class Mixin2 extends Mixin(\n * [ Mixin1 ],\n * (base : AnyConstructor) =>\n *\n * class Mixin2 extends base {\n * }\n * ){}\n *\n * And `Mixin3` requires both `Mixin1` and `Mixin2` (even that its redundant, since `Mixin2` already requires `Mixin1`,\n * but suppose we don't know the implementation details of the `Mixin2`):\n *\n * class Mixin3 extends Mixin(\n * [ Mixin1, Mixin2 ],\n * (base : AnyConstructor) =>\n *\n * class Mixin3 extends base {\n * }\n * ){}\n *\n * Now, `Mixin4` requires `Mixin3`, plus, it requires the base class to be `SomeBaseClass`:\n *\n * class SomeBaseClass {}\n *\n * class Mixin4 extends Mixin(\n * [ Mixin3, SomeBaseClass ],\n * (base : AnyConstructor<\n * Mixin3 & SomeBaseClass, typeof Mixin3 & typeof SomeBaseClass\n * >) =>\n *\n * class Mixin4 extends base {\n * }\n * ){}\n *\n * As already briefly mentioned, the requirements are \"scanned\" deep and included only once. Also all minimal classes are cached -\n * for example the creation of the Mixin3\u00A0will reuse the minimal class of the Mixin2\u00A0instead of creating a new intermediate class.\n * This means that all edges of the mixin dependencies graph are created only once (up to the base class).\n *\n * Requirements can not form cycles - that will generate both compilation error and run-time stack overflow.\n *\n * The typing for the `Mixin` function will provide a compilation error, if the requirements don't match, e.g. some requirement is\n * listed in the array, but missed in the types. This protects you from trivial mistakes. However, the typing is done up to 10 requirements only.\n * If you need more than 10 requirements for the mixin, use the [[MixinAny]] function, which is an exact analog of `Mixin`, but without\n * this type-level protection for requirements mismatch.\n *\n * It is possible to simplify the type of the `base` argument a bit, by using the [[ClassUnion]] helper. However, it seems in certain edge cases\n * it may lead to compilation errors. If your scenarios are not so complex you should give it a try. Using the [[ClassUnion]] helper, the\n * `Mixin3` can be defined as:\n *\n * class Mixin3 extends Mixin(\n * [ Mixin1, Mixin2 ],\n * (base : ClassUnion) =>\n *\n * class Mixin3 extends base {\n * }\n * ){}\n *\n * Note, that due to this [issue](https://github.com/Microsoft/TypeScript/issues/7342), if you use decorators in your mixin class,\n * the declaration needs to be slightly more verbose (can not use compact notation for the arrow functions):\n *\n * class Mixin2 extends Mixin(\n * [ Mixin1 ],\n * (base : AnyConstructor) => {\n * class Mixin2 extends base {\n * @decorator\n * prop2 : string\n * }\n * return Mixin2\n * }\n * ){}\n *\n * As you noticed, the repeating listing of the requirements is somewhat verbose. Suggestions how the pattern can be improved\n * are [very welcomed](mailto:nickolay8@gmail.com).\n *\n * Mixin instantiation. Mixin constructor. `instanceof`\n * --------------------------------\n *\n * You can instantiate any mixin class just by using its constructor:\n *\n * const instance1 = new Mixin1()\n * const instance2 = new Mixin2()\n *\n * As explained in details [here](https://mariusschulz.com/blog/typescript-2-2-mixin-classes), mixin constructor should accept variable number of arguments\n * with the `any` type. This is simply because the mixin is supposed to be applicable to any other base class, which may have its own type\n * of the constructor arguments.\n *\n * class Mixin2 extends Mixin(\n * [ Mixin1 ],\n * (base : AnyConstructor) => {\n * class Mixin2 extends base {\n * prop2 : string\n *\n * constructor (...args: any[]) {\n * super(...args)\n * this.prop2 = ''\n * }\n * }\n * return Mixin2\n * }\n * ){}\n *\n * In other words, its not possible to provide any type-safety for mixin instantiation using regular class constructor.\n *\n * However, if we change the way we create class instances a little, we can get the type-safety back. For that,\n * we need to use a \"uniform\" class constructor - a constructor which has the same form for all classes. The [[Base]] class\n * provides such constructor as its static [[Base.new|new]] method. The usage of `Base` class is not required - you can use\n * any other base class.\n *\n * The `instanceof` operator works as expected for instances of the mixin classes. It also takes into account all the requirements.\n * For example:\n *\n * const instance2 = new Mixin2()\n *\n * const isMixin2 = instance2 instanceof Mixin2 // true\n * const isMixin1 = instance2 instanceof Mixin1 // true, since Mixin2 requires Mixin1\n *\n * See also [[isInstanceOf]].\n *\n * \"Manual\" class derivation\n * --------------------------------\n *\n * You have defined a mixin using the `Mixin` function. Now you want to apply it to some base class to get the \"specific\" class to be able\n * to instantiate it. As described above - you don't have to, you can instantiate it directly.\n *\n * Sometimes however, you still want to derive the class \"manually\". For that, you can use static methods `mix` and `derive`, available\n * on all mixins.\n *\n * The `mix` method provides a direct access to the mixin lambda. It does not take requirements into account - that's the implementor's responsibility.\n * The `derive` method is something like \"accumulated\" mixin lambda - mixin lambda with all requirements.\n *\n * Both `mix` and `derive` provide the reasonably typed outcome.\n *\n * class Mixin1 extends Mixin(\n * [],\n * (base : AnyConstructor) =>\n *\n * class Mixin1 extends base {\n * prop1 : string\n * }\n * ){}\n *\n * class Mixin2 extends Mixin(\n * [ Mixin1 ],\n * (base : AnyConstructor) =>\n *\n * class Mixin2 extends base {\n * prop2 : string\n * }\n * ){}\n *\n * const ManualMixin1 = Mixin1.mix(Object)\n * const ManualMixin2 = Mixin2.mix(Mixin1.mix(Object))\n *\n * const AnotherManualMixin1 = Mixin1.derive(Object)\n * const AnotherManualMixin2 = Mixin2.derive(Object)\n *\n * Generics\n * --------\n *\n * Using generics with mixins is tricky because TypeScript does not have higher-kinded types and type inference for generics. Still some form\n * of generic arguments is possible, using the interface merging trick.\n *\n * Here's the pattern:\n *\n * ```ts\n * class Duplicator extends Mixin(\n * [],\n * (base : AnyConstructor) =>\n *\n * class Duplicator extends base {\n * Element : any\n *\n * duplicate (value : this[ 'Element' ]) : this[ 'Element' ][] {\n * return [ value, value ]\n * }\n * }\n * ){}\n *\n * interface Duplicator {\n * Element : Element\n * }\n *\n * const dup = new Duplicator()\n *\n * dup.duplicate('foo') // TS2345: Argument of type '\"foo\"' is not assignable to parameter of type 'boolean'.\n * ```\n *\n * In the example above, we've defined a generic argument `Element` for the outer mixin class, but in fact, that argument is not used anywhere in the\n * nested class definition in the mixin lambda. Instead, in the nested class, we define a property `Element`, which plays the role of the\n * generic argument.\n *\n * Mixin class methods then can refer to the generic type as `this[ 'Element' ]`.\n *\n * The generic arguments of the outer and nested classes are tied together in the additional interface declaration, which, by TypeScript rules\n * is merged together with the class definition. In this declaration, we specify that property `Element` has type of the `Element` generic argument.\n *\n * Limitations\n * ---------\n *\n * The most important limitation we found (which affect the old pattern as well) is the compilation error, which will be issued for\n * the private/protected methods, when compiling with declarations emitting (*.d.ts files generation).\n *\n * This is a [well-known problem](https://github.com/microsoft/TypeScript/issues/35822) in the TypeScript world \u2013 the *.d.ts files do not represent\n * the internal data structures of the TypeScript compiler well. Instead they use some simplified syntax, optimized for human editing.\n * This is why the compiler may generate false positives in the incremental compilation mode \u2013 it uses *.d.ts files internally.\n *\n * This can be a show-stopper for the people that use declaration files (usually for publishing). Keep in mind though, that you can always\n * publish actual TypeScript sources along with the generated JavaScript files, instead of publishing JavaScript + declarations files.\n *\n */\nexport const Mixin = mixin;\n/**\n * This is an exact analog of the [[Mixin]] function, but without type-level protection for requirements mismatch.\n * It supports unlimited number of requirements.\n */\nexport const MixinAny = mixin;\n", "import { Base } from \"../class/Base.js\";\nimport { CI } from \"../collection/Iterator.js\";\nimport { matchAll } from \"../util/Helpers.js\";\n//---------------------------------------------------------------------------------------------------------------------\nexport const DEBUG = false;\nconst emptyFn = (...args) => undefined;\nexport const DEBUG_ONLY = (func) => DEBUG ? func : emptyFn;\nexport const debug = DEBUG_ONLY((e) => {\n debugger;\n});\n//---------------------------------------------------------------------------------------------------------------------\nexport const warn = DEBUG_ONLY((e) => {\n if (typeof console !== 'undefined')\n console.warn(e);\n});\n//---------------------------------------------------------------------------------------------------------------------\nexport class StackEntry extends Base {\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport class SourceLinePoint extends Base {\n constructor() {\n super(...arguments);\n this.stackEntries = [];\n }\n static fromError(e) {\n const res = SourceLinePoint.new({\n exception: e,\n stackEntries: parseErrorStack(e.stack)\n });\n return res;\n }\n static fromThisCall() {\n const sourceLinePoint = this.fromError(new Error());\n sourceLinePoint.stackEntries.splice(0, 2);\n return sourceLinePoint;\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\n// sample stack\n// Error\n// at exceptionCatcher (http://lh/bryntum-suite/SchedulingEngine/lib/ChronoGraph/environment/Debug.js:15:11)\n// at Function.fromCurrentCall (http://lh/bryntum-suite/SchedulingEngine/lib/ChronoGraph/environment/Debug.js:39:38)\n// at Object.get (http://lh/bryntum-suite/SchedulingEngine/lib/ChronoGraph/replica/Entity.js:31:73)\n// at MinimalGanttProject.set (http://lh/bryntum-suite/SchedulingEngine/lib/ChronoGraph/replica/Entity.js:222:23)\n// at MinimalGanttProject.set data [as data] (http://lh/bryntum-suite/SchedulingEngine/lib/Engine/chrono/ChronoModelMixin.js:48:31)\n// at MinimalGanttProject.construct (http://lh/bryntum-suite/SchedulingEngine/lib/Core/data/Model.js:290:17)\n// at MinimalGanttProject.construct (http://lh/bryntum-suite/SchedulingEngine/lib/Core/mixin/Events.js:236:15)\n// at MinimalGanttProject.construct (http://lh/bryntum-suite/SchedulingEngine/lib/Engine/chrono/ChronoModelMixin.js:21:19)\n// at MinimalGanttProject.construct (http://lh/bryntum-suite/SchedulingEngine/lib/Engine/quark/model/scheduler_basic/SchedulerBasicProjectMixin.js:53:19)\n// at new Base (http://lh/bryntum-suite/SchedulingEngine/lib/Core/Base.js:55:14)\"\nconst parseErrorStack = (stack) => {\n return CI(matchAll(/^ +at\\s*(.*?)\\s*\\((https?:\\/\\/.*?):(\\d+):(\\d+)/gm, stack))\n .map(match => StackEntry.new({\n statement: match[1],\n sourceFile: match[2],\n sourceLine: Number(match[3]),\n sourceCharPos: Number(match[4])\n }))\n .toArray();\n};\n", "import { Effect, Reject } from \"../chrono/Effect.js\";\nimport { Mixin } from \"../class/Mixin.js\";\nimport { isPromise } from \"../util/Helpers.js\";\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Symbol to denote the synchronous calculation context\n */\nexport const ContextSync = Symbol('ContextSync');\n/**\n * Symbol to denote the generator calculation context\n */\nexport const ContextGen = Symbol('ContextGen');\n//---------------------------------------------------------------------------------------------------------------------\nexport class CalculationGen extends Mixin([], (base) => class CalculationGen extends base {\n constructor() {\n super(...arguments);\n this.iterator = undefined;\n this.iterationResult = undefined;\n }\n isCalculationStarted() {\n return Boolean(this.iterator || this.iterationResult);\n }\n isCalculationCompleted() {\n return Boolean(this.iterationResult && this.iterationResult.done);\n }\n get result() {\n return this.iterationResult && this.iterationResult.done ? this.iterationResult.value : undefined;\n }\n startCalculation(onEffect, ...args) {\n const iterator = this.iterator = this.calculation.call(this.context || this, onEffect, ...args);\n return this.iterationResult = iterator.next();\n }\n continueCalculation(value) {\n return this.iterationResult = this.iterator.next(value);\n }\n cleanupCalculation() {\n this.iterationResult = undefined;\n this.iterator = undefined;\n }\n *calculation(onEffect, ...args) {\n throw new Error(\"Abstract method `calculation` called\");\n }\n runSyncWithEffect(onEffect, ...args) {\n this.startCalculation(onEffect, ...args);\n while (!this.isCalculationCompleted()) {\n this.continueCalculation(onEffect(this.iterationResult.value));\n }\n // help to garbage collector\n this.iterator = undefined;\n return this.result;\n }\n async runAsyncWithEffect(onEffect, ...args) {\n this.startCalculation(onEffect, ...args);\n while (!this.isCalculationCompleted()) {\n this.continueCalculation(await onEffect(this.iterationResult.value));\n }\n // help to garbage collector\n this.iterator = undefined;\n return this.result;\n }\n}) {\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport const SynchronousCalculationStarted = Symbol('SynchronousCalculationStarted');\nconst calculationStartedConstant = { value: SynchronousCalculationStarted };\nexport class CalculationSync extends Mixin([], (base) => class CalculationSync extends base {\n constructor() {\n super(...arguments);\n this.iterationResult = undefined;\n }\n isCalculationStarted() {\n return Boolean(this.iterationResult);\n }\n isCalculationCompleted() {\n return Boolean(this.iterationResult && this.iterationResult.done);\n }\n get result() {\n return this.iterationResult && this.iterationResult.done ? this.iterationResult.value : undefined;\n }\n startCalculation(onEffect, ...args) {\n // this assignment allows other code to observe, that calculation has started\n this.iterationResult = calculationStartedConstant;\n return this.iterationResult = {\n done: true,\n value: this.calculation.call(this.context || this, onEffect, ...args)\n };\n }\n continueCalculation(value) {\n throw new Error(\"Can not continue synchronous calculation\");\n }\n cleanupCalculation() {\n this.iterationResult = undefined;\n }\n calculation(onEffect, ...args) {\n throw new Error(\"Abstract method `calculation` called\");\n }\n runSyncWithEffect(onEffect, ...args) {\n this.startCalculation(onEffect, ...args);\n return this.result;\n }\n async runAsyncWithEffect(onEffect, ...args) {\n throw new Error('Can not run synchronous calculation asynchronously');\n }\n}) {\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function runGeneratorSyncWithEffect(effect, func, args, scope) {\n const gen = func.apply(scope || null, args);\n let iteration = gen.next();\n while (!iteration.done) {\n iteration = gen.next(effect(iteration.value));\n }\n return iteration.value;\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport async function runGeneratorAsyncWithEffect(effect, func, args, scope) {\n const gen = func.apply(scope || null, args);\n let iteration = gen.next();\n while (!iteration.done) {\n let effectResolution;\n let repeat = false;\n do {\n repeat = false;\n try {\n effectResolution = effect(iteration.value);\n }\n catch (e) {\n // this is very bad, or even terrible - the high-level `Effect` class is mentioned in the \"primitives\",\n // we compare 'resolution' with the magic string 'Cancel' (defined in Engine) and we also use `Reject`\n // constructor\n // but, we are trying to shove an async handling in sync computation (impossible by definition)\n // so we are desperate, and even seems to work...\n // other piece of this code is in `onComputationCycleHandlerSync` in `Engine/lib/Engine/chrono/Replica.ts`\n if (e instanceof Effect) {\n // @ts-ignore\n let resolution = await effect(e);\n if (resolution === 'Cancel') {\n // @ts-ignore\n effect(Reject(e));\n return;\n }\n else {\n repeat = true;\n }\n }\n }\n } while (repeat);\n if (isPromise(effectResolution))\n iteration = gen.next(await effectResolution);\n else\n iteration = gen.next(effectResolution);\n }\n return iteration.value;\n}\n", "import { Base } from \"../class/Base.js\";\nexport var OnCycleAction;\n(function (OnCycleAction) {\n OnCycleAction[\"Cancel\"] = \"Cancel\";\n OnCycleAction[\"Resume\"] = \"Resume\";\n})(OnCycleAction || (OnCycleAction = {}));\n//---------------------------------------------------------------------------------------------------------------------\nexport const WalkSource = Symbol('WalkSource');\nexport const NOT_VISITED = -1;\nexport const VISITED_TOPOLOGICALLY = -2;\n//---------------------------------------------------------------------------------------------------------------------\nexport class WalkContext extends Base {\n constructor() {\n super(...arguments);\n this.visited = new Map();\n this.toVisit = [];\n this.currentEpoch = 0;\n }\n startFrom(sourceNodes) {\n this.continueFrom(sourceNodes);\n }\n continueFrom(sourceNodes) {\n this.toVisit.push.apply(this.toVisit, sourceNodes.map(node => { return { node: node, from: WalkSource, label: undefined }; }));\n this.walkDepth();\n }\n onNode(node, walkStep) {\n }\n onTopologicalNode(node) {\n }\n onCycle(node, stack) {\n return OnCycleAction.Cancel;\n }\n forEachNext(node, func) {\n throw new Error(\"Abstract method called\");\n }\n collectNext(node, toVisit, visitInfo) {\n throw new Error(\"Abstract method called\");\n }\n getVisitedInfo(node) {\n return this.visited.get(node);\n }\n setVisitedInfo(node, visitedAt, info) {\n if (!info) {\n info = { visitedAt, visitEpoch: this.currentEpoch };\n this.visited.set(node, info);\n }\n else {\n info.visitedAt = visitedAt;\n info.visitEpoch = this.currentEpoch;\n }\n return info;\n }\n walkDepth() {\n const visited = this.visited;\n const toVisit = this.toVisit;\n let depth;\n while (depth = toVisit.length) {\n const node = toVisit[depth - 1].node;\n const visitedInfo = this.getVisitedInfo(node);\n // this supports the \"ahead-of-time\" creation of the \"visited\" entries, which actually lead to improved benchmarks,\n // so it might be a default\n if (visitedInfo && visitedInfo.visitedAt === VISITED_TOPOLOGICALLY && visitedInfo.visitEpoch === this.currentEpoch) {\n toVisit.pop();\n continue;\n }\n if (visitedInfo && visitedInfo.visitEpoch === this.currentEpoch && visitedInfo.visitedAt !== NOT_VISITED) {\n // it is valid to find itself \"visited\", but only if visited at the current depth\n // (which indicates stack unwinding)\n // if the node has been visited at earlier depth - its a cycle\n if (visitedInfo.visitedAt < depth) {\n // ONLY resume if explicitly returned `Resume`, cancel in all other cases (undefined, etc)\n if (this.onCycle(node, toVisit) !== OnCycleAction.Resume)\n break;\n }\n else {\n visitedInfo.visitedAt = VISITED_TOPOLOGICALLY;\n this.onTopologicalNode(node);\n }\n toVisit.pop();\n }\n else {\n // if we break here, we can re-enter the loop later\n if (this.onNode(node, toVisit[depth - 1]) === false)\n break;\n // first entry to the node\n const visitedInfo2 = this.setVisitedInfo(node, depth, visitedInfo);\n const lengthBefore = toVisit.length;\n this.collectNext(node, toVisit, visitedInfo2);\n // if there's no outgoing edges, node is at topological position\n // it would be enough to just continue the `while` loop and the `onTopologicalNode`\n // would happen on next iteration, but with this \"inlining\" we save one call to `visited.get()`\n // at the cost of length comparison\n if (toVisit.length === lengthBefore) {\n visitedInfo2.visitedAt = VISITED_TOPOLOGICALLY;\n this.onTopologicalNode(node);\n toVisit.pop();\n }\n }\n }\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport function cycleInfo(stack) {\n const length = stack.length;\n if (length === 0)\n return [];\n const cycleSource = stack[length - 1].node;\n const cycle = [cycleSource];\n let current = length - 1;\n let cursor = current;\n while (current >= 0 && stack[current].from !== cycleSource) {\n // going backward in steps, skipping the nodes with identical `from`\n while (current >= 0 && stack[current].from === stack[cursor].from)\n current--;\n if (current >= 0) {\n // the first node with different `from` will be part of the cycle path\n cycle.push(stack[current].node);\n cursor = current;\n }\n }\n // no cycle\n if (current < 0)\n return [];\n cycle.push(cycleSource);\n return cycle.reverse();\n}\n", "import { MixinAny } from \"../class/Mixin.js\";\nimport { NOT_VISITED } from \"../graph/WalkDepth.js\";\nimport { MAX_SMI, MIN_SMI } from \"../util/Helpers.js\";\n//---------------------------------------------------------------------------------------------------------------------\nexport var EdgeType;\n(function (EdgeType) {\n EdgeType[EdgeType[\"Normal\"] = 1] = \"Normal\";\n EdgeType[EdgeType[\"Past\"] = 2] = \"Past\";\n})(EdgeType || (EdgeType = {}));\nlet ORIGIN_ID = 0;\n//---------------------------------------------------------------------------------------------------------------------\nexport class Quark extends MixinAny([Map], (base) => class Quark extends base {\n constructor() {\n super(...arguments);\n this.identifier = undefined;\n // quark state\n this.value = undefined;\n this.proposedValue = undefined;\n this.proposedIsPrevious = false;\n this.proposedArguments = undefined;\n this.usedProposedOrPrevious = false;\n // eof quark state\n this.previous = undefined;\n this.origin = undefined;\n this.originId = MIN_SMI;\n this.needToBuildProposedValue = false;\n this.edgesFlow = 0;\n this.visitedAt = NOT_VISITED;\n this.visitEpoch = 0;\n this.promise = undefined;\n this.$outgoingPast = undefined;\n }\n static new(props) {\n const instance = new this();\n props && Object.assign(instance, props);\n return instance;\n }\n get level() {\n return this.identifier.level;\n }\n get calculation() {\n return this.identifier.calculation;\n }\n get context() {\n return this.identifier.context || this.identifier;\n }\n forceCalculation() {\n this.edgesFlow = MAX_SMI;\n }\n cleanup() {\n this.cleanupCalculation();\n }\n isShadow() {\n return Boolean(this.origin && this.origin !== this);\n }\n resetToEpoch(epoch) {\n this.visitEpoch = epoch;\n this.visitedAt = NOT_VISITED;\n // we were clearing the edgeFlow on epoch change, however see `030_propagation_2.t.ts` for a counter-example\n if (this.edgesFlow < 0)\n this.edgesFlow = 0;\n this.usedProposedOrPrevious = false;\n this.cleanupCalculation();\n // if there's no value, then generally should be no outgoing edges\n // (which indicates that the value has been used somewhere else)\n // but there might be outgoing \"past\" edges, created if `HasProposedValue`\n // or similar effect has been used on the identifier\n // if (this.value !== undefined) this.clearOutgoing()\n // the `this.value !== undefined` condition above smells very \"monkey-patching\"\n // it was probably solving some specific problem in Gantt/SchedulerPro\n // (engine tests seems to pass w/o it)\n // in general, should always clear the outgoing edges on new epoch\n this.clearOutgoing();\n this.promise = undefined;\n if (this.origin && this.origin === this) {\n this.proposedArguments = undefined;\n // only overwrite the proposed value if the actual value has been already calculated\n // otherwise, keep the proposed value as is\n if (this.value !== undefined) {\n this.proposedValue = this.value;\n }\n this.value = undefined;\n }\n else {\n this.origin = undefined;\n this.value = undefined;\n }\n if (this.identifier.proposedValueIsBuilt && this.proposedValue !== TombStone) {\n this.needToBuildProposedValue = true;\n this.proposedValue = undefined;\n }\n }\n copyFrom(origin) {\n this.value = origin.value;\n this.proposedValue = origin.proposedValue;\n this.proposedArguments = origin.proposedArguments;\n this.usedProposedOrPrevious = origin.usedProposedOrPrevious;\n }\n clearProperties() {\n this.value = undefined;\n this.proposedValue = undefined;\n this.proposedArguments = undefined;\n }\n mergePreviousOrigin(latestScope) {\n const origin = this.origin;\n if (origin !== this.previous)\n throw new Error(\"Invalid state\");\n this.copyFrom(origin);\n const outgoing = this.getOutgoing();\n for (const [identifier, quark] of origin.getOutgoing()) {\n const ownOutgoing = outgoing.get(identifier);\n if (!ownOutgoing) {\n const latest = latestScope.get(identifier);\n if (!latest || latest.originId === quark.originId)\n outgoing.set(identifier, latest || quark);\n }\n }\n if (origin.$outgoingPast !== undefined) {\n const outgoingPast = this.getOutgoingPast();\n for (const [identifier, quark] of origin.getOutgoingPast()) {\n const ownOutgoing = outgoingPast.get(identifier);\n if (!ownOutgoing) {\n const latest = latestScope.get(identifier);\n if (!latest || latest.originId === quark.originId)\n outgoingPast.set(identifier, latest || quark);\n }\n }\n }\n // changing `origin`, but keeping `originId`\n this.origin = this;\n // some help for garbage collector\n origin.clearProperties();\n origin.clear();\n }\n setOrigin(origin) {\n this.origin = origin;\n this.originId = origin.originId;\n }\n getOrigin() {\n if (this.origin)\n return this.origin;\n return this.startOrigin();\n }\n startOrigin() {\n this.originId = ORIGIN_ID++;\n return this.origin = this;\n }\n getOutgoing() {\n return this;\n }\n getOutgoingPast() {\n if (this.$outgoingPast !== undefined)\n return this.$outgoingPast;\n return this.$outgoingPast = new Map();\n }\n addOutgoingTo(toQuark, type) {\n const outgoing = type === EdgeType.Normal ? this : this.getOutgoingPast();\n outgoing.set(toQuark.identifier, toQuark);\n }\n clearOutgoing() {\n this.clear();\n if (this.$outgoingPast !== undefined)\n this.$outgoingPast.clear();\n }\n getValue() {\n const origin = this.origin;\n return origin === this\n ? this.value\n : origin\n ? origin.getValue()\n : undefined;\n }\n setValue(value) {\n if (this.origin && this.origin !== this)\n throw new Error('Can not set value to the shadow entry');\n this.getOrigin().value = value;\n // // @ts-ignore\n // if (value !== TombStone) this.identifier.DATA = value\n }\n hasValue() {\n return this.getValue() !== undefined;\n }\n hasProposedValue() {\n if (this.isShadow())\n return false;\n return this.hasProposedValueInner();\n }\n hasProposedValueInner() {\n return this.proposedValue !== undefined;\n }\n getProposedValue(transaction) {\n if (this.needToBuildProposedValue) {\n this.proposedValue = this.identifier.buildProposedValue.call(this.identifier.context || this.identifier, this.identifier, this, transaction);\n // setting this flag _after_ attempt to build the proposed value, because it might actually throw\n // (if there's a cycle during sync computation, like during `effectiveDirection`)\n // in such case, we need to re-enter this block\n this.needToBuildProposedValue = false;\n }\n return this.proposedValue;\n }\n outgoingInTheFutureCb(revision, forEach) {\n let current = this;\n while (current) {\n for (const outgoing of current.getOutgoing().values()) {\n if (outgoing.originId === revision.getLatestEntryFor(outgoing.identifier).originId)\n forEach(outgoing);\n }\n if (current.isShadow())\n current = current.previous;\n else\n current = null;\n }\n }\n outgoingInTheFutureAndPastCb(revision, forEach) {\n let current = this;\n while (current) {\n for (const outgoing of current.getOutgoing().values()) {\n const latestEntry = revision.getLatestEntryFor(outgoing.identifier);\n if (latestEntry && outgoing.originId === latestEntry.originId)\n forEach(outgoing);\n }\n if (current.$outgoingPast !== undefined) {\n for (const outgoing of current.$outgoingPast.values()) {\n const latestEntry = revision.getLatestEntryFor(outgoing.identifier);\n if (latestEntry && outgoing.originId === latestEntry.originId)\n forEach(outgoing);\n }\n }\n if (current.isShadow())\n current = current.previous;\n else\n current = null;\n }\n }\n outgoingInTheFutureAndPastTransactionCb(transaction, forEach) {\n let current = this;\n while (current) {\n for (const outgoing of current.getOutgoing().values()) {\n const latestEntry = transaction.getLatestStableEntryFor(outgoing.identifier);\n if (latestEntry && outgoing.originId === latestEntry.originId)\n forEach(outgoing);\n }\n if (current.$outgoingPast !== undefined) {\n for (const outgoing of current.$outgoingPast.values()) {\n const latestEntry = transaction.getLatestStableEntryFor(outgoing.identifier);\n if (latestEntry && outgoing.originId === latestEntry.originId)\n forEach(outgoing);\n }\n }\n if (current.isShadow())\n current = current.previous;\n else\n current = null;\n }\n }\n // ignores the \"past\" edges by design, as they do not form cycles\n outgoingInTheFutureTransactionCb(transaction, forEach) {\n let current = this;\n while (current) {\n for (const outgoing of current.getOutgoing().values()) {\n const latestEntry = transaction.getLatestEntryFor(outgoing.identifier);\n if (latestEntry && outgoing.originId === latestEntry.originId)\n forEach(outgoing);\n }\n if (current.isShadow())\n current = current.previous;\n else\n current = null;\n }\n }\n}) {\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport const TombStone = Symbol('Tombstone');\n", "var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nimport { Base } from \"../class/Base.js\";\nimport { CalculationGen, CalculationSync } from \"../primitives/Calculation.js\";\nimport { prototypeValue } from \"../util/Helpers.js\";\nimport { ProposedOrPrevious } from \"./Effect.js\";\nimport { Quark } from \"./Quark.js\";\n//---------------------------------------------------------------------------------------------------------------------\n/**\nLevels of the [[Identifier|identifiers]] as simple integers. Defines the order of calculation, enforced by the following rule -\nall lower level identifiers should be already calculated before the calculation of the identifier with the higher level starts.\nBecause of this, the lower level identifiers can not depend on higher level identifiers.\nThis rule means that effects from all identifiers of the lower levels will be already processed, when calculating\nan identifier of the higher level.\nNormally you don't need to specify a level for your identifiers.\n*/\nexport var Levels;\n(function (Levels) {\n // must be sync\n Levels[Levels[\"UserInput\"] = 0] = \"UserInput\";\n Levels[Levels[\"DependsOnlyOnUserInput\"] = 1] = \"DependsOnlyOnUserInput\";\n Levels[Levels[\"DependsOnlyOnDependsOnlyOnUserInput\"] = 2] = \"DependsOnlyOnDependsOnlyOnUserInput\";\n // asynchronicity starts from here\n Levels[Levels[\"DependsOnSelfKind\"] = 3] = \"DependsOnSelfKind\";\n})(Levels || (Levels = {}));\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * The base class for [[Identifier|identifiers]]. It contains only \"meta\" properties that describes \"abstract\" identifier.\n * The [[Field]] class inherit from this class.\n *\n * To understand the difference between the \"abstract\" identifier and the \"specific\" identifier,\n * imagine a set of instances of the same entity class. Lets say that class has a field \"name\".\n * All of those instances each will have different \"specific\" identifiers for the field \"name\".\n *\n * In the same time, some properties are common for all \"specific\" identifiers, like [[Meta.equality|equality]], [[Meta.lazy|lazy]] etc.\n * Such properties, that does not change between every \"specific\" identifier we will call \"meta\" properties.\n *\n * This class has 2 generic arguments - `ValueT` and `ContextT`. The 1st one defines the type of the identifier's value.\n * The 2nd - the identifier's computation context (synchronous of generator).\n */\nexport class Meta extends Base {\n constructor() {\n super(...arguments);\n /**\n * The name of the identifiers. Not an id, does not imply uniqueness.\n */\n this.name = undefined;\n /**\n * Whether this identifier is lazy (`true`) or strict (`false`).\n *\n * Lazy identifiers are calculated on-demand (when read from graph or used by another identifiers).\n *\n * Strict identifiers will be calculated on read or during the [[ChronoGraph.commit|commit]] call.\n */\n this.lazy = false;\n // no cancels\n this.total = true;\n // no \"nested\" writes\n this.pure = true;\n this.proposedValueIsBuilt = false;\n }\n /**\n * The calculation function of the identifier. Its returning value has a generic type, that is converted to a specific type,\n * based on the generic attribute `ContextT`.\n *\n * This function will receive a single argument - current calculation context (effects handler).\n *\n * When using generators, there's no need to use this handler - one can \"yield\" the value directly, using the `yield` construct.\n *\n * Compare:\n *\n * class Author extends Entity.mix(Base) {\n * @field()\n * firstName : string\n * @field()\n * lastName : string\n * @field()\n * fullName : string\n *\n * @calculate('fullName')\n * * calculateFullName () : ChronoIterator {\n * return (yield this.$.firstName) + ' ' + (yield this.$.lastName)\n * }\n *\n * @calculate('fullName')\n * calculateFullName (Y) : string {\n * return Y(this.$.firstName) + ' ' + Y(this.$.lastName)\n * }\n * }\n *\n * @param Y\n */\n calculation(Y) {\n throw new Error(\"Abstract method `calculation` called\");\n }\n /**\n * The equality check of the identifier. By default is performed with `===`.\n *\n * @param v1 First value\n * @param v2 Second value\n */\n equality(v1, v2) {\n return v1 === v2;\n }\n}\n__decorate([\n prototypeValue(Levels.DependsOnSelfKind)\n], Meta.prototype, \"level\", void 0);\n__decorate([\n prototypeValue(true)\n], Meta.prototype, \"sync\", void 0);\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * The generic \"specific\" identifier class (see [[Meta]] for \"abstract\" properties). This class is generic in the sense that it does not\n * specify the type of the calculation function - it can be either synchronous or generator-based.\n *\n * It is also low-level and generally not supposed to be used directly in the application. Instead, one should\n * declare identifiers as fields (decorated class properties) in the [[Replica|replica]].\n */\nexport class Identifier extends Meta {\n constructor() {\n super(...arguments);\n /**\n * The scope (`this` value) for the calculation function.\n */\n this.context = undefined;\n // flag to set during the `write` inside the `addIdentifier` call\n this.isWritingUndefined = false;\n }\n newQuark(createdAt) {\n // micro-optimization - we don't pass a config object to the `new` constructor\n // but instead assign directly to instance\n const newQuark = this.quarkClass.new();\n newQuark.identifier = this;\n newQuark.needToBuildProposedValue = this.proposedValueIsBuilt;\n return newQuark;\n }\n write(me, transaction, quark, proposedValue, ...args) {\n quark = quark || transaction.getWriteTarget(me);\n quark.proposedValue = proposedValue;\n quark.proposedArguments = args.length > 0 ? args : undefined;\n quark.proposedIsPrevious = transaction.graph.isWritingPreviousData;\n }\n writeToTransaction(transaction, proposedValue, ...args) {\n transaction.write(this, proposedValue, ...args);\n }\n /**\n * Write a value to this identifier, in the context of `graph`.\n *\n * @param graph\n * @param proposedValue\n * @param args\n */\n writeToGraph(graph, proposedValue, ...args) {\n graph.write(this, proposedValue, ...args);\n }\n /**\n * Read the value of this identifier, in the context of `graph`, asynchronously\n * @param graph\n */\n readFromGraphAsync(graph) {\n return graph.readAsync(this);\n }\n /**\n * Read the value of this identifier, in the context of `graph`, synchronously\n * @param graph\n */\n readFromGraph(graph) {\n return graph.read(this);\n }\n readFromTransaction(transaction) {\n return transaction.read(this);\n }\n readFromTransactionAsync(transaction) {\n return transaction.readAsync(this);\n }\n // readFromGraphDirtySync (graph : CheckoutI) : ValueT {\n // return graph.readDirty(this)\n // }\n buildProposedValue(me, quark, transaction) {\n return undefined;\n }\n /**\n * Template method, which is called, when this identifier \"enters\" the graph.\n *\n * @param graph\n */\n enterGraph(graph) {\n }\n /**\n * Template method, which is called, when this identifier \"leaves\" the graph.\n *\n * @param graph\n */\n leaveGraph(graph) {\n }\n}\n/**\n * Constructor for the [[Identifier]] class. Used only for typization purposes, to be able to specify the generics arguments.\n */\nexport const IdentifierC = (config) => Identifier.new(config);\n//@ts-ignore\nexport const QuarkSync = Quark.mix(CalculationSync.mix(Map));\n//@ts-ignore\nexport const QuarkGen = Quark.mix(CalculationGen.mix(Map));\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Variable is a subclass of [[Identifier]], that does not perform any calculation and instead is always equal to a user-provided value.\n * It is a bit more light-weight\n */\nexport class Variable extends Identifier {\n calculation(YIELD) {\n throw new Error(\"The 'calculation' method of the variables should never be called. Instead, the value will be set directly to quark\");\n }\n write(me, transaction, quark, proposedValue, ...args) {\n quark = quark || transaction.getWriteTarget(me);\n quark.value = proposedValue;\n quark.proposedArguments = args.length > 0 ? args : undefined;\n }\n}\n__decorate([\n prototypeValue(Levels.UserInput)\n], Variable.prototype, \"level\", void 0);\n__decorate([\n prototypeValue(QuarkSync)\n], Variable.prototype, \"quarkClass\", void 0);\n/**\n * Constructor for the [[Variable]] class. Used only for typization purposes.\n */\nexport function VariableC(...args) {\n return Variable.new(...args);\n}\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Subclass of the [[Identifier]], representing synchronous computation.\n */\nexport class CalculatedValueSync extends Identifier {\n calculation(YIELD) {\n return YIELD(ProposedOrPrevious);\n }\n}\n__decorate([\n prototypeValue(QuarkSync)\n], CalculatedValueSync.prototype, \"quarkClass\", void 0);\n/**\n * Constructor for the [[CalculatedValueSync]] class. Used only for typization purposes.\n */\nexport function CalculatedValueSyncC(...args) {\n return CalculatedValueSync.new(...args);\n}\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Subclass of the [[Identifier]], representing generator-based computation.\n */\nexport class CalculatedValueGen extends Identifier {\n *calculation(YIELD) {\n return yield ProposedOrPrevious;\n }\n}\n__decorate([\n prototypeValue(QuarkGen)\n], CalculatedValueGen.prototype, \"quarkClass\", void 0);\n/**\n * Constructor for the [[CalculatedValueGen]] class. Used only for typization purposes.\n */\nexport function CalculatedValueGenC(...args) {\n return CalculatedValueGen.new(...args);\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport const throwUnknownIdentifier = (identifier) => { throw new Error(`Unknown identifier ${identifier}`); };\n", "import { Base } from \"../class/Base.js\";\nimport { TombStone } from \"./Quark.js\";\nlet CLOCK = 0;\nexport class Revision extends Base {\n constructor() {\n super(...arguments);\n this.createdAt = CLOCK++;\n this.name = 'revision-' + this.createdAt;\n this.previous = undefined;\n this.scope = new Map();\n this.reachableCount = 0;\n this.referenceCount = 0;\n this.selfDependent = new Set();\n }\n getLatestEntryFor(identifier) {\n let revision = this;\n while (revision) {\n const entry = revision.scope.get(identifier);\n if (entry)\n return entry;\n revision = revision.previous;\n }\n return null;\n }\n hasIdentifier(identifier) {\n const latestEntry = this.getLatestEntryFor(identifier);\n return Boolean(latestEntry && latestEntry.getValue() !== TombStone);\n }\n *previousAxis() {\n let revision = this;\n while (revision) {\n yield revision;\n revision = revision.previous;\n }\n }\n}\n", "import { MAX_SMI } from \"./Helpers.js\";\n// Leveled LIFO queue\nexport class LeveledQueue {\n constructor() {\n this.length = 0;\n this.levels = [];\n this.lowestLevel = MAX_SMI;\n }\n getLowestLevel() {\n for (let i = this.lowestLevel !== MAX_SMI ? this.lowestLevel : 0; i < this.levels.length; i++) {\n if (this.levels[i])\n return this.lowestLevel = i;\n }\n return this.lowestLevel = MAX_SMI;\n }\n takeLowestLevel() {\n for (let i = this.lowestLevel !== MAX_SMI ? this.lowestLevel : 0; i < this.levels.length; i++) {\n const level = this.levels[i];\n if (level) {\n this.length -= level.length;\n this.levels[i] = null;\n this.lowestLevel = i + 1;\n return level;\n }\n }\n }\n // resetCachedPosition () {\n // this.lowestLevel = MAX_SMI\n // }\n // last () {\n // for (let i = this.lowestLevel !== MAX_SMI ? this.lowestLevel : 0; i < this.levels.length; i++) {\n // const level = this.levels[ i ]\n //\n // if (level && level.length > 0) {\n // this.lowestLevel = i\n //\n // return level[ level.length - 1 ]\n // }\n // }\n // }\n pop() {\n for (let i = this.lowestLevel !== MAX_SMI ? this.lowestLevel : 0; i < this.levels.length; i++) {\n const level = this.levels[i];\n this.lowestLevel = i;\n if (level && level.length > 0) {\n this.length--;\n return level.pop();\n }\n }\n this.lowestLevel = MAX_SMI;\n }\n push(el) {\n const elLevel = el.level;\n let level = this.levels[elLevel];\n if (!level) {\n // avoid holes in the array\n for (let i = this.levels.length; i < elLevel; i++)\n this.levels[i] = null;\n level = this.levels[elLevel] = [];\n }\n level.push(el);\n this.length++;\n if (elLevel < this.lowestLevel)\n this.lowestLevel = elLevel;\n }\n *[Symbol.iterator]() {\n for (let i = 0; i < this.levels.length; i++) {\n const level = this.levels[i];\n if (level)\n yield* level;\n }\n }\n}\n", "import { Base } from \"../class/Base.js\";\nimport { NOT_VISITED, OnCycleAction, WalkContext } from \"../graph/WalkDepth.js\";\n//---------------------------------------------------------------------------------------------------------------------\nexport class ComputationCycle extends Base {\n toString() {\n const cycleIdentifiers = [];\n const cycleEvents = [];\n this.cycle.forEach(({ name, context }) => {\n cycleIdentifiers.push(name);\n if (cycleEvents[cycleEvents.length - 1] !== context)\n cycleEvents.push(context);\n });\n return 'events: \\n' +\n cycleEvents.map(event => '#' + event.id).join(' => ') +\n '\\n\\nidentifiers: \\n' +\n cycleIdentifiers.join('\\n');\n // return this.cycle.map(identifier => {\n // return identifier.name\n // // //@ts-ignore\n // // const sourcePoint : SourceLinePoint = identifier.SOURCE_POINT\n // //\n // // if (!sourcePoint) return identifier.name\n // //\n // // const firstEntry = sourcePoint.stackEntries[ 0 ]\n // //\n // // if (firstEntry) {\n // // return `${identifier}\\n yielded at ${firstEntry.sourceFile}:${firstEntry.sourceLine}:${firstEntry.sourceCharPos || ''}`\n // // } else\n // // return identifier.name\n // }).join(' => \\n')\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport class TransactionCycleDetectionWalkContext extends WalkContext {\n constructor() {\n // baseRevision : Revision = undefined\n super(...arguments);\n this.transaction = undefined;\n }\n onCycle(node, stack) {\n return OnCycleAction.Cancel;\n }\n doCollectNext(from, to, toVisit) {\n let visit = this.visited.get(to);\n if (!visit) {\n visit = { visitedAt: NOT_VISITED, visitEpoch: this.currentEpoch };\n this.visited.set(to, visit);\n }\n toVisit.push({ node: to, from, label: undefined });\n }\n collectNext(from, toVisit) {\n const latestEntry = this.transaction.getLatestEntryFor(from);\n if (latestEntry) {\n latestEntry.outgoingInTheFutureTransactionCb(this.transaction, outgoingEntry => {\n this.doCollectNext(from, outgoingEntry.identifier, toVisit);\n });\n }\n // for (const outgoingIdentifier of visitInfo.getOutgoing().keys()) {\n // this.doCollectNext(from, outgoingIdentifier, toVisit)\n // }\n }\n}\n", "import { Base } from \"../class/Base.js\";\nimport { NOT_VISITED, OnCycleAction, VISITED_TOPOLOGICALLY } from \"../graph/WalkDepth.js\";\nimport { Levels } from \"./Identifier.js\";\n//---------------------------------------------------------------------------------------------------------------------\nexport class TransactionWalkDepth extends Base {\n constructor() {\n super(...arguments);\n this.visited = new Map();\n this.transaction = undefined;\n this.baseRevision = undefined;\n this.pushTo = undefined;\n this.toVisit = [];\n this.currentEpoch = 0;\n }\n startFrom(sourceNodes) {\n this.continueFrom(sourceNodes);\n }\n continueFrom(sourceNodes) {\n this.toVisit.push.apply(this.toVisit, sourceNodes);\n this.walkDepth();\n }\n startNewEpoch() {\n if (this.toVisit.length)\n throw new Error(\"Can not start new walk epoch in the middle of the walk\");\n this.currentEpoch++;\n }\n onTopologicalNode(identifier, visitInfo) {\n if (!identifier.lazy && identifier.level !== Levels.UserInput)\n this.pushTo.push(visitInfo);\n }\n onCycle(node, stack) {\n return OnCycleAction.Resume;\n }\n // it is more efficient (=faster) to create new quarks for yet unvisited identifiers\n // in batches, using this method, instead of in normal flow in the `walkDepth` method\n // this is probably because of the CPU context switch between the `this.visited` and `this.baseRevision.getLatestEntryFor`\n doCollectNext(from, to, toVisit) {\n let quark = this.visited.get(to);\n if (!quark) {\n quark = to.newQuark(this.baseRevision);\n quark.visitEpoch = this.currentEpoch;\n this.visited.set(to, quark);\n }\n toVisit.push(to);\n }\n collectNext(from, toVisit, visitInfo) {\n const latestEntry = this.baseRevision.getLatestEntryFor(from);\n if (latestEntry) {\n // since `collectNext` is called exactly once for every node, all quarks\n // will have the `previous` property populated\n visitInfo.previous = latestEntry;\n latestEntry.outgoingInTheFutureAndPastTransactionCb(this.transaction, outgoingEntry => {\n this.doCollectNext(from, outgoingEntry.identifier, toVisit);\n });\n }\n for (const outgoingIdentifier of visitInfo.getOutgoing().keys()) {\n this.doCollectNext(from, outgoingIdentifier, toVisit);\n }\n if (visitInfo.$outgoingPast !== undefined)\n for (const outgoingIdentifier of visitInfo.getOutgoingPast().keys()) {\n this.doCollectNext(from, outgoingIdentifier, toVisit);\n }\n }\n walkDepth() {\n const visited = this.visited;\n const toVisit = this.toVisit;\n let depth;\n while (depth = toVisit.length) {\n const node = toVisit[depth - 1];\n let visitInfo = visited.get(node);\n if (visitInfo && visitInfo.visitedAt === VISITED_TOPOLOGICALLY && visitInfo.visitEpoch === this.currentEpoch) {\n visitInfo.edgesFlow++;\n toVisit.pop();\n continue;\n }\n if (visitInfo && visitInfo.visitEpoch === this.currentEpoch && visitInfo.visitedAt !== NOT_VISITED) {\n // it is valid to find itself \"visited\", but only if visited at the current depth\n // (which indicates stack unwinding)\n // if the node has been visited at earlier depth - its a cycle\n if (visitInfo.visitedAt < depth) {\n // ONLY resume if explicitly returned `Resume`, cancel in all other cases (undefined, etc)\n if (this.onCycle(node, toVisit) !== OnCycleAction.Resume)\n break;\n visitInfo.edgesFlow++;\n }\n else {\n visitInfo.visitedAt = VISITED_TOPOLOGICALLY;\n this.onTopologicalNode(node, visitInfo);\n }\n toVisit.pop();\n }\n else {\n const lengthBefore = toVisit.length;\n if (!visitInfo) {\n visitInfo = node.newQuark(this.baseRevision);\n visitInfo.visitEpoch = this.currentEpoch;\n visited.set(node, visitInfo);\n }\n this.collectNext(node, toVisit, visitInfo);\n if (visitInfo.visitEpoch < this.currentEpoch) {\n visitInfo.resetToEpoch(this.currentEpoch);\n }\n visitInfo.visitedAt = depth;\n visitInfo.edgesFlow++;\n // if there's no outgoing edges, node is at topological position\n // it would be enough to just continue the `while` loop and the `onTopologicalNode`\n // would happen on next iteration, but with this \"inlining\" we save one call to `visited.get()`\n // at the cost of length comparison\n if (toVisit.length === lengthBefore) {\n visitInfo.visitedAt = VISITED_TOPOLOGICALLY;\n this.onTopologicalNode(node, visitInfo);\n toVisit.pop();\n }\n }\n }\n }\n}\n", "import { Base } from \"../class/Base.js\";\nimport { DEBUG } from \"../environment/Debug.js\";\nimport { cycleInfo, OnCycleAction } from \"../graph/WalkDepth.js\";\nimport { runGeneratorAsyncWithEffect, SynchronousCalculationStarted } from \"../primitives/Calculation.js\";\nimport { delay, isPromise, MAX_SMI } from \"../util/Helpers.js\";\nimport { LeveledQueue } from \"../util/LeveledQueue.js\";\nimport { BreakCurrentStackExecution, RejectEffect } from \"./Effect.js\";\nimport { Identifier, Levels, throwUnknownIdentifier } from \"./Identifier.js\";\nimport { EdgeType, TombStone } from \"./Quark.js\";\nimport { Revision } from \"./Revision.js\";\nimport { ComputationCycle, TransactionCycleDetectionWalkContext } from \"./TransactionCycleDetectionWalkContext.js\";\nimport { TransactionWalkDepth } from \"./TransactionWalkDepth.js\";\n//---------------------------------------------------------------------------------------------------------------------\n// weird stack overflow on 1300 deep benchmark, when using `EdgeType.Normal` w/o aliasing it to constant first\nexport const EdgeTypeNormal = EdgeType.Normal;\nexport const EdgeTypePast = EdgeType.Past;\n//---------------------------------------------------------------------------------------------------------------------\nexport class Transaction extends Base {\n constructor() {\n super(...arguments);\n this.baseRevision = undefined;\n this.candidateClass = Revision;\n this.candidate = undefined;\n this.graph = undefined;\n this.isClosed = false;\n this.walkContext = undefined;\n this.entries = new Map();\n // // we use 2 different stacks, because they support various effects\n // stackSync : LeveledQueue = new LeveledQueue()\n // the `stackGen` supports async effects notably\n this.stackGen = new LeveledQueue();\n // is used for tracking the active quark entry (quark entry being computed)\n this.activeStack = [];\n this.onEffectSync = undefined;\n this.onEffectAsync = undefined;\n //---------------------\n this.propagationStartDate = 0;\n this.lastProgressNotificationDate = 0;\n this.startProgressNotificationsAfterMs = 500;\n this.emitProgressNotificationsEveryMs = 200;\n this.emitProgressNotificationsEveryCalculations = 100;\n this.plannedTotalIdentifiersToCalculate = 0;\n // writes : WriteInfo[] = []\n this.ongoing = Promise.resolve();\n this.selfDependedMarked = false;\n this.rejectedWith = undefined;\n this.stopped = false;\n this.hasEntryWithProposedValue = false;\n this.hasVariableEntry = false;\n }\n initialize(...args) {\n super.initialize(...args);\n this.walkContext = TransactionWalkDepth.new({\n visited: this.entries,\n transaction: this,\n baseRevision: this.baseRevision,\n pushTo: this.stackGen\n });\n if (!this.candidate)\n this.candidate = this.candidateClass.new({ previous: this.baseRevision });\n // the `onEffectSync` should be bound to the `yieldSync` of course, and `yieldSync` should look like:\n // yieldSync (effect : YieldableValue) : any {\n // if (effect instanceof Identifier) return this.read(effect)\n // }\n // however, the latter consumes more stack frames - every read goes through `yieldSync`\n // since `read` is the most used effect anyway, we bind `onEffectSync` to `read` and\n // instead inside of `read` delegate to `yieldSync` for non-identifiers\n this.onEffectSync = /*this.onEffectAsync =*/ this.read.bind(this);\n this.onEffectAsync = this.readAsync.bind(this);\n }\n get dirty() {\n return this.entries.size > 0;\n }\n markSelfDependent() {\n if (this.selfDependedMarked)\n return;\n this.selfDependedMarked = true;\n for (const selfDependentIden of this.baseRevision.selfDependent) {\n const existing = this.entries.get(selfDependentIden);\n if (existing && existing.getValue() === TombStone)\n continue;\n this.touch(selfDependentIden);\n }\n }\n // onNewWrite () {\n // this.writes.forEach(writeInfo => {\n // const identifier = writeInfo.identifier\n //\n // identifier.write.call(identifier.context || identifier, identifier, this, null, ...writeInfo.proposedArgs)\n // })\n //\n // this.writes.length = 0\n // }\n getActiveEntry() {\n return this.activeStack[this.activeStack.length - 1];\n // // `stackSync` is always empty, except when the synchronous \"batch\" is being processed\n // const activeStack = this.stackSync.length > 0 ? this.stackSync : this.stackGen\n //\n // return activeStack.last()\n }\n yieldAsync(effect) {\n if (isPromise(effect))\n return effect;\n return this.graph[effect.handler](effect, this);\n }\n // see the comment for the `onEffectSync`\n yieldSync(effect) {\n if (isPromise(effect)) {\n throw new Error(\"Can not yield a promise in the synchronous context\");\n }\n return this.graph[effect.handler](effect, this);\n }\n // this seems to be an optimistic version\n readAsync(identifier) {\n // see the comment for the `onEffectSync`\n if (!(identifier instanceof Identifier))\n return this.yieldAsync(identifier);\n let entry;\n const activeEntry = this.getActiveEntry();\n if (activeEntry) {\n entry = this.addEdge(identifier, activeEntry, EdgeTypeNormal);\n }\n else {\n entry = this.entries.get(identifier);\n if (!entry) {\n const previousEntry = this.baseRevision.getLatestEntryFor(identifier);\n if (!previousEntry)\n throwUnknownIdentifier(identifier);\n entry = previousEntry.hasValue() ? previousEntry : this.touch(identifier);\n }\n }\n if (entry.hasValue())\n return entry.getValue();\n if (entry.promise)\n return entry.promise;\n //----------------------\n // now need to repeat the logic\n if (!entry.previous || !entry.previous.hasValue())\n entry.forceCalculation();\n return this.ongoing = entry.promise = this.ongoing.then(() => {\n return (async () => {\n //----------------------\n while (this.stackGen.lowestLevel < identifier.level) {\n await runGeneratorAsyncWithEffect(this.onEffectAsync, this.calculateTransitionsStackGen, [this.onEffectAsync, this.stackGen.takeLowestLevel()], this);\n }\n this.markSelfDependent();\n // entry might be already calculated (in the `ongoing` promise), so no need to calculate it\n if (entry.getValue() === undefined)\n return runGeneratorAsyncWithEffect(this.onEffectAsync, this.calculateTransitionsStackGen, [this.onEffectAsync, [entry]], this);\n })();\n }).then(() => {\n if (this.rejectedWith)\n throw new Error(`Transaction rejected: ${String(this.rejectedWith.reason)}`);\n // we clear the promise in the `resetToEpoch` should be enough?\n // entry.promise = undefined\n if (!entry.hasValue())\n throw new Error('Computation cycle. Sync');\n return entry.getValue();\n });\n }\n // `ignoreActiveEntry` should be used when the atom needs to be read outside the currently ongoing transaction context\n // in such case we still might need to calculate the atom, but should ignore any currently active\n // calculation of the another atom\n get(identifier) {\n // see the comment for the `onEffectSync`\n if (!(identifier instanceof Identifier))\n return this.yieldSync(identifier);\n let entry;\n const activeEntry = this.getActiveEntry();\n if (activeEntry) {\n entry = this.addEdge(identifier, activeEntry, EdgeTypeNormal);\n }\n else {\n entry = this.entries.get(identifier);\n if (!entry) {\n const previousEntry = this.baseRevision.getLatestEntryFor(identifier);\n if (!previousEntry)\n throwUnknownIdentifier(identifier);\n entry = previousEntry.hasValue() ? previousEntry : this.touch(identifier);\n }\n }\n const value1 = entry.getValue();\n if (value1 === TombStone)\n throwUnknownIdentifier(identifier);\n // the `&& entry.hasValue()` part was added to allow KEEP_TRYING_TO_RESOLVE feature for references\n if (value1 !== undefined && entry.hasValue())\n return value1;\n if (entry.promise)\n return entry.promise;\n //----------------------\n // now need to repeat the logic\n if (!entry.previous || !entry.previous.hasValue())\n entry.forceCalculation();\n //----------------------\n while (this.stackGen.getLowestLevel() < identifier.level) {\n // here we force the computations for lower level identifiers should be sync\n this.calculateTransitionsStackSync(this.onEffectSync, this.stackGen.takeLowestLevel());\n }\n this.markSelfDependent();\n if (identifier.sync) {\n this.calculateTransitionsStackSync(this.onEffectSync, [entry]);\n const value = entry.getValue();\n if (value === undefined)\n throw new Error('Cycle during synchronous computation');\n if (value === TombStone)\n throwUnknownIdentifier(identifier);\n return value;\n }\n else {\n const promise = this.ongoing = entry.promise = this.ongoing.then(() => {\n // entry might be already calculated (in the `ongoing` promise), so no need to calculate it\n if (entry.getValue() === undefined)\n return runGeneratorAsyncWithEffect(this.onEffectAsync, this.calculateTransitionsStackGen, [this.onEffectAsync, [entry]], this);\n }).then(() => {\n if (this.rejectedWith)\n throw new Error(`Transaction rejected: ${String(this.rejectedWith.reason)}`);\n // we clear the promise in the `resetToEpoch` should be enough?\n // entry.promise = undefined\n const value = entry.getValue();\n if (value === undefined)\n throw new Error('Computation cycle. Async get');\n if (value === TombStone)\n throwUnknownIdentifier(identifier);\n return value;\n // \n // if (!entry.hasValue()) throw new Error('Computation cycle. Async get')\n //\n // return entry.getValue()\n });\n if (DEBUG) {\n // @ts-ignore\n promise.quark = entry;\n }\n return promise;\n // return runGeneratorAsyncWithEffect(this.onEffectAsync, this.calculateTransitionsStackGen, [ this.onEffectAsync, [ entry ] ], this).then(() => {\n // const value = entry.getValue()\n //\n // \n // if (value === undefined) throw new Error('Cycle during synchronous computation')\n // if (value === TombStone) throwUnknownIdentifier(identifier)\n //\n // return value\n // })\n }\n }\n // this seems to be an optimistic version\n read(identifier) {\n // see the comment for the `onEffectSync`\n if (!(identifier instanceof Identifier))\n return this.yieldSync(identifier);\n let entry;\n const activeEntry = this.getActiveEntry();\n if (activeEntry) {\n entry = this.addEdge(identifier, activeEntry, EdgeTypeNormal);\n }\n else {\n entry = this.entries.get(identifier);\n if (!entry) {\n const previousEntry = this.baseRevision.getLatestEntryFor(identifier);\n if (!previousEntry)\n throwUnknownIdentifier(identifier);\n entry = previousEntry.hasValue() ? previousEntry : this.touch(identifier);\n }\n }\n const value1 = entry.getValue();\n if (value1 === TombStone)\n throwUnknownIdentifier(identifier);\n if (value1 !== undefined)\n return value1;\n // if (!identifier.sync) throw new Error(\"Can not calculate asynchronous identifier synchronously\")\n // now need to repeat the logic\n if (!entry.previous || !entry.previous.hasValue())\n entry.forceCalculation();\n //----------------------\n while (this.stackGen.getLowestLevel() < identifier.level) {\n this.calculateTransitionsStackSync(this.onEffectSync, this.stackGen.takeLowestLevel());\n }\n //----------------------\n this.markSelfDependent();\n this.calculateTransitionsStackSync(this.onEffectSync, [entry]);\n const value = entry.getValue();\n if (value === undefined)\n throw new Error('Cycle during synchronous computation');\n if (value === TombStone)\n throwUnknownIdentifier(identifier);\n return value;\n }\n // semantic is actually - read the most-fresh value\n readCurrentOrProposedOrPrevious(identifier) {\n const dirtyQuark = this.entries.get(identifier);\n if (dirtyQuark) {\n const value = dirtyQuark.getValue();\n if (value !== undefined)\n return value;\n if (dirtyQuark.proposedValue !== undefined)\n return dirtyQuark.proposedValue;\n }\n return this.readPrevious(identifier);\n }\n readCurrentOrProposedOrPreviousAsync(identifier) {\n const dirtyQuark = this.entries.get(identifier);\n if (dirtyQuark) {\n const value = dirtyQuark.getValue();\n if (value !== undefined)\n return value;\n if (dirtyQuark.proposedValue !== undefined)\n return dirtyQuark.proposedValue;\n }\n return this.readPreviousAsync(identifier);\n }\n readPrevious(identifier) {\n const previousEntry = this.baseRevision.getLatestEntryFor(identifier);\n if (!previousEntry)\n return undefined;\n const value = previousEntry.getValue();\n return value !== TombStone ? (value === undefined && identifier.lazy ? this.read(identifier) : value) : undefined;\n }\n readPreviousAsync(identifier) {\n const previousEntry = this.baseRevision.getLatestEntryFor(identifier);\n if (!previousEntry)\n return undefined;\n const value = previousEntry.getValue();\n return value !== TombStone ? (value !== undefined ? value : this.readAsync(identifier)) : undefined;\n }\n readProposedOrPrevious(identifier) {\n const dirtyQuark = this.entries.get(identifier);\n if (dirtyQuark && dirtyQuark.proposedValue !== undefined) {\n return dirtyQuark.proposedValue;\n }\n else {\n return this.readPrevious(identifier);\n }\n }\n readProposedOrPreviousAsync(identifier) {\n const dirtyQuark = this.entries.get(identifier);\n if (dirtyQuark && dirtyQuark.proposedValue !== undefined) {\n return dirtyQuark.proposedValue;\n }\n else {\n return this.readPreviousAsync(identifier);\n }\n }\n write(identifier, proposedValue, ...args) {\n if (proposedValue === undefined)\n proposedValue = null;\n // this.writes.push(WriteEffect.new({\n // identifier : identifier,\n // proposedArgs : [ proposedValue, ...args ]\n // }))\n //\n // this.onNewWrite()\n identifier.write.call(identifier.context || identifier, identifier, this, null, /*this.getWriteTarget(identifier),*/ proposedValue, ...args);\n const entry = this.entries.get(identifier);\n this.hasVariableEntry = this.hasVariableEntry || (!entry.isShadow() && identifier.level === Levels.UserInput);\n this.hasEntryWithProposedValue = this.hasEntryWithProposedValue || entry.hasProposedValue();\n }\n // acquireQuark (identifier : T) : InstanceType {\n // return this.touch(identifier).startOrigin() as InstanceType\n // }\n getWriteTarget(identifier) {\n return this.touch(identifier).startOrigin();\n }\n // return quark if it exists and is non-shadowing, otherwise undefined\n acquireQuarkIfExists(identifier) {\n const entry = this.entries.get(identifier);\n return entry && entry.origin === entry ? entry.origin : undefined;\n }\n touch(identifier) {\n const existingEntry = this.entries.get(identifier);\n if (!existingEntry || existingEntry.visitEpoch < this.walkContext.currentEpoch)\n this.walkContext.continueFrom([identifier]);\n const entry = existingEntry || this.entries.get(identifier);\n entry.forceCalculation();\n return entry;\n }\n // touchInvalidate (identifier : Identifier) : Quark {\n // const existingEntry = this.entries.get(identifier)\n //\n // if (existingEntry && existingEntry.hasValue()) {\n // this.walkContext.startNewEpoch()\n // }\n //\n // if (!existingEntry || existingEntry.visitEpoch < this.walkContext.currentEpoch) this.walkContext.continueFrom([ identifier ])\n //\n // const entry = existingEntry || this.entries.get(identifier)\n //\n // entry.forceCalculation()\n //\n // return entry\n // }\n hasIdentifier(identifier) {\n const activeEntry = this.entries.get(identifier);\n if (activeEntry && activeEntry.getValue() === TombStone)\n return false;\n return Boolean(activeEntry || this.baseRevision.getLatestEntryFor(identifier));\n }\n // this is actually an optimized version of `write`, which skips the graph walk phase\n // (since the identifier is assumed to be new, there should be no dependent quarks)\n addIdentifier(identifier, proposedValue, ...args) {\n // however, the identifier may be already in the transaction, for example if the `write` method\n // of some other identifier writes to this identifier\n let entry = this.entries.get(identifier);\n const alreadyHadEntry = Boolean(entry);\n const isVariable = identifier.level === Levels.UserInput;\n if (!entry) {\n entry = identifier.newQuark(this.baseRevision);\n entry.previous = this.baseRevision.getLatestEntryFor(identifier);\n entry.forceCalculation();\n this.entries.set(identifier, entry);\n if (!identifier.lazy && !isVariable)\n this.stackGen.push(entry);\n this.hasVariableEntry = this.hasVariableEntry || (!entry.isShadow() && isVariable);\n this.hasEntryWithProposedValue = this.hasEntryWithProposedValue || entry.hasProposedValue();\n }\n if (proposedValue !== undefined || isVariable) {\n entry.startOrigin();\n // we should not write if there's already an entry with some values (and we are trying to add it again)\n // this means there were some other identifier that has written into this one even before it was added\n // (probably in its `write` method)\n const shouldNotWrite = alreadyHadEntry && (entry.proposedValue !== undefined || entry.value !== undefined);\n // however, if that entry contain TombStone marks, we should always write - means we are\n // actually re-adding the identifier, which has been removed in the same transaction\n if (!shouldNotWrite || entry.proposedValue === TombStone || entry.value === TombStone) {\n identifier.isWritingUndefined = proposedValue === undefined;\n identifier.write.call(identifier.context || identifier, identifier, this, entry, proposedValue === undefined && isVariable ? null : proposedValue, ...args);\n identifier.isWritingUndefined = false;\n }\n }\n // if we are re-adding the same identifier in the same transaction, clear the TombStone flag\n if (entry.getValue() === TombStone)\n entry.value = undefined;\n if (entry.proposedValue === TombStone)\n entry.proposedValue = undefined;\n identifier.enterGraph(this.graph);\n return entry;\n }\n removeIdentifier(identifier) {\n identifier.leaveGraph(this.graph);\n const entry = this.touch(identifier).startOrigin();\n entry.setValue(TombStone);\n // removing the identifier from self-dependent, otherwise there will be an attempt to evaluate it\n this.candidate.selfDependent.delete(identifier);\n }\n populateCandidateScopeFromTransitions(candidate, scope) {\n if (candidate.scope.size === 0) {\n // in this branch we can overwrite the whole map\n candidate.scope = scope;\n }\n else {\n // in this branch candidate's scope already has some content - this is the case for calculating lazy values\n // \n // entries.forEach((entry : QuarkEntry, identifier : Identifier) => {\n // candidate.scope.set(identifier, entry)\n // })\n for (const [identifier, quark] of scope) {\n if (quark.isShadow()) {\n const latestEntry = candidate.getLatestEntryFor(identifier);\n // and we iterate over the edges from \"origin\" anyway\n quark.getOutgoing().forEach((toQuark, toIdentifier) => latestEntry.getOutgoing().set(toIdentifier, toQuark));\n }\n else {\n candidate.scope.set(identifier, quark);\n }\n }\n }\n }\n preCommit(args) {\n if (this.isClosed)\n throw new Error('Can not propagate closed revision');\n this.markSelfDependent();\n this.isClosed = true;\n this.propagationStartDate = Date.now();\n this.plannedTotalIdentifiersToCalculate = this.stackGen.length;\n }\n postCommit() {\n this.populateCandidateScopeFromTransitions(this.candidate, this.entries);\n // won't be available after next line\n const entries = this.entries;\n // for some reason need to cleanup the `walkContext` manually, otherwise the extra revisions hangs in memory\n this.walkContext = undefined;\n return { revision: this.candidate, entries, transaction: this };\n }\n commit(args) {\n this.preCommit(args);\n this.calculateTransitionsSync(this.onEffectSync);\n // runGeneratorSyncWithEffect(this.onEffectSync, this.calculateTransitionsStackGen, [ this.onEffectSync, stack ], this)\n return this.postCommit();\n }\n reject(rejection = RejectEffect.new()) {\n this.rejectedWith = rejection;\n this.walkContext = undefined;\n }\n // stops the calculations, but does not reject\n stop() {\n this.stopped = true;\n }\n clearRejected() {\n for (const quark of this.entries.values()) {\n quark.cleanup();\n // quark.clearOutgoing()\n }\n this.entries.clear();\n }\n // // propagation that does not use generators at all\n // propagateSync (args? : PropagateArguments) : TransactionPropagateResult {\n // const stack = this.prePropagate(args)\n //\n // this.calculateTransitionsStackSync(this.onEffectSync, stack)\n // // runGeneratorSyncWithEffect(this.onEffectSync, this.calculateTransitionsStackGen, [ this.onEffectSync, stack ], this)\n //\n // return this.postPropagate()\n // }\n async commitAsync(args) {\n this.preCommit(args);\n return this.ongoing = this.ongoing.then(() => {\n return runGeneratorAsyncWithEffect(this.onEffectAsync, this.calculateTransitions, [this.onEffectAsync], this);\n }).then(() => {\n return this.postCommit();\n });\n // await runGeneratorAsyncWithEffect(this.onEffectAsync, this.calculateTransitions, [ this.onEffectAsync ], this)\n //\n // return this.postCommit()\n }\n getLatestEntryFor(identifier) {\n let entry = this.entries.get(identifier) || this.baseRevision.getLatestEntryFor(identifier);\n if (entry && entry.getValue() === TombStone)\n return undefined;\n return entry;\n }\n // check the transaction \"entries\" first, but only return an entry\n // from that, if it is already calculated, otherwise - take it\n // from the base revision\n getLatestStableEntryFor(identifier) {\n let entry = this.entries.get(identifier);\n if (entry) {\n const value = entry.getValue();\n if (value === TombStone)\n return undefined;\n return value === undefined ? this.baseRevision.getLatestEntryFor(identifier) : entry;\n }\n else {\n return this.baseRevision.getLatestEntryFor(identifier);\n }\n }\n addEdge(identifierRead, activeEntry, type) {\n const identifier = activeEntry.identifier;\n if (identifier.level < identifierRead.level)\n throw new Error('Identifier can not read from higher level identifier');\n let entry = this.entries.get(identifierRead);\n // creating \"shadowing\" entry, to store the new edges\n if (!entry) {\n const previousEntry = this.baseRevision.getLatestEntryFor(identifierRead);\n if (!previousEntry)\n throwUnknownIdentifier(identifierRead);\n entry = identifierRead.newQuark(this.baseRevision);\n entry.setOrigin(previousEntry);\n entry.previous = previousEntry;\n this.entries.set(identifierRead, entry);\n }\n entry.addOutgoingTo(activeEntry, type);\n return entry;\n }\n onQuarkCalculationCompleted(entry, value) {\n // cleanup the iterator\n entry.cleanup();\n const identifier = entry.identifier;\n const previousEntry = entry.previous;\n //--------------------\n const sameAsPrevious = Boolean(previousEntry && previousEntry.hasValue() && identifier.equality(value, previousEntry.getValue()));\n if (sameAsPrevious) {\n previousEntry.outgoingInTheFutureAndPastTransactionCb(this, previousOutgoingEntry => {\n const outgoingEntry = this.entries.get(previousOutgoingEntry.identifier);\n if (outgoingEntry)\n outgoingEntry.edgesFlow--;\n });\n // this is a \"workaround\" for the following problem:\n // there might be several copies of the same quark in the calculation stack, this is normal\n // because if quark is requested by some other quark it is just pushed to the stack,\n // which may already contain this quark\n // then when the quark is calculated (this code) it propagates the `edgesFlow` decrease\n // but next time it will be encountered in the stack, its `edgesFlow` might be decreased by other\n // identifiers, which will trigger another round of `edgesFlow` decrease propagation\n // so we set the `edgesFlow` to MAX_SMI after decrease been propagated to prevent repeated such propagation\n entry.edgesFlow = MAX_SMI;\n entry.setOrigin(previousEntry.origin);\n }\n else {\n entry.startOrigin();\n entry.setValue(value);\n }\n //--------------------\n let ignoreSelfDependency = false;\n if (entry.usedProposedOrPrevious) {\n if (entry.proposedValue !== undefined) {\n if (identifier.equality(value, entry.proposedValue))\n ignoreSelfDependency = true;\n }\n else {\n // ignore the uninitialized atoms (`proposedValue` === undefined && !previousEntry)\n // which has been calculated to `null` - we don't consider this as a change\n if (sameAsPrevious || (!previousEntry && value === null))\n ignoreSelfDependency = true;\n }\n if (!ignoreSelfDependency)\n this.candidate.selfDependent.add(identifier);\n }\n }\n onReadIdentifier(identifierRead, activeEntry, stack) {\n const requestedEntry = this.addEdge(identifierRead, activeEntry, EdgeTypeNormal);\n // this is a workaround for references with failed resolution problem in gantt\n // those references return `hasValue() === false` even that they actually have value\n // (which is `null` and needed to be recalculated)\n if (requestedEntry.hasValue() || requestedEntry.value !== undefined) {\n const value = requestedEntry.getValue();\n if (value === TombStone)\n throwUnknownIdentifier(identifierRead);\n return activeEntry.continueCalculation(value);\n }\n else if (requestedEntry.isShadow()) {\n // shadow entry is shadowing a quark w/o value - it is still transitioning or lazy\n // in both cases start new calculation\n requestedEntry.startOrigin();\n requestedEntry.forceCalculation();\n stack.push(requestedEntry);\n return undefined;\n }\n else {\n if (!requestedEntry.isCalculationStarted()) {\n stack.push(requestedEntry);\n if (!requestedEntry.previous || !requestedEntry.previous.hasValue())\n requestedEntry.forceCalculation();\n return undefined;\n }\n else {\n // cycle - the requested quark has started calculation (means it was encountered in the calculation loop before)\n // but the calculation did not complete yet (even that requested quark is calculated before the current)\n let cycle;\n const walkContext = TransactionCycleDetectionWalkContext.new({\n transaction: this,\n onCycle(node, stack) {\n cycle = ComputationCycle.new({\n cycle: cycleInfo(stack),\n requestedEntry,\n activeEntry,\n });\n return OnCycleAction.Cancel;\n }\n });\n walkContext.startFrom([requestedEntry.identifier]);\n return cycle;\n }\n }\n }\n *calculateTransitions(context) {\n const queue = this.stackGen;\n while (queue.length) {\n // some identifiers from the queue??\n yield* this.calculateTransitionsStackGen(context, queue.takeLowestLevel());\n }\n }\n calculateTransitionsSync(context) {\n const queue = this.stackGen;\n while (queue.length) {\n this.calculateTransitionsStackSync(context, queue.takeLowestLevel());\n }\n }\n // this method is not decomposed into smaller ones intentionally, as that makes benchmarks worse\n // it seems that overhead of calling few more functions in such tight loop as this outweighs the optimization\n *calculateTransitionsStackGen(context, stack) {\n if (this.rejectedWith || this.stopped)\n return;\n this.walkContext.startNewEpoch();\n const entries = this.entries;\n const propagationStartDate = this.propagationStartDate;\n const enableProgressNotifications = this.graph ? this.graph.enableProgressNotifications : false;\n let counter = 0;\n const prevActiveStack = this.activeStack;\n this.activeStack = stack;\n while (stack.length && !this.rejectedWith && !this.stopped) {\n if (enableProgressNotifications && !(counter++ % this.emitProgressNotificationsEveryCalculations)) {\n const now = Date.now();\n const elapsed = now - propagationStartDate;\n if (elapsed > this.startProgressNotificationsAfterMs) {\n const lastProgressNotificationDate = this.lastProgressNotificationDate;\n if (!lastProgressNotificationDate || (now - lastProgressNotificationDate) > this.emitProgressNotificationsEveryMs) {\n this.lastProgressNotificationDate = now;\n this.graph.onPropagationProgressNotification({\n total: this.plannedTotalIdentifiersToCalculate,\n remaining: this.stackGen.length + stack.length,\n phase: 'propagating'\n });\n // need to \"exit\" the context of the current transaction for the time of the following `delay()`\n // otherwise, any reads from graph during that time will be recorded as the dependencies\n // of the currently active atom\n this.activeStack = prevActiveStack;\n yield delay(0);\n this.activeStack = stack;\n }\n }\n }\n if (this.rejectedWith || this.stopped)\n break;\n const entry = stack[stack.length - 1];\n const identifier = entry.identifier;\n const ownEntry = entries.get(identifier);\n if (ownEntry !== entry) {\n entry.cleanup();\n stack.pop();\n continue;\n }\n if (entry.edgesFlow == 0) {\n // even if we delete the entry there might be other copies in stack, so reduce the `edgesFlow` to -1\n // to indicate that those are already processed\n entry.edgesFlow--;\n const previousEntry = entry.previous;\n previousEntry && previousEntry.outgoingInTheFutureAndPastTransactionCb(this, outgoing => {\n const outgoingEntry = entries.get(outgoing.identifier);\n if (outgoingEntry)\n outgoingEntry.edgesFlow--;\n });\n }\n // the \"edgesFlow < 0\" indicates that none of the incoming deps of this quark has changed\n // thus we don't need to calculate it, moreover, we can remove the quark from the `entries`\n // to expose the value from the previous revision\n // however, we only do it, when there is a quark from previous revision and it has \"origin\" (some value)\n if (entry.edgesFlow < 0 && entry.previous && entry.previous.origin) {\n // even if the entry will be deleted from the transaction, we set the correct origin for it\n // this is because there might be other references to this entry in the stack\n // and also the entry may be referenced as dependency of some other quark\n // in such case the correct `originId` will preserve dependency during revisions compactification\n entry.setOrigin(entry.previous.origin);\n // if there's no outgoing edges we remove the quark\n if (entry.size === 0) {\n entries.delete(identifier);\n }\n // reduce garbage collection workload\n entry.cleanup();\n stack.pop();\n continue;\n }\n if ( /*entry.isShadow() ||*/entry.hasValue() || entry.proposedValue === TombStone) {\n entry.cleanup();\n stack.pop();\n continue;\n }\n const startedAtEpoch = entry.visitEpoch;\n let iterationResult = entry.isCalculationStarted() ? entry.iterationResult : entry.startCalculation(this.onEffectSync);\n while (iterationResult && !this.rejectedWith && !this.stopped) {\n const value = iterationResult.value === undefined ? null : iterationResult.value;\n if (entry.isCalculationCompleted()) {\n if (entry.visitEpoch == startedAtEpoch) {\n this.onQuarkCalculationCompleted(entry, value);\n }\n stack.pop();\n break;\n }\n else if (value instanceof Identifier) {\n const onReadIdentifierResult = this.onReadIdentifier(value, entry, stack);\n // handle the cycle\n if (onReadIdentifierResult instanceof ComputationCycle) {\n this.walkContext.startNewEpoch();\n yield* this.graph.onComputationCycleHandler(onReadIdentifierResult);\n entry.cleanupCalculation();\n iterationResult = undefined;\n }\n else {\n iterationResult = onReadIdentifierResult;\n }\n }\n else if (value === SynchronousCalculationStarted) {\n // the fact, that we've encountered `SynchronousCalculationStarted` constant can mean 2 things:\n // 1) there's a cycle during synchronous computation (we throw exception in `read` method)\n // 2) some other computation is reading synchronous computation, that has already started\n // in such case its safe to just unwind the stack\n stack.pop();\n break;\n }\n else {\n // bypass the unrecognized effect to the outer context\n const effectResult = yield value;\n // the calculation can be interrupted (`cleanupCalculation`) as a result of the effect (WriteEffect)\n // in such case we can not continue calculation and just exit the inner loop\n if (effectResult === BreakCurrentStackExecution)\n break;\n // // the calculation can be interrupted (`cleanupCalculation`) as a result of the effect (WriteEffect)\n // // in such case we can not continue calculation and just exit the inner loop\n // if (entry.iterationResult)\n if (entry.visitEpoch === startedAtEpoch) {\n iterationResult = entry.continueCalculation(effectResult);\n }\n else {\n stack.pop();\n break;\n }\n // else\n // iterationResult = null\n }\n }\n }\n this.activeStack = prevActiveStack;\n }\n // THIS METHOD HAS TO BE KEPT SYNCED WITH THE `calculateTransitionsStackGen` !!!\n calculateTransitionsStackSync(context, stack) {\n if (this.rejectedWith || this.stopped)\n return;\n this.walkContext.startNewEpoch();\n const entries = this.entries;\n const prevActiveStack = this.activeStack;\n this.activeStack = stack;\n while (stack.length && !this.rejectedWith && !this.stopped) {\n const entry = stack[stack.length - 1];\n const identifier = entry.identifier;\n const ownEntry = entries.get(identifier);\n if (ownEntry !== entry) {\n entry.cleanup();\n stack.pop();\n continue;\n }\n if (entry.edgesFlow == 0) {\n // even if we delete the entry there might be other copies in stack, so reduce the `edgesFlow` to -1\n // to indicate that those are already processed\n entry.edgesFlow--;\n const previousEntry = entry.previous;\n previousEntry && previousEntry.outgoingInTheFutureAndPastTransactionCb(this, outgoing => {\n const outgoingEntry = entries.get(outgoing.identifier);\n if (outgoingEntry)\n outgoingEntry.edgesFlow--;\n });\n }\n // the \"edgesFlow < 0\" indicates that none of the incoming deps of this quark has changed\n // thus we don't need to calculate it, moreover, we can remove the quark from the `entries`\n // to expose the value from the previous revision\n // however, we only do it, when there is a quark from previous revision and it has \"origin\" (some value)\n if (entry.edgesFlow < 0 && entry.previous && entry.previous.origin) {\n // even if the entry will be deleted from the transaction, we set the correct origin for it\n // this is because there might be other references to this entry in the stack\n // and also the entry may be referenced as dependency of some other quark\n // in such case the correct `originId` will preserve dependency during revisions compactification\n entry.setOrigin(entry.previous.origin);\n // if there's no outgoing edges we remove the quark\n if (entry.size === 0) {\n entries.delete(identifier);\n }\n // reduce garbage collection workload\n entry.cleanup();\n stack.pop();\n continue;\n }\n if ( /*entry.isShadow() ||*/entry.hasValue() || entry.proposedValue === TombStone) {\n entry.cleanup();\n stack.pop();\n continue;\n }\n const startedAtEpoch = entry.visitEpoch;\n let iterationResult = entry.isCalculationStarted() ? entry.iterationResult : entry.startCalculation(this.onEffectSync);\n while (iterationResult && !this.rejectedWith && !this.stopped) {\n const value = iterationResult.value === undefined ? null : iterationResult.value;\n if (entry.isCalculationCompleted()) {\n if (entry.visitEpoch == startedAtEpoch) {\n this.onQuarkCalculationCompleted(entry, value);\n }\n stack.pop();\n break;\n }\n else if (value instanceof Identifier) {\n const onReadIdentifierResult = this.onReadIdentifier(value, entry, stack);\n // handle the cycle\n if (onReadIdentifierResult instanceof ComputationCycle) {\n this.walkContext.startNewEpoch();\n this.graph.onComputationCycleHandlerSync(onReadIdentifierResult, this);\n entry.cleanupCalculation();\n iterationResult = undefined;\n }\n else {\n iterationResult = onReadIdentifierResult;\n }\n }\n else if (value === SynchronousCalculationStarted) {\n // the fact, that we've encountered `SynchronousCalculationStarted` constant can mean 2 things:\n // 1) there's a cycle during synchronous computation (we throw exception in `read` method)\n // 2) some other computation is reading synchronous computation, that has already started\n // in such case its safe to just unwind the stack\n stack.pop();\n break;\n }\n else {\n // bypass the unrecognized effect to the outer context\n const effectResult = context(value);\n if (isPromise(effectResult))\n throw new Error(\"Effect resolved to promise in the synchronous context, check that you marked the asynchronous calculations accordingly\");\n // the calculation can be interrupted (`cleanupCalculation`) as a result of the effect (WriteEffect)\n // in such case we can not continue calculation and just exit the inner loop\n if (effectResult === BreakCurrentStackExecution)\n break;\n // // the calculation can be interrupted (`cleanupCalculation`) as a result of the effect (WriteEffect)\n // // in such case we can not continue calculation and just exit the inner loop\n // if (entry.iterationResult)\n if (entry.visitEpoch === startedAtEpoch) {\n iterationResult = entry.continueCalculation(effectResult);\n }\n else {\n stack.pop();\n break;\n }\n // else\n // iterationResult = null\n }\n }\n }\n this.activeStack = prevActiveStack;\n }\n}\n", "import { Base } from \"../class/Base.js\";\nimport { concat } from \"../collection/Iterator.js\";\nimport { warn } from \"../environment/Debug.js\";\nimport { copySetInto, isGeneratorFunction } from \"../util/Helpers.js\";\nimport { BreakCurrentStackExecution, HasProposedNotPreviousValueSymbol, HasProposedValueSymbol, OwnIdentifierSymbol, OwnQuarkSymbol, PreviousValueOfSymbol, ProposedArgumentsOfSymbol, ProposedOrPreviousSymbol, ProposedOrPreviousValueOfSymbol, ProposedValueOfSymbol, RejectEffect, RejectSymbol, TransactionSymbol, UnsafePreviousValueOfSymbol, UnsafeProposedOrPreviousValueOfSymbol, WriteSeveralSymbol, WriteSymbol } from \"./Effect.js\";\nimport { CalculatedValueGen, CalculatedValueGenC, CalculatedValueSyncC, VariableC } from \"./Identifier.js\";\nimport { TombStone } from \"./Quark.js\";\nimport { Revision } from \"./Revision.js\";\nimport { EdgeTypePast, Transaction } from \"./Transaction.js\";\n/**\n * A constant which will be used a commit result, when graph is not available.\n */\nexport const CommitZero = {\n rejectedWith: null\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport class Listener extends Base {\n constructor() {\n super(...arguments);\n this.handlers = [];\n }\n trigger(value) {\n for (let i = 0; i < this.handlers.length; i++)\n this.handlers[i](value);\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Generic reactive graph. Consists from [[Identifier]]s, depending on each other. This is a low-level representation\n * of the ChronoGraph dataset, it is not \"aware\" of the entity/relation framework and operates as \"just graph\".\n *\n * For higher-level (and more convenient) representation, please refer to [[Replica]].\n *\n * An example of usage:\n *\n * const graph = ChronoGraph.new({ historyLimit : 10 })\n *\n * const var1 = graph.variable(1)\n * const var2 = graph.variable(2)\n * const iden1 = graph.identifier((Y) => Y(var1) + Y(var2))\n *\n * graph.read(iden1) // 3\n *\n * graph.commit()\n *\n * graph.write(var1, 2)\n *\n * graph.read(iden1) // 4\n *\n * graph.reject()\n *\n * graph.read(var1) // 1\n * graph.read(iden1) // 3\n *\n */\nexport class ChronoGraph extends Base {\n constructor() {\n super(...arguments);\n this.baseRevisionStable = undefined;\n this.baseRevisionTentative = undefined;\n this.baseRevision = Revision.new();\n // the revision to follow to, when performing `redo` operation\n this.topRevision = undefined;\n /**\n * Integer value, indicating how many transactions to keep in memory, to be available for [[undo]] call.\n * Default value is 0 - previous transaction is cleared immediately.\n *\n * Increase this config to opt-in for the [[undo]]/[[redo]] functionality.\n */\n this.historyLimit = 0;\n this.listeners = new Map();\n // this flag is set when the data being written to the graph is \"undo/redo\" data\n // in such case, we shouldn't treat it as user input, but instead as a side-effect free\n // state restoration\n // this flag is used in the CycleResolverChrono and in general is engine specific\n this.isWritingPreviousData = false;\n this.$activeTransaction = undefined;\n this.isCommitting = false;\n this.enableProgressNotifications = false;\n this.ongoing = Promise.resolve();\n this._isInitialCommit = true;\n //-------------------------------------\n // a \"cross-platform\" trick to avoid specifying the type of the `autoCommitTimeoutId` explicitly\n this.autoCommitTimeoutId = null;\n /**\n * If this option is enabled with `true` value, all data modification calls ([[write]], [[addIdentifier]], [[removeIdentifier]]) will trigger\n * a delayed [[commit]] call (or [[commitAsync]], depending from the [[autoCommitMode]] option).\n */\n this.autoCommit = false;\n /**\n * Indicates the default commit mode, which is used in [[autoCommit]].\n */\n this.autoCommitMode = 'sync';\n this.autoCommitHandler = null;\n this.onWriteDuringCommit = 'throw';\n this.onComputationCycle = 'throw';\n this.transactionClass = Transaction;\n this.isJustCleared = false;\n this.$followingRevision = undefined;\n }\n initialize(...args) {\n super.initialize(...args);\n if (!this.topRevision)\n this.topRevision = this.baseRevision;\n if (this.autoCommit) {\n this.autoCommitHandler = this.autoCommitMode === 'sync' ? arg => this.commit(arg) : async (arg) => this.commitAsync(arg);\n }\n this.markAndSweep();\n }\n /**\n * Returns boolean, indicating whether the auto-commit is pending.\n */\n hasPendingAutoCommit() {\n return this.autoCommitTimeoutId !== null;\n }\n get dirty() {\n return this.activeTransaction.dirty;\n }\n clear() {\n this.reject();\n this.unScheduleAutoCommit();\n // some stale state - `clear` called at sensitive time\n this.baseRevision.scope && this.baseRevision.scope.clear();\n this.baseRevision.previous = null;\n this.listeners.clear();\n this.topRevision = this.baseRevision;\n this.$followingRevision = undefined;\n this.$activeTransaction = undefined;\n this.markAndSweep();\n this.isJustCleared = true;\n }\n clearBranch() {\n this.reject();\n this.unScheduleAutoCommit();\n // dereference all revisions\n for (const [revision, isReachable] of this.eachReachableRevision()) {\n if (isReachable)\n revision.reachableCount--;\n revision.referenceCount--;\n }\n // some stale state - `clear` called at sensitive time\n // this.baseRevision.scope && this.baseRevision.scope.clear()\n this.baseRevision.previous = null;\n this.listeners.clear();\n this.topRevision = this.baseRevision;\n this.$followingRevision = undefined;\n this.$activeTransaction = undefined;\n }\n *eachReachableRevision() {\n let isBetweenTopBottom = true;\n let counter = 0;\n for (const revision of this.topRevision.previousAxis()) {\n yield [revision, isBetweenTopBottom || counter < this.historyLimit];\n if (revision === this.baseRevision) {\n isBetweenTopBottom = false;\n }\n else {\n if (!isBetweenTopBottom)\n counter++;\n }\n }\n }\n get isInitialCommit() {\n return this._isInitialCommit;\n }\n set isInitialCommit(value) {\n this._isInitialCommit = value;\n }\n markAndSweep() {\n let lastReferencedRevision;\n const unreachableRevisions = [];\n for (const [revision, isReachable] of this.eachReachableRevision()) {\n if (isReachable) {\n revision.reachableCount++;\n lastReferencedRevision = revision;\n }\n else\n unreachableRevisions.push(revision);\n revision.referenceCount++;\n }\n unreachableRevisions.unshift(lastReferencedRevision);\n for (let i = unreachableRevisions.length - 1; i >= 1 && unreachableRevisions[i].reachableCount === 0; i--) {\n this.compactRevisions(unreachableRevisions[i - 1], unreachableRevisions[i]);\n }\n }\n compactRevisions(newRev, prevRev) {\n if (prevRev.reachableCount > 0 || newRev.previous !== prevRev)\n throw new Error(\"Invalid compact operation\");\n // we can only shred revision if its being referenced maximum 1 time (from the current Checkout instance)\n if (prevRev.referenceCount <= 1) {\n for (const [identifier, entry] of newRev.scope) {\n if (entry.getValue() === TombStone) {\n prevRev.scope.delete(identifier);\n }\n else {\n const prevQuark = prevRev.scope.get(identifier);\n if (entry.origin === entry) {\n if (prevQuark) {\n prevQuark.clear();\n prevQuark.clearProperties();\n }\n }\n else if (prevQuark && entry.origin === prevQuark) {\n entry.mergePreviousOrigin(newRev.scope);\n }\n else if (identifier.lazy && !entry.origin && prevQuark && prevQuark.origin) {\n // for lazy quarks, that depends on the `ProposedOrPrevious` effect, we need to save the value or proposed value\n // from the previous revision\n entry.startOrigin().proposedValue = prevQuark.origin.value !== undefined ? prevQuark.origin.value : prevQuark.origin.proposedValue;\n }\n entry.previous = undefined;\n prevRev.scope.set(identifier, entry);\n }\n }\n copySetInto(newRev.selfDependent, prevRev.selfDependent);\n // some help for garbage collector\n // this clears the \"entries\" in the transaction commit result in the \"finalizeCommitAsync\"\n // newRev.scope.clear()\n newRev.scope = prevRev.scope;\n // make sure the previous revision won't be used inconsistently\n prevRev.scope = null;\n }\n // otherwise, we have to copy from it, and keep it intact\n else {\n newRev.scope = new Map(concat(prevRev.scope, newRev.scope));\n newRev.selfDependent = new Set(concat(prevRev.selfDependent, newRev.selfDependent));\n prevRev.referenceCount--;\n }\n // in both cases break the `previous` chain\n newRev.previous = null;\n }\n get followingRevision() {\n if (this.$followingRevision !== undefined)\n return this.$followingRevision;\n const revisions = Array.from(this.topRevision.previousAxis());\n const entries = [];\n for (let i = revisions.length - 1; i > 0; i--)\n entries.push([revisions[i], revisions[i - 1]]);\n return this.$followingRevision = new Map(entries);\n }\n get activeTransaction() {\n if (this.$activeTransaction)\n return this.$activeTransaction;\n return this.$activeTransaction = this.transactionClass.new({\n baseRevision: this.baseRevisionTentative || this.baseRevision,\n graph: this\n });\n }\n /**\n * Creates a new branch of this graph. Only committed data will be \"visible\" in the new branch.\n *\n * ```ts\n * const graph2 = ChronoGraph.new()\n *\n * const variable13 : Variable = graph2.variable(5)\n *\n * const branch2 = graph2.branch()\n *\n * branch2.write(variable13, 10)\n *\n * const value13_1 = graph2.read(variable13) // 5\n * const value13_2 = branch2.read(variable13) // 10\n * ```\n *\n * When using the branching feature in [[Replica]], you need to reference the field values by yielding their\n * corresponding identifiers. This is because ChronoGraph need to know in context of which branch\n * the calculation happens and this information is encoded in the outer context. This may improve in the future.\n *\n * ```ts\n * class Author extends Entity.mix(Base) {\n * @calculate('fullName')\n * calculateFullName (Y) : string {\n * return Y(this.$.firstName) + ' ' + Y(this.$.lastName)\n * }\n *\n * @calculate('fullName')\n * * calculateFullName (Y) : CalculationIterator {\n * return (yield this.$.firstName) + ' ' + (yield this.$.lastName)\n * }\n * }\n * ```\n *\n * @param config Configuration object for the new graph instance.\n */\n branch(config) {\n const Constructor = this.constructor;\n return Constructor.new(Object.assign({}, config, { baseRevision: this.baseRevision }));\n }\n propagate(args) {\n return this.commit(args);\n }\n /**\n * Rejects the current changes in the graph and revert it to the state of the previous [[commit]].\n *\n * See also [[RejectEffect]].\n *\n * @param reason Any value, describing why reject has happened\n */\n reject(reason) {\n this.activeTransaction.reject(RejectEffect.new({ reason }));\n // reject resets the `ongoing` promise (which is possibly rejected because of cycle exception)\n this.ongoing = Promise.resolve();\n this.$activeTransaction = undefined;\n this.baseRevisionTentative = undefined;\n if (this.baseRevisionStable) {\n this.baseRevision = this.baseRevisionStable;\n this.baseRevisionStable = undefined;\n }\n }\n /**\n * Synchronously commit the state of the graph. All potentially changed [[Identifier.lazy|strict]] identifiers\n * will be calculated during this call. If any of such identifiers will be [[Identifier.sync|async]], an exception\n * will be thrown.\n *\n * This call marks a \"stable\" state of the graph and a transaction border. Using the [[undo]] call one can revert to the previous\n * state.\n *\n * See also [[reject]].\n *\n * @param args\n */\n commit(args) {\n this.isJustCleared = false;\n this.unScheduleAutoCommit();\n this.baseRevisionStable = this.baseRevision;\n const activeTransaction = this.activeTransaction;\n const transactionCommitResult = activeTransaction.commit(args);\n this.$activeTransaction = undefined;\n const result = this.finalizeCommit(transactionCommitResult);\n this.baseRevisionStable = undefined;\n this.isInitialCommit = false;\n return result;\n }\n async propagateAsync(args) {\n return this.commitAsync(args);\n }\n /**\n * Asynchronously commit the state of the replica. All potentially changed strict identifiers (see [[Identifier.lazy]])\n * will be calculated during this call.\n *\n * This call marks a \"stable\" state of the graph and a transaction border. Using the [[undo]] call one can revert to the previous\n * state.\n *\n * See also [[reject]].\n *\n * @param args\n */\n async commitAsync(args) {\n if (this.isCommitting)\n return this.ongoing;\n this.isJustCleared = false;\n this.isCommitting = true;\n this.baseRevisionStable = this.baseRevision;\n let result;\n return this.ongoing = this.ongoing.then(() => {\n return this.doCommitAsync(args);\n }).then(res => {\n result = res;\n return res;\n }).finally(() => {\n this.baseRevisionStable = undefined;\n this.baseRevisionTentative = undefined;\n this.isInitialCommit = false;\n this.isCommitting = false;\n });\n }\n async doCommitAsync(args) {\n this.unScheduleAutoCommit();\n const activeTransaction = this.activeTransaction;\n const transactionResult = await activeTransaction.commitAsync(args);\n const rejectedDuringCommit = Boolean(activeTransaction.rejectedWith);\n const prevBaseTentative = this.baseRevisionTentative;\n if (!rejectedDuringCommit)\n this.baseRevisionTentative = activeTransaction.candidate;\n this.$activeTransaction = undefined;\n await this.finalizeCommitAsync(transactionResult);\n if (this.isJustCleared)\n return { rejectedWith: RejectEffect.new({ reason: 'Graph cleared' }) };\n if (activeTransaction.rejectedWith && !rejectedDuringCommit) {\n this.baseRevisionTentative = prevBaseTentative;\n this.$activeTransaction = undefined;\n }\n const result = this.finalizeCommit(transactionResult);\n if (activeTransaction.rejectedWith)\n activeTransaction.clearRejected();\n if (this.dirty && !activeTransaction.rejectedWith) {\n await this.doCommitAsync(args);\n }\n return result;\n }\n finalizeCommit(transactionResult) {\n const { revision, entries, transaction } = transactionResult;\n if (!transaction.rejectedWith) {\n if (revision.previous !== this.baseRevision)\n throw new Error('Invalid revisions chain');\n // dereference all revisions\n for (const [revision, isReachable] of this.eachReachableRevision()) {\n if (isReachable)\n revision.reachableCount--;\n revision.referenceCount--;\n }\n this.baseRevision = this.topRevision = revision;\n // activating listeners BEFORE the `markAndSweep`, because in that call, `baseRevision`\n // might be already merged with previous\n for (const [identifier, quarkEntry] of entries) {\n quarkEntry.cleanup();\n // ignore \"shadowing\" and lazy entries\n if (quarkEntry.isShadow() || !quarkEntry.hasValue())\n continue;\n const listener = this.listeners.get(identifier);\n if (listener)\n listener.trigger(quarkEntry.getValue());\n }\n this.$followingRevision = undefined;\n this.markAndSweep();\n }\n else {\n // `baseRevisionStable` might be already cleared in the `reject` method of the graph\n if (this.baseRevisionStable)\n this.baseRevision = this.baseRevisionStable;\n this.baseRevisionStable = undefined;\n this.baseRevisionTentative = undefined;\n }\n return { rejectedWith: transaction.rejectedWith };\n }\n async finalizeCommitAsync(transactionResult) {\n }\n *onComputationCycleHandler(cycle) {\n const exception = new Error(\"Computation cycle:\\n\" + cycle);\n //@ts-ignore\n exception.cycle = cycle;\n switch (this.onComputationCycle) {\n case 'ignore':\n console.log(exception.message);\n const { requestedEntry, activeEntry } = cycle;\n // if we ignore the cycle we just continue the calculation with the best possible value\n return activeEntry.continueCalculation(requestedEntry.proposedValue !== undefined ? requestedEntry.proposedValue : requestedEntry.value);\n case 'throw':\n throw exception;\n case 'reject':\n this.reject(exception);\n break;\n case 'warn':\n warn(exception);\n break;\n }\n }\n onComputationCycleHandlerSync(cycle, transaction) {\n const exception = new Error(\"Computation cycle:\\n\" + cycle);\n //@ts-ignore\n exception.cycle = cycle;\n switch (this.onComputationCycle) {\n case 'ignore':\n console.log(exception.message);\n const { requestedEntry, activeEntry } = cycle;\n // if we ignore the cycle we just continue the calculation with the best possible value\n return activeEntry.continueCalculation(requestedEntry.proposedValue !== undefined ? requestedEntry.proposedValue : requestedEntry.value);\n case 'throw':\n throw exception;\n case 'reject':\n this.reject(exception);\n break;\n case 'warn':\n warn(exception);\n break;\n }\n }\n scheduleAutoCommit() {\n // the `&& !this.isCommitting` part was added for the conflicts branch\n // however, it seems to fail several tests\n // commenting for now, to be reviewed later\n if (this.autoCommitTimeoutId === null && !this.isCommitting) {\n this.autoCommitTimeoutId = setTimeout(this.autoCommitHandler, 10);\n }\n }\n unScheduleAutoCommit() {\n if (this.autoCommitTimeoutId !== null) {\n clearTimeout(this.autoCommitTimeoutId);\n this.autoCommitTimeoutId = null;\n }\n }\n /**\n * Creates a variable identifier with the given initial value and adds it to graph.\n *\n * @param value The initial value. The `undefined` value will be converted to `null`\n */\n variable(value) {\n const variable = VariableC();\n // always initialize variables with `null`\n return this.addIdentifier(variable, value === undefined ? null : value);\n }\n /**\n * Creates a named variable identifier with the given initial value and adds it to graph.\n *\n * @param name The [[Variable.name]] property of the newly created variable\n * @param value The initial value. The `undefined` value will be converted to `null`\n */\n variableNamed(name, value) {\n const variable = VariableC({ name });\n // always initialize variables with `null`\n return this.addIdentifier(variable, value === undefined ? null : value);\n }\n /**\n * Creates an identifier based on the given calculation function and adds it to this graph. Depending form the type of the function\n * (sync/generator) either [[CalculatedValueGen]] or [[CalculatedValueSync]] will be created.\n *\n * To have full control on the identifier creation, instantiate it yourself and add to graph using the [[ChronoGraph.addIdentifier]] call.\n *\n * @param calculation The calculation function of the identifier.\n * @param context The [[Identifier.context|context]] property of the newly created identifier\n */\n identifier(calculation, context) {\n const identifier = isGeneratorFunction(calculation) ?\n CalculatedValueGenC({ calculation, context })\n :\n CalculatedValueSyncC({ calculation, context });\n return this.addIdentifier(identifier);\n }\n /**\n * Creates a named identifier based on the given calculation function and adds it to this graph. Depending form the type of the function\n * (sync/generator) either [[CalculatedValueGen]] or [[CalculatedValueSync]] will be created.\n *\n * To have full control on the identifier creation, instantiate it yourself and add to graph using the [[ChronoGraph.addIdentifier]] call.\n *\n * @param name The [[Identifier.name]] property of the newly created identifier\n * @param calculation The calculation function of the identifier.\n * @param context The [[Identifier.context]] property of the newly created identifier\n */\n identifierNamed(name, calculation, context) {\n const identifier = calculation.constructor.name === 'GeneratorFunction' ?\n CalculatedValueGenC({ name, calculation, context })\n :\n CalculatedValueSyncC({ name, calculation, context });\n return this.addIdentifier(identifier);\n }\n /**\n * Adds an identifier to this graph. Optionally [[write|writes]] the `proposedValue` to it afterwards.\n *\n * @param identifier\n * @param proposedValue\n * @param args\n */\n addIdentifier(identifier, proposedValue, ...args) {\n if (this.isCommitting) {\n if (this.onWriteDuringCommit === 'throw')\n throw new Error('Adding identifier during commit');\n else if (this.onWriteDuringCommit === 'warn')\n warn(new Error('Adding identifier during commit'));\n }\n this.activeTransaction.addIdentifier(identifier, proposedValue, ...args);\n if (this.autoCommit)\n this.scheduleAutoCommit();\n return identifier;\n }\n /**\n * Removes an identifier from this graph.\n *\n * @param identifier\n */\n removeIdentifier(identifier) {\n if (this.isCommitting) {\n if (this.onWriteDuringCommit === 'throw')\n throw new Error('Removing identifier during commit');\n else if (this.onWriteDuringCommit === 'warn')\n warn(new Error('Removinfg identifier during commit'));\n }\n this.activeTransaction.removeIdentifier(identifier);\n this.listeners.delete(identifier);\n if (this.autoCommit)\n this.scheduleAutoCommit();\n }\n /**\n * Tests, whether this graph has given identifier.\n *\n * @param identifier\n */\n hasIdentifier(identifier) {\n return this.activeTransaction.hasIdentifier(identifier);\n }\n /**\n * Writes a value to the given `identifier`.\n *\n * @param identifier\n * @param proposedValue\n * @param args\n */\n write(identifier, proposedValue, ...args) {\n if (this.isCommitting) {\n if (this.onWriteDuringCommit === 'throw')\n throw new Error('Write during commit');\n else if (this.onWriteDuringCommit === 'warn')\n warn(new Error('Write during commit'));\n }\n this.activeTransaction.write(identifier, proposedValue, ...args);\n if (this.autoCommit)\n this.scheduleAutoCommit();\n }\n // keep if possible?\n // pin (identifier : Identifier) : Quark {\n // return this.activeTransaction.pin(identifier)\n // }\n // Synchronously read the \"previous\", \"stable\" value from the graph. If its a lazy entry, it will be calculated\n // Synchronous read can not calculate lazy asynchronous identifiers and will throw exception\n // Lazy identifiers supposed to be \"total\" (or accept repeating observes?)\n readPrevious(identifier) {\n return this.activeTransaction.readPrevious(identifier);\n }\n // Asynchronously read the \"previous\", \"stable\" value from the graph. If its a lazy entry, it will be calculated\n // Asynchronous read can calculate both synchornous and asynchronous lazy identifiers.\n // Lazy identifiers supposed to be \"total\" (or accept repeating observes?)\n readPreviousAsync(identifier) {\n return this.activeTransaction.readPreviousAsync(identifier);\n }\n /**\n * Synchronously read the value of the given identifier from the graph.\n *\n * Synchronous read can not calculate asynchronous identifiers and will throw exception\n *\n * @param identifier\n */\n read(identifier) {\n return this.activeTransaction.read(identifier);\n }\n /**\n * Asynchronously read the value of the given identifier from the graph.\n *\n * Asynchronous read can calculate both synchronous and asynchronous identifiers\n *\n * @param identifier\n */\n readAsync(identifier) {\n return this.activeTransaction.readAsync(identifier);\n }\n /**\n * Read the value of the identifier either synchronously or asynchronously, depending on its type (see [[Identifier.sync]])\n *\n * @param identifier\n */\n get(identifier) {\n return this.activeTransaction.get(identifier);\n }\n // // read the identifier value, return the proposed value if no \"current\" value is calculated yet\n // readDirty (identifier : Identifier) : T {\n // return this.activeTransaction.readDirty(identifier)\n // }\n //\n //\n // // read the identifier value, return the proposed value if no \"current\" value is calculated yet\n // readDirtyAsync (identifier : Identifier) : Promise {\n // return this.activeTransaction.readDirtyAsync(identifier)\n // }\n observe(observerFunc, onUpdated) {\n const identifier = this.addIdentifier(CalculatedValueGen.new({\n // observers are explicitly eager\n lazy: false,\n calculation: observerFunc,\n }));\n this.addListener(identifier, onUpdated);\n return identifier;\n }\n observeContext(observerFunc, context, onUpdated) {\n const identifier = this.addIdentifier(CalculatedValueGen.new({\n // observers are explicitly eager\n lazy: false,\n calculation: observerFunc,\n context: context,\n }));\n this.addListener(identifier, onUpdated);\n return identifier;\n }\n addListener(identifier, onUpdated) {\n let listener = this.listeners.get(identifier);\n if (!listener) {\n listener = Listener.new();\n this.listeners.set(identifier, listener);\n }\n listener.handlers.push(onUpdated);\n }\n /**\n * Revert the replica to the state of previous transaction (marked with the [[commit]] call).\n *\n * To enable this feature, you need to opt-in using the [[ChronoGraph.historyLimit|historyLimit]] configuration property.\n *\n * Returns boolean, indicating whether the state transition actually happened.\n */\n undo() {\n const baseRevision = this.baseRevision;\n const previous = baseRevision.previous;\n if (!previous)\n return false;\n this.baseRevision = previous;\n // note: all unpropagated \"writes\" are lost\n this.$activeTransaction = undefined;\n return true;\n }\n /**\n * Advance the replica to the state of next transaction (marked with the [[commit]] call). Only meaningful\n * if a [[ChronoGraph.undo|undo]] call has been made earlier.\n *\n * To enable this feature, you need to opt-in using the [[historyLimit]] configuration property.\n *\n * Returns boolean, indicating whether the state transition actually happened.\n */\n redo() {\n const baseRevision = this.baseRevision;\n if (baseRevision === this.topRevision)\n return false;\n const nextRevision = this.followingRevision.get(baseRevision);\n this.baseRevision = nextRevision;\n // note: all unpropagated \"writes\" are lost\n this.$activeTransaction = undefined;\n return true;\n }\n onPropagationProgressNotification(notification) {\n }\n [ProposedOrPreviousSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n activeEntry.usedProposedOrPrevious = true;\n const proposedValue = activeEntry.getProposedValue(transaction);\n if (proposedValue !== undefined)\n return proposedValue;\n // newly added identifier\n if (!activeEntry.previous)\n return undefined;\n const identifier = activeEntry.identifier;\n if (identifier.lazy) {\n if (activeEntry.previous.hasValue())\n return activeEntry.previous.getValue();\n if (activeEntry.previous.hasProposedValue())\n return activeEntry.previous.getProposedValue(transaction);\n return null;\n }\n return transaction.readPrevious(activeEntry.identifier);\n }\n [RejectSymbol](effect, transaction) {\n this.reject(effect.reason);\n return BreakCurrentStackExecution;\n }\n [TransactionSymbol](effect, transaction) {\n return transaction;\n }\n [OwnQuarkSymbol](effect, transaction) {\n return transaction.getActiveEntry();\n }\n [OwnIdentifierSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n return activeEntry.identifier;\n }\n [WriteSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n if (activeEntry.identifier.lazy)\n throw new Error('Lazy identifiers can not use `Write` effect');\n const writeToHigherLevel = effect.identifier.level > activeEntry.identifier.level;\n if (!writeToHigherLevel)\n transaction.walkContext.startNewEpoch();\n transaction.write(effect.identifier, ...effect.proposedArgs);\n // // transaction.writes.push(effect)\n //\n // // const writeTo = effect.identifier\n // //\n // // writeTo.write.call(writeTo.context || writeTo, writeTo, transaction, null, ...effect.proposedArgs)\n //\n // transaction.onNewWrite()\n return writeToHigherLevel ? undefined : BreakCurrentStackExecution;\n }\n [WriteSeveralSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n if (activeEntry.identifier.lazy)\n throw new Error('Lazy identifiers can not use `Write` effect');\n let writeToHigherLevel = true;\n // effect.writes.forEach(writeInfo => {\n effect.writes.forEach(writeInfo => {\n if (writeInfo.identifier.level <= activeEntry.identifier.level && writeToHigherLevel) {\n transaction.walkContext.startNewEpoch();\n writeToHigherLevel = false;\n }\n transaction.write(writeInfo.identifier, ...writeInfo.proposedArgs);\n });\n // const identifier = writeInfo.identifier\n //\n // identifier.write.call(identifier.context || identifier, identifier, transaction, null, ...writeInfo.proposedArgs)\n // })\n // transaction.onNewWrite()\n return writeToHigherLevel ? undefined : BreakCurrentStackExecution;\n }\n [PreviousValueOfSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n const source = effect.identifier;\n transaction.addEdge(source, activeEntry, EdgeTypePast);\n return transaction.readPrevious(source);\n }\n [ProposedValueOfSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n const source = effect.identifier;\n transaction.addEdge(source, activeEntry, EdgeTypePast);\n const quark = transaction.entries.get(source);\n const proposedValue = quark && !quark.isShadow() ? quark.getProposedValue(transaction) : undefined;\n return proposedValue;\n }\n [HasProposedValueSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n const source = effect.identifier;\n transaction.addEdge(source, activeEntry, EdgeTypePast);\n const quark = transaction.entries.get(source);\n return quark ? quark.hasProposedValue() : false;\n }\n [HasProposedNotPreviousValueSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n const source = effect.identifier;\n transaction.addEdge(source, activeEntry, EdgeTypePast);\n const quark = transaction.entries.get(source);\n return quark ? quark.hasProposedValue() && !quark.proposedIsPrevious : false;\n }\n [ProposedOrPreviousValueOfSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n const source = effect.identifier;\n transaction.addEdge(source, activeEntry, EdgeTypePast);\n return transaction.readProposedOrPrevious(source);\n }\n [UnsafeProposedOrPreviousValueOfSymbol](effect, transaction) {\n return transaction.readProposedOrPrevious(effect.identifier);\n }\n [UnsafePreviousValueOfSymbol](effect, transaction) {\n return transaction.readPrevious(effect.identifier);\n }\n [ProposedArgumentsOfSymbol](effect, transaction) {\n const activeEntry = transaction.getActiveEntry();\n const source = effect.identifier;\n transaction.addEdge(source, activeEntry, EdgeTypePast);\n const quark = transaction.entries.get(source);\n return quark && !quark.isShadow() ? quark.proposedArguments : undefined;\n }\n}\n", "import { Base } from \"../class/Base.js\";\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * This class describes an entity. Entity is simply a collection of [[Field]]s. Entity also may have a parent entity,\n * from which it inherit the fields.\n */\nexport class EntityMeta extends Base {\n constructor() {\n super(...arguments);\n /**\n * The name of the entity\n */\n this.name = undefined;\n this.ownFields = new Map();\n this.schema = undefined;\n this.$skeleton = {};\n this.$allFields = undefined;\n }\n /**\n * Checks whether the entity has a field with given name (possibly inherited from parent entity).\n *\n * @param name\n */\n hasField(name) {\n return this.getField(name) !== undefined;\n }\n /**\n * Returns a field with given name (possibly inherited) or `undefined` if there's none.\n *\n * @param name\n */\n getField(name) {\n return this.allFields.get(name);\n }\n /**\n * Adds a field to this entity.\n *\n * @param field\n */\n addField(field) {\n const name = field.name;\n if (!name)\n throw new Error(`Field must have a name`);\n if (this.ownFields.has(name))\n throw new Error(`Field with name [${name}] already exists`);\n field.entity = this;\n this.ownFields.set(name, field);\n return field;\n }\n forEachParent(func) {\n let entity = this;\n while (entity) {\n func(entity);\n entity = entity.parentEntity;\n }\n }\n get allFields() {\n if (this.$allFields !== undefined)\n return this.$allFields;\n const allFields = new Map();\n const visited = new Set();\n this.forEachParent(entity => {\n entity.ownFields.forEach((field, name) => {\n if (!visited.has(name)) {\n visited.add(name);\n allFields.set(name, field);\n }\n });\n });\n return this.$allFields = allFields;\n }\n /**\n * Iterator for all fields of this entity (including inherited).\n *\n * @param func\n */\n forEachField(func) {\n this.allFields.forEach(func);\n }\n}\n", "import { ChronoGraph } from \"../chrono/Graph.js\";\nimport { Mixin } from \"../class/Mixin.js\";\nexport var ReadMode;\n(function (ReadMode) {\n ReadMode[ReadMode[\"Current\"] = 0] = \"Current\";\n ReadMode[ReadMode[\"Previous\"] = 1] = \"Previous\";\n ReadMode[ReadMode[\"ProposedOrPrevious\"] = 2] = \"ProposedOrPrevious\";\n ReadMode[ReadMode[\"CurrentOrProposedOrPrevious\"] = 3] = \"CurrentOrProposedOrPrevious\";\n})(ReadMode || (ReadMode = {}));\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Reactive graph, operating on the set of entities (see [[Entity]] and [[EntityMeta]]), each having a set of fields (see [[Field]]).\n *\n * Entities are mapped to JS classes and fields - to their properties, decorated with [[field]].\n *\n * The calculation function for some field can be mapped to the class method, using the [[calculate]] decorator.\n *\n * An example of usage:\n *\n * ```ts\n * class Author extends Entity.mix(Base) {\n * @field()\n * firstName : string\n * @field()\n * lastName : string\n * @field()\n * fullName : string\n *\n * @calculate('fullName')\n * calculateFullName () : string {\n * return this.firstName + ' ' + this.lastName\n * }\n * }\n * ```\n */\nexport class Replica extends Mixin([ChronoGraph], (base) => class Replica extends base {\n constructor() {\n super(...arguments);\n /**\n * Replica re-defines the default value of the `autoCommit` property to `true`.\n */\n this.autoCommit = true;\n this.readMode = ReadMode.Current;\n }\n /**\n * Add entity instance to the replica\n *\n * @param entity\n */\n addEntity(entity) {\n entity.enterGraph(this);\n }\n /**\n * Add several entity instances to the replica\n *\n * @param entity\n */\n addEntities(entities) {\n entities.forEach(entity => this.addEntity(entity));\n }\n /**\n * Remove entity instance from the replica\n *\n * @param entity\n */\n removeEntity(entity) {\n entity.leaveGraph(this);\n }\n /**\n * Remove several entity instances from the replica\n *\n * @param entity\n */\n removeEntities(entities) {\n entities.forEach(entity => this.removeEntity(entity));\n }\n}) {\n}\n", "import { CalculatedValueGen, CalculatedValueSync, Identifier, Variable } from \"../chrono/Identifier.js\";\nimport { Mixin } from \"../class/Mixin.js\";\nimport { ReadMode } from \"./Replica.js\";\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Mixin, for the identifier that represent a field of the entity. Requires the [[Identifier]] (or its subclass)\n * as a base class. See more about mixins: [[Mixin]]\n */\nexport class FieldIdentifier extends Mixin([Identifier], (base) => class FieldIdentifier extends base {\n constructor() {\n super(...arguments);\n /**\n * Reference to the [[Field]] this identifier represents\n */\n this.field = undefined;\n /**\n * Reference to the [[Entity]] this identifier represents\n */\n this.self = undefined;\n // temp storage for value for the phase, when identifier is created, but has not joined any graph\n // is cleared during the 1st join to the graph\n this.DATA = undefined;\n }\n // standaloneQuark : InstanceType\n // readFromGraphDirtySync (graph : Checkout) {\n // if (graph)\n // return graph.readDirty(this)\n // else\n // return this.DATA\n // }\n // returns the value itself if there were no affecting writes for it\n // otherwise - promise\n getFromGraph(graph) {\n if (graph) {\n if (graph.readMode === ReadMode.Current)\n return graph.get(this);\n if (graph.readMode === ReadMode.Previous)\n return graph.activeTransaction.readPrevious(this);\n if (graph.readMode === ReadMode.ProposedOrPrevious)\n graph.activeTransaction.readProposedOrPrevious(this);\n return graph.activeTransaction.readCurrentOrProposedOrPrevious(this);\n }\n else\n return this.DATA;\n }\n readFromGraph(graph) {\n if (graph)\n return graph.read(this);\n else\n return this.DATA;\n }\n writeToGraph(graph, proposedValue, ...args) {\n if (graph)\n graph.write(this, proposedValue, ...args);\n else\n this.DATA = proposedValue;\n }\n leaveGraph(graph) {\n const entry = graph.activeTransaction.getLatestStableEntryFor(this);\n if (entry)\n this.DATA = entry.getValue();\n super.leaveGraph(graph);\n }\n toString() {\n return this.name;\n }\n}) {\n}\nexport class MinimalFieldIdentifierSync extends FieldIdentifier.mix(CalculatedValueSync) {\n}\nexport class MinimalFieldIdentifierGen extends FieldIdentifier.mix(CalculatedValueGen) {\n}\nexport class MinimalFieldVariable extends FieldIdentifier.mix(Variable) {\n}\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Mixin, for the identifier that represent an entity as a whole. Requires the [[Identifier]] (or its subclass)\n * as a base class. See more about mixins: [[Mixin]]\n */\nexport class EntityIdentifier extends Mixin([Identifier], (base) => class EntityIdentifier extends base {\n constructor() {\n super(...arguments);\n /**\n * [[EntityMeta]] instance of the entity this identifier represents\n */\n this.entity = undefined;\n /**\n * Reference to the [[Entity]] this identifier represents\n */\n this.self = undefined;\n }\n // entity atom is considered changed if any of its incoming atoms has changed\n // this just means if it's calculation method has been called, it should always\n // assign a new value\n equality() {\n return false;\n }\n toString() {\n return `Entity identifier [${this.self}]`;\n }\n}) {\n}\nexport class MinimalEntityIdentifier extends EntityIdentifier.mix(CalculatedValueGen) {\n}\n", "import { Meta } from \"../chrono/Identifier.js\";\nimport { MinimalFieldIdentifierGen, MinimalFieldIdentifierSync, MinimalFieldVariable } from \"../replica/Identifier.js\";\nimport { isGeneratorFunction } from \"../util/Helpers.js\";\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * This class describes a field of some [[EntityMeta]].\n */\nexport class Field extends Meta {\n constructor() {\n super(...arguments);\n /**\n * Boolean flag, indicating whether this field should be persisted\n */\n this.persistent = true;\n }\n getIdentifierClass(calculationFunction) {\n if (this.identifierCls)\n return this.identifierCls;\n if (!calculationFunction)\n return MinimalFieldVariable;\n return isGeneratorFunction(calculationFunction) ? MinimalFieldIdentifierGen : MinimalFieldIdentifierSync;\n }\n}\n", "import { CommitZero } from \"../chrono/Graph.js\";\nimport { Identifier } from \"../chrono/Identifier.js\";\nimport { Mixin } from \"../class/Mixin.js\";\nimport { DEBUG, debug, SourceLinePoint } from \"../environment/Debug.js\";\nimport { runGeneratorSyncWithEffect } from \"../primitives/Calculation.js\";\nimport { EntityMeta } from \"../schema/EntityMeta.js\";\nimport { Field } from \"../schema/Field.js\";\nimport { defineProperty, uppercaseFirst } from \"../util/Helpers.js\";\nimport { MinimalEntityIdentifier } from \"./Identifier.js\";\nconst isEntityMarker = Symbol('isEntity');\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Entity [[Mixin|mixin]]. When applied to some base class (recommended one is [[Base]]), turns it into entity.\n * Entity may have several fields, which are properties decorated with [[field]] decorator.\n *\n * To apply this mixin use the `Entity.mix` property, which represents the mixin lambda.\n *\n * Another decorator, [[calculate]], marks the method, that will be used to calculate the value of field.\n *\n * Example:\n *\n * ```ts\n * class Author extends Entity.mix(Base) {\n * @field()\n * firstName : string\n * @field()\n * lastName : string\n * @field()\n * fullName : string\n *\n * @calculate('fullName')\n * calculateFullName () : string {\n * return this.firstName + ' ' + this.lastName\n * }\n * }\n * ```\n *\n */\nexport class Entity extends Mixin([], (base) => {\n class Entity extends base {\n // marker in the prototype to identify whether the parent class is Entity mixin itself\n // it is not used for `instanceof` purposes and not be confused with the [MixinInstanceOfProperty]\n // (though it is possible to use MixinInstanceOfProperty for this purpose, that would require to\n // make it public\n [isEntityMarker]() { }\n /**\n * An [[EntityMeta]] instance, representing the \"meta\" information about the entity class. It is shared among all instances\n * of the class.\n */\n get $entity() {\n // this will lazily create an EntityData instance in the prototype\n return createEntityOnPrototype(this.constructor.prototype);\n }\n /**\n * An object, which properties corresponds to the ChronoGraph [[Identifier]]s, created for every field.\n *\n * For example:\n *\n * ```ts\n * class Author extends Entity.mix(Base) {\n * @field()\n * firstName : string\n * @field()\n * lastName : string\n * }\n *\n * const author = Author.new()\n *\n * // identifier for the field `firstName`\n * author.$.firstName\n *\n * const firstName = replica.read(author.$.firstName)\n * ```\n */\n get $() {\n const $ = {};\n this.$entity.forEachField((field, name) => {\n $[name] = this.createFieldIdentifier(field);\n });\n if (DEBUG) {\n const proxy = new Proxy($, {\n get(entity, property, receiver) {\n if (!entity[property])\n debug(new Error(`Attempt to read a missing field ${String(property)} on ${entity}`));\n entity[property].SOURCE_POINT = SourceLinePoint.fromThisCall();\n return entity[property];\n }\n });\n return defineProperty(this, '$', proxy);\n }\n else {\n return defineProperty(this, '$', $);\n }\n }\n /**\n * A graph identifier, that represents the whole entity.\n */\n get $$() {\n return defineProperty(this, '$$', MinimalEntityIdentifier.new({\n name: this.$entityName,\n entity: this.$entity,\n calculation: this.calculateSelf,\n context: this,\n self: this,\n }));\n }\n get $entityName() {\n return this.constructor.name || this.$entity.name;\n }\n *calculateSelf() {\n return this;\n }\n createFieldIdentifier(field) {\n const name = field.name;\n const entity = this.$entity;\n const constructor = this.constructor;\n const skeleton = entity.$skeleton;\n if (!skeleton[name])\n skeleton[name] = constructor.getIdentifierTemplateClass(this, field);\n const identifier = new skeleton[name]();\n identifier.context = this;\n identifier.self = this;\n identifier.name = `${this.$$.name}.$.${field.name}`;\n return identifier;\n }\n forEachFieldIdentifier(func) {\n this.$entity.forEachField((field, name) => func(this.$[name], name, field));\n }\n /**\n * This method is called when entity is added to some replica.\n *\n * @param replica\n */\n enterGraph(replica) {\n if (this.graph)\n throw new Error('Already entered replica');\n this.graph = replica;\n replica.addIdentifier(this.$$);\n this.$entity.forEachField((field, name) => {\n const identifier = this.$[name];\n replica.addIdentifier(identifier, identifier.DATA);\n identifier.DATA = undefined;\n });\n }\n /**\n * This method is called when entity is removed from the replica it's been added to.\n */\n leaveGraph(graph) {\n const ownGraph = this.graph;\n const removeFrom = graph || ownGraph;\n if (!removeFrom)\n return;\n this.$entity.forEachField((field, name) => removeFrom.removeIdentifier(this.$[name]));\n removeFrom.removeIdentifier(this.$$);\n if (removeFrom === ownGraph)\n this.graph = undefined;\n }\n // isPropagating () {\n // return this.getGraph().isPropagating\n // }\n propagate(arg) {\n return this.commit(arg);\n }\n /**\n * This is a convenience method, that just delegates to the [[ChronoGraph.commit]] method of this entity's graph.\n *\n * If there's no graph (entity has not been added to any replica) a [[CommitZero]] constant will be returned.\n */\n commit(arg) {\n const graph = this.graph;\n if (!graph)\n return CommitZero;\n return graph.commit(arg);\n }\n async propagateAsync() {\n return this.commitAsync();\n }\n /**\n * This is a convenience method, that just delegates to the [[ChronoGraph.commitAsync]] method of this entity's graph.\n *\n * If there's no graph (entity has not been added to any replica) a resolved promise with [[CommitZero]] constant will be returned.\n */\n async commitAsync(arg) {\n const graph = this.graph;\n if (!graph)\n return Promise.resolve(CommitZero);\n return graph.commitAsync(arg);\n }\n /**\n * An [[EntityMeta]] instance, representing the \"meta\" information about the entity class. It is shared among all instances\n * of the class.\n */\n static get $entity() {\n return ensureEntityOnPrototype(this.prototype);\n }\n static getIdentifierTemplateClass(me, field) {\n const name = field.name;\n const config = {\n name: `${me.$$.name}.$.${name}`,\n field: field\n };\n //------------------\n if (field.hasOwnProperty('sync'))\n config.sync = field.sync;\n if (field.hasOwnProperty('lazy'))\n config.lazy = field.lazy;\n if (field.hasOwnProperty('equality'))\n config.equality = field.equality;\n //------------------\n const calculationFunction = me.$calculations && me[me.$calculations[name]];\n if (calculationFunction)\n config.calculation = calculationFunction;\n //------------------\n const writeFunction = me.$writes && me[me.$writes[name]];\n if (writeFunction)\n config.write = writeFunction;\n //------------------\n const buildProposedFunction = me.$buildProposed && me[me.$buildProposed[name]];\n if (buildProposedFunction) {\n config.buildProposedValue = buildProposedFunction;\n config.proposedValueIsBuilt = true;\n }\n //------------------\n const template = field.getIdentifierClass(calculationFunction).new(config);\n const TemplateClass = function () { };\n TemplateClass.prototype = template;\n return TemplateClass;\n }\n // unfortunately, the better typing:\n // run > (methodName : Name, ...args : Parameters)\n // : ReturnType extends CalculationIterator ? Res : ReturnType\n // yields \"types are exceedingly long and possibly infinite on the application side\n run(methodName, ...args) {\n const onEffect = (effect) => {\n if (effect instanceof Identifier)\n return this.graph.read(effect);\n throw new Error(\"Helper methods can not yield effects during computation\");\n };\n const transaction = this.graph.activeTransaction;\n const prevActiveStack = transaction.activeStack;\n transaction.activeStack = [];\n const res = runGeneratorSyncWithEffect(onEffect, this[methodName], args, this);\n transaction.activeStack = prevActiveStack;\n return res;\n }\n static createPropertyAccessorsFor(fieldName) {\n // idea is to indicate to the v8, that `propertyKey` is a constant and thus\n // it can optimize access by it\n const propertyKey = fieldName;\n const target = this.prototype;\n Object.defineProperty(target, propertyKey, {\n get: function () {\n return this.$[propertyKey].getFromGraph(this.graph);\n },\n set: function (value) {\n this.$[propertyKey].writeToGraph(this.graph, value);\n }\n });\n }\n static createMethodAccessorsFor(fieldName) {\n // idea is to indicate to the v8, that `propertyKey` is a constant and thus\n // it can optimize access by it\n const propertyKey = fieldName;\n const target = this.prototype;\n const getterFnName = `get${uppercaseFirst(propertyKey)}`;\n const setterFnName = `set${uppercaseFirst(propertyKey)}`;\n const putterFnName = `put${uppercaseFirst(propertyKey)}`;\n if (!(getterFnName in target)) {\n target[getterFnName] = function () {\n return this.$[propertyKey].getFromGraph(this.graph);\n };\n }\n if (!(setterFnName in target)) {\n target[setterFnName] = function (value, ...args) {\n this.$[propertyKey].writeToGraph(this.graph, value, ...args);\n return this.graph\n ?\n (this.graph.autoCommitMode === 'sync' ? this.graph.commit() : this.graph.commitAsync())\n :\n Promise.resolve(CommitZero);\n };\n }\n if (!(putterFnName in target)) {\n target[putterFnName] = function (value, ...args) {\n this.$[propertyKey].writeToGraph(this.graph, value, ...args);\n };\n }\n }\n }\n return Entity;\n}) {\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport const createEntityOnPrototype = (proto) => {\n let parent = Object.getPrototypeOf(proto);\n // the `hasOwnProperty` condition will be `true` for the `Entity` mixin itself\n // if the parent is `Entity` mixin, then this is a top-level entity\n return defineProperty(proto, '$entity', EntityMeta.new({\n parentEntity: parent.hasOwnProperty(isEntityMarker) ? null : parent.$entity,\n name: proto.constructor.name\n }));\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const ensureEntityOnPrototype = (proto) => {\n if (!proto.hasOwnProperty('$entity'))\n createEntityOnPrototype(proto);\n return proto.$entity;\n};\n/*\n * The \"generic\" field decorator, in the sense, that it allows specifying both field config and field class.\n * This means it can create any field instance.\n */\nexport const generic_field = (fieldConfig, fieldCls = Field) => {\n return function (target, fieldName) {\n const entity = ensureEntityOnPrototype(target);\n const field = entity.addField(fieldCls.new(Object.assign(fieldConfig || {}, {\n name: fieldName\n })));\n const cons = target.constructor;\n cons.createPropertyAccessorsFor(fieldName);\n cons.createMethodAccessorsFor(fieldName);\n };\n};\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Field decorator. The type signature is:\n *\n * ```ts\n * field : (fieldConfig? : Partial>, fieldCls : T | typeof Field = Field) => PropertyDecorator\n * ```\n * Its a function, that accepts field config object and optionally a field class (default is [[Field]]) and returns a property decorator.\n *\n * Example:\n *\n * ```ts\n * const ignoreCaseCompare = (a : string, b : string) : boolean => a.toUpperCase() === b.toUpperCase()\n *\n * class MyField extends Field {}\n *\n * class Author extends Entity.mix(Base) {\n * @field({ equality : ignoreCaseCompare })\n * firstName : string\n *\n * @field({ lazy : true }, MyField)\n * lastName : string\n * }\n * ```\n *\n * For every field, there are generated get and set accessors, with which you can read/write the data:\n *\n * ```ts\n * const author = Author.new({ firstName : 'Mark' })\n *\n * author.firstName // Mark\n * author.lastName = 'Twain'\n * ```\n *\n * The getters are basically using [[Replica.get]] and setters [[Replica.write]].\n *\n * Note, that if the identifier is asynchronous, reading from it will return a promise. But, immediately after the [[Replica.commit]] call, getter will return\n * plain value. This is a compromise between the convenience and correctness and this behavior may change (or made configurable) in the future.\n *\n * Additionally to the accessors, the getter and setter methods are generated. The getter method's name is formed as `get` followed by the field name\n * with upper-cased first letter. The setter's name is formed in the same way, with `set` prefix.\n *\n * The getter method is an exact equivalent of the get accessor. The setter method, in addition to data write, immediately after that\n * performs a call to [[Replica.commit]] (or [[Replica.commitAsync]], depending from the [[Replica.autoCommitMode]] option)\n * and return its result.\n *\n * ```ts\n * const author = Author.new({ firstName : 'Mark' })\n *\n * author.getFirstName() // Mark\n * await author.setLastName('Twain') // issues asynchronous commit\n * ```\n */\nexport const field = generic_field;\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Decorator for the method, that calculates a value of some field\n *\n * ```ts\n *\n * @entity()\n * class Author extends Entity.mix(Base) {\n * @field()\n * firstName : string\n * @field()\n * lastName : string\n * @field()\n * fullName : string\n *\n * @calculate('fullName')\n * calculateFullName () : string {\n * return this.firstName + ' ' + this.lastName\n * }\n * }\n * ```\n *\n * @param fieldName The name of the field the decorated method should be \"tied\" to.\n */\nexport const calculate = function (fieldName) {\n // `target` will be a prototype of the class with Entity mixin\n return function (target, propertyKey, _descriptor) {\n ensureEntityOnPrototype(target);\n let calculations;\n if (!target.$calculations) {\n calculations = target.$calculations = {};\n }\n else {\n if (!target.hasOwnProperty('$calculations')) {\n calculations = target.$calculations = Object.create(target.$calculations);\n }\n else\n calculations = target.$calculations;\n }\n calculations[fieldName] = propertyKey;\n };\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const write = function (fieldName) {\n // `target` will be a prototype of the class with Entity mixin\n return function (target, propertyKey, _descriptor) {\n ensureEntityOnPrototype(target);\n let writes;\n if (!target.$writes) {\n writes = target.$writes = {};\n }\n else {\n if (!target.hasOwnProperty('$writes')) {\n writes = target.$writes = Object.create(target.$writes);\n }\n else\n writes = target.$writes;\n }\n writes[fieldName] = propertyKey;\n };\n};\n//---------------------------------------------------------------------------------------------------------------------\nexport const build_proposed = function (fieldName) {\n // `target` will be a prototype of the class with Entity mixin\n return function (target, propertyKey, _descriptor) {\n ensureEntityOnPrototype(target);\n let buildProposed;\n if (!target.$buildProposed) {\n buildProposed = target.$buildProposed = {};\n }\n else {\n if (!target.hasOwnProperty('$buildProposed')) {\n buildProposed = target.$buildProposed = Object.create(target.$buildProposed);\n }\n else\n buildProposed = target.$buildProposed;\n }\n buildProposed[fieldName] = propertyKey;\n };\n};\n", "/**\n * The enumeration for the time units\n */\nexport var TimeUnit;\n(function (TimeUnit) {\n TimeUnit[\"Millisecond\"] = \"millisecond\";\n TimeUnit[\"Second\"] = \"second\";\n TimeUnit[\"Minute\"] = \"minute\";\n TimeUnit[\"Hour\"] = \"hour\";\n TimeUnit[\"Day\"] = \"day\";\n TimeUnit[\"Week\"] = \"week\";\n TimeUnit[\"Month\"] = \"month\";\n TimeUnit[\"Quarter\"] = \"quarter\";\n TimeUnit[\"Year\"] = \"year\";\n})(TimeUnit || (TimeUnit = {}));\n/**\n * The enumeration for the project constraint resolution ways.\n */\nexport var ProjectConstraintResolution;\n(function (ProjectConstraintResolution) {\n /**\n * Adjust the event dates to honor the constraint.\n */\n ProjectConstraintResolution[\"Honor\"] = \"honor\";\n /**\n * Ignore the constraint date and keep the event dates.\n */\n ProjectConstraintResolution[\"Ignore\"] = \"ignore\";\n /**\n * Yield a conflict to pick a resolution based on some application logic\n * (like UI dialog allowing user to choose a resolution).\n */\n ProjectConstraintResolution[\"Conflict\"] = \"conflict\";\n})(ProjectConstraintResolution || (ProjectConstraintResolution = {}));\n/**\n * The enumeration for the supported constraint types\n */\nexport var ConstraintType;\n(function (ConstraintType) {\n /**\n * \"Must start on\" constraint.\n * Restricts an event to start on a [[HasDateConstraintMixin.constraintDate|specified date]].\n * The constraint cannot be used for a summary event.\n */\n ConstraintType[\"MustStartOn\"] = \"muststarton\";\n /**\n * \"Must finish on\" constraint.\n * Restricts an event to finish on a [[HasDateConstraintMixin.constraintDate|specified date]].\n * The constraint cannot be used for a summary event.\n */\n ConstraintType[\"MustFinishOn\"] = \"mustfinishon\";\n /**\n * \"Start no earlier than\" constraint.\n * Restricting an event to start on or after a [[HasDateConstraintMixin.constraintDate|specified date]].\n */\n ConstraintType[\"StartNoEarlierThan\"] = \"startnoearlierthan\";\n /**\n * \"Start no later than\" constraint.\n * Restricting an event to start on or before a [[HasDateConstraintMixin.constraintDate|specified date]].\n *\n * The constraint cannot be used for a summary task.\n */\n ConstraintType[\"StartNoLaterThan\"] = \"startnolaterthan\";\n /**\n * \"Finish no earlier than\" constraint.\n * Restricting an event to finish on or after a [[HasDateConstraintMixin.constraintDate|specified date]].\n *\n * The constraint cannot be used for a summary task.\n */\n ConstraintType[\"FinishNoEarlierThan\"] = \"finishnoearlierthan\";\n /**\n * \"Finish no later than\" constraint.\n * Restricting an event to finish on or before a [[HasDateConstraintMixin.constraintDate|specified date]].\n */\n ConstraintType[\"FinishNoLaterThan\"] = \"finishnolaterthan\";\n /**\n * \"As soon as possible\" constraint.\n * Note this is not a date constraint per se, but a flag, that indicates that a task \"gravitates\" (is \"stickying\")\n * to the project's start date.\n */\n ConstraintType[\"AsSoonAsPossible\"] = \"assoonaspossible\";\n /**\n * \"As late as possible\" constraint.\n * Note this is not a date constraint per se, but a flag, that indicates that a task \"gravitates\" (is \"stickying\")\n * to the project's end date.\n */\n ConstraintType[\"AsLateAsPossible\"] = \"aslateaspossible\";\n})(ConstraintType || (ConstraintType = {}));\n/**\n * The enumeration for the supported scheduling modes\n */\nexport var SchedulingMode;\n(function (SchedulingMode) {\n SchedulingMode[\"Normal\"] = \"Normal\";\n SchedulingMode[\"FixedDuration\"] = \"FixedDuration\";\n SchedulingMode[\"FixedEffort\"] = \"FixedEffort\";\n SchedulingMode[\"FixedUnits\"] = \"FixedUnits\";\n})(SchedulingMode || (SchedulingMode = {}));\n/**\n * The enumeration for the dependency validation result\n */\nexport var DependencyValidationResult;\n(function (DependencyValidationResult) {\n /**\n * Dependency has no errors\n */\n DependencyValidationResult[DependencyValidationResult[\"NoError\"] = 0] = \"NoError\";\n /**\n * Indicates that the validated dependency builds a cycle\n */\n DependencyValidationResult[DependencyValidationResult[\"CyclicDependency\"] = 1] = \"CyclicDependency\";\n /**\n * Indicates that a dependency with the same predecessor and successor as validated one's already exists\n */\n DependencyValidationResult[DependencyValidationResult[\"DuplicatingDependency\"] = 2] = \"DuplicatingDependency\";\n})(DependencyValidationResult || (DependencyValidationResult = {}));\n/**\n * The enumeration for the supported dependency types\n */\nexport var DependencyType;\n(function (DependencyType) {\n /**\n * Start-to-Start (_SS_)\n *\n * With this dependency type, the succeeding event is delayed to start not earlier than the preceding event starts.\n */\n DependencyType[DependencyType[\"StartToStart\"] = 0] = \"StartToStart\";\n /**\n * Start-to-Finish (_SF_)\n *\n * The finish of the succeeding event is constrained by the start of the preceding event.\n * So the successor cannot finish before the predecessor starts.\n */\n DependencyType[DependencyType[\"StartToEnd\"] = 1] = \"StartToEnd\";\n /**\n * Finish-to-Start (_FS_)\n *\n * This type of dependency, restricts the dependent event to not start earlier than the preceding event finishes.\n */\n DependencyType[DependencyType[\"EndToStart\"] = 2] = \"EndToStart\";\n /**\n * Finish-to-Finish (_FF_)\n *\n * The succeeding event cannot finish before the completion of the preceding event.\n */\n DependencyType[DependencyType[\"EndToEnd\"] = 3] = \"EndToEnd\";\n})(DependencyType || (DependencyType = {}));\n/**\n * The enumeration for the supported sources of the calendar for the dependency.\n */\nexport var DependenciesCalendar;\n(function (DependenciesCalendar) {\n DependenciesCalendar[\"Project\"] = \"Project\";\n DependenciesCalendar[\"FromEvent\"] = \"FromEvent\";\n DependenciesCalendar[\"ToEvent\"] = \"ToEvent\";\n})(DependenciesCalendar || (DependenciesCalendar = {}));\n/**\n * Engine provides with different project types, the enumeration describes the types currently available\n */\nexport var ProjectType;\n(function (ProjectType) {\n ProjectType[ProjectType[\"SchedulerBasic\"] = 1] = \"SchedulerBasic\";\n ProjectType[ProjectType[\"SchedulerPro\"] = 2] = \"SchedulerPro\";\n ProjectType[ProjectType[\"Gantt\"] = 3] = \"Gantt\";\n})(ProjectType || (ProjectType = {}));\n/**\n * The enumeration for the scheduling direction\n */\nexport var Direction;\n(function (Direction) {\n /**\n * Forward (or As Soon As Possible (ASAP)) scheduling.\n */\n Direction[\"Forward\"] = \"Forward\";\n /**\n * Backward (or As Late As Possible (ALAP)) scheduling.\n */\n Direction[\"Backward\"] = \"Backward\";\n Direction[\"None\"] = \"None\";\n})(Direction || (Direction = {}));\nexport const isEqualEffectiveDirection = (a, b) => {\n if (a && !b || !a && b)\n return false;\n if (!a && !b)\n return true;\n return (a.direction === b.direction)\n && (a.kind === 'own' && b.kind === 'own'\n || (a.kind === 'enforced' && b.kind === 'enforced' && a.enforcedBy === b.enforcedBy)\n || (a.kind === 'inherited' && b.kind === 'inherited' && a.inheritedFrom === b.inheritedFrom));\n};\nexport var ConstraintIntervalSide;\n(function (ConstraintIntervalSide) {\n ConstraintIntervalSide[\"Start\"] = \"Start\";\n ConstraintIntervalSide[\"End\"] = \"End\";\n})(ConstraintIntervalSide || (ConstraintIntervalSide = {}));\n", "// http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1\n/**\n * Minimal date representable with native Date class\n */\nexport const MIN_DATE = new Date(-8640000000000000);\n/**\n * Maximal date representable with native Date class\n */\nexport const MAX_DATE = new Date(8640000000000000);\nexport const isDateFinite = (date) => {\n if (!date)\n return false;\n const time = date.getTime();\n return time !== MIN_DATE.getTime() && time !== MAX_DATE.getTime();\n};\n", "import { DEBUG_ONLY } from \"../environment/Debug.js\";\nconst RequiredProperties = Symbol('RequiredProperties');\nconst emptyFn = () => undefined;\nexport const required = DEBUG_ONLY((proto, propertyKey) => {\n let required = proto[RequiredProperties];\n if (!required)\n required = proto[RequiredProperties] = [];\n required.push(propertyKey);\n});\nexport const validateRequiredProperties = DEBUG_ONLY((context) => {\n const required = context[RequiredProperties];\n if (required) {\n for (let i = 0; i < required.length; i++)\n if (context[required[i]] === undefined)\n throw new Error(`Required attribute [${String(required[i])}] is not provided`);\n }\n});\n", "var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\n return c > 3 && r && Object.defineProperty(target, key, r), r;\n};\nimport { Base } from \"../class/Base.js\";\nimport { Mixin } from \"../class/Mixin.js\";\nimport { required, validateRequiredProperties } from \"../class/RequiredProperty.js\";\nimport { CI, concatIterable, map, uniqueOnly } from \"../collection/Iterator.js\";\nimport { DEBUG } from \"../environment/Debug.js\";\nimport { OnCycleAction, WalkContext } from \"../graph/WalkDepth.js\";\nlet FORMULA_ID = 0;\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Pre-defined constant formula id. If assigned to some variable, specifies, that this variable should keep the value proposed by user\n * (user input), or, if there's none, its previous value.\n */\nexport const CalculateProposed = FORMULA_ID++;\n// export const CalculatePure : FormulaId = FORMULA_ID++\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Class, describing a formula, which is part of the cyclic set. Formula just specifies its input variables and output variable,\n * it does not contain actual calculation.\n *\n * It is assumed that formula can only be \"activated\" if all of its inputs has value. It can be either a value from the previous iteration,\n * a value provided by user, or an output value of some other formula. See [[VariableInputState]] and [[CycleResolutionInput]].\n */\nexport class Formula extends Base {\n constructor() {\n super(...arguments);\n /**\n * The id of the formula. It is assigned automatically, should not be changed.\n */\n this.formulaId = FORMULA_ID++;\n /**\n * A set of the input variables for this formula.\n */\n this.inputs = new Set();\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport class VariableWalkContext extends WalkContext {\n collectNext(sourceNode, toVisit) {\n if (sourceNode instanceof Formula) {\n toVisit.push({ node: sourceNode.output, from: sourceNode, label: undefined });\n }\n else {\n const formulas = this.cache.formulasByInput.get(sourceNode);\n formulas && formulas.forEach(formula => toVisit.push({ node: formula, from: sourceNode, label: undefined }));\n }\n }\n}\n//---------------------------------------------------------------------------------------------------------------------\nexport class FormulasCache extends Mixin([Base], (base) => class FormulasCache extends base {\n constructor() {\n super(...arguments);\n /**\n * A set of variables, which forms cyclic computation\n */\n this.variables = new Set();\n /**\n * A set of formulas, which forms cyclic computation\n */\n this.formulas = new Set();\n this.$formulasByInput = undefined;\n this.$formulasByOutput = undefined;\n }\n get formulasByInput() {\n if (this.$formulasByInput !== undefined)\n return this.$formulasByInput;\n this.fillCache();\n return this.$formulasByInput;\n }\n get formulasByOutput() {\n if (this.$formulasByOutput !== undefined)\n return this.$formulasByOutput;\n this.fillCache();\n return this.$formulasByOutput;\n }\n add(formula) {\n this.$formulasByInput = undefined;\n this.$formulasByOutput = undefined;\n this.formulas.add(formula);\n }\n has(formula) {\n return this.formulas.has(formula);\n }\n fillCache() {\n this.$formulasByInput = new Map();\n this.$formulasByOutput = new Map();\n this.formulas.forEach(formula => {\n let formulasByOutput = this.$formulasByOutput.get(formula.output);\n if (!formulasByOutput) {\n formulasByOutput = new Set();\n this.$formulasByOutput.set(formula.output, formulasByOutput);\n }\n formulasByOutput.add(formula);\n formula.inputs.forEach(input => {\n let formulasByInput = this.$formulasByInput.get(input);\n if (!formulasByInput) {\n formulasByInput = new Set();\n this.$formulasByInput.set(input, formulasByInput);\n }\n formulasByInput.add(formula);\n });\n });\n }\n allInputVariables() {\n return uniqueOnly(concatIterable(map(this.formulas, formula => formula.inputs.values())));\n }\n isCyclic() {\n let isCyclic = false;\n const walkContext = VariableWalkContext.new({ cache: this, onCycle: () => { isCyclic = true; return OnCycleAction.Cancel; } });\n walkContext.startFrom(Array.from(this.allInputVariables()));\n return isCyclic;\n }\n}) {\n}\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Abstract description of the cycle. Does not include the default formula resolution, only variables and formulas. See also [[CycleResolution]].\n */\nexport class CycleDescription extends FormulasCache {\n}\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Class describing the cycle resolution process. Requires the abstract cycle [[description]] and a set of default formulas.\n *\n * The resolution is performed with [[CycleResolution.resolve]] method.\n *\n * Resolution are memoized, based on the input. You should generally have a single instance of this class for a single set of default formulas,\n * to accumulate the results and make resolution fast.\n */\nexport class CycleResolution extends Base {\n constructor() {\n super(...arguments);\n /**\n * Abstract cycle description for this resolution.\n */\n this.description = undefined;\n /**\n * A set of default formulas for this resolution. Default formulas specifies how the calculation should be performed, if there's no user input\n * for any variable (or there's input for all of them). Also, default formulas are preferred, if several formulas can be chosen to continue the resolution.\n */\n this.defaultResolutionFormulas = new Set();\n this.resolutionsByInputHash = new Map();\n }\n // the caching space is 3^var_num might need to clear the memory at some time\n clear() {\n this.resolutionsByInputHash.clear();\n }\n /**\n * This method accepts an input object and returns a cycle resolution.\n * Resolution are memoized, based on the input.\n *\n * @param input\n */\n resolve(input) {\n const cached = this.resolutionsByInputHash.get(input.hash);\n if (cached !== undefined)\n return cached;\n const resolution = this.buildResolution(input);\n this.resolutionsByInputHash.set(input.hash, resolution);\n return resolution;\n }\n buildResolution(input) {\n const walkContext = WalkState.new({ context: this, input });\n const allResolutions = Array.from(walkContext.next()).map(state => {\n return {\n resolution: state.asResolution(),\n nbrOfDefaultFormulas: Array.from(state.activatedFormulas.formulas).reduce((count, formula) => state.formulaIsDefault(formula) ? count + 1 : count, 0),\n unCoveredInputWeight: state.unCoveredInputWeight()\n };\n });\n allResolutions.sort((res1, res2) => {\n if (res1.unCoveredInputWeight < res2.unCoveredInputWeight)\n return -1;\n if (res1.unCoveredInputWeight > res2.unCoveredInputWeight)\n return 1;\n return res2.nbrOfDefaultFormulas - res1.nbrOfDefaultFormulas;\n });\n if (allResolutions.length > 0)\n return allResolutions[0].resolution;\n else\n debugger; // return default? or all-proposed?\n }\n}\n/**\n * Enumeration for various states of the input data for variables in the cycle. Individual members corresponds to binary bits and can be set simultaneously, like:\n *\n * ```ts\n * const input : VariableInputState = VariableInputState.HasPreviousValue | VariableInputState.HasProposedValue\n * ```\n */\nexport var VariableInputState;\n(function (VariableInputState) {\n VariableInputState[VariableInputState[\"NoInput\"] = 0] = \"NoInput\";\n /**\n * This bit indicates that variable has some previous value, when resolution starts. It can be any non-`undefined` value, including `null`.\n */\n VariableInputState[VariableInputState[\"HasPreviousValue\"] = 1] = \"HasPreviousValue\";\n /**\n * This bit indicates that variable has user input, when resolution starts. It can be any non-`undefined` value, including `null`.\n */\n VariableInputState[VariableInputState[\"HasProposedValue\"] = 2] = \"HasProposedValue\";\n /**\n * This bit indicates, that user intention is to keep this variable unchanged, if that is possible (does not contradict to other user input).\n */\n VariableInputState[VariableInputState[\"KeepIfPossible\"] = 4] = \"KeepIfPossible\";\n})(VariableInputState || (VariableInputState = {}));\n//---------------------------------------------------------------------------------------------------------------------\n/**\n * Class, describing the input data for a set of variables during cycle resolution.\n */\nexport class CycleResolutionInput extends Base {\n constructor() {\n super(...arguments);\n /**\n * A cycle resolution instance this input corresponds to.\n */\n this.context = undefined;\n this.input = undefined;\n this.$hash = '';\n }\n get hash() {\n if (this.$hash !== '')\n return this.$hash;\n return this.$hash = this.buildHash();\n }\n get description() { return this.context.description; }\n /**\n * Returns the same result as calling [[CycleResolution.resolve]] on this input instance\n */\n get resolution() {\n return this.context.resolve(this);\n }\n initialize(...args) {\n super.initialize(...args);\n validateRequiredProperties(this);\n this.input = new Map(CI(this.description.variables).map(variable => [variable, VariableInputState.NoInput]));\n }\n buildHash() {\n return String.fromCharCode(...CI(this.description.variables).inBatchesBySize(5).map(batch => this.batchToCharCode(batch)));\n }\n batchToCharCode(batch) {\n return batch.reduceRight((charCode, variable, index) => charCode | (this.input.get(variable) << index * 3), 0);\n }\n //---------------------\n /**\n * This method sets the [[HasProposedValue]] flag for the specified variable.\n *\n * @param variable\n */\n addProposedValueFlag(variable) {\n if (DEBUG) {\n if (!this.description.variables.has(variable))\n throw new Error('Unknown variable');\n if (this.$hash !== '')\n throw new Error('Already hashed');\n }\n const input = this.input.get(variable);\n this.input.set(variable, input | VariableInputState.HasProposedValue);\n }\n hasProposedValue(variable) {\n return Boolean(this.input.get(variable) & VariableInputState.HasProposedValue);\n }\n hasProposedValueVars() {\n return CI(this.description.variables).filter(variable => this.hasProposedValue(variable));\n }\n //---------------------\n /**\n * This method sets the [[HasPreviousValue]] flag for the specified variable.\n *\n * @param variable\n */\n addPreviousValueFlag(variable) {\n if (DEBUG) {\n if (!this.description.variables.has(variable))\n throw new Error('Unknown variable');\n if (this.$hash !== '')\n throw new Error('Already hashed');\n }\n const input = this.input.get(variable);\n this.input.set(variable, input | VariableInputState.HasPreviousValue);\n }\n hasPreviousValue(variable) {\n return Boolean(this.input.get(variable) & VariableInputState.HasPreviousValue);\n }\n hasPreviousValueVars() {\n return CI(this.description.variables).filter(variable => this.hasPreviousValue(variable));\n }\n //---------------------\n /**\n * This method sets the [[KeepIfPossible]] flag for the specified variable.\n *\n * @param variable\n */\n addKeepIfPossibleFlag(variable) {\n if (DEBUG) {\n if (!this.description.variables.has(variable))\n throw new Error('Unknown variable');\n if (this.$hash !== '')\n throw new Error('Already hashed');\n }\n const input = this.input.get(variable);\n this.input.set(variable, input | VariableInputState.KeepIfPossible);\n }\n keepIfPossible(variable) {\n return Boolean(this.input.get(variable) & VariableInputState.KeepIfPossible);\n }\n keepIfPossibleVars() {\n return CI(this.description.variables).filter(variable => this.keepIfPossible(variable));\n }\n}\n__decorate([\n required\n], CycleResolutionInput.prototype, \"context\", void 0);\n//---------------------------------------------------------------------------------------------------------------------\nexport class WalkState extends Base {\n constructor() {\n super(...arguments);\n this.context = undefined;\n this.input = undefined;\n this.previous = undefined;\n this.activatedFormula = undefined;\n this.$activatedFormulas = undefined;\n }\n get activatedFormulas() {\n if (this.$activatedFormulas !== undefined)\n return this.$activatedFormulas;\n const cache = FormulasCache.new({\n variables: this.description.variables,\n formulas: CI(this.thisAndPreviousStates()).map(state => state.activatedFormula).toSet()\n });\n return this.$activatedFormulas = cache;\n }\n get description() { return this.context.description; }\n *thisAndPreviousStates() {\n let current = this;\n while (current && current.activatedFormula) {\n yield current;\n current = current.previous;\n }\n }\n formulaHasProposedValueInInput(formula) {\n return Array.from(formula.inputs).some(variable => this.input.hasProposedValue(variable));\n }\n // this method counts\n unCoveredInputWeight() {\n const proposedVars = map(this.input.hasProposedValueVars(), variable => { return { variable, isProposed: true }; });\n const keepIfPossibleVars = map(this.input.keepIfPossibleVars(), variable => { return { variable, isProposed: false }; });\n const allInputVars = CI([proposedVars, keepIfPossibleVars]).concat().uniqueOnlyBy(el => el.variable);\n return allInputVars.reduce((totalWeight, { variable, isProposed }) => {\n let weight = 0;\n //-----------------\n const isOverwrittenByFormulas = this.activatedFormulas.formulasByOutput.get(variable);\n if (isOverwrittenByFormulas) {\n const formula = isOverwrittenByFormulas.size === 1 ? Array.from(isOverwrittenByFormulas)[0] : null;\n // the case, when some user input is overwritten with the default formula should be weighted less than\n // its overwritten with regular formula\n if (formula && this.formulaIsDefault(formula) && this.formulaHasProposedValueInInput(formula)) {\n if (isProposed)\n weight += 1e6;\n else\n weight += 1e4;\n }\n else {\n if (isProposed)\n weight += 1e7;\n else\n weight += 1e5;\n }\n }\n //-----------------\n const usedInFormulas = this.activatedFormulas.formulasByInput.get(variable);\n if (!(usedInFormulas && usedInFormulas.size > 0)) {\n if (isProposed)\n weight += 1e3;\n else\n weight += 1e2;\n }\n return totalWeight + weight;\n }, 0);\n }\n preferFormula(formula1, formula2) {\n const allInputsHasProposed1 = this.formulaAllInputsHasProposed(formula1);\n const allInputsHasProposed2 = this.formulaAllInputsHasProposed(formula2);\n if (allInputsHasProposed1 && !allInputsHasProposed2)\n return -1;\n if (allInputsHasProposed2 && !allInputsHasProposed1)\n return 1;\n const countInputsWithProposedOrKeep1 = this.formulaCountInputsWithProposedOrKeep(formula1);\n const countInputsWithProposedOrKeep2 = this.formulaCountInputsWithProposedOrKeep(formula2);\n if (countInputsWithProposedOrKeep1 > countInputsWithProposedOrKeep2)\n return -1;\n if (countInputsWithProposedOrKeep1 < countInputsWithProposedOrKeep2)\n return 1;\n if (this.formulaIsDefault(formula1) && !this.formulaIsDefault(formula2))\n return -1;\n if (this.formulaIsDefault(formula2) && !this.formulaIsDefault(formula1))\n return 1;\n return 0;\n }\n formulaIsDefault(formula) {\n return this.context.defaultResolutionFormulas.has(formula);\n }\n formulaCountInputsWithProposedOrKeep(formula) {\n let count = 0;\n Array.from(formula.inputs).forEach(variable => {\n if (this.input.hasProposedValue(variable) || this.input.keepIfPossible(variable))\n count++;\n });\n return count;\n }\n formulaAllInputsHasProposedOrKeep(formula) {\n return Array.from(formula.inputs).every(variable => this.input.hasProposedValue(variable) || this.input.keepIfPossible(variable));\n }\n formulaAllInputsHasProposed(formula) {\n return Array.from(formula.inputs).every(variable => this.input.hasProposedValue(variable));\n }\n formulaIsApplicable(formula) {\n const everyFormulaInputHasValue = Array.from(formula.inputs).every(variable => this.input.hasProposedValue(variable)\n || this.input.hasPreviousValue(variable)\n || this.activatedFormulas.formulasByOutput.has(variable));\n const cache = FormulasCache.new({ formulas: new Set(this.activatedFormulas.formulas) });\n cache.add(formula);\n return everyFormulaInputHasValue && !cache.isCyclic();\n }\n // in general the semantic of this method is very similar to `formulaIsApplicable`\n formulaIsInsignificant(formula) {\n const outputVariableAlreadyCalculated = this.activatedFormulas.formulasByOutput.has(formula.output);\n const outputVariableHasPreviousValue = this.input.hasPreviousValue(formula.output);\n return outputVariableAlreadyCalculated\n || outputVariableHasPreviousValue && Array.from(formula.inputs).some(variable => {\n // so we should ignore the formula, if some of its inputs\n // does not have value provided (neither previous nor proposed)\n return !this.input.hasPreviousValue(variable) && !this.input.hasProposedValue(variable)\n // ..and we haven't planned calculation of that input via another formula\n && !this.activatedFormulas.formulasByOutput.has(variable);\n });\n }\n unvisitedFormulas() {\n return Array.from(this.description.formulas).filter(formula => !this.activatedFormulas.has(formula));\n }\n *next() {\n const unvisitedFormulas = this.unvisitedFormulas();\n unvisitedFormulas.sort(this.preferFormula.bind(this));\n let isFinal = true;\n for (const formula of unvisitedFormulas) {\n if (!this.formulaIsApplicable(formula) || this.formulaIsInsignificant(formula))\n continue;\n const nextState = WalkState.new({\n previous: this,\n context: this.context,\n input: this.input,\n activatedFormula: formula\n });\n yield* nextState.next();\n isFinal = false;\n }\n if (isFinal)\n yield this;\n }\n asResolution() {\n return new Map(CI(this.description.variables).map(variable => {\n const formulas = this.activatedFormulas.formulasByOutput.get(variable);\n if (formulas) {\n for (const firstFormula of formulas) {\n return [variable, firstFormula.formulaId];\n }\n }\n return [variable, CalculateProposed];\n }));\n }\n}\n", "/**\n * @module Core/helper/BrowserHelper\n */\n/**\n * Static helper class that does browser or platform detection and provides other helper functions.\n */\nexport default class BrowserHelper {\n static supportsPointerEvents = Boolean(globalThis.PointerEvent || globalThis.MSPointerEvent);\n // Locker Service does not allow to instantiate PointerEvents. LWS apparently does, however.\n // https://github.com/bryntum/support/issues/5578\n static supportsPointerEventConstructor = typeof PointerEvent !== 'undefined';\n static PointerEventConstructor = globalThis.PointerEvent || globalThis.CustomEvent;\n //region Init\n /**\n * Yields `true` if the platform running is a phone (screen width or height <= 414 CSS pixels)\n * @property {Boolean}\n * @readonly\n * @static\n * @category Platform\n */\n static isPhone = globalThis.matchMedia?.('(max-height:414px) or (max-width:414px)').matches;\n static cacheFlags(platform = navigator.platform, userAgent = navigator.userAgent) {\n const me = this;\n // os\n me._isLinux = Boolean(platform.match(/Linux/));\n me._isMac = Boolean(platform.match(/Mac/));\n me._isWindows = Boolean(platform.match(/Win32/));\n me._isMobile = Boolean(userAgent.match(/Mobile|Opera Mini|Opera Mobi|Puffin/) || typeof globalThis.orientation === 'number');\n // Edge user agent contains webkit too.\n // This is not a typo. Edge has \"Safari/537.36 Edg/96.0.1054.34\"\n me._isWebkit = Boolean(userAgent.match(/WebKit/) && !userAgent.match(/Edg/));\n me._firefoxVersion = me.getVersion(userAgent, /Firefox\\/(\\d+)\\./);\n me._isFirefox = me._firefoxVersion > 0;\n me._chromeVersion = me.getVersion(userAgent, /Chrom(?:e|ium)\\/(\\d+)\\./);\n me._isChrome = me._chromeVersion > 0;\n me._isSafari = Boolean(userAgent.match(/Safari/)) && !me._isChrome;\n me._isMobileSafari = Boolean(userAgent.match(/Mobile.*Safari/));\n me._safariVersion = me.getVersion(userAgent, /Version\\/(.*).Safari/);\n me._isAndroid = Boolean(userAgent.match(/Android/g));\n }\n //endregion\n //region Device\n /**\n * Yields `true` if the current browser supports CSS style `overflow:clip`.\n * @property {Boolean}\n * @readonly\n * @internal\n */\n static get supportsOverflowClip() {\n if (this._supportsOverflowClip == null) {\n const div = document.createElement('div');\n div.style.overflow = 'clip';\n div.style.display = 'none';\n // If we're called before DOMContentLoaded, body won't be available.\n // HTML element works for style calcs.\n document.documentElement.appendChild(div);\n this._supportsOverflowClip = div.ownerDocument.defaultView.getComputedStyle(div).getPropertyValue('overflow') === 'clip';\n div.remove();\n }\n return this._supportsOverflowClip;\n }\n /**\n * Yields `true` if the current browser supports CSS style `position:sticky`.\n * @property {Boolean}\n * @readonly\n * @internal\n */\n static get supportsSticky() {\n return true;\n }\n /**\n * Returns matched version for userAgent.\n * @param {String} versionRe version match regular expression\n * @returns {Number} matched version\n * @readonly\n * @internal\n */\n static getVersion(userAgent, versionRe) {\n const match = userAgent.match(versionRe);\n return match ? parseFloat(match[1]) : 0;\n }\n /**\n * Determines if the user is using a touch device.\n * @property {Boolean}\n * @readonly\n * @internal\n */\n static get isTouchDevice() {\n // Allow tests or client code to set\n if (this._isTouchDevice === undefined) {\n this._isTouchDevice = globalThis.matchMedia('(pointer:coarse)').matches;\n }\n return this._isTouchDevice;\n }\n // Reports true by default for our tests\n static get isHoverableDevice() {\n if (this._isHoverableDevice === undefined) {\n this._isHoverableDevice = globalThis.matchMedia('(any-hover: hover)').matches;\n }\n return this._isHoverableDevice;\n }\n //endregion\n //region Platform\n static get isBrowserEnv() {\n // This window reference is left on purpose, globalThis is always defined\n // eslint-disable-next-line bryntum/no-window-in-lib\n return typeof window !== 'undefined';\n }\n /**\n * Checks if platform is Mac.\n * @property {Boolean}\n * @readonly\n * @category Platform\n */\n static get isMac() {\n return this._isMac;\n }\n /**\n * Checks if platform is Windows.\n * @property {Boolean}\n * @readonly\n * @category Platform\n */\n static get isWindows() {\n return this._isWindows;\n }\n /**\n * Checks if platform is Linux.\n * @property {Boolean}\n * @readonly\n * @category Platform\n */\n static get isLinux() {\n return this._isLinux;\n }\n /**\n * Checks if platform is Android.\n * @property {Boolean}\n * @readonly\n * @category Platform\n */\n static get isAndroid() {\n return this._isAndroid;\n }\n //endregion\n //region Browser\n /**\n * Checks if browser is Webkit.\n * @property {Boolean}\n * @readonly\n * @category Browser\n */\n static get isWebkit() {\n return this._isWebkit;\n }\n /**\n * Checks if browser is Chrome or Chromium based browser.\n * Returns truthy value for Edge Chromium.\n * @property {Boolean}\n * @readonly\n * @category Browser\n */\n static get isChrome() {\n return this._isChrome;\n }\n /**\n * Returns the major Chrome version or 0 for other browsers.\n * @property {Number}\n * @readonly\n * @category Browser\n */\n static get chromeVersion() {\n return this._chromeVersion;\n }\n /**\n * Checks if browser is Firefox.\n * @property {Boolean}\n * @readonly\n * @category Browser\n */\n static get isFirefox() {\n return this._isFirefox;\n }\n /**\n * Returns the major Firefox version or 0 for other browsers.\n * @property {Number}\n * @readonly\n * @category Browser\n */\n static get firefoxVersion() {\n return this._firefoxVersion;\n }\n /**\n * Checks if browser is Safari.\n * @property {Boolean}\n * @readonly\n * @category Browser\n */\n static get isSafari() {\n return this._isSafari;\n }\n static get safariVersion() {\n return this._safariVersion;\n }\n /**\n * Checks if browser is mobile Safari\n * @property {Boolean}\n * @readonly\n * @category Browser\n */\n static get isMobileSafari() {\n return this._isMobileSafari;\n }\n /**\n * Checks if the active device is a mobile device\n * @property {Boolean}\n * @readonly\n * @category Browser\n */\n static get isMobile() {\n return this._isMobile;\n }\n static get platform() {\n const me = this;\n return me._isLinux ? 'linux'\n : me._isMac ? 'mac'\n : me._isWindows ? 'windows'\n : me._isAndroid ? 'android'\n : me._isMobileSafari ? 'ios'\n : null;\n }\n /**\n * Returns `true` if the browser supports passive event listeners.\n * @property {Boolean}\n * @internal\n * @deprecated Since 5.0. All modern browsers now support passive event listeners.\n * @category Browser\n */\n static get supportsPassive() {\n return true;\n }\n // Only works in secure contexts\n static get supportsRandomUUID() {\n if (this._supportsRandomUUID === undefined) {\n try {\n this._supportsRandomUUID = Boolean(globalThis.crypto.randomUUID().length > 0);\n }\n catch (e) {\n this._supportsRandomUUID = false;\n }\n }\n return this._supportsRandomUUID;\n }\n //endregion\n //region Storage\n // https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API\n static get storageAvailable() {\n let storage, x;\n try {\n storage = localStorage;\n x = '__storage_test__';\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n }\n catch (e) {\n return e instanceof DOMException && (\n // everything except Firefox\n e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === 'QuotaExceededError' ||\n // Firefox\n e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage.length !== 0;\n }\n }\n static setLocalStorageItem(key, value) {\n this.storageAvailable && localStorage.setItem(key, value);\n }\n static getLocalStorageItem(key) {\n return this.storageAvailable && localStorage.getItem(key);\n }\n static removeLocalStorageItem(key) {\n this.storageAvailable && localStorage.removeItem(key);\n }\n //endregion\n //region Helpers\n /**\n * Returns parameter value from search string by parameter name.\n * @param {String} paramName search parameter name\n * @param {String} [defaultValue] default value if parameter not found\n * @param {String} [search] search string. Defaults to `document.location.search`\n * @returns {String} search parameter string value\n * @category Helper\n */\n static searchParam(paramName, defaultValue = null, search = document.location.search) {\n const\n re = new RegExp(`[?&]${paramName}=?([^&]*)`),\n match = search.match(re);\n return (match && match[1]) || defaultValue;\n }\n /**\n * Returns cookie by name.\n * @param {String} name cookie name\n * @returns {String} cookie string value\n * @category Helper\n */\n static getCookie(name) {\n const\n nameEq = encodeURIComponent(name) + '=',\n cookieItems = document.cookie.split(';');\n for (let i = 0; i < cookieItems.length; i++) {\n let c = cookieItems[i];\n while (c.charAt(0) === ' ') {\n c = c.substring(1, c.length);\n }\n if (c.indexOf(nameEq) === 0) {\n return decodeURIComponent(c.substring(nameEq.length, c.length));\n }\n }\n return '';\n }\n /**\n * Triggers a download of a file with the specified name / URL.\n * @param {String} filename The filename of the file to be downloaded\n * @param {String} [url] The URL where the file is to be downloaded from\n * @internal\n * @category Download\n */\n static download(filename, url) {\n const a = document.createElement('a');\n a.download = filename;\n a.href = url || filename;\n a.style.cssText = 'display:none';\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n }\n /**\n * Triggers a download of a Blob with the specified name.\n * @param {Blob} blob The Blob to be downloaded\n * @param {String} filename The filename of the file to be downloaded\n * @internal\n * @category Download\n */\n static downloadBlob(blob, filename) {\n const url = globalThis.URL.createObjectURL(blob);\n this.download(filename, url);\n globalThis.URL.revokeObjectURL(url);\n }\n static get queryString() {\n // new URLSearchParams throws in salesforce\n // https://github.com/salesforce/lwc/issues/1812\n const params = new URL(globalThis.location.href).searchParams;\n // ?. to be nice to users with Chrome versions < 73\n return Object.fromEntries?.(params.entries());\n }\n // Used by docs fiddle\n static copyToClipboard(code) {\n let success = true;\n const textArea = document.createElement('textarea');\n textArea.value = code;\n textArea.style.height = textArea.style.width = 0;\n document.body.appendChild(textArea);\n textArea.select();\n try {\n document.execCommand('copy');\n }\n catch (e) {\n success = false;\n }\n textArea.remove();\n return success;\n }\n static isBryntumOnline(searchStrings) {\n searchStrings = Array.isArray(searchStrings) ? searchStrings : [searchStrings];\n return Boolean(/^(www\\.)?bryntum\\.com/.test(globalThis.location.host) || searchStrings?.some(str => this.queryString[str] != null));\n }\n /**\n * Returns truthy value if page contains Content Security Policy meta tag or globalThis.bryntum.CSP is truthy value\n * @returns {Boolean}\n * @internal\n **/\n static get isCSP() {\n const { bryntum, document } = globalThis;\n if (bryntum.CSP == null) {\n bryntum.CSP = Boolean(document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]'));\n }\n return bryntum.CSP;\n }\n //endregion\n}\nif (BrowserHelper.isBrowserEnv) {\n BrowserHelper.cacheFlags();\n}\nBrowserHelper._$name = 'BrowserHelper';", "// IMPORTANT - adding imports here can create problems for Base class\nimport Objects from './util/Objects.js';\nimport BrowserHelper from './BrowserHelper.js';\n/**\n * @module Core/helper/StringHelper\n */\nlet charsToEncode, entitiesToDecode, htmlEncodeRe, htmlDecodeRe;\nconst\n camelLettersRe = /([a-z])([A-Z])/g,\n crlfRe = /[\\n\\r]/g,\n escapeRegExpRe = /[.*+?^${}()|[\\]\\\\]/g, // same as NPM escape-string-regexp\n htmlRe = /[&<]/,\n idRe = /(^[^a-z]+[^\\w]+)/gi,\n whiteSpaceRe = /\\s+/,\n domIdRe = /^[^a-z]+|[^\\w:.-]+/gi,\n htmlDecoder = (m, captured) => entitiesToDecode[captured.toLowerCase()] || String.fromCharCode(parseInt(captured.substr(2), 10)),\n htmlEncoder = (m, captured) => charsToEncode[captured],\n hyphenateCamelLetters = (all, g1, g2) => {\n return `${g1}-${g2.toLowerCase()}`;\n },\n separateCamelLetters = (all, g1, g2) => {\n return `${g1} ${g2.toLowerCase()}`;\n },\n replaceNonIdChar = c => {\n if (c) {\n return `_x${[...c].map((ch) => ch.charCodeAt(0).toString(16)).join('')}`;\n }\n return '__blank__';\n },\n hyphenateCache = {},\n separatedCache = {},\n // Adopted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value\n ancestors = [],\n circularReplacer = function(key, value) {\n if (value && typeof value === 'object') {\n // `this` is the object that value is contained in, i.e., its direct parent.\n while (ancestors.length && ancestors[ancestors.length - 1] !== this) {\n ancestors.pop();\n }\n if (ancestors.includes(value)) {\n return '[Circular]';\n }\n ancestors.push(value);\n }\n return value;\n };\n/**\n * Helper for string manipulation.\n */\nexport default class StringHelper {\n //region Transform\n /**\n * Capitalizes the first letter of a string, \"myString\" -> \"MyString\".\n * @param {String} string The string to capitalize\n * @returns {String} The capitalized string or the value of `string` if falsy.\n * @category String formatting\n */\n static capitalize(string) {\n return string && (string[0].toUpperCase() + string.substr(1));\n }\n /**\n * Makes the first letter of a string lowercase, \"MyString\" -> \"myString\".\n * @param {String} string The string to un-capitalize.\n * @returns {String} The un-capitalized string or the value of `string` if falsy.\n * @category String formatting\n */\n static uncapitalize(string) {\n return string && (string[0].toLowerCase() + string.substr(1));\n }\n /**\n * Converts the passed camelCased string to a hyphen-separated string. eg \"minWidth\" -> \"min-width\"\n * @param {String} string The string to convert.\n * @returns {String} The string with adjoining lower and upper case letters\n * separated by hyphens and converted to lower case.\n * @category String formatting\n * @internal\n */\n static hyphenate(string) {\n // Cached since it is used heavily with DomHelper.sync()\n const cached = hyphenateCache[string];\n if (cached) {\n return cached;\n }\n return hyphenateCache[string] = string.replace(camelLettersRe, hyphenateCamelLetters);\n }\n /**\n * Converts the passed camelCased string to a capitalized, space-separated string. eg \"startDate\" -> \"Start date\".\n * @param {String} string The string to convert.\n * @returns {String} The string with spaces separating words.\n * @category String formatting\n * @internal\n */\n static separate(string) {\n // Cached since it may be used heavily\n const cached = separatedCache[string];\n if (cached) {\n return cached;\n }\n return separatedCache[string] = this.capitalize(string.replace(camelLettersRe, separateCamelLetters));\n }\n /**\n * Creates an alphanumeric identifier from any passed string. Encodes spaces and non-alpha characters.\n * @param {String} inString The string from which to strip non-identifier characters.\n * @returns {String}\n * @category Misc\n * @internal\n */\n static createId(inString) {\n return String(inString).replace(idRe, replaceNonIdChar);\n }\n static makeValidDomId(id, replaceValue = '') {\n if (id == null) {\n return null;\n }\n return String(id).replace(domIdRe, replaceValue);\n }\n //endregion\n //region Html\n /**\n * Escapes special RegExp characters.\n * @param {String} string String to escape\n * @privateparam {String} [flags] Optional flags\n * @returns {String} Escaped string\n */\n static escapeRegExp(string, flags) {\n // $& means the whole matched string\n let ret = string.replace(escapeRegExpRe, '\\\\$&');\n if (flags !== undefined) {\n ret = new RegExp(ret, flags);\n }\n return ret;\n }\n /**\n * This method decodes HTML entities and returns the original HTML.\n *\n * See also {@link #function-encodeHtml-static}.\n * @param {String} str\n * @returns {String}\n * @category HTML\n */\n static decodeHtml(str) {\n return str && String(str).replace(htmlDecodeRe, htmlDecoder);\n }\n /**\n * This method encodes HTML entities and returns a string that can be placed in the document and produce the\n * original text rather than be interpreted as HTML. Using this method with user-entered values prevents those\n * values from executing as HTML (i.e., a cross-site scripting or \"XSS\" security issue).\n *\n * See also {@link #function-decodeHtml-static}.\n * @param {String} str\n * @returns {String}\n * @category HTML\n */\n static encodeHtml(str = '') {\n return str && String(str).replace(htmlEncodeRe, htmlEncoder);\n }\n /**\n * This method is similar to {@link #function-encodeHtml-static} except that `\\n` and `\\r` characters in the\n * given `str` are replaced by `
` tags _after_ first being encoded by {@link #function-encodeHtml-static}.\n * @param {String} str\n * @returns {String}\n * @category HTML\n * @internal\n */\n static encodeHtmlBR(str) {\n return StringHelper.encodeHtml(str)?.replace(crlfRe, '
');\n }\n /**\n * Returns `true` if the provided `text` contains special HTML characters.\n * @param {String} text\n * @returns {Boolean}\n * @category HTML\n * @internal\n */\n static isHtml(text) {\n return typeof text === 'string' && htmlRe.test(text || '');\n }\n /**\n * Initializes HTML entities used by {@link #function-encodeHtml-static} and {@link #function-decodeHtml-static}.\n * @param {Object} [mappings] An object whose keys are characters that should be encoded and values are the HTML\n * entity for the character.\n * @private\n */\n static initHtmlEntities(mappings) {\n mappings = mappings || {\n '&' : '&',\n '>' : '>',\n '<' : '<',\n '\"' : '"',\n \"'\" : '''\n };\n const chars = Object.keys(mappings);\n // Maps '<' to '<'\n charsToEncode = mappings;\n // Inverts the mapping so we can convert '<' to '<'\n entitiesToDecode = chars.reduce((prev, val) => {\n prev[mappings[val]] = val;\n return prev;\n }, {});\n // Creates a regex char set like /([<&>])/g to match the characters that need to be encoded (escaping any of\n // the regex charset special chars '[', ']' and '-'):\n htmlEncodeRe = new RegExp(`([${chars.map(c => '[-]'.includes(c) ? '\\\\' + c : c).join('')}])`, 'g');\n // Creates a regex like /(<|&|>)/ig to match encoded entities... good news is that (valid) HTML\n // entities do not contain any regex special characters:\n htmlDecodeRe = new RegExp(`(${Object.values(mappings).join('|')}|&#[0-9]+;)`, 'ig');\n }\n //endregion\n //region JSON\n /**\n * Parses JSON inside a try-catch block. Returns null if the string could not be parsed.\n *\n * @param {String} string String to parse\n * @returns {Object} Resulting object or `null` if parse failed\n * @category JSON\n */\n static safeJsonParse(string) {\n let parsed = null;\n try {\n parsed = JSON.parse(string);\n }\n catch (e) {\n }\n return parsed;\n }\n /**\n * Stringifies an object inside a try-catch block. Returns null if an exception is encountered.\n *\n * See [JSON.stringify on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify)\n * for more information on the arguments.\n *\n * @param {Object} object The object to stringify\n * @param {Function|'circular'|String[]|Number[]} [replacer] A function or array of string/number used to determine\n * properties to include in the JSON string. Also accepts the string 'circular' to use a built-in replacer handling\n * circular references, by replacing them with `'[Circular]'`.\n * See [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Cyclic_object_value) for more\n * information.\n * @param {String|Number} [space] Number of spaces to indent or string used as whitespace\n * @returns {String} Resulting object or null if stringify failed\n * @category JSON\n */\n static safeJsonStringify(object, replacer = null, space = null) {\n let result = null;\n try {\n if (replacer === 'circular') {\n ancestors.length = 0;\n replacer = circularReplacer;\n }\n result = JSON.stringify(object, replacer, space);\n }\n catch {}\n return result;\n }\n //endregion\n //region Split & join\n /**\n * Joins all given paths together using the separator as a delimiter and normalizes the resulting path.\n * @param paths {Array} array of paths to join\n * @param pathSeparator [{String}] path separator. Default value is '/'\n * @returns {String}\n * @category Misc\n * @internal\n */\n static joinPaths(paths, pathSeparator = '/') {\n return paths.join(pathSeparator).replace(new RegExp('\\\\' + pathSeparator + '+', 'g'), pathSeparator);\n }\n /**\n * Returns the provided string split on whitespace. If the string is empty or consists of only whitespace, the\n * returned array will be empty. If `str` is not a string, it is simply returned. This allows `null` or already\n * split strings (arrays) to be passed through.\n *\n * For example:\n * ```\n * console.log(StringHelper.split(' abc def xyz '));\n * > ['abc', 'def', 'xyz']\n * console.log(StringHelper.split(''));\n * > []\n * ```\n * Compare to the standard `split()` method:\n * ```\n * console.log(' abc def xyz '.split(/\\s+/));\n * > ['', 'abc', 'def', 'xyz', '']\n * console.log(''.split(/\\s+/));\n * > ['']\n * ```\n * @param {String} str\n * @param {String|RegExp} delimiter\n * @returns {String[]}\n * @category Misc\n * @internal\n */\n static split(str, delimiter = whiteSpaceRe) {\n let ret = str;\n if (typeof ret === 'string') {\n ret = str.trim(); // w/o trim() whitespace on the ends will give us '' in the array\n ret = ret ? ret.split(delimiter) : []; // also ''.split() = ['']\n }\n return ret;\n }\n //endregion\n //region XSS\n /**\n * This is a tagged template function that performs HTML encoding on replacement values to avoid XSS (Cross-Site\n * Scripting) attacks.\n *\n * For example:\n *\n * ```javascript\n * eventRenderer(eventRecord) {\n * return StringHelper.xss`${eventRecord.name}`;\n * }\n * ```\n *\n * @param {TemplateStringsArray} strings The template string array\n * @param {...any} values The interpolated values in the template string\n * @returns {String} The encoded string\n * See {@link Core.helper.StringHelper#function-encodeHtml-static}.\n */\n static xss(strings, ...values) {\n const buf = [];\n let i = values.length;\n buf[i] = strings[i];\n while (i-- > 0) {\n buf[i] = strings[i] + StringHelper.encodeHtml(values[i]);\n }\n return buf.join('');\n }\n /**\n * This is a tagged template function that performs HTML encoding on replacement values to avoid XSS (Cross-Site\n * Scripting) attacks. Unlike {@link Core.helper.StringHelper#function-xss-static}, this method converts `\\n` and\n * `\\r` characters into `
` tags.\n *\n * For example:\n *\n * ```javascript\n * eventRenderer(eventRecord) {\n * return StringHelper.xssBR`${eventRecord.name}`;\n * }\n * ```\n *\n * See {@link Core.helper.StringHelper#function-encodeHtmlBR-static}.\n * @internal\n */\n static xssBR(strings, ...values) {\n const buf = [];\n let i = values.length;\n buf[i] = strings[i];\n while (i-- > 0) {\n buf[i] = strings[i] + StringHelper.encodeHtmlBR(values[i]);\n }\n return buf.join('');\n }\n //endregion\n //region JavaScript string\n /**\n * Converts a value to a JavaScript string (not JSON).\n *\n * For example a date to `\"new Date(y, m, d)\"`, an array to `\"[...]\"` etc.\n *\n * @param {*} value\n * @param {Object} [options]\n * @returns {String}\n * @internal\n */\n static toJavaScriptValue(value, options) {\n const type = Objects.typeOf(value);\n if (type === 'boolean' || type === 'string' || type === 'number' || value === null) {\n return StringHelper.safeJsonStringify(value);\n }\n if (value === globalThis) {\n return 'window';\n }\n if (type === 'date') {\n return `new Date(${value.getFullYear()}, ${value.getMonth()}, ${value.getDate()}, ${value.getHours()}, ${value.getMinutes()}, ${value.getSeconds()}, ${value.getMilliseconds()})`;\n }\n if (type === 'array') {\n return `[${value.map(v => StringHelper.toJavaScriptValue(v, options))}]`;\n }\n if (type === 'object' || type === 'instance') {\n return this.toJavaScriptString(value, options);\n }\n if (type === 'function') {\n let contents = value.toString();\n // async myFunction() {} => async function() {}\n if (contents.match(/^async (\\w+?)\\(/)) {\n contents = contents.replace(/^async (\\w+?)\\(/, 'async function(');\n }\n // Not an arrow fn? Replace name with function since we always add prop name prior to getting here\n // eventRenderer() {} -> function() {}\n else if (!contents.startsWith('async(') && contents.match(/^(\\w+?)\\(/)) {\n contents = contents.replace(/^(\\w+?)\\(/, 'function(');\n }\n return contents;\n }\n if (type === 'class') {\n if (value.toJavaScriptValue) {\n return value.toJavaScriptValue(options);\n }\n return Object.prototype.hasOwnProperty.call(value, '$name') ? value.$name : value.name;\n }\n }\n /**\n * Converts an object into a JavaScript string (not JSON).\n *\n * For example `{ a: 1, b: [2, 3] }` -> `\"'{ a: 1, b: [2, 3] }'\"`\n *\n * @param {Object} obj\n * @param {Object} [options]\n * @returns {String}\n * @internal\n */\n static toJavaScriptString(obj, options = {}) {\n const\n level = options.level ?? 0,\n intendSize = 2;\n // Not using template strings to have control over indentation\n return '{\\n' +\n Object.keys(obj).map(key =>\n // All properties in an object are indented one step further than the object itself\n ' '.repeat((level + 1) * intendSize) + (key.match(/[- *]/) ? `\"${key}\"` : key) + `: ${StringHelper.toJavaScriptValue(obj[key], { ...options, level : level + 1 })}`\n ).join(',\\n') +\n // Closing brace is indented to same level as the object\n '\\n' + ' '.repeat((level) * intendSize) + '}';\n }\n /**\n * Escapes \" and \\ in CSS attribute selectors, e.g. [data-id=\"somevalue\"]\n *\n * Usage:\n * ```javascript\n * document.querySelector(StringHelper.cssAttributeQuery('data-id', 'id with & \\\\ chars'))\n * ```\n *\n * @param {String} attr\n * @param {String|Number} value\n * @returns {String}\n */\n static encodeAttributeSelector(attr, value) {\n return `[${attr}=\"${String(value).replace(/[\"\\\\]/g, '\\\\$&')}\"]`;\n }\n //endregion\n //region UUID\n static fakeNodeUUIDIndex = 0;\n /**\n * Generates a UUID. Uses `Crypto.randomUUID()` if available, otherwise generates a random UUID using\n * `Crypto.getRandomValues()`.\n *\n * @returns {String}\n */\n static generateUUID() {\n if (BrowserHelper.supportsRandomUUID) {\n return globalThis.crypto.randomUUID();\n }\n // Node does not have crypto built-in\n if (globalThis.crypto?.getRandomValues) {\n // https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid\n return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>\n (c ^ globalThis.crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)\n );\n }\n // Node specific code, should never get here outside of node. Not actually a UUID, but should still be unique\n // enough for our purposes, as long as value is not serialized\n return `${Date.now()}-${++StringHelper.fakeNodeUUIDIndex}`;\n }\n //endregion\n}\nStringHelper.initHtmlEntities();\nStringHelper._$name = 'StringHelper';", "// IMPORTANT - adding imports here can create problems for Base class\n// That is why this file was split from ObjectHelper\nimport StringHelper from '../StringHelper.js';\n/**\n * @module Core/helper/util/Objects\n */\nconst\n { hasOwnProperty, toString } = Object.prototype,\n { isFrozen } = Object,\n afterRe = /\\s*<\\s*/,\n beforeRe = /\\s*>\\s*/,\n blendOptions = {},\n typeCache = {},\n emptyObject = Object.freeze({});\n// Static methods are not displayed in derived class documentation. Therefore, since this is an internal class, the\n// workaround is to copy method documentation to ObjectHelper (the public interface). Also tried making ObjectHelper\n// a singleton.\n/**\n * Helper for low-level Object manipulation.\n *\n * While documented on {@link Core.helper.ObjectHelper}, the following static methods are implemented by this class:\n *\n * - `{@link Core.helper.ObjectHelper#function-assign-static}`\n * - `{@link Core.helper.ObjectHelper#function-assignIf-static}`\n * - `{@link Core.helper.ObjectHelper#function-clone-static}`\n * - `{@link Core.helper.ObjectHelper#function-createTruthyKeys-static}`\n * - `{@link Core.helper.ObjectHelper#function-getPath-static}`\n * - `{@link Core.helper.ObjectHelper#function-getTruthyKeys-static}`\n * - `{@link Core.helper.ObjectHelper#function-getTruthyValues-static}`\n * - `{@link Core.helper.ObjectHelper#function-isEmpty-static}`\n * - `{@link Core.helper.ObjectHelper#function-isObject-static}`\n * - `{@link Core.helper.ObjectHelper#function-merge-static}`\n * - `{@link Core.helper.ObjectHelper#function-setPath-static}`\n * - `{@link Core.helper.ObjectHelper#function-typeOf-static}`\n * @internal\n */\nexport default class Objects {\n static assign(dest, ...sources) {\n for (let source, key, i = 0; i < sources.length; i++) {\n source = sources[i];\n if (source) {\n for (key in source) {\n dest[key] = source[key];\n }\n }\n }\n return dest;\n }\n static assignIf(dest, ...sources) {\n for (let source, key, i = 0; i < sources.length; i++) {\n source = sources[i];\n if (source) {\n for (key in source) {\n if (!(key in dest) || dest[key] === undefined) {\n dest[key] = source[key];\n }\n }\n }\n }\n return dest;\n }\n static blend(dest, source, options) {\n options = options || blendOptions;\n dest = dest || {};\n const { clone = Objects.clone, merge = Objects.blend } = options;\n if (Array.isArray(source)) {\n if (source.length > 1) {\n source.forEach(s => {\n dest = Objects.blend(dest, s, options);\n });\n return dest;\n }\n source = source[0];\n }\n if (source) {\n let destValue, key, value;\n for (key in source) {\n value = source[key];\n if (value && Objects.isObject(value)) {\n destValue = dest[key];\n options.key = key;\n if (destValue && Objects.isObject(destValue)) {\n if (isFrozen(destValue)) {\n dest[key] = destValue = clone(destValue, options);\n }\n value = merge(destValue, value, options);\n }\n else {\n // We don't need to clone frozen objects, but we do clone mutable objects as they get\n // applied to the dest.\n value = isFrozen(value) ? value : clone(value, options);\n }\n }\n dest[key] = value;\n }\n }\n return dest;\n }\n static clone(value, handler) {\n let cloned = value,\n key;\n if (value && typeof value === 'object') {\n const options = handler && typeof handler === 'object' && handler;\n if (options) {\n // When using blend(), the 2nd argument is the options object, so ignore that case\n handler = null;\n }\n if (Objects.isObject(value)) {\n // When using DomSync, DomConfigs are usually recreated from scratch on each sync, we allow opting out\n // of cloning them (costly for many elements)\n if (value.skipClone) {\n cloned = value;\n }\n else {\n cloned = {};\n for (key in value) {\n cloned[key] = Objects.clone(value[key]);\n }\n }\n }\n else if (Array.isArray(value)) {\n cloned = [];\n // Loop backwards to:\n // 1. read source.length once\n // 2. get result array sized on first pass (avoid growing)\n for (key = value.length; key-- > 0; /* empty */) {\n cloned[key] = Objects.clone(value[key]);\n }\n }\n else if (Objects.isDate(value)) {\n cloned = new Date(value.getTime());\n }\n else if (handler) {\n // Allow other types to be handled (e.g., DOM nodes).\n cloned = handler(value);\n }\n }\n return cloned;\n }\n static createTruthyKeys(source) {\n const\n keys = StringHelper.split(source),\n result = keys && {};\n if (keys) {\n for (const key of keys) {\n // StringHelper.split won't return empty keys if passed a string, but we\n // could have been passed a String[]\n if (key) {\n result[key] = true;\n }\n }\n }\n return result;\n }\n /**\n * Returns value for a given path in the object\n * @param {Object} object Object to check path on\n * @param {String} path Dot-separated path, e.g. 'object.childObject.someKey'\n * @returns {*} Value associated with passed key\n */\n static getPath(object, path) {\n return path.split('.').reduce((result, key) => {\n return (result || emptyObject)[key];\n }, object);\n }\n /**\n * Returns value for a given path in the object, placing a passed default value in at the\n * leaf property and filling in undefined properties all the way down.\n * @param {Object} object Object to get path value for.\n * @param {String|Number|String[]|Number[]} path Dot-separated path, e.g. 'firstChild.childObject.someKey',\n * or the key path as an array, e.g. ['firstChild', 'childObject', 'someKey'].\n * @param {*} [defaultValue] Optionally the value to put in as the `someKey` property.\n * @returns {*} Value at the leaf position of the path.\n */\n static getPathDefault(object, path, defaultValue) {\n const\n keys = Array.isArray(path) ? path : typeof path === 'string' ? path.split('.') : [path],\n length = keys.length - 1;\n return keys.reduce((result, key, index) => {\n if (defaultValue && !(key in result)) {\n // Can't use emptyObject here, we are creating a node in the object tree\n result[key] = index === length ? defaultValue : {};\n }\n return (result || emptyObject)[key];\n }, object);\n }\n /**\n * Determines if the specified path exists\n * @param {Object} object Object to check path on\n * @param {String} path Dot-separated path, e.g. 'object.childObject.someKey'\n * @returns {Boolean}\n */\n static hasPath(object, path) {\n return path.split('.').every(key => {\n if (object && key in object) {\n object = object[key];\n return true;\n }\n return false;\n });\n }\n static getTruthyKeys(source) {\n const keys = [];\n for (const key in source) {\n if (source[key]) {\n keys.push(key);\n }\n }\n return keys;\n }\n static getTruthyValues(source) {\n const values = [];\n for (const key in source) {\n if (source[key]) {\n values.push(source[key]);\n }\n }\n return values;\n }\n static isClass(object) {\n if (typeof object === 'function' && object.prototype?.constructor === object) {\n return true;\n }\n return false;\n }\n static isDate(object) {\n // A couple quick rejections but only sure way is typeOf:\n return Boolean(object?.getUTCDate) && Objects.typeOf(object) === 'date';\n }\n /**\n * Check if passed object is a Promise or contains `then` method.\n * Used to fix problems with detecting promises in code with `instance of Promise` when\n * Promise class is replaced with any other implementation like `ZoneAwarePromise` in Angular.\n * Related to these issues:\n * https://github.com/bryntum/support/issues/791\n * https://github.com/bryntum/support/issues/2990\n *\n * @param {Object} object object to check\n * @returns {Boolean} truthy value if object is a Promise\n * @internal\n */\n static isPromise(object) {\n if (Promise && Promise.resolve) {\n return Promise.resolve(object) === object || typeof object?.then === 'function';\n }\n throw new Error('Promise not supported in your environment');\n }\n static isEmpty(object) {\n if (object && typeof object === 'object') {\n // noinspection LoopStatementThatDoesntLoopJS\n for (const p in object) { // eslint-disable-line no-unused-vars,no-unreachable-loop\n return false;\n }\n }\n return true;\n }\n static isObject(value) {\n const C = value?.constructor;\n return Boolean(C\n // Most things have a .constructor property\n ? (\n // An in-frame instance of Object\n C === Object ||\n // Detect cross-frame objects, but exclude instance of custom classes named Object. typeOf(value) is\n // \"object\" even for instances of a class and typeOf(C) is \"function\" for all constructors. We'll have\n // to settle for relying on the fact that getPrototypeOf(Object.prototype) === null.\n // NOTE: this issue does come up in Scheduler unit tests at least.\n (C.getPrototypeOf && C.prototype && !Object.getPrototypeOf(C.prototype))\n )\n // Since all classes have a constructor property, an object w/o one is likely from Object.create(null). Of\n // course, primitive types do not have \".constructor\"\n : (value && typeof value === 'object')\n );\n }\n static isInstantiated(object) {\n return object ? typeof object === 'object' && !Objects.isObject(object) : false;\n }\n static merge(dest, ...sources) {\n return Objects.blend(dest, sources);\n }\n /**\n * Merges two \"items\" objects. An items object is a simple object whose keys act as identifiers and whose values\n * are \"item\" objects. An item can be any object type. This method is used to merge such objects while maintaining\n * their property order. Special key syntax is used to allow a source object to insert a key before or after a key\n * in the `dest` object.\n *\n * For example:\n * ```javascript\n * let dest = {\n * foo : {},\n * bar : {},\n * fiz : {}\n * }\n *\n * console.log(Object.keys(dest));\n * > [\"foo\", \"bar\", \"fiz\"]\n *\n * dest = mergeItems(dest, {\n * 'zip > bar' : {} // insert \"zip\" before \"bar\"\n * 'bar < zap' : {} // insert \"zap\" after \"bar\"\n * });\n *\n * console.log(Object.keys(dest));\n * > [\"foo\", \"zip\", \"bar\", \"zap\", \"fiz\"]\n * ```\n *\n * @param {Object} dest The destination object.\n * @param {Object|Object[]} src The source object or array of source objects to merge into `dest`.\n * @param {Object} [options] The function to use to merge items.\n * @param {Function} [options.merge] The function to use to merge items.\n * @returns {Object} The merged object. This will be the `dest` object.\n * @internal\n */\n static mergeItems(dest, src, options) {\n options = options || blendOptions;\n let anchor, delta, index, indexMap, key, shuffle, srcVal;\n const { merge = Objects.blend } = options;\n dest = dest || {};\n if (Array.isArray(src)) {\n src.forEach(s => {\n dest = Objects.mergeItems(dest, s, options);\n });\n }\n else if (src) {\n // https://2ality.com/2015/10/property-traversal-order-es6.html\n // Bottom line: Object keys are iterated in declared/insertion order... unless the key is an integer or\n // Symbol, but we don't care about those generally.\n for (key in src) {\n srcVal = src[key];\n anchor = null;\n // Allow a key to be added before or after another:\n //\n // {\n // 'foo > bar' : {\n // ...\n // },\n // 'bar < derp' : {\n // ...\n // }\n // }\n //\n // The goal above is to add a 'foo' key before the existing 'bar' key while adding a 'derp' key after\n // 'bar'.\n if (key.includes('>')) {\n [key, anchor] = key.split(beforeRe);\n delta = 0;\n }\n else if (key.includes('<')) {\n [anchor, key] = key.split(afterRe);\n delta = 1;\n }\n if (key in dest) {\n // Changing the value of a key does not change its iteration order. Since \"key in dest\" we can do\n // what we need directly.\n if (srcVal && dest[key] && merge) {\n options.key = key;\n srcVal = merge(dest[key], srcVal, options);\n }\n dest[key] = srcVal;\n }\n else if (!anchor) {\n dest[key] = srcVal;\n indexMap?.set(key, indexMap.size);\n }\n else {\n // Lazily sprout the item index map. When we first merge an item into an items object, we create this\n // Map to control the ordering. This is because any keys we add would necessarily be iterated after\n // the original properties.\n if (!indexMap) {\n indexMap = new Map();\n index = 0;\n for (const k in dest) {\n indexMap.set(k, index++);\n }\n }\n index = indexMap.get(anchor);\n dest[key] = srcVal;\n if (index == null && delta) {\n index = indexMap.size;\n }\n else {\n shuffle = shuffle || [];\n index = (index || 0) + delta;\n // Adjust all key indices >= index up by 1 to maintain integer indices (required by the above\n // use case).\n for (const item of indexMap) {\n const [k, v] = item;\n if (index <= v) {\n /*\n Consider object w/the following order:\n {\n foo : {}',\n bar : {},\n baz : {},\n zip : {},\n goo : {},\n fiz : {}\n }\n The indexMap is:\n foo : 0\n bar : 1\n baz : 2\n zip : 3\n goo : 4\n fiz : 5\n To insert before goo, we populate shuffle thusly (to set up for popping):\n +-----+-----+\n | fiz | goo |\n +-----+-----+\n 0 1\n =6-5-1 =6-4-1\n */\n shuffle && (shuffle[indexMap.size - v - 1] = k);\n indexMap.set(k, v + 1);\n }\n }\n // Delete and re-add the keys that should follow the new key to establish the iteration order\n // we need:\n if (shuffle) {\n while (shuffle.length) {\n const\n k = shuffle.pop(),\n v = dest[k];\n delete dest[k];\n dest[k] = v;\n }\n }\n }\n indexMap.set(key, index);\n }\n }\n }\n return dest;\n }\n /**\n * Sets value for a given path in the object\n * @param {Object} object Target object\n * @param {String} path Dot-separated path, e.g. 'object.childObject.someKey'\n * @param {*} value Value for a given path\n * @returns {Object} Returns passed object\n */\n static setPath(object, path, value) {\n path.split('.').reduce((result, key, index, array) => {\n const isLast = index === array.length - 1;\n if (isLast) {\n return result[key] = value;\n }\n else if (!(result[key] instanceof Object)) {\n result[key] = {};\n }\n return result[key];\n }, object);\n return object;\n }\n static typeOf(value) {\n let trueType, type;\n if (value === null) {\n type = 'null';\n }\n // NaN is the only value that is !== to itself\n else if (value !== value) { // eslint-disable-line no-self-compare\n type = 'nan';\n }\n else {\n type = typeof value;\n if (type === 'object') {\n if (value.isBase) {\n type = 'instance';\n }\n else if (Array.isArray(value)) {\n type = 'array';\n }\n else if (!(type = typeCache[trueType = toString.call(value)])) {\n typeCache[trueType] = type = trueType.slice(8, -1).toLowerCase(); // '[object Date]' => 'date'\n }\n }\n else if (type === 'function' && value.isBase) {\n type = 'class';\n }\n }\n return type;\n }\n}\nObject.defineProperty(Objects, 'hasOwn', {\n // When available, this avoids an extra layer of function call around it:\n value : Object.hasOwn || ((object, property) => hasOwnProperty.call(object, property))\n});\nObjects._$name = 'Objects';", "import BrowserHelper from './BrowserHelper.js';\nimport StringHelper from './StringHelper.js';\n/**\n * @module Core/helper/VersionHelper\n */\n/**\n * Helper for version handling\n *\n * ```javascript\n * VersionHelper.setVersion('grid', '1.5');\n * if (VersionHelper.getVersion('grid').isNewerThan('1.0')) {\n * ...\n * }\n * ```\n *\n * @private\n */\nexport default class VersionHelper {\n /**\n * Set version for specified product\n * @private\n * @param {String} product\n * @param {String} version\n */\n static setVersion(product, version) {\n product = product.toLowerCase();\n VH[product] = {\n version,\n isNewerThan(otherVersion) {\n return VersionHelper.semanticCompareVersion(otherVersion, version, '<');\n },\n isOlderThan(otherVersion) {\n return VersionHelper.semanticCompareVersion(otherVersion, version, '>');\n }\n };\n let bundleFor = '';\n // Var productName is only defined in bundles, it is internal to bundle so not available on window. Used to\n // tell importing combinations of grid/scheduler/gantt bundles apart from loading same bundle twice\n if (typeof productName !== 'undefined') {\n // eslint-disable-next-line no-undef\n bundleFor = productName;\n }\n // Set \"global\" flag to detect bundle being loaded twice\n const globalKey = `${bundleFor}.${product}${version.replace(/\\./g, '-')}`;\n if (BrowserHelper.isBrowserEnv && !globalThis.bryntum.silenceBundleException) {\n if (globalThis.bryntum[globalKey] === true) {\n if (this.isTestEnv) {\n globalThis.BUNDLE_EXCEPTION = true;\n }\n else {\n let errorProduct = bundleFor || product;\n if (errorProduct === 'core') {\n errorProduct = 'grid';\n }\n let capitalized = StringHelper.capitalize(errorProduct);\n if (errorProduct === 'schedulerpro') {\n capitalized = 'SchedulerPro';\n }\n throw new Error(\n `The Bryntum ${capitalized} bundle was loaded multiple times by the application.\\n\\n` +\n `Common reasons you are getting this error includes:\\n\\n` +\n `* Imports point to different types of the bundle (e.g. *.module.js and *.umd.js)\\n` +\n `* Imports point to both sources and bundle\\n` +\n `* Imports do not use the shortest relative path, JS treats them as different files\\n` +\n `* Cache busters differ between imports, JS treats ${errorProduct}.module.js?1 and ${errorProduct}.module.js?2 as different files\\n` +\n `* Imports missing file type, verify they all end in .js\\n\\n` +\n `See https://bryntum.com/products/${errorProduct}/docs/guide/${capitalized}/gettingstarted/es6bundle#troubleshooting for more information\\n\\n`\n );\n }\n }\n else {\n globalThis.bryntum[globalKey] = true;\n }\n }\n }\n /**\n * Get (previously set) version for specified product\n * @private\n * @param {String} product\n */\n static getVersion(product) {\n product = product.toLowerCase();\n if (!VH[product]) {\n throw new Error('No version specified! Please check that you import VersionHelper correctly into the class from where you call `deprecate` function.');\n }\n return VH[product].version;\n }\n /**\n * Checks the version1 against the passed version2 using the comparison operator.\n * Supports `rc`, `beta`, `alpha` release states. Eg. `1.2.3-alpha-1`.\n * State which is not listed above means some version below `alpha`.\n * @param {String} version1 The version to test against\n * @param {String} version2 The version to test against\n * @param {String} [comparison] The comparison operator, `<=`, `<`, `=`, `>` or `>=`.\n * @returns {Boolean} `true` if the test passes.\n * @internal\n */\n static semanticCompareVersion(version1, version2, comparison = '=') {\n version1 = version1 || '';\n version2 = version2 || '';\n const\n version1Arr = version1.split(/[-.]/),\n version2Arr = version2.split(/[-.]/),\n isLower = comparison.includes('<'),\n normalizeArr = (arr, maxLength) => {\n const\n states = ['rc', 'beta', 'alpha'],\n result = arr.map(v => {\n if (states.includes(v)) {\n return -states.indexOf(v) - 2;\n }\n const res = Number.parseInt(v);\n return Number.isNaN(res) ? -states.length : res;\n });\n while (result.length < maxLength) {\n result.push(-1);\n }\n return result;\n },\n compareArr = () => {\n const\n maxLength = Math.max(version1Arr.length, version2Arr.length),\n arr1 = normalizeArr(version1Arr, maxLength),\n arr2 = normalizeArr(version2Arr, maxLength);\n for (let i = 0; i < maxLength; i++) {\n if (arr1[i] !== arr2[i]) {\n return isLower ? arr1[i] < arr2[i] : arr1[i] > arr2[i];\n }\n }\n return true;\n };\n switch (comparison) {\n case '=':\n return version1 === version2;\n case '<=':\n case '>=':\n return (version1 === version2) || compareArr();\n case '<':\n case '>':\n return (version1 !== version2) && compareArr();\n }\n return false;\n }\n /**\n * Checks the passed product against the passed version using the passed test.\n * @param {String} product The name of the product to test the version of\n * @param {String} version The version to test against\n * @param {String} operator The test operator, `<=`, `<`, `=`, `>` or `>=`.\n * @returns {Boolean} `true` if the test passes.\n * @internal\n */\n static checkVersion(product, version, operator) {\n return VersionHelper.semanticCompareVersion(VH.getVersion(product), version, operator);\n }\n /**\n * Based on a comparison of current product version and the passed version this method either outputs a console.warn\n * or throws an error.\n * @param {String} product The name of the product\n * @param {String} invalidAsOfVersion The version where the offending code is invalid (when any compatibility layer\n * is actually removed).\n * @param {String} message Required! A helpful warning message to show to the developer using a deprecated API.\n * @internal\n */\n static deprecate(product, invalidAsOfVersion, message) {\n const justWarn = VH.checkVersion(product, invalidAsOfVersion, '<');\n if (justWarn) {\n // During the grace period (until the next major release following the deprecated code), just show a console warning\n console.warn(`Deprecation warning: You are using a deprecated API which will change in v${invalidAsOfVersion}. ${message}`);\n }\n else {\n throw new Error(`Deprecated API use. ${message}`);\n }\n }\n /**\n * Returns truthy value if environment is in testing mode\n * @returns {Boolean}\n * @internal\n **/\n static get isTestEnv() {\n const isTestEnv = Boolean(globalThis.bryntum?.isTestEnv);\n try {\n return isTestEnv || Boolean(globalThis.parent?.bryntum?.isTestEnv);\n }\n catch (e) {\n // Accessing parent may cause CORS violation\n return isTestEnv;\n }\n }\n static get isDebug() {\n let result = false;\n return result;\n }\n}\nconst VH = VersionHelper;\nif (BrowserHelper.isBrowserEnv) {\n if (VH.isTestEnv) {\n BrowserHelper._isHoverableDevice = true;\n }\n globalThis.bryntum = Object.assign(globalThis.bryntum || {}, {\n getVersion : VH.getVersion.bind(VH),\n checkVersion : VH.checkVersion.bind(VH),\n deprecate : VH.deprecate.bind(VH),\n license : '%LICENSE%'\n });\n}\nVersionHelper._$name = 'VersionHelper';", "import Objects from './helper/util/Objects.js';\n// We cannot import ObjectHelper because of the import cycle:\n// ObjectHelper -> DateHelper -> LocaleManager -> Base -> us\n/**\n * @module Core/Config\n */\nconst\n { defineProperty, getOwnPropertyDescriptor } = Reflect,\n { hasOwnProperty, toString } = Object.prototype,\n instancePropertiesSymbol = Symbol('instanceProperties'),\n configuringSymbol = Symbol('configuring'),\n lazyConfigValues = Symbol('lazyConfigValues'),\n DATE_TYPE = toString.call(new Date()),\n whitespace = /\\s+/,\n createClsProps = (result, cls) => {\n result[cls] = 1;\n return result;\n };\n/**\n * This class holds the description of a config property. Only one instance of this class is needed for each config\n * name (e.g., \"text\"). If config options are supplied, however, they also contribute to the cached instance.\n *\n * Instances should always be retrieved by calling `Config.get()`.\n *\n * The **Configs** of this class correspond to `options` that can be supplied to the `get()` method. These affect the\n * behavior of the config property in some way, as descried by their respective documentation.\n *\n * This class is not used directly.\n *\n * ## The Setter\n * The primary functionality provided by `Config` is its standard setter. This setter function ensures consistent\n * behavior when modifying config properties.\n *\n * The standard setter algorithm is as follows (using the `'text'` config for illustration):\n *\n * - If the class defines a `changeText()` method, call it passing the new value and the current value:\n * `changeText(newText, oldText)`.
\n * Then:\n * * If `changeText()` exits without returning a value (i.e., `undefined`), exit and do nothing further. The\n * assumption is that the changer method has done all that is required.\n * * Otherwise, the return value of `changeText()` replaces the incoming value passed to the setter.\n * - If the new value (or the value returned by `changeText()`) is `!==` to the current value:\n * * Update the stored config value in `this._text`.\n * * If the class defines an `updateText()` method, call it passing the new value and the previous value.\n * `updateText(newText, oldText)`\n * * If the class defines an `onConfigChange()` method, call it passing an object with the following properties:\n * - `name` - The config's name\n * - `value` - The new value\n * - `was` - The previous value\n * - `config` - The `Config` instance.\n *\n * NOTE: unlike `changeText()` and `updateText()`, the name of the `onConfigChange()` method is unaffected by the\n * config's name.\n *\n * @internal\n */\nexport default class Config {\n /**\n * Returns the `Config` instance for the given `name` and `options`.\n * @param {String} name The name of the config (e.g., 'text' for the text config).\n * @param {Object} [options] Config behavior options.\n * @returns {Core.Config}\n * @internal\n */\n static get(name, options) {\n const\n { cache } = this,\n baseCfg = cache[name] || (cache[name] = new Config(name));\n let cfg = baseCfg,\n key;\n if (options) {\n key = Config.makeCacheKey(name, options);\n if (!(cfg = key && cache[key])) {\n cfg = baseCfg.extend(options);\n if (key) {\n cache[key] = cfg;\n }\n }\n }\n return cfg;\n }\n constructor(name) {\n const\n me = this,\n cap = name[0].toUpperCase() + name.substr(1);\n me.base = me; // so extend()ed configs have a link to the base definition\n me.name = name;\n me.field = '_' + name;\n me.capName = cap;\n me.changer = 'change' + cap;\n me.initializing = 'initializing' + cap;\n me.updater = 'update' + cap;\n }\n /**\n * The descriptor to use with `Reflect.defineProperty()` for defining this config's getter and setter.\n * @property {Object}\n * @private\n */\n get descriptor() {\n let descriptor = this._descriptor;\n if (!descriptor || !hasOwnProperty.call(this, '_descriptor')) {\n // lazily make the descriptor\n this._descriptor = descriptor = this.makeDescriptor();\n }\n return descriptor;\n }\n /**\n * The descriptor to use with `Reflect.defineProperty()` for defining this config's initter.\n * @property {Object}\n * @private\n */\n get initDescriptor() {\n let descriptor = this._initDescriptor;\n if (!descriptor || !hasOwnProperty.call(this, '_initDescriptor')) {\n // lazily make the descriptor\n this._initDescriptor = descriptor = this.makeInitter();\n }\n return descriptor;\n }\n /**\n * This method compares two values for semantic equality. By default, this is based on the `===` operator. This\n * is often overridden for configs that accept `Date` or array values.\n * @param {*} value1\n * @param {*} value2\n * @returns {Boolean}\n * @internal\n */\n equal(value1, value2) {\n return value1 === value2;\n }\n /**\n * Extends this config with a given additional set of options. These objects are just prototype extensions of this\n * instance.\n * @param {Object} options\n * @returns {Core.Config}\n * @internal\n */\n extend(options) {\n const\n cfg = Object.assign(Object.create(this), options),\n { equal, merge } = options,\n { equalityMethods } = Config;\n if (typeof equal === 'string') {\n if (equal.endsWith('[]')) {\n cfg.equal = Config.makeArrayEquals(equalityMethods[equal.substr(0, equal.length - 2)]);\n }\n else {\n cfg.equal = equalityMethods[equal];\n }\n }\n if (typeof merge === 'string') {\n // Base uses { merge : 'replace' } for defaultConfig properties\n cfg.merge = Config.mergeMethods[merge];\n }\n return cfg;\n }\n /**\n * Defines the property on a given target object via `Reflect.defineProperty()`. If the object has its own getter,\n * it will be preserved. It is invalid to define a setter.\n * @param {Object} target\n * @internal\n */\n define(target) {\n const existing = getOwnPropertyDescriptor(target, this.name);\n let descriptor = this.descriptor;\n if (existing && existing.get) {\n descriptor = Object.assign({}, descriptor);\n descriptor.get = existing.get;\n }\n defineProperty(target, this.name, descriptor);\n }\n /**\n * Defines the property initter on the `target`. This is a property getter/setter that propagates the configured\n * value when the property is read.\n * @param {Object} target\n * @param {*} value\n * @internal\n */\n defineInitter(target, value) {\n const\n { name } = this,\n properties = target[instancePropertiesSymbol];\n let lazyValues, prop;\n // If there is an existing property with a getter/setter, *not* a value\n // defined on the object for this config we must call it in our injected getter/setter.\n if (!properties[name] && (/* assign */prop = getOwnPropertyDescriptor(target, name)) && !('value' in prop)) {\n properties[name] = prop;\n }\n // Set up a temporary instance property which will pull in the value from the initialConfig if the getter\n // is called first.\n defineProperty(target, name, this.initDescriptor);\n if (this.lazy) {\n lazyValues = target[lazyConfigValues] || (target[lazyConfigValues] = new Map());\n lazyValues.set(name, value);\n }\n }\n /**\n * Returns an equality function for arrays of a base type, for example `'date'`.\n * @param {Function} [fn] The function to use to compare array elements. By default, operator `===` is used.\n * @returns {Function}\n * @private\n */\n static makeArrayEquals(fn) {\n return (value1, value2) => {\n let i,\n equal = value1 && value2 && value1.length === (i = value2.length);\n if (equal && Array.isArray(value1) && Array.isArray(value2)) {\n if (fn) {\n while (equal && i-- > 0) {\n equal = fn(value1[i], value2[i]);\n }\n }\n else {\n while (equal && i-- > 0) {\n equal = value1[i] === value2[i];\n }\n }\n }\n else {\n equal = fn ? fn(value1, value2) : (value1 === value2);\n }\n return equal;\n };\n }\n /**\n * Returns the key to use in the Config `cache`.\n * @param {String} name The name of the config property.\n * @param {Object} options The config property options.\n * @returns {String}\n * @private\n */\n static makeCacheKey(name, options) {\n const keys = Object.keys(options).sort();\n for (let key, type, value, i = keys.length; i-- > 0; /* empty */) {\n value = options[key = keys[i]];\n if (value == null && value === false) {\n keys.splice(i, 1);\n }\n else {\n type = typeof value;\n if (type === 'function') {\n return null;\n }\n if (type === 'string') {\n keys[i] = `${key}:\"${value}\"`;\n }\n else if (type === 'number') {\n keys[i] = `${key}:${value}`;\n }\n // that leaves bool and object, but there are no (valid) config options that are objects... so ignore\n }\n }\n return keys.length ? `${name}>${keys.join('|')}` : name; // eg: 'text>render|merge:v => v|bar'\n }\n /**\n * Creates and returns a property descriptor for this config suitable to be passed to `Reflect.defineProperty()`.\n * @returns {Object}\n * @private\n */\n makeDescriptor() {\n const\n config = this,\n { base, field, changer, updater, name } = config;\n if (base !== config && base.equal === config.equal) {\n // At present only the equal option affects the setter, so all configs can share the\n // descriptor of the base-most config definition unless their equality test fns differ.\n return base.descriptor;\n }\n return {\n get() {\n // Allow folks like Widget.compose() to monitor getter calls\n this.configObserver?.get(name, this);\n return this[field];\n },\n set(value) {\n const me = this;\n let was = me[field],\n applied, newValue;\n // Resolve values starting with 'up.' by traversing owners to find it\n if (typeof value === 'string') {\n let resolvedValue = value;\n if (value.startsWith('up.')) {\n resolvedValue = me.owner?.resolveProperty(value.substr(3));\n }\n else if (value.startsWith('this.')) {\n resolvedValue = me.resolveProperty(value.substr(5));\n }\n if (resolvedValue !== undefined && typeof resolvedValue !== 'function') {\n value = resolvedValue;\n }\n }\n // If the \"changeTitle()\" fellow falls off the end, it must have changed all the needful things.\n // Otherwise, it returned the final config value (it may have changed it instead, for example, making\n // an instance from a config object).\n if (me[changer]) {\n applied = (newValue = me[changer](value, was)) === undefined;\n if (!applied) {\n value = newValue;\n was = me[field]; // in case it was modified by the changer fn...\n }\n }\n // inline the default equal() for better perf:\n if (!applied && !((config.equal === equal) ? was === value : config.equal(was, value))) {\n me[field] = value;\n applied = true;\n // Check for a \"updateTitle()\" method and call it if present.\n me[updater]?.(value, was);\n }\n // Trigger config change if the value changed, and updater did not lead to our destruction\n if (applied && !me.isDestroyed && !me.onConfigChange.$nullFn) {\n me.onConfigChange({ name, value, was, config });\n }\n }\n };\n }\n /**\n * Creates and returns a property descriptor for this config's initter suitable to pass to\n * `Reflect.defineProperty()`.\n * @returns {Object}\n * @private\n */\n makeInitter() {\n const config = this;\n if (config !== config.base) {\n if (config.lazy) {\n return config.makeLazyInitter();\n }\n // At present no other options affect the setter, so all configs can share the descriptor of the base-most\n // config definition.\n return config.base.initDescriptor;\n }\n return config.makeBasicInitter();\n }\n makeBasicInitter() {\n const\n config = this,\n { initializing, name } = config;\n return {\n configurable : true,\n get() {\n const me = this;\n config.removeInitter(me);\n // Set the value from the configuration.\n me[initializing] = true;\n me[name] = me[configuringSymbol][name];\n me[initializing] = false;\n // The property has been *pulled* from the configuration.\n // Prevent the setting loop in configure from setting it again.\n me.configDone[name] = true;\n // Finally, allow the prototype getter to return the value.\n return me[name];\n },\n set(value) {\n config.removeInitter(this);\n // The config has been set (some internal code may have called the setter)\n // so prevent it from being called again and overwritten with data from initialConfig.\n this.configDone[name] = true;\n // Set the property normally (Any prototype setter will be invoked)\n this[name] = value;\n }\n };\n }\n makeLazyInitter() {\n const\n config = this,\n { initializing, name } = config;\n return {\n configurable : true,\n get() {\n const\n me = this,\n value = me[lazyConfigValues].get(name);\n config.removeInitter(me);\n if (!me.isDestroying) {\n // Set the value from the lazy config object.\n me[initializing] = true;\n me[name] = value;\n me[initializing] = false;\n }\n // Finally, allow the prototype getter to return the value.\n return me[name];\n },\n set(value) {\n config.removeInitter(this);\n // Set the property normally (Any prototype setter will be invoked)\n this[name] = value;\n }\n };\n }\n /**\n * Removes the property initter and restores the instance to its original form.\n * @param {Object} instance\n * @private\n */\n removeInitter(instance) {\n const\n { name } = this,\n instanceProperty = instance[instancePropertiesSymbol][name],\n lazyValues = instance[lazyConfigValues];\n // If we took over from an instance property, replace it\n if (instanceProperty) {\n defineProperty(instance, name, instanceProperty);\n }\n // Otherwise just delete the instance property who's getter we are in.\n else {\n delete instance[name];\n }\n if (lazyValues?.delete(name) && !lazyValues.size) {\n // we delete the keys so that we can tell if this particular lazy config has been initialized\n delete instance[lazyConfigValues];\n }\n }\n setDefault(cls, value) {\n defineProperty(cls.prototype, this.field, {\n configurable : true,\n writable : true, // or else \"this._value = x\" will fail\n value\n });\n }\n /**\n * This method combines (merges) two config values. This is called in two cases:\n *\n * - When a derived class specifies the value of a config defined in a super class.\n * - When a value is specified in the instance config object.\n *\n * @param {*} newValue In the case of derived classes, this is the config value of the derived class. In the case\n * of the instance config, this is the instance config value.\n * @param {*} currentValue In the case of derived classes, this is the config value of the super class. In the case\n * of the instance config, this is the class config value.\n * @param {Object} metaNew The class meta object from which the `newValue` is coming. This parameter is `null` if\n * the `newValue` is from an instance configuration.\n * @param {Object} metaCurrent The class meta object from which the `currentValue` is coming. This parameter is\n * `null` if the `currentValue` is not from a class configuration.\n * @returns {*}\n * @internal\n */\n merge(newValue, currentValue) {\n if (currentValue && newValue && Objects.isObject(newValue)) {\n // If existing value is a class instance, clone and merge won't work. Set the configs.\n if (currentValue.isBase) {\n return currentValue.setConfig(newValue);\n }\n if (Objects.isObject(currentValue)) {\n newValue = Objects.merge(Objects.clone(currentValue), newValue);\n }\n }\n return newValue;\n }\n}\nconst\n { prototype } = Config,\n { equal } = prototype;\nConfig.symbols = {\n configuring : configuringSymbol,\n instanceProperties : instancePropertiesSymbol,\n lazyConfigs : lazyConfigValues\n};\n/**\n * This object holds `Config` instances keyed by their name. For example:\n *\n * ```javascript\n * Config.cache = {\n * disabled : Config.get('disabled'),\n * text : Config.get('text'),\n * title : Config.get('title')\n * };\n * ```\n *\n * @member {Object} cache\n * @static\n * @private\n */\nConfig.cache = Object.create(null); // object w/no properties not even inherited ones\n/**\n * This object holds config value equality methods. By default, the `===` operator is used to compare config values for\n * semantic equality. When an `equal` option is specified as a string, that string is used as a key into this object.\n *\n * All equality methods in this object have the same signature as the {@link #function-equal equal()} method.\n *\n * This object has the following equality methods:\n *\n * - `array` : Compares arrays of values using `===` on each element.\n * - `date` : Compares values of `Date` type.\n * - `strict` : The default equal algorithm based on `===` operator.\n * @member {Object} equalityMethods\n * @static\n * @private\n */\nConfig.equalityMethods = {\n array : Config.makeArrayEquals(),\n date(value1, value2) {\n if (value1 === value2) {\n return true;\n }\n // see DateHelper.isDate() but cannot import due to circularity\n if (value1 && value2 && toString.call(value1) === DATE_TYPE && toString.call(value2) === DATE_TYPE) {\n // https://jsbench.me/ltkb3vk0ji/1 - getTime is >2x faster vs valueOf/Number/op+\n return value1.getTime() === value2.getTime();\n }\n return false;\n },\n strict : Config.equal = equal\n};\n/**\n * This object holds config value merge methods. By default, {@link Core.helper.ObjectHelper#function-merge-static} is\n * used to merge object's by their properties. Config merge methods are used to combine config values from derived\n * classes with config values from super classes, as well as instance config values with those of the class.\n *\n * All merge methods in this object have the same signature as the {@link #function-merge merge()} method.\n *\n * This object has the following merge methods:\n *\n * - `distinct` : Combines arrays of values ensuring that no value is duplicated. When given an object, its truthy\n * keys are included, while its falsy keys are removed from the result.\n * - `merge` : The default merge algorithm for `configurable()` properties, based on\n * {@link Core.helper.ObjectHelper#function-merge-static}.\n * - `items` : Similar to `merge`, but allows reordering (see `Objects.mergeItems`).\n * - `objects` : The same as to `merge` except this method promotes `true` to an empty object.\n * - 'classList' : Incoming strings are converted to an object where the string is a property name with a truthy value.\n * - `replace` : Always returns `newValue` to replace the super class value with the derived class value, or the\n * class value with the instance value.\n * @member {Object} mergeMethods\n * @static\n * @internal\n */\nConfig.mergeMethods = {\n distinct(newValue, oldValue) {\n let ret = oldValue ? oldValue.slice() : [];\n if (newValue != null) {\n if (Objects.isObject(newValue)) {\n if (oldValue === undefined) {\n ret = newValue;\n }\n else {\n let key, index;\n for (key in newValue) {\n index = ret.indexOf(key);\n if (newValue[key]) {\n if (index < 0) {\n ret.push(key);\n }\n }\n else if (index > -1) {\n ret.splice(index, 1);\n }\n }\n }\n }\n else if (Array.isArray(newValue)) {\n newValue.forEach(v => !ret.includes(v) && ret.push(v));\n }\n else if (!ret.includes(newValue)) {\n ret.push(newValue);\n }\n }\n return ret;\n },\n merge : Config.merge = prototype.merge,\n classList(newValue, oldValue) {\n // 'foo bar' -> { foo : 1, bar : 1 }\n if (typeof newValue === 'string') {\n if (!newValue.length) {\n return oldValue;\n }\n newValue = newValue.split(whitespace);\n }\n if (Array.isArray(newValue)) {\n newValue = newValue.reduce(createClsProps, {});\n }\n return Config.merge(newValue, oldValue);\n },\n objects(newValue, oldValue) {\n return (newValue === true) ? oldValue || {} : Config.merge(newValue, oldValue);\n },\n replace(newValue) {\n return newValue;\n },\n items(newValue, oldValue, metaNew, metaCurrent) {\n if (metaCurrent) {\n // When we have metaCurrent, we are merging with a class config object, so we apply the smart merge algo\n // only in that case. Merging instance configs would lose the 'clever > syntax' info needed when the\n // time comes to actually configure an instance.\n return Objects.mergeItems(oldValue, newValue, {\n merge : (oldValue, newValue) => prototype.merge(newValue, oldValue)\n });\n }\n return prototype.merge(newValue, oldValue);\n }\n};\nObject.assign(prototype, {\n _descriptor : null,\n _initDescriptor : null,\n /**\n * A function that compares values for equality. This test is used to determine if the `update` method should be\n * called when the setter is invoked.\n *\n * To handle `Date` values:\n * ```\n * class Foo extends Base {\n * static get configurable() {\n * return {\n * date : {\n * $config : {\n * equal : 'date'\n * },\n *\n * value : null\n * }\n * }\n * }\n *\n * updateDate(date) {\n * // date has changed\n * }\n * }\n * ```\n *\n * Also useful for some configs:\n * ```\n * class Foo extends Base {\n * static get configurable() {\n * return {\n * bar : {\n * $config : {\n * equal : ObjectHelper.isEqual\n * },\n *\n * value : null\n * }\n * }\n * }\n *\n * updateBar(value) {\n * // value has changed\n * }\n * }\n * ```\n * @config {Function} equal\n * @internal\n */\n /**\n * Indicates that this config property should not automatically initialize during construction. When this property\n * is set to `true`, initialization is triggered by the first use of the config property's getter.\n *\n * This property can alternatively be set to a string, in which case it can be initialized as a group using the\n * {@link Core.Base#function-triggerConfigs} method which will initialize all lazy configs with the same value for\n * this property. Note: the config will still initialize on first use if that occurs prior to the call to\n * `triggerConfigs`.\n * @config {Boolean|String}\n * @default\n * @internal\n */\n lazy : false,\n /**\n * Indicates that this config property should automatically be set to `null` on destroy.\n * @config {Boolean}\n * @default\n * @internal\n */\n nullify : false,\n /**\n * Indicates that this config participates in rendering. This has does not affect the behavior of the property\n * directly, but allows classes that perform rendering to detect which config changes will affect the rendered\n * result.\n * @config {Boolean}\n * @default\n * @internal\n */\n render : false\n});\nConfig._$name = 'Config';", "/**\n * @module Core/Base\n */\nimport Objects from './helper/util/Objects.js';\nimport StringHelper from './helper/StringHelper.js';\nimport VersionHelper from './helper/VersionHelper.js';\nimport BrowserHelper from './helper/BrowserHelper.js';\nimport Config from './Config.js';\nclass MetaClass {\n constructor(options) {\n options && Object.assign(this, options);\n }\n getInherited(name, create = true) {\n let ret = this[name];\n // We use \"in this\" to allow the object to be set to null\n if (!(name in this)) {\n // If there is no object on this metaclass, but there may be one on a super class. If create=false, the\n // idea is that a super class object will be \"properly\" inherited but otherwise no object will be created.\n ret = this.super?.getInherited(name, create);\n if (ret || create) {\n this[name] = ret = Object.create(ret || null);\n }\n }\n return ret;\n }\n}\nconst\n // Using Object.getPrototypeOf instead of Reflect.getPrototypeOf because:\n // 1. They are almost the same, according to the MDN difference is handling getPrototypeOf('string')\n // 2. It allows us to pass security check in SalesForce environment\n { getPrototypeOf } = Object,\n { hasOwn } = Objects,\n { defineProperty } = Reflect,\n metaSymbol = Symbol('classMetaData'),\n mixinTagSymbol = Symbol('mixinTag'),\n originalConfigSymbol = Symbol('originalConfig'),\n createdAtSymbol = Symbol('createdAt'),\n configuringSymbol = Config.symbols.configuring,\n instancePropertiesSymbol = Config.symbols.instanceProperties,\n lazyConfigsSymbol = Config.symbols.lazyConfigs,\n defaultConfigOptions = { merge : 'replace', simple : true },\n emptyFn = () => {},\n newMeta = o => new MetaClass(o),\n setupNames = { /* foo : 'setupFoo' */ },\n emptyObject = Object.freeze({}),\n emptyArray = Object.freeze([]);\n/**\n * Base class for all configurable classes.\n *\n * Subclasses do not have to implement a constructor with its restriction of having to call super()\n * before there is a `this` reference. Subclasses instead implement a `construct` method which is\n * called by the `Base` constructor. This may call its `super` implementation at any time.\n *\n * The `Base` constructor applies all configs to properties of the new instance. The instance\n * will have been configured after the `super.construct(config)` is called.\n *\n * See the Class System documentation in the guides for more information.\n *\n * @abstract\n */\nexport default class Base {\n static get isBase() {\n return true;\n }\n get isBase() {\n return true;\n }\n // defaultConfig & properties made private to not spam all other classes\n /**\n * A class property getter to add additional, special class properties.\n *\n * For example, a class adds a `declarable` class property like so:\n * ```\n * class Something extends Base {\n * static get declarable() {\n * return ['extra'];\n * }\n *\n * static setupExtra(cls, meta) {\n * // use cls.extra\n * }\n * }\n * ```\n * A derived class can then specify this property like so:\n * ```\n * class Derived extends Something {\n * static get extra() {\n * // return extra information\n * }\n * }\n * ```\n * When the `Derived` class is initialized, the `setupExtra()` method is called and `Derived` is passed as the\n * argument. It is also the `this` pointer, but the parameter is minifiable. The second argument passed is the\n * `$meta` object for the class.\n *\n * Classes are initialized at the first occurrence of the following:\n *\n * - An instance is created\n * - The class `$meta` property is accessed\n *\n * @member {String[]} declarable\n * @static\n * @category Configuration\n * @internal\n */\n static get declarable() {\n return [\n 'declarable',\n /**\n * A class property getter for the configuration properties of the class, which can be overridden by\n * configurations passed at construction time.\n *\n * Unlike a normal `static` property, this property is only ever used for the class that defines it (as in,\n * `hasOwnProperty`). It is retrieved for all classes in a class hierarchy, to gather their configs\n * individually and then combine them with those of derived classes.\n *\n * For example, a `Label` might declare a `text` config like so:\n * ```javascript\n * class Label extends Base {\n * static get configurable() {\n * return {\n * text : null\n * };\n * }\n * }\n * ```\n * The `text` config is automatically inherited by classes derived from Label. By implementing\n * `get configurable()`, derived classes can change the default value of inherited configs, or define new\n * configs, or both.\n *\n * When a config property is declared in this way, the class author can also implement either of two\n * special methods that will be called when the config property is assigned a new value:\n *\n * - `changeText()`\n * - `updateText()`\n *\n * In the example above, the `Label` class could implement a `changeText()` method, an `updateText()`\n * method, or both. The generated property setter ensures these methods will be called when the `text`\n * property is assigned.\n *\n * The generated setter (for `text` in this example) performs the following steps:\n *\n * - If the class defines a `changeText()` method, call it passing the new value and the current value:\n * `changeText(newText, oldText)`.
\n * Then:\n * * If `changeText()` exits without returning a value (i.e., `undefined`), exit and do nothing\n * further. The assumption is that the changer method has done all that is required.\n * * Otherwise, the return value of `changeText()` replaces the incoming value passed to the setter.\n * - If the new value (or the value returned by `changeText()`) is `!==` to the current value:\n * * Update the stored config value in `this._text`.\n * * If the class defines an `updateText()` method, call it passing the new value and the previous value.\n * `updateText(newText, oldText)`\n *\n * #### Resolving a value from an owner\n * By specifying a value starting with `'up.'` for a config, the config system will resolve that value by\n * examining the ownership hierarchy. It will walk up the hierarchy looking for a property matching the name\n * (or dot separated path) after 'up.'. If one is found, the value will be read and used as the initial\n * value.\n *\n * ```javascript\n * class Parent extends Base {\n * static get configurable() {\n * return [\n * 'importantValue'\n * ]\n * }\n * }\n *\n * class Child extends Base {\n * static get configurable() {\n * return [\n * 'value'\n * ]\n * }\n * }\n *\n * const parent = new Parent({\n * importantValue : 123\n * });\n *\n * const child = new Child({\n * owner : parent,\n * // Will be resolved from the owner\n * value : 'up.importantValue'\n * });\n *\n * console.log(child.value); // logs 123\n * ```\n * Please note that this is for now a one way one time binding, the value will only be read initially and\n * not kept up to date on later changes.\n *\n * #### Value Merging\n * When a config property value is an object, the value declared by the base class is merged with values\n * declared by derived classes and the value passed to the constructor.\n * ```javascript\n * class Example extends Base {\n * static get configurable() {\n * return {\n * config : {\n * foo : 1,\n * bar : 2\n * }\n * };\n * }\n * }\n *\n * class Example2 extends Example {\n * static get configurable() {\n * return {\n * config : {\n * bar : 42,\n * zip : 'abc'\n * }\n * };\n * }\n * }\n *\n * let ex = new Example2({\n * config : {\n * zip : 'xyz'\n * }\n * });\n * ```\n * The result of the merge would set `config` to:\n * ```javascript\n * ex.foo = {\n * foo : 1, // from Example\n * bar : 42, // from Example2\n * zip : 'xyz' // from constructor\n * }\n * ```\n *\n * #### Config Options\n * Some config properties require additional options such as declarative information about the config that\n * may be useful to automate some operation. Consider a `Button`. It could declare that its `text` config\n * affects the rendered HTML by applying a `render` property to the config definition. Its base class could\n * then examine the config definition to find this property.\n *\n * To support this, config options ca be declared like so:\n * ```javascript\n * class Button extends Widget {\n * static get configurable() {\n * return {\n * text : {\n * value : null,\n * $config : {\n * render : true\n * }\n * }\n * };\n * }\n * }\n * ```\n * The `$config` property can alternatively be just the names of the options that should be enabled (set\n * to `true`).\n *\n * For example, the following is equivalent to the above:\n * ```javascript\n * class Button extends Widget {\n * static get configurable() {\n * return {\n * text : {\n * value : null,\n * $config : 'render'\n * }\n * };\n * }\n * ```\n *\n * #### Default Value\n * It is common to set a config to a `null` value to take advantage of internal optimizations for `null`\n * values. In most cases the fact that this produces `undefined` as the actual initial value of the config\n * is acceptable. When this is not acceptable, a config can be declared like so:\n * ```javascript\n * class Widget {\n * static get configurable() {\n * return {\n * disabled : {\n * $config : null,\n * value : null,\n * default : false\n * }\n * };\n * }\n * ```\n * The `default` property above determines the value of the config while still gaining the benefits of\n * minimal processing due to the `null` value of the `value` property.\n * @member {Object} configurable\n * @static\n * @category Configuration\n * @internal\n */\n 'configurable',\n /**\n * A class property getter for the default configuration of the class, which can be overridden by\n * configurations passed at construction time.\n *\n * Unlike a normal `static` property, this property is only ever used for the class that defines it (as in,\n * `hasOwnProperty`). It is retrieved for all classes in a class hierarchy, to gather their configs\n * individually and then combine them with those of derived classes.\n *\n * For example, a `Store` might declare its `url` config like so:\n * ```\n * class Store extends Base {\n * static get defaultConfig() {\n * return {\n * url : null\n * };\n * }\n * }\n * ```\n * The `url` config is automatically inherited by classes derived from Store. By implementing\n * `get defaultConfig()`, derived classes can change the default value of inherited configs, or define new\n * configs, or both. When defining new configs, however, `configurable` is preferred.\n *\n * Config properties introduced to a class by this declaration do not participate in value merging and do\n * not get a generated setter. Config properties introduced by a base class using `configurable` can be\n * set to a different value using `defaultConfig` and in doing so, the values will be merged as appropriate\n * for `configurable`.\n *\n * @member {Object} defaultConfig\n * @static\n * @category Configuration\n * @internal\n */\n 'defaultConfig',\n /**\n * A class property getter for the default values of internal properties for this class.\n * @member {Object} properties\n * @static\n * @category Configuration\n * @internal\n */\n 'properties',\n /**\n * A class property getter for properties that will be applied to the class prototype.\n * @member {Object} prototypeProperties\n * @static\n * @category Configuration\n * @internal\n */\n 'prototypeProperties'\n ];\n }\n /**\n * Base constructor, passes arguments to {@link #function-construct}.\n * @param {...Object} [args] Usually called with a config object, but accepts any params\n * @function constructor\n * @category Lifecycle\n * @advanced\n */\n constructor(...args) {\n const\n me = this,\n C = me.constructor;\n if (me.$meta.class !== C) {\n // This will happen only once for each class. We need to call the C.$meta getter which puts $meta on our\n // prototype. Since that alone would be optimized away (and would generate IDE and lint warnings), we call\n // emptyFn and simply pass the value.\n emptyFn(C.$meta);\n }\n // Allow subclasses to have a pseudo constructor with \"this\" already set:\n me.construct(...args);\n me.afterConstruct();\n me.isConstructing = false;\n }\n /**\n * Factory version of the Base constructor. Merges all arguments to create a config object that is passed along to\n * the constructor.\n * @param {...Object} [configs] Allows passing multiple config objects\n * @returns {Core.Base} New instance\n * @private\n */\n static new(...configs) {\n configs = configs.filter(c => c);\n return new this(configs.length > 1 ? this.mergeConfigs(...configs) : configs[0]);\n }\n /**\n * Base implementation applies configuration.\n *\n * Subclasses need only implement this if they have to initialize instance specific\n * properties required by the class. Often a `construct` method is\n * unnecessary. All initialization of incoming configuration properties can be\n * done in a `set propName` implementation.\n * @param {...Object} [args] Usually called with a config object, but accepts any params\n * @category Lifecycle\n * @advanced\n */\n construct(...args) {\n // Passing null to base construct means bypass the config system and stack creation (to gain performance)\n if (args[0] !== null) {\n this.configure(...args);\n }\n this.afterConfigure();\n }\n /**\n * Destroys the provided objects by calling their {@link #function-destroy} method.\n * Skips empty values or objects that are already destroyed.\n *\n * ```javascript\n * Base.destroy(myButton, toolbar1, helloWorldMessageBox);\n * ```\n * @param {...Object} [args] Objects to be destroyed\n * @category Lifecycle\n * @advanced\n */\n static destroy(...args) {\n const shredder = object => {\n if (object?.destroy) {\n object.destroy();\n }\n else if (Array.isArray(object)) {\n object.forEach(shredder);\n }\n };\n shredder(args);\n }\n /**\n * Destroys this object.\n *\n * {@advanced}\n * This is primarily accomplished by calling {@link #function-doDestroy}, however, prior to\n * calling `doDestroy`, {@link #property-isDestroying} is set to `true`. After {@link #function-doDestroy} returns,\n * {@link #property-isDestroyed} is set to `true`.\n *\n * Do not override this method in subclasses. To provide class-specific cleanup, implement {@link #function-doDestroy}\n * instead.\n * {/@advanced}\n *\n * @category Lifecycle\n */\n destroy() {\n const\n me = this,\n { id } = me;\n // Let everyone know the object is going inert:\n me.isDestroying = true;\n // Make calling destroy() harmless:\n me.destroy = emptyFn;\n me.doDestroy();\n Object.setPrototypeOf(me, null);\n // Clear all remaining instance properties.\n for (const key in me) {\n if (key !== 'destroy' && key !== 'isDestroying') {\n delete me[key];\n }\n }\n delete me[originalConfigSymbol];\n // Let everyone know the object is inert:\n me.isDestroyed = true;\n me.id = id; // for diagnostic reasons\n }\n /**\n * This method is required to help `unused` getters to survive production build process. Some tools, like angular,\n * will remove `unused` code in production build, making our side-effected getters behind, breaking code heavily.\n * @internal\n * @param getter Getter to evaluate\n */\n _thisIsAUsedExpression(getter) {}\n static get $$name() {\n return hasOwn(this, '$name') && this.$name ||\n // _$name is filled by webpack for every class (cls._$name = '...')\n hasOwn(this, '_$name') && this._$name ||\n this.name;\n }\n get $$name() {\n return this.constructor.$$name;\n }\n /**\n * Base implementation so that all subclasses and mixins may safely call super.startConfigure.\n *\n * This is called by the Base class before setting configuration properties, but after\n * the active initial getters have been set, so all configurations are available.\n *\n * This method allows all classes in the hierarchy to force some configs to be evaluated before others.\n * @internal\n * @category Lifecycle\n * @params {Object} config The configuration object use to set the initial state.\n */\n startConfigure(config) {\n }\n /**\n * Base implementation so that all subclasses and mixins may safely call super.finishConfigure.\n *\n * This is called by the Base class before exiting the {@link #function-configure} method.\n *\n * At this point, all configs have been applied, but the `isConfiguring` property is still set.\n *\n * This method allows all classes in the hierarchy to inject functionality\n * into the config phase.\n * @internal\n * @category Lifecycle\n * @params {Object} config The configuration object use to set the initial state.\n */\n finishConfigure(config) {\n }\n /**\n * Base implementation so that all subclasses and mixins may safely call `super.afterConfigure`. This is called by the Base class after the {@link #function-configure} method has been\n * called. At this point, all configs have been applied.\n *\n * This method allows all classes in the hierarchy to inject functionality\n * either before or after the super.afterConstruct();\n * @internal\n * @category Lifecycle\n */\n afterConfigure() {\n }\n /**\n * Base implementation so that all subclasses and mixins may safely call super.afterConstruct.\n *\n * This is called by the Base class after the {@link #function-construct} method has been\n * called.\n *\n * At this point, all configs have been applied.\n *\n * This method allows all classes in the hierarchy to inject functionality\n * either before or after the super.afterConstruct();\n * @internal\n * @function afterConstructor\n * @category Lifecycle\n */\n afterConstruct() {\n }\n /**\n * Provides a way of calling callbacks which may have been specified as the _name_ of a function\n * and optionally adds scope resolution.\n *\n * For example, if the callback is specified as a string, then if it is prefixed with `'this.'`\n * then the function is resolved in this object. This is useful when configuring listeners\n * at the class level.\n *\n * If the callback name is prefixed with `'up.'` then the ownership hierarchy is queried\n * using the `owner` property until an object with the named function is present, then the\n * named function is called upon that object.\n *\n * If a named function is not found, an error is thrown. If the function should be only called when present,\n * and may not be present, add a `?` as a suffix.\n *\n * @param {String|Function} fn The function to call, or the name of the function to call.\n * @param {Object} thisObject The `this` object of the function.\n * @param {Object[]} args The argument list to pass.\n * @category Misc\n * @advanced\n */\n callback(fn, thisObject, args = emptyArray) { // Maintainer: do not make args ...args. This method may acquire more arguments\n const { handler, thisObj } = this.resolveCallback(fn, thisObject === 'this' ? this : thisObject) || emptyObject;\n return handler?.apply(thisObj, args);\n }\n resolveProperty(propertyPath) {\n let thisObj = this;\n while (thisObj) {\n if (Objects.hasPath(thisObj, propertyPath)) {\n return Objects.getPath(thisObj, propertyPath);\n }\n thisObj = thisObj.owner;\n }\n return undefined;\n }\n /**\n * Provides a way of locating callbacks which may have been specified as the _name_ of a function\n * and optionally adds scope resolution.\n *\n * For example, if the callback is specified as a string, then if it is prefixed with `'this.'`\n * then the function is resolved in this object. This is useful when configuring listeners\n * at the class level.\n *\n * If the callback name is prefixed with `'up.'` then the ownership hierarchy is queried\n * using the `owner` property until an object with the named function is present, then the\n * named function is called upon that object.\n * @param {String|Function} handler The function to call, or the name of the function to call.\n * @param {Object} thisObj The `this` object of the function.\n * @param {Boolean} [enforceCallability = true] Pass `false` if the function may not exist, and a null return value is acceptable.\n * @returns {Object} `{ handler, thisObj }`\n * @category Misc\n * @advanced\n */\n resolveCallback(handler, thisObj = this, enforceCallability = true) {\n // It's a string, we find it in its own thisObj\n if (handler?.substring) {\n if (handler.endsWith('?')) {\n enforceCallability = false;\n handler = handler.substring(0, handler.length - 1);\n }\n if (handler.startsWith('up.')) {\n handler = handler.substring(3);\n // Empty loop until we find the function owner\n for (thisObj = this.owner; thisObj && !thisObj[handler]; thisObj = thisObj.owner);\n if (!thisObj) {\n return;\n }\n }\n else if (handler.startsWith('this.')) {\n handler = handler.substring(5);\n thisObj = this;\n }\n if (!thisObj || !(thisObj instanceof Object)) {\n return;\n }\n handler = thisObj[handler];\n }\n // Any other type than string or function results in unresolved callback\n if (typeof handler === 'function') {\n return { handler, thisObj };\n }\n if (enforceCallability) {\n throw new Error(`No method named ${handler} on ${thisObj.$$name || 'thisObj object'}`);\n }\n }\n bindCallback(inHandler, inThisObj = this) {\n if (inHandler) {\n const { handler, thisObj } = this.resolveCallback(inHandler, inThisObj);\n if (handler) {\n return handler.bind(thisObj);\n }\n }\n }\n /**\n * Delays the execution of the passed function by the passed time quantum, or if the time is omitted\n * or not a number, delays until the next animation frame. Note that this will use\n * {@link Core.mixin.Delayable#function-setTimeout} || {@link Core.mixin.Delayable#function-requestAnimationFrame}\n * if this class mixes in `Delayable`, otherwise it uses the global methods. The function will\n * be called using `this` object as its execution scope.\n * @param {Function} fn The function to call on a delay.\n * @param {Number} [delay] The number of milliseconds to delay.\n * @param {String} [name] The name of delay\n * @returns {Number} The created timeout id.\n * @private\n */\n delay(fn, delay, name = fn.name || fn) {\n // Force scope on the fn if we are not a Delayable\n fn = this.setTimeout ? fn : fn.bind(this);\n const invoker = this.setTimeout ? this : globalThis;\n return invoker[typeof delay === 'number' ? 'setTimeout' : 'requestAnimationFrame'](fn, delay, name);\n }\n /**\n * Classes implement this method to provide custom cleanup logic before calling `super.doDestroy()`. The general\n * pattern is as follows:\n *\n * ```javascript\n * class Foo extends Base {\n * doDestroy() {\n * // perform custom cleanup\n *\n * super.doDestroy();\n * }\n * }\n * ```\n *\n * This method is called by {@link #function-destroy} which also prevents multiple calls from reaching `doDestroy`.\n * Prior to calling `doDestroy`, {@link #property-isDestroying} is set to `true`. Upon return, the object is fully\n * destructed and {@link #property-isDestroyed} is set to `true`.\n *\n * Do not call this method directly. Instead call {@link #function-destroy}.\n * @category Lifecycle\n * @advanced\n */\n doDestroy() {\n const\n me = this,\n { nullify } = me.$meta;\n if (nullify) {\n for (let i = 0; i < nullify.length; ++i) {\n if (me[nullify[i].field] != null) { // if backing property is null/undefined then skip\n me[nullify[i].name] = null; // else, call setter to run through change/update\n }\n }\n }\n }\n /**\n * Destroys the named properties if they have been initialized, and if they have a `destroy` method.\n * Deletes the property from this object. For example:\n *\n * this.destroyProperties('store', 'resourceStore', 'eventStore', 'dependencyStore', 'assignmentStore');\n *\n * @param {String} properties The names of the properties to destroy.\n * @internal\n * @category Lifecycle\n */\n destroyProperties(...properties) {\n const me = this;\n let key;\n for (key of properties) {\n // If the value has *not* been pulled in from the configuration object yet\n // we must not try to access it, as that will cause the property to be initialized.\n if (key in me && (!me[configuringSymbol] || !me[configuringSymbol][key])) {\n me[key]?.destroy?.();\n delete me[key];\n }\n }\n }\n /**\n * Called by the Base constructor to apply configs to this instance. This must not be called.\n * @param {Object} config The configuration object from which instance properties are initialized.\n * @private\n * @category Lifecycle\n */\n configure(config = {}) {\n const\n me = this,\n meta = me.$meta,\n { beforeConfigure } = config,\n configs = meta.configs,\n fullConfig = me.getDefaultConfiguration();\n let cfg, key, value;\n me.initialConfig = config;\n // Important flag for setters to know whether they are being called during\n // configuration when this object is not fully alive, or whether it's being reconfigured.\n me.isConfiguring = true;\n // Assign any instance properties declared by the class.\n Object.assign(me, me.getProperties());\n // Apply configuration to default from class definition. This is safe because it's either chained from or a\n // fork of the class values.\n for (key in config) {\n value = config[key];\n cfg = configs[key];\n fullConfig[key] = cfg ? cfg.merge(value, fullConfig[key], null, meta) : value;\n }\n if (beforeConfigure) {\n delete fullConfig.beforeConfigure;\n // noinspection JSValidateTypes\n beforeConfigure(me, fullConfig);\n }\n // Cache me.config for use by get config.\n me.setConfig(me[originalConfigSymbol] = fullConfig, true);\n me.isConfiguring = false;\n }\n /**\n * Returns the value of the specified config property. This is a method to allow\n * property getters to be explicitly called in a way that does not get optimized out.\n *\n * The following triggers the getter call, but optimizers will remove it:\n *\n * inst.foo; // also raises \"expression has no side-effects\" warning\n *\n * Instead, do the following to trigger a getter:\n *\n * inst.getConfig('foo');\n *\n * @param {String} name\n * @internal\n * @category Configuration\n */\n getConfig(name) {\n return this[name];\n }\n /**\n * Sets configuration options this object with all the properties passed in the parameter object.\n * Timing is taken care of. If the setter of one config is called first, and references\n * the value of another config which has not yet been set, that config will be set just\n * in time, and the *new* value will be used.\n * @param {Object} config An object containing configurations to change.\n * @category Lifecycle\n * @advanced\n */\n setConfig(config, isConstructing) {\n const\n me = this,\n wasConfiguring = me[configuringSymbol],\n configDone = wasConfiguring ? me.configDone : (me.configDone = {}),\n configs = me.$meta.configs;\n let cfg, key;\n me[instancePropertiesSymbol] = {};\n // Cache configuration for use by injected property initializers.\n me[configuringSymbol] = wasConfiguring ? Object.setPrototypeOf(Object.assign({}, config), wasConfiguring) : config;\n // For each incoming non-null configuration, create a temporary getter which will\n // pull the value in from the initialConfig so that it doesn't matter in\n // which order properties are set. You can access any property at any time.\n for (key in config) {\n // Don't default null configs in unless it's a direct property of the\n // the passed configuration. When used at construct time, defaultConfigs\n // will be prototype-chained onto the config.\n if (config[key] != null || hasOwn(config, key)) {\n cfg = configs[key] || Config.get(key);\n cfg.defineInitter(me, config[key]);\n if (!isConstructing) {\n configDone[key] = false;\n }\n // else if (cfg.lazy) {\n // // This was done originally to prevent our for-loop below from poking the value on the instance\n // // at this stage. It was removed since it confused triggerConfig, and it just isn't true that the\n // // lazy config is done...\n // configDone[key] = true;\n // }\n }\n else {\n configDone[key] = true;\n }\n }\n if (isConstructing) {\n me.startConfigure(config);\n }\n // Set all our properties from the config object.\n // If one of the properties needs to access a property that has not\n // yet been set, the above temporary property will pull it through.\n // Can't use Object.assign because that only uses own properties.\n // config value blocks are prototype chained subclass->superclass\n for (key in config) {\n // Only push the value through if the property initializer is still present.\n // If it gets triggered to pull the configuration value in, it deleted itself.\n if (!configDone[key] && !configs[key]?.lazy) {\n me[key] = config[key];\n }\n }\n if (wasConfiguring) {\n me[configuringSymbol] = wasConfiguring;\n }\n else {\n delete me[configuringSymbol];\n }\n if (isConstructing) {\n me.finishConfigure(config);\n }\n return me;\n }\n /**\n * Returns `true` if this instance has a non-null value for the specified config. This will not activate a lazy\n * config.\n *\n * @param {String} name The name of the config property.\n * @returns {Boolean}\n * @internal\n */\n hasConfig(name) {\n const\n me = this,\n config = me[configuringSymbol];\n return Boolean(\n (me['_' + name] != null) || // value has been assigned to backing property\n me[lazyConfigsSymbol]?.get(name) != null || // a lazy value is pending\n (\n // config value has not been assigned but will be\n !me.configDone[name] &&\n config && (config[name] != null || hasOwn(config, name))\n )\n );\n }\n /**\n * Returns the value of an uningested config *without* ingesting the config or transforming\n * it from its raw value using its `changeXxxxx` method.\n *\n * @param {String} name The name of the config property.\n * @returns {*} The raw incoming config value.\n * @internal\n */\n peekConfig(name) {\n const\n me = this,\n lazyConfig = me[lazyConfigsSymbol],\n config = me[configuringSymbol];\n // It's waiting in the lazy configs\n if (lazyConfig?.has(name)) {\n return lazyConfig.get(name);\n }\n if (config && (name in config)) {\n // It's been read in, so use the current value\n if (me.configDone[name]) {\n return me[name];\n }\n if (config[name] != null || hasOwn(config, name)) {\n return config[name];\n }\n }\n }\n /**\n * Ensures that the specified config is initialized if it is needed. If there is a config value specified, and it\n * was initialized by this call, this method returns `true`. If there was a config value specified, and it was\n * already initialized, this method returns `false`. If there was no value specified for the given config, this\n * method returns `null`.\n *\n * This is not the same as just reading the property, because some property getters exist that do not actually just\n * read the config value back, but instead produce some result. Reading such properties to incidentally trigger a\n * possible config initializer can lead to incorrect results. For example, the Combo items config.\n *\n * @param {String} name The name of the config property.\n * @returns {Boolean}\n * @internal\n */\n triggerConfig(name) {\n const\n me = this,\n { configDone } = me,\n lazyConfig = me[lazyConfigsSymbol],\n config = me[configuringSymbol],\n triggered = (lazyConfig?.has(name) || (config && (config[name] != null || hasOwn(config, name))))\n ? !configDone[name] : null;\n if (triggered) {\n me.getConfig(name);\n }\n return triggered;\n }\n /**\n * This call will activate any pending {@link Core.Config#config-lazy} configs that were assigned a string value\n * equal to the `group` parameter.\n *\n * @param {String} group The config property group as defined by a matching {@link Core.Config#config-lazy} value.\n * @returns {String[]} The names of any configs triggered by this call or `null` if no configs were triggered.\n * @internal\n */\n triggerConfigs(group) {\n const\n me = this,\n configs = me.$meta.configs,\n lazyConfigs = me[lazyConfigsSymbol],\n triggered = lazyConfigs ? [...lazyConfigs.keys()].filter(k => configs[k].lazy === group) : emptyArray;\n for (const key of triggered) {\n me.triggerConfig(key);\n }\n return triggered.length ? triggered : null;\n }\n onConfigChange() {} // declared above because lint/IDE get angry about not declaring the args...\n /**\n * This method is called when any config changes.\n * @param {Object} info Object containing information regarding the config change.\n * @param {String} info.name The name of the config that changed.\n * @param {*} info.value The new value of the config.\n * @param {*} info.was The previous value of the config.\n * @param {Core.Config} info.config The `Config` object for the changed config property.\n * @method onConfigChange\n * @internal\n * @category Configuration\n */\n /**\n * Returns a *copy* of the full configuration which was used to configure this object.\n * @property {Object}\n * @category Lifecycle\n * @readonly\n * @advanced\n */\n get config() {\n const\n result = {},\n myConfig = this[originalConfigSymbol];\n // The configuration was created as a prototype chain of the class hierarchy's\n // defaultConfig values hanging off a copy of the initialConfig object, so\n // we must loop and copy since Object.assign only copies own properties.\n for (const key in myConfig) {\n result[key] = myConfig[key];\n }\n return result;\n }\n // region Extract config\n static processConfigValue(currentValue, options) {\n if (currentValue === globalThis) {\n return globalThis;\n }\n else if (Array.isArray(currentValue)) {\n return currentValue.map(v => Base.processConfigValue(v, options));\n }\n // Not using isBase to avoid classes (modelClass for example)\n else if (currentValue instanceof Base) {\n if (options.visited.has(currentValue)) {\n return;\n }\n return currentValue.getCurrentConfig(options);\n }\n // appendTo, floatRoot etc\n else if (currentValue instanceof HTMLElement || currentValue instanceof DocumentFragment) {\n return null;\n }\n // Go deeply into objects, might have instances of our classes in them\n else if (Objects.isObject(currentValue)) {\n const result = {};\n for (const key in currentValue) {\n // Only step \"down\", not \"up\"\n if (key !== 'owner') {\n result[key] = Base.processConfigValue(currentValue[key], options);\n }\n }\n return result;\n }\n return currentValue;\n };\n // Recursively get the value of a config. Only intended to be called by getCurrentConfig()\n getConfigValue(name, options) {\n const\n me = this,\n lazyConfigs = me[lazyConfigsSymbol];\n // Do not trigger lazy configs\n if (!me.$meta.configs[name]?.lazy) {\n return Base.processConfigValue(me[name], options);\n }\n // Instead pull their initial config in\n if (lazyConfigs?.has(name)) {\n return Base.processConfigValue(lazyConfigs.get(name), options);\n }\n }\n // Allows removing / adding configs before values are extracted\n preProcessCurrentConfigs() {}\n // Extract the current values for all initially used configs, in a format that can be used to create a new instance.\n // Not intended to be called by any other code than getConfigString()\n getCurrentConfig(options = { }) {\n const\n me = this,\n configs = options.configs === 'all' ? me.config : Objects.clone(me.initialConfig),\n visited = options.visited || (options.visited = new Set()),\n depth = options.depth || (options.depth = 0),\n result = {};\n if (visited.has(me)) {\n return undefined;\n }\n visited.add(me);\n this.preProcessCurrentConfigs(configs);\n for (const name in configs) {\n const value = me.getConfigValue(name, { ...options, depth : depth + 1 });\n if (value !== undefined) {\n result[name] = value;\n }\n }\n return result;\n }\n // Extract the current values for all initially used configs and convert them to a JavaScript string\n getConfigString(options = {}) {\n return StringHelper.toJavaScriptString(this.getCurrentConfig(options));\n }\n // Experimental helper function, extracts the currently used configs and wraps them as an app, returning code as a\n // string.\n //\n // This function is intended to simplify creating test cases for issue reporting on Bryntum's support forum.\n //\n getTestCase(options = {}) {\n //\n const Product = this.isGantt ? 'Gantt' : this.isSchedulerPro ? 'SchedulerPro' : this.isCalendar ? 'Calendar' : this.isScheduler ? 'Scheduler' : this.isGrid ? 'Grid' : this.isTaskBoard ? 'TaskBoard' : null;\n if (Product) {\n const\n product = Product.toLowerCase(),\n // bundlePath = `https://bryntum.com/dist/${product}/build/${product}.module.js`,\n bundlePath = `../../build/${product}.module.js`;\n let preamble, postamble;\n if (options.import === 'static') {\n preamble =\n `import * as module from \"${bundlePath}\";` +\n 'Object.assign(window, module);'; // for (const c in module) window[c] = module[c];\n postamble = '';\n }\n else {\n preamble = `import(\"${bundlePath}\").then(module => { Object.assign(window, module);\\n`;\n postamble = '});';\n }\n const version = VersionHelper.getVersion(product);\n if (version) {\n preamble += `\\nconsole.log('${Product} ${version}');\\n`;\n }\n // De-indented on purpose\n return `${preamble} \\nconst ${product} = new ${Product}(${this.getConfigString(options)});\\n${postamble}`;\n }\n //\n }\n /**\n * Experimental helper function, extracts the currently used configs and wraps them as an app, downloading the\n * resulting JS file.\n *\n * This function is intended to simplify creating test cases for issue reporting on Bryntum's support forum.\n * @category Misc\n */\n downloadTestCase(options = {}) {\n options.output = 'return';\n const app = this.getTestCase(options);\n BrowserHelper.download(`app.js`, 'data:application/javascript;charset=utf-8,' + escape(app));\n }\n //endregion\n /**\n * Registers this class type with its Factory\n * @category Misc\n * @advanced\n */\n static initClass() {\n return this.$meta.class;\n }\n /**\n * The class's {@link #property-$meta-static meta} object.\n * @member {Object} $meta\n * @internal\n * @category Misc\n */\n /**\n * An object owned by this class that does not share properties with its super class.\n *\n * This object may contain other properties which are added as needed and are not documented here.\n *\n * @property {Object} $meta The class meta object.\n * @property {Function} $meta.class The class constructor that owns the meta object.\n * @property {Object} $meta.super The `$meta` object for the super class. This is `null` for `Base`.\n * @property {Object} $meta.config The object holding the default configuration values for this class.\n * @property {Object} $meta.configs An object keyed by config name that holds the defined configs for the class.\n * The value of each property is a {@link Core/Config} instance.\n * @property {Boolean} $meta.forkConfigs This will be `true` if the default configuration values for this class\n * (in the `config` property of the meta object) must be forked to avoid object sharing, or if the object can be\n * passed to `Object.create()` for efficiency.\n * @property {Function[]} $meta.hierarchy The array of classes in the ancestry of this class. This will start with\n * `Base` at index 0 and ends with this class.\n * @property {Function[]} $meta.properties The array of classes that define a \"static get properties()\" getter.\n * @internal\n * @static\n * @category Misc\n */\n static get $meta() {\n const me = this;\n let meta = me[metaSymbol];\n if (!hasOwn(me, metaSymbol)) {\n me[metaSymbol] = meta = newMeta();\n meta.class = me;\n me.setupClass(meta);\n }\n return meta;\n }\n /**\n * This optional class method is called when a class is mixed in using the {@link #function-mixin-static mixin()}\n * method.\n * @internal\n */\n static onClassMixedIn() {\n // empty\n }\n /**\n * Returns the merge of the `baseConfig` and `config` config objects based on the configs defined by this class.\n * @param {Object} baseConfig The base config or defaults.\n * @param {...Object} configs One or more config objects that takes priority over `baseConfig`.\n * @returns {Object}\n * @internal\n */\n static mergeConfigs(baseConfig, ...configs) {\n const\n classConfigs = this.$meta.configs,\n result = Objects.clone(baseConfig) || {};\n let config, i, key, value;\n for (i = 0; i < configs.length; ++i) {\n config = configs[i];\n if (config) {\n for (key in config) {\n value = config[key];\n if (classConfigs[key]) {\n value = classConfigs[key].merge(value, result[key]);\n }\n else if (result[key] && value) {\n value = Config.merge(value, result[key]);\n }\n result[key] = value;\n }\n }\n }\n return result;\n }\n /**\n * Applies one or more `mixins` to this class and returns the produced class constructor.\n *\n * For example, instead of writing this:\n * ```\n * class A extends Delayable(Events(Localizable(Base))) {\n * // ...\n * }\n * ```\n *\n * Using this method, one would write this:\n * ```\n * class A extends Base.mixin(Localizable, Events, Delayable) {\n * // ...\n * }\n * ```\n * If one of the mixins specified has already been mixed into the class, it will be ignored and not mixed in a\n * second time.\n * @param {...Function} mixins\n * @returns {Function}\n * @category Misc\n * @advanced\n */\n static mixin(...mixins) {\n // Starting w/the first class C = this\n let C = this,\n i;\n // wrap each class C using mixins[i] to produce the next class\n for (i = 0; i < mixins.length; ++i) {\n const\n mixin = mixins[i],\n // Grab or create a unique Symbol for this mixin so we can tell if we've already mixed it in\n tag = mixin[mixinTagSymbol] || (mixin[mixinTagSymbol] = Symbol('mixinTag'));\n if (C[tag]) {\n continue;\n }\n C = mixin(C);\n C[tag] = true; // properties on the constructor are inherited to subclass constructors...\n if (hasOwn(C, 'onClassMixedIn')) {\n C.onClassMixedIn();\n }\n }\n return C;\n }\n /**\n * This method is called only once for any class. This can occur when the first instance is created or when the\n * `$meta` object is first requested.\n * @param {Object} meta The `$meta` object for the class.\n * @internal\n * @category Misc\n */\n static setupClass(meta) {\n const\n cls = meta.class,\n // Trigger setupClass on the super class (if it has yet to happen):\n base = getPrototypeOf(cls).$meta,\n name = cls.$$name,\n names = base.names,\n proto = cls.prototype;\n defineProperty(proto, '$meta', {\n value : meta\n });\n Object.assign(meta, {\n super : base,\n config : Object.create(base.config),\n configs : Object.create(base.configs),\n declarables : base.declarables,\n forkConfigs : base.forkConfigs,\n hierarchy : Object.freeze([...base.hierarchy, cls]),\n names : names.includes(name) ? names : Object.freeze([...names, name]),\n properties : base.properties,\n nullify : base.nullify?.slice()\n });\n if (names !== meta.names) {\n const\n isName = `is${name}`,\n defineIsProperty = obj => {\n if (!hasOwn(obj, isName)) {\n defineProperty(obj, isName, {\n get() {\n return true;\n }\n });\n }\n };\n defineIsProperty(proto);\n defineIsProperty(cls);\n }\n // NOTE: we always use meta.declarables because setupDeclarable() can replace the array on the meta object\n // when new declarable properties are added...\n for (let decl, setupName, i = 0; i < meta.declarables.length; ++i) {\n decl = meta.declarables[i];\n if (hasOwn(cls, decl)) {\n setupName = setupNames[decl] || (setupNames[decl] = `setup${StringHelper.capitalize(decl)}`);\n cls[setupName](cls, meta);\n }\n }\n /* Add slash to the front of this line to enable the diagnostic block:\n /**/\n }\n /**\n * This method is called as part of `setupClass()`. It will process the `configurable()` return object and the\n * `defaultConfig` return object.\n * @param {Object} meta The `meta` object for this class.\n * @param {Object} configs The config definition object.\n * @param {Boolean} simple `true` when processing `defaultConfig` and `false` when processing `configurable`.\n * @private\n * @category Configuration\n */\n static setupConfigs(meta, configs, simple) {\n const\n classConfigValues = meta.config,\n classConfigs = meta.configs,\n cls = meta.class,\n superMeta = meta.super;\n let { nullify } = meta,\n cfg, defaultValue, options, setDefault, value, wasNullify;\n for (const name in configs) {\n value = configs[name];\n if (simple) {\n // Using \"defaultConfig\"\n if (!(cfg = classConfigs[name])) {\n cfg = Config.get(name, defaultConfigOptions);\n }\n else {\n // The property may be declared in a base class using configurable(), so it may have special\n // merge processing:\n value = cfg.merge(value, classConfigValues[name], meta, superMeta);\n }\n /* Add slash to the front of this line to enable the diagnostic block:\n /**/\n }\n else {\n // Using \"configurable\"\n defaultValue = options = setDefault = undefined;\n if (value && typeof value === 'object' && '$config' in value) {\n options = value.$config;\n if (options && !Objects.isObject(options)) {\n options = Objects.createTruthyKeys(options);\n }\n setDefault = 'default' in value;\n defaultValue = setDefault ? value.default : defaultValue;\n value = value.value;\n }\n if (!(cfg = classConfigs[name])) {\n cfg = Config.get(name, options);\n cfg.define(cls.prototype);\n setDefault = !(cfg.field in cls.prototype); // reduce object shape changes (helps JIT)\n wasNullify = false;\n }\n else {\n wasNullify = cfg.nullify;\n if (options) {\n // Defined by a base class, but maybe being adjusted by derived.\n cfg = cfg.extend(options);\n // In the future, we may need to redefine the property here if options affect the descriptor (such\n // as event firing)\n }\n value = cfg.merge(value, classConfigValues[name], meta, superMeta);\n }\n if (setDefault) {\n cfg.setDefault(cls, defaultValue);\n }\n if (cfg.nullify && !wasNullify) {\n (nullify || (nullify = (meta.nullify || (meta.nullify = [])))).push(cfg);\n }\n }\n // If any default properties are *mutable* Objects or Array we need to clone them.\n // so that instances do not share configured values.\n if (value && (Objects.isObject(value) || Array.isArray(value)) && !Object.isFrozen(value)) {\n meta.forkConfigs = true;\n }\n classConfigs[name] = cfg;\n classConfigValues[name] = value;\n }\n }\n static setupConfigurable(cls, meta) {\n cls.setupConfigs(meta, cls.configurable, false);\n }\n static setupDefaultConfig(cls, meta) {\n cls.setupConfigs(meta, cls.defaultConfig, true);\n }\n static setupDeclarable(cls, meta) {\n const declarable = cls.declarable;\n let all = meta.declarables,\n forked, i;\n for (i = 0; i < declarable.length; ++i) {\n if (!all.includes(declarable[i])) {\n if (!forked) {\n meta.declarables = forked = all = all.slice();\n }\n all.push(declarable[i]);\n }\n }\n }\n static setupProperties(cls, meta) {\n meta.properties = meta.super.properties.slice();\n meta.properties.push(cls);\n Object.freeze(meta.properties);\n }\n static setupPrototypeProperties(cls) {\n Object.assign(cls.prototype, cls.prototypeProperties);\n }\n /**\n * Gets the full {@link #property-defaultConfig-static} block for this object's entire inheritance chain\n * all the way up to but not including {@link Core.Base}\n * @returns {Object} All default config values for this class.\n * @private\n * @category Configuration\n */\n getDefaultConfiguration() {\n return this.constructor.getDefaultConfiguration();\n }\n /**\n * Gets the full {@link #property-defaultConfig-static} block for the entire inheritance chain for this class\n * all the way up to but not including {@link Core.Base}\n * @returns {Object} All default config values for this class.\n * @private\n * @category Configuration\n */\n static getDefaultConfiguration() {\n const\n meta = this.$meta,\n config = meta.forkConfigs ? Base.fork(meta.config) : Object.create(meta.config);\n if (VersionHelper.isTestEnv && BrowserHelper.isBrowserEnv &&\n config.testConfig && globalThis.__applyTestConfigs) {\n for (const o in config.testConfig) {\n config[o] = config.testConfig[o];\n }\n }\n return config;\n }\n static fork(obj) {\n let ret = obj,\n key, value;\n if (obj && Objects.isObject(obj) && !Object.isFrozen(obj)) {\n ret = Object.create(obj);\n for (key in obj) {\n value = obj[key];\n if (value) {\n if (Objects.isObject(value)) {\n ret[key] = Base.fork(value);\n }\n else if (Array.isArray(value)) {\n ret[key] = value.slice();\n }\n }\n }\n }\n return ret;\n }\n /**\n * Gets the full {@link #property-properties-static} block for this class's entire inheritance chain\n * all the way up to but not including {@link Core.Base}\n * @returns {Object} All default config values for this class.\n * @private\n * @category Configuration\n */\n getProperties() {\n const\n // The meta.properties array is an array of classes that define \"static get properties()\"\n hierarchy = this.$meta.properties,\n result = {};\n for (let i = 0; i < hierarchy.length; i++) {\n // Gather the class result in top-down order so that subclass properties override superclass properties\n Object.assign(result, hierarchy[i].properties);\n }\n return result;\n }\n static get superclass() {\n return getPrototypeOf(this);\n }\n /**\n * Used by the Widget and GridFeatureManager class internally. Returns the class hierarchy of this object\n * starting from the `topClass` class (which defaults to `Base`).\n *\n * For example `classHierarchy(Widget)` on a Combo would yield `[Widget, Field, TextField, PickerField, Combo]`\n * @param {Function} [topClass] The topmost class constructor to start from.\n * @returns {Function[]} The class hierarchy of this instance.\n * @private\n * @category Configuration\n */\n classHierarchy(topClass) {\n const\n hierarchy = this.$meta.hierarchy,\n index = topClass ? hierarchy.indexOf(topClass) : 0;\n return (index > 0) ? hierarchy.slice(index) : hierarchy;\n }\n /**\n * Checks if an obj is of type using object's $$name property and doing string comparison of the property with the\n * type parameter.\n *\n * @param {String} type\n * @returns {Boolean}\n * @category Misc\n * @advanced\n */\n static isOfTypeName(type) {\n return this.$meta.names.includes(type);\n }\n /**\n * Removes all event listeners that were registered with the given `name`.\n * @param {String|Symbol} name The name of the event listeners to be removed.\n * @category Events\n * @advanced\n */\n detachListeners(name) {\n let detachers = this.$detachers;\n detachers = detachers?.[name];\n if (detachers) {\n while (detachers.length) {\n detachers.pop()();\n }\n }\n }\n /**\n * Tracks a detacher function for the specified listener name.\n * @param {String} name The name assigned to the associated listeners.\n * @param {Function} detacher The detacher function.\n * @private\n */\n trackDetacher(name, detacher) {\n const\n detachers = this.$detachers || (this.$detachers = {}),\n bucket = detachers[name] || (detachers[name] = []);\n bucket.push(detacher);\n }\n /**\n * Removes all detacher functions for the specified `Events` object. This is called\n * by the `removeAllListeners` method on that object which is typically called by its\n * `destroy` invocation.\n * @param {Core.mixin.Events} eventer The `Events` instance to untrack.\n * @private\n */\n untrackDetachers(eventer) {\n const detachers = this.$detachers;\n if (detachers) {\n for (const name in detachers) {\n const bucket = detachers[name];\n for (let i = bucket.length; i-- > 0; /* empty */) {\n if (bucket[i].eventer === eventer) {\n bucket.splice(i, 1);\n }\n }\n }\n }\n }\n}\nconst proto = Base.prototype;\n// Informs the standard config setter there is no need to call this fn:\nproto.onConfigChange.$nullFn = emptyFn.$nullFn = true;\nBase[metaSymbol] = proto.$meta = newMeta({\n class : Base,\n config : Object.freeze({}),\n configs : Object.create(null),\n declarables : Base.declarable,\n forkConfigs : false,\n hierarchy : Object.freeze([Base]),\n names : Object.freeze(['Base']),\n nullify : null,\n properties : Object.freeze([]),\n super : null\n});\n// Avoid some object shape changes:\nObject.assign(proto, {\n $detachers : null,\n configObserver : null,\n /**\n * This property is set to `true` before the `constructor` returns.\n * @member {Boolean}\n * @readonly\n * @category Lifecycle\n * @advanced\n */\n isConstructing : true,\n /**\n * This property is set to `true` by {@link #function-destroy} after destruction.\n *\n * It is also one of the few properties that remains on the object after returning from `destroy()`. This property\n * is often checked in code paths that may encounter a destroyed object (like some event handlers) or in the\n * destruction path during cleanup.\n *\n * @member {Boolean}\n * @readonly\n * @category Lifecycle\n */\n isDestroyed : false,\n /**\n * This property is set to `true` on entry to the {@link #function-destroy} method. It remains on the objects after\n * returning from `destroy()`. If {@link #property-isDestroyed} is `true`, this property will also be `true`, so\n * there is no need to test for both (for example, `comp.isDestroying || comp.isDestroyed`).\n * @member {Boolean}\n * @readonly\n * @category Lifecycle\n * @advanced\n */\n isDestroying : false\n});\nBase.emptyFn = emptyFn;\nVersionHelper.setVersion('core', '5.6.0');\nBase._$name = 'Base';", "/**\n * @module Core/helper/AjaxHelper\n */\nimport Objects from './util/Objects.js';\n/**\n * Options for the requests. Please see\n * [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) for details\n *\n * To set default values for the options please use {@link #property-DEFAULT_FETCH_OPTIONS-static} property:\n *\n * ```javascript\n * // enable passing parameters in request body by default\n * AjaxHelper.DEFAULT_FETCH_OPTIONS = { addQueryParamsToBody : true };\n * ```\n *\n * @typedef {Object} FetchOptions\n * @property {'GET'|'POST'|'PUT'|'PATCH'|'DELETE'} [method] The request method, e.g., `GET`, `POST`\n * @property {Object} [queryParams] A key-value pair Object containing the params to add to the query string\n * @property {Object} [headers] Any headers you want to add to your request, contained within a `Headers` object or an\n * object literal with ByteString values\n * @property {Object} [body] Any body that you want to add to your request: this can be a `Blob`, `BufferSource`,\n * `FormData`, `URLSearchParams`, or `USVString` object. Note that a request using the `GET` or `HEAD` method cannot have a body.\n * @property {Boolean} [addQueryParamsToBody=false] Indicates whether `queryParams` should be passed in the request\n * body. Adding them to the body applies for `application/x-www-form-urlencoded` and `multipart/form-data`\n * content types only, so make sure to pass corresponding `Content-Type` header to `headers`.\n *\n * When the argument is `true` and:\n * - if `application/x-www-form-urlencoded` content-type header is passed\n * the method will make a `URLSearchParams` instance with `queryParams` and set it as the request body.\n * And if `body` already has a `URLSearchParams` instance provided the parameters will be set there.\n * - if `multipart/form-data` content-type header is passed\n * the method will make a `FormData` instance with `queryParams` and set it as the request body.\n * And if `body` already has a `FormData` instance provided the parameters will be set there.\n *\n * Otherwise, `queryParams` are added to the query string.\n * @property {'cors'|'no-cors'|'same-origin'} [mode] The mode you want to use for the request, e.g., `'cors'`, `'no-cors'`, or `'same-origin'`.\n * @property {'omit'|'same-origin'|'include'} [credentials] The request credentials you want to use for the request: `'omit'`, `'same-origin'`, or\n * `'include'`. To automatically send cookies for the current domain, this option must be provided\n * @property {Boolean} [parseJson] Specify `true` to parses the response and attach the resulting object to the\n * `Response` object as `parsedJson`\n */\nconst\n paramValueRegExp = /^(\\w+)=(.*)$/,\n parseParams = function(paramString) {\n const\n result = {},\n params = paramString.split('&');\n // loop through each 'filter={\"field\":\"name\",\"operator\":\"=\",\"value\":\"Sweden\",\"caseSensitive\":true}' string\n // So we cannot use .split('=')\n for (const nameValuePair of params) {\n const\n [match, name, value] = paramValueRegExp.exec(nameValuePair),\n decodedName = decodeURIComponent(name),\n decodedValue = decodeURIComponent(value);\n if (match) {\n let paramValue = result[decodedName];\n if (paramValue) {\n if (!Array.isArray(paramValue)) {\n paramValue = result[decodedName] = [paramValue];\n }\n paramValue.push(decodedValue);\n }\n else {\n result[decodedName] = decodedValue;\n }\n }\n }\n return result;\n };\n/**\n * Simplifies Ajax requests. Uses fetch & promises.\n *\n * ```javascript\n * AjaxHelper.get('some-url').then(response => {\n * // process request response here\n * });\n * ```\n *\n * Uploading file to server via FormData interface.\n * Please visit [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) for details.\n *\n * ```javascript\n * const formData = new FormData();\n * formData.append('file', 'fileNameToUpload');\n * AjaxHelper.post('file-upload-url', formData).then(response => {\n * // process request response here\n * });\n * ```\n *\n */\nexport default class AjaxHelper {\n /**\n * Sets default options for {@link #function-fetch-static AjaxHelper#fetch()} calls. Please see\n * {@link #typedef-FetchOptions} and\n * [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch) for details.\n *\n * ```javascript\n * // default content-type for all requests will be \"application/json\"\n * AjaxHelper.DEFAULT_FETCH_OPTIONS = {\n * headers : {\n * 'content-type' : 'application/json'\n * }\n * };\n * ```\n * @member {FetchOptions} DEFAULT_FETCH_OPTIONS\n * @static\n */\n static DEFAULT_FETCH_OPTIONS = {};\n /**\n * Make a request (using GET) to the specified url.\n * @param {String} url URL to `GET` from\n * @param {FetchOptions} [options] The options for the `fetch` API\n * @returns {Promise} The fetch Promise, which can be aborted by calling a special `abort` method\n * @async\n */\n static get(url, options) {\n return this.fetch(url, options);\n }\n /**\n * POST data to the specified URL.\n * @param {String} url URL to `POST` to\n * @param {String|Object|FormData} payload The data to post. If an object is supplied, it will be stringified\n * @param {FetchOptions} [options] The options for the `fetch` API\n * @returns {Promise} The fetch Promise, which can be aborted by calling a special `abort` method\n * @async\n */\n static post(url, payload, options = {}) {\n if (!(payload instanceof FormData) && !(typeof payload === 'string')) {\n payload = JSON.stringify(payload);\n options.headers = options.headers || {};\n options.headers['Content-Type'] = options.headers['Content-Type'] || 'application/json';\n }\n return this.fetch(url, Object.assign({\n method : 'POST',\n body : payload\n }, options));\n }\n /**\n * Fetch the specified resource using the `fetch` API.\n * @param {String} url URL to fetch from\n * @param {FetchOptions} [options] The options for the `fetch` API\n * @returns {Promise} The fetch Promise, which can be aborted by calling a special `abort` method\n * @async\n */\n static fetch(url, options) {\n let controller;\n // inherit global options\n options = Objects.merge({}, AjaxHelper.DEFAULT_FETCH_OPTIONS, options);\n // AbortController is not supported by LockerService\n // https://github.com/bryntum/support/issues/3689\n if (typeof AbortController !== 'undefined') {\n controller = options.abortController = new AbortController();\n options.signal = controller.signal;\n }\n if (!('credentials' in options)) {\n options.credentials = 'include';\n }\n if (options.queryParams) {\n const params = Object.entries(options.queryParams);\n if (params.length) {\n let paramsAdded = false;\n // for some content types we are going to add parameters to body (if that's not disabled)\n if (options.headers && options.addQueryParamsToBody === true) {\n const contentType = new Headers(options.headers).get('Content-Type');\n let bodyClass;\n switch (contentType) {\n case 'application/x-www-form-urlencoded':\n bodyClass = URLSearchParams;\n break;\n case 'multipart/form-data':\n bodyClass = FormData;\n break;\n }\n // if that's one of supported content types\n if (bodyClass) {\n const body = options.body || (options.body = new bodyClass());\n // put parameters to body if it's of supported type\n if (body instanceof bodyClass) {\n params.forEach(([key, value]) => body.set(key, value));\n // remember parameters are already added\n paramsAdded = true;\n }\n }\n }\n // if parameters are not added yet append them to the query string\n if (!paramsAdded) {\n url += (url.includes('?') ? '&' : '?') + params.map(([param, value]) =>\n `${param}=${encodeURIComponent(value)}`\n ).join('&');\n }\n }\n }\n // Promise that will be resolved either when network request is finished or when json is parsed\n const promise = new Promise((resolve, reject) => {\n fetch(url, options).then(\n response => {\n if (options.parseJson) {\n response.json().then(json => {\n response.parsedJson = json;\n resolve(response);\n }).catch(error => {\n response.parsedJson = null;\n response.error = error;\n reject(response);\n });\n }\n else {\n resolve(response);\n }\n }\n ).catch(error => {\n error.stack = promise.stack;\n reject(error);\n });\n });\n promise.stack = new Error().stack;\n promise.abort = function() {\n controller?.abort();\n };\n return promise;\n }\n /**\n * Registers the passed URL to return the passed mocked up Fetch Response object to the\n * AjaxHelper's promise resolve function.\n * @param {String} url The url to return mock data for\n * @param {Object|Function} response A mocked up Fetch Response object which must contain\n * at least a `responseText` property, or a function to which the `url` and a `params` object\n * and the `Fetch` `options` object is passed which returns that.\n * @param {String} response.responseText The data to return.\n * @param {Boolean} [response.synchronous] resolve the Promise immediately\n * @param {Number} [response.delay=100] resolve the Promise after this number of milliseconds.\n */\n static mockUrl(url, response) {\n const me = this;\n (me.mockAjaxMap || (me.mockAjaxMap = {}))[url] = response;\n // Inject the override into the AjaxHelper instance\n if (!AjaxHelper.originalFetch) {\n AjaxHelper.originalFetch = AjaxHelper.fetch;\n AjaxHelper.fetch = me.mockAjaxFetch.bind(me);\n }\n }\n static async mockAjaxFetch(url, options) {\n const urlAndParams = url.split('?');\n let result = this.mockAjaxMap[urlAndParams[0]],\n parsedJson = null;\n if (result) {\n if (typeof result === 'function') {\n result = await result(urlAndParams[0], urlAndParams[1] && parseParams(urlAndParams[1]), options);\n }\n try {\n parsedJson = options?.parseJson && JSON.parse(result.responseText);\n }\n catch (error) {\n parsedJson = null;\n result.error = error;\n }\n result = Object.assign({\n status : 200,\n ok : true,\n headers : new Headers(),\n statusText : 'OK',\n url,\n parsedJson,\n text : () => new Promise((resolve) => {\n resolve(result.responseText);\n }),\n json : () => new Promise((resolve) => {\n resolve(parsedJson);\n })\n }, result);\n return new Promise(function(resolve, reject) {\n if (result.synchronous) {\n resolve(result);\n }\n else {\n setTimeout(function() {\n resolve(result);\n }, ('delay' in result ? result.delay : 100));\n }\n });\n }\n else {\n return AjaxHelper.originalFetch(url, options);\n }\n }\n}\nAjaxHelper._$name = 'AjaxHelper';", "/**\n * @module Core/helper/ArrayHelper\n */\n/**\n * Helper with useful functions for handling Arrays\n * @internal\n */\nexport default class ArrayHelper {\n static clean(array) {\n return array.reduce((res, item) => {\n if (item !== null && item !== undefined && !(Array.isArray(item) && item.length === 0) && item !== '') res.push(item);\n return res;\n }, []);\n }\n /**\n * Similar to [`Array.from()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)\n * this method creates an array from an `iterable` object. Where `Array.from()` accepts a mapper function as the\n * second argument, this method accepts a `filter` function as its second argument. If a mapper function is also\n * needed, it can be passed as the third argument. Unlike `Array.from()`, if this method is passed `null`, it will\n * return an empty array.\n * @param {Array} iterable The iterable object to convert (must support `for-of` loop iteration).\n * @param {Function} [filter] A function to apply to each item of the `iterable` which must return a truthy value\n * to include that item in the resulting array.\n * @param {Function} [map] A function to apply to each item of the `iterable` that returns the actual value to put\n * into the returned array. If a `filter` is also supplied, this method is only called for those items that pass\n * the filter test.\n * @returns {Array}\n */\n static from(iterable, filter, map) {\n const array = [];\n if (iterable) {\n for (const it of iterable) {\n if (!filter || filter(it)) {\n array.push(map ? map(it) : it);\n }\n }\n }\n return array;\n }\n /**\n * Remove one or more items from an array\n * @param {Array} array Array to remove from\n * @param {Object[]|Set} items One or more items to remove, or one Set containing items to remove\n * @returns {Boolean} Returns true if any item was removed\n */\n static remove(array, ...items) {\n let index,\n item,\n removed = false;\n items = items[0] instanceof Set ? [...items[0]] : items;\n for (let i = 0; i < items.length; i++) {\n item = items[i];\n if ((index = array.indexOf(item)) !== -1) {\n array.splice(index, 1);\n removed = true;\n }\n }\n return removed;\n }\n /**\n * Calculates the insertion index of a passed object into the passed Array according\n * to the passed comparator function. Note that the passed Array *MUST* already be ordered.\n * @param {Object} item The item to calculate the insertion index for.\n * @param {Array} array The array into which the item is to be inserted.\n * @param {Function} comparatorFn The comparison function. Must return -1 or 0 or 1.\n * @param {Object} comparatorFn.lhs The left object to compare.\n * @param {Object} comparatorFn.rhs The right object to compare.\n * @param {Number} index The possible correct index to try first before a binary\n * search is instigated.\n * @internal\n */\n static findInsertionIndex(item, array, comparatorFn = this.lexicalCompare, index) {\n const len = array.length;\n let beforeCheck, afterCheck;\n if (index < len) {\n beforeCheck = index > 0 ? comparatorFn(array[index - 1], item) : 0;\n afterCheck = index < len - 1 ? comparatorFn(item, array[index]) : 0;\n if (beforeCheck < 1 && afterCheck < 1) {\n return index;\n }\n }\n return this.binarySearch(array, item, comparatorFn);\n }\n /**\n * Similar to the native `Array.find()` call, but this finds the *last* element in the array for which\n * the passed function returns a truthy value.\n * @param {Object[]} array The array to find in.\n * @param {Function} fn The testing function.\n * @param {Object} [thisObj] The scope (`this` reference) in which to call the function.\n */\n static findLast(array, fn, thisObj) {\n for (let { length } = array, i = length - 1; i >= 0; i--) {\n if (fn.call(thisObj, array[i], i, array)) {\n return array[i];\n }\n }\n }\n /**\n * This method returns the index that a given item would be inserted into the\n * given (sorted) `array`. Note that the given `item` may or may not be in the\n * array. This method will return the index of where the item *should* be.\n *\n * For example:\n *\n * var array = [ 'A', 'D', 'G', 'K', 'O', 'R', 'X' ];\n * var index = ArrayHelper.binarySearch(array, 'E');\n *\n * console.log('index: ' + index);\n * // logs \"index: 2\"\n *\n * array.splice(index, 0, 'E');\n *\n * console.log('array : ' + array.join(''));\n * // logs \"array: ADEGKORX\"\n *\n * @param {Object[]} array The array to search.\n * @param {Object} item The item that you want to insert into the `array`.\n * @param {Number} [begin=0] The first index in the `array` to consider.\n * @param {Number} [end=array.length] The index that marks the end of the range\n * to consider. The item at this index is *not* considered.\n * @param {Function} [compareFn] The comparison function that matches the sort\n * order of the `array`. The default `compareFn` compares items using less-than\n * and greater-than operators.\n * @returns {Number} The index for the given item in the given array based on\n * the passed `compareFn`.\n */\n static binarySearch(array, item, begin = 0, end = array.length, compareFn = this.lexicalCompare) {\n const length = array.length;\n let middle, comparison;\n if (begin instanceof Function) {\n compareFn = begin;\n begin = 0;\n }\n else if (end instanceof Function) {\n compareFn = end;\n end = length;\n }\n --end;\n while (begin <= end) {\n middle = (begin + end) >> 1;\n comparison = compareFn(item, array[middle]);\n if (comparison >= 0) {\n begin = middle + 1;\n }\n else if (comparison < 0) {\n end = middle - 1;\n }\n }\n return begin;\n }\n magnitudeCompare(lhs, rhs) {\n return (lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0);\n }\n lexicalCompare(lhs, rhs) {\n lhs = String(lhs);\n rhs = String(rhs);\n return (lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0);\n }\n /**\n * Similar to Array.prototype.fill(), but constructs a new array with the specified item count and fills it with\n * clones of the supplied item.\n * @param {Number} count Number of entries to create\n * @param {Object|Array} itemOrArray Item or array of items to clone (uses object spread to create shallow clone)\n * @param {Function} [fn] An optional function that is called for each item added, to allow processing\n * @returns {Array} A new populated array\n */\n static fill(count, itemOrArray = {}, fn = null) {\n const\n result = [],\n items = Array.isArray(itemOrArray) ? itemOrArray : [itemOrArray];\n for (let i = 0; i < count; i++) {\n for (const item of items) {\n // Using object spread here forces us to use more babel plugins and will make\n // react_typescript demo very difficult to setup\n const processedItem = Object.assign({}, item);\n if (fn) {\n fn(processedItem, i);\n }\n result.push(processedItem);\n }\n }\n return result;\n }\n /**\n * Populates an array with the return value from `fn`.\n * @param {Number} count Number of entries to create\n * @param {Function} fn A function that is called `count` times, return value is added to array\n * @param {Number} fn.index Current index in the array\n * @privateparam {Boolean} [oneBased] Add 1 to the index before calling the fn (making it 1 based)\n * @returns {Array} A new populated array\n */\n static populate(count, fn, oneBased = false) {\n const items = [];\n for (let i = 0; i < count; i++) {\n items.push(fn(i + (oneBased ? 1 : 0)));\n }\n return items;\n }\n /**\n * Pushes `item` on to the `array` if not already included\n * @param {Array} array Array to push to\n * @param {...Object} items Item(s) to push if not already included\n */\n static include(array, ...items) {\n for (const item of items) {\n if (!array.includes(item)) {\n array.push(item);\n }\n }\n }\n /**\n * Returns a new array with the unique items from the supplied array.\n * @param {Array} array Input array\n * @returns {Array} New array with unique items\n */\n static unique(array) {\n return [...new Set(array)];\n }\n // Kept for future reference : Wanted to create an indexer on Stores.\n static allowNegative(array) {\n // From https://github.com/sindresorhus/negative-array\n return new Proxy(array, {\n get(target, name, receiver) {\n if (typeof name !== 'string') {\n return Reflect.get(target, name, receiver);\n }\n const index = Number(name);\n if (Number.isNaN(index)) {\n return Reflect.get(target, name, receiver);\n }\n return target[index < 0 ? target.length + index : index];\n },\n set(target, name, value, receiver) {\n if (typeof name !== 'string') {\n return Reflect.set(target, name, value, receiver);\n }\n const index = Number(name);\n if (Number.isNaN(index)) {\n return Reflect.set(target, name, value, receiver);\n }\n target[index < 0 ? target.length + index : index] = value;\n return true;\n }\n });\n }\n static delta(a, b, useRelativeNaming = false) {\n // Nicer syntax but about 40% slower (an extra iteration)\n // const\n // onlyInA = a.filter(item => !b.includes(item)),\n // onlyInB = b.filter(item => !a.includes(item)),\n // inBoth = a.filter(item => b.includes(item));\n // Quick bailout for nonexisting target array\n if (!b) {\n return useRelativeNaming\n ? { toAdd : a, toRemove : [], toKeep : [] }\n : { onlyInA : a, onlyInB : [], inBoth : [] };\n }\n const\n onlyInA = [],\n onlyInB = [],\n inBoth = new Set(),\n bSet = new Set(b);\n for (let i = 0; i < a.length; i++) {\n const item = a[i];\n if (bSet.has(item)) {\n inBoth.add(item);\n }\n else {\n onlyInA.push(item);\n }\n }\n for (let i = 0; i < b.length; i++) {\n const item = b[i];\n if (!inBoth.has(item)) {\n onlyInB.push(item);\n }\n }\n if (useRelativeNaming) {\n return { toAdd : onlyInA, toRemove : onlyInB, toKeep : inBoth };\n }\n return { onlyInA, onlyInB, inBoth : [...inBoth] };\n }\n /**\n * Returns the passed object wrapped in an array. Special handling of the following cases:\n * * Passing an array returns it as is\n * * Passing a `Set` returns it converted to an Array\n * * Passing `null`/`undefined` returns the passed value\n *\n * ```javascript\n * const records = ArrayHelper.asArray(record);\n *\n * // { id : 1 } -> [{ id : 1 }]\n * // [{ id : 1 }] -> [{ id : 1 }]\n * ```\n *\n * @param {*} arrayOrObject\n * @returns {Array|null}\n * @internal\n */\n static asArray(arrayOrObject) {\n if (arrayOrObject == null) {\n return arrayOrObject;\n }\n if (arrayOrObject instanceof Set) {\n return Array.from(arrayOrObject);\n }\n return Array.isArray(arrayOrObject) ? arrayOrObject : [arrayOrObject];\n }\n /**\n * Identity function that returns its input.\n * @param {*} Any value\n * @returns {*} The input value\n * @internal\n */\n static identity(x) {\n return x;\n }\n /**\n * Transform an array into a key:value dictionary using the specified\n * key and value getters. Does not group values, so only one result will\n * appear in the output for a given key.\n *\n * ```javascript\n * const input = [{\n * id: '1',\n * other: 'one'\n * },{\n * id: '2',\n * other: 'two'\n * }];\n *\n * keyBy(input, rec => rec.id)\n *\n * // {\n * // '1': { id: '1', other: 'one' },\n * // '2': { id: '2', other: 'two' }\n * // }\n * ```\n *\n * @param {Array} array Array from which to build dictionary\n * @param {Function|String} getKey Function to produce the key for a given array entry, or a string property name to read\n * @param {Function} getValue Optional function to transform array elements. Defaults to returning the element itself\n * @returns {Object} A key->value dictionary with keys as returned by `getKey` and values returned by `getValue`\n * @internal\n */\n static keyBy(array, keyGetter, valueGetter = ArrayHelper.identity) {\n const\n getKey = typeof keyGetter === 'string' ? o => o?.[keyGetter] : keyGetter,\n getValue = typeof valueGetter === 'string' ? o => o?.[valueGetter] : valueGetter;\n return array.reduce((dict, next) => {\n dict[getKey(next)] = getValue(next);\n return dict;\n }, {});\n }\n /**\n * Combines provided arrays of by aggregating their element values.\n * For example the below code sums up numeric elements of the arrays:\n *\n * ```javascript\n * ArrayHelper.aggregate(\n * [\n * [0, 1, 2, 33]\n * [10, 1, -1],\n * [100, 1, -1]\n * ],\n * entry => entry || 0, // \"|| 0\" here to make it work for different array sizes\n * (aggregated, entry) => aggregated + entry, // aggregate by summing up\n * () => 0 //initial value is zero\n * );\n *\n * // returns [111, 3, 0, 33] array\n * ```\n *\n * @param {Array[]} arrays Array to combine\n * @param {Function} getEntryValueFn Function that extracts an array entry for aggregating.\n * @param {Function} aggregatorFn A function to execute for each element in the arrays. It's purpose is to\n * aggregate the element value to the corresponding entry of the resulting array.\n * The function's return value becomes the value of the `aggregated` parameter on the next invocation of\n * `aggregatorFn`.\n * The function is called with the following arguments:\n *\n * @param {Object} aggregatorFn.aggregated Resulting array entry value. On the first call\n * `getInitialValueFn` result.\n * @param {Object} aggregatorFn.entry Current entry to aggregate into `aggregated`.\n * @param {Number} aggregatorFn.arrayIndex Index of current array (in the provided `arrays`).\n * @param {Object[]} aggregatorFn.entryIndex Index of the current entry.\n * @param {Object} aggregationContext A shared object providing extra aggregation call context.\n * @param {Function} getInitialValueFn Function that returns an initial value for the combined array entries.\n * @param {Object} [aggregationContext] Optional object that is passed to all of the above functions that can\n * be used for keeping some additional parameters used when aggregating.\n * Out of the box the object will contain `arrays` and `targetArray` properties containing\n * input and resulting arrays respectively.\n */\n static aggregate(arrays, getEntryValueFn, aggregatorFn, getInitialValueFn, aggregationContext = {}) {\n const\n rowLength = arrays.length,\n columnLength = arrays[0].length,\n result = [];\n // provide some context by default\n // the resulting array reference and list of array given for aggregating\n aggregationContext.targetArray = result;\n aggregationContext.arrays = arrays;\n for (let colIndex = 0; colIndex < columnLength; colIndex++) {\n aggregationContext.entryIndex = colIndex;\n result.push(getInitialValueFn(colIndex, aggregationContext));\n }\n // iterate provided arrays\n for (let rowIndex = 0; rowIndex < rowLength; rowIndex++) {\n const row = arrays[rowIndex];\n aggregationContext.rowIndex = rowIndex;\n for (let colIndex = 0; colIndex < columnLength; colIndex++) {\n aggregationContext.entryIndex = colIndex;\n const entryValue = getEntryValueFn(row[colIndex], aggregationContext);\n // aggregate them\n result[colIndex] = aggregatorFn(result[colIndex], entryValue, rowIndex, colIndex, aggregationContext);\n }\n }\n return result;\n }\n /**\n * Group an array by keys (either the values in a specified property name, or the results of a string-generating function accepting\n * an array entry as input), returning an Object with those keys, whose values are arrays containing the array entries that\n * produced that key.\n *\n * ```javascript\n * const input = [{\n * id: 1,\n * color: 'red'\n * },{\n * id: 2,\n * color: 'green'\n * },{\n * id: 3,\n * color: 'green'\n * }];\n *\n * groupBy(input, 'color')\n *\n * // {\n * // 'red': [ { id: '1', color: 'red' } ],\n * // 'green': [ { id: '2', color: 'green' }, { id: '3', color: 'green' } ]\n * // }\n *\n * groupBy(input, rec => rec.color?.substr(0, 1))\n *\n * // {\n * // 'r': [ { id: '1', color: 'red' } ],\n * // 'g': [ { id: '2', color: 'green' }, { id: '3', color: 'green' } ]\n * // }\n * ```\n *\n * @param {Object} array Array from which to build dictionary\n * @param {Function|String} getGroupKey Function to produce the key for a given array entry, or a string property name to read\n * @returns {Object} A key->value[] dictionary with keys as returned by `getKey` and arrays of matching items in original order as values\n * @internal\n */\n static groupBy(array, groupKeyGetter) {\n const getKey = typeof groupKeyGetter === 'string' ? o => o?.[groupKeyGetter] : groupKeyGetter;\n return array.reduce((grouped, value) => {\n const key = getKey(value);\n (grouped[key] = grouped[key] || []).push(value);\n return grouped;\n }, {});\n }\n}\nArrayHelper._$name = 'ArrayHelper';", "/**\n * @module Core/helper/FunctionHelper\n */\nconst\n commaSepRe = /,\\s*/,\n decompiledSym = Symbol('decompiled'),\n // [async] p => ...\n fnRe1 = /^\\s*(async\\s+)?([a-z_]\\w*)\\s*=>([\\s\\S]+)$/i,\n // [async] (p1?[, px]*) => ...\n fnRe2 = /^\\s*(async\\s*)?\\s*\\(((?:[a-z_]\\w*(?:, [a-z_]\\w*)*)?)\\)\\s+=>([\\s\\S]+)$/i,\n // [async] [function] [name] (p1?[, px]*) ...\n fnRe3 = /^(\\s*async)?(?:\\s*function)?(?:\\s*([a-z_]\\w*))?\\s*\\(((?:[a-z_]\\w*(?:, [a-z_]\\w*)*)?)\\)([\\s\\S]+)$/i,\n { hasOwnProperty } = Object.prototype;\n/**\n * Provides functionality for working with functions\n * @internal\n */\nexport default class FunctionHelper {\n /**\n * Inserts a function after the specified `method` is called on an `object`. To remove this hook, invoke the\n * function returned by this method.\n * ```\n * class A {\n * method() {\n * console.log('method');\n * }\n * }\n *\n * let instance = new A();\n *\n * let detach = FunctionHelper.after(instance, 'method', () => { console.log('after') });\n *\n * instance.method();\n * > method\n * > after\n *\n * detach();\n * instance.method();\n * > method\n * ```\n * The value returned by the original method is passed as the first argument to `fn` followed by all the arguments\n * passed by the caller.\n *\n * If `fn` returns a value (not `undefined`), that value is returned from the method call instead of the value\n * returned by the original method.\n * ```\n * class A {\n * method(x) {\n * console.log('method', x);\n * return x * 2\n * }\n * }\n *\n * let instance = new A();\n *\n * let detach = FunctionHelper.after(instance, 'method', (ret, x) => {\n * console.log('after', ret, x);\n * return x / 2;\n * });\n *\n * console.log(instance.method(50));\n * > method 50\n * > after 100 50\n * > 25\n *\n * detach();\n * console.log(instance.method(50));\n * > method 50\n * > 100\n * ```\n *\n * @param {Object} object The object to hook.\n * @param {String} method The name of the method on `object` to hook.\n * @param {Function|String} fn The function or method name (on `thisObj`) to call after `method`.\n * @param {Object} [thisObj] The `this` pointer value for calling `fn`.\n * @param {Object} [options] Additional options\n * @param {Boolean} [options.return=true] Specify `false` to not include the return value of the hooked method as\n * the first argument to `fn`.\n * @returns {Function} The function to call to remove the hook.\n */\n static after(object, method, fn, thisObj, options) {\n const\n named = typeof fn === 'string',\n withReturn = options?.return !== false,\n hook = (...args) => {\n const\n // if object.destroy() occurs, our hook will be removed, so this fn won't be called in that case\n origResult = hook.$nextHook.call(object, ...args),\n hookResult = thisObj?.isDestroyed ? undefined : (withReturn\n ? (named ? thisObj[fn](origResult, ...args) : fn.call(thisObj, origResult, ...args))\n : (named ? thisObj[fn](...args) : fn.call(thisObj, ...args))\n );\n return (hookResult === undefined) ? origResult : hookResult;\n };\n return FunctionHelper.hookMethod(object, method, hook);\n }\n /**\n * Inserts a function before the specified `method` is called on an `object`. To remove this hook, invoke the\n * function returned by this method.\n * ```\n * class A {\n * method() {\n * console.log('method');\n * }\n * }\n *\n * let instance = new A();\n *\n * let detach = FunctionHelper.before(instance, 'method', () => { console.log('before') });\n *\n * instance.method();\n * > before\n * > method\n *\n * detach();\n * instance.method();\n * > method\n * ```\n * If `fn` returns `false`, the original method is not invoked and `false` is returned to the caller.\n * ```\n * class A {\n * method(x) {\n * console.log('method', x);\n * return x * 2;\n * }\n * }\n *\n * let instance = new A();\n *\n * let detach = FunctionHelper.before(instance, 'method', x => {\n * console.log('before', x);\n * return false;\n * });\n *\n * console.log(instance.method(50));\n * > before 50\n * > false\n *\n * detach();\n * console.log(instance.method(50));\n * > method 50\n * > 100\n * ```\n *\n * @param {Object} object The object to hook.\n * @param {String} method The name of the method on `object` to hook.\n * @param {Function|String} fn The function or method name (on `thisObj`) to call before `method`.\n * @param {Object} [thisObj] The `this` pointer value for calling `fn`.\n * @returns {Function} The function to call to remove the hook.\n */\n static before(object, method, fn, thisObj) {\n const\n named = typeof fn === 'string',\n hook = (...args) => {\n const ret = (thisObj?.isDestroyed\n ? 0\n : (named ? thisObj[fn](...args) : fn.call(thisObj, ...args))\n );\n return (ret === false) ? ret : hook.$nextHook.call(object, ...args);\n };\n return FunctionHelper.hookMethod(object, method, hook);\n }\n static curry(func) {\n return function curried(...args) {\n if (args.length >= func.length) {\n return func.apply(this, args);\n }\n else {\n return function(...args2) {\n return curried.apply(this, args.concat(args2));\n };\n }\n };\n }\n static bindAll(obj) {\n for (const key in obj) {\n if (typeof obj[key] === 'function') {\n obj[key] = obj[key].bind(obj);\n }\n }\n }\n /**\n * Returns a function which calls the passed `interceptor` function first, and the passed `original` after\n * as long as the `interceptor` does not return `false`.\n * @param {Function} original The function to call second.\n * @param {Function} interceptor The function to call first.\n * @param {Object} [thisObj] The `this` reference when the functions are called.\n * @returns {Function} A function which yields the return value from the `original` function **if it was called**, else `false`.\n */\n static createInterceptor(original, interceptor, thisObj) {\n return function(...args) {\n const theThis = thisObj || this;\n if (interceptor.call(theThis, ...args) !== false) {\n return original.call(theThis, ...args);\n }\n return false;\n };\n }\n /**\n * Returns a function which calls the passed `sequence` function after calling\n * the passed `original`.\n * @param {Function} original The function to call first.\n * @param {Function} sequence The function to call second.\n * @param {Object} [thisObj] The `this` reference when the functions are called.\n * @returns {Function} A function which yields the value returned from the sequence if it returned a value, else the return\n * value from the original function.\n */\n static createSequence(original, sequence, thisObj) {\n return (...args) => {\n const origResult = original.call(thisObj, ...args),\n sequenceResult = sequence.call(thisObj, ...args);\n return (sequenceResult === undefined) ? origResult : sequenceResult;\n };\n }\n /**\n * Create a \"debounced\" function which will call on the \"leading edge\" of a timer period.\n * When first invoked will call immediately, but invocations after that inside its buffer\n * period will be rejected, and *one* invocation will be made after the buffer period has expired.\n *\n * This is useful for responding immediately to a first mousemove, but from then on, only\n * calling the action function on a regular timer while the mouse continues to move.\n *\n * @param {Function} fn The function to call.\n * @param {Number} buffer The milliseconds to wait after each execution before another execution takes place.\n * @param {Object} [thisObj] `this` reference for the function.\n * @param {Array} [extraArgs] The argument list to append to those passed to the function.\n * @param {Function} [alt] A function to call when the invocation is rejected due to buffer time not having expired.\n * @returns {Function} A function which calls the passed `fn` only if at least the passed `buffer`\n * milliseconds has elapsed since its last invocation.\n */\n static createThrottled(fn, buffer, thisObj, extraArgs, alt) {\n let lastCallTime = -Number.MAX_VALUE,\n callArgs,\n timerId;\n const\n invoke = () => {\n timerId = 0;\n lastCallTime = performance.now();\n callArgs.push.apply(callArgs, extraArgs);\n fn.apply(thisObj, callArgs);\n },\n result = function(...args) {\n const elapsed = performance.now() - lastCallTime;\n callArgs = args;\n // If it's been more then the buffer period since we invoked, we can call it now\n if (elapsed >= buffer) {\n clearTimeout(timerId);\n invoke();\n }\n // Otherwise, kick off a timer for the requested period.\n else {\n if (!timerId) {\n timerId = setTimeout(invoke, buffer - elapsed);\n }\n if (alt) {\n callArgs.push.apply(callArgs, extraArgs);\n alt.apply(thisObj, callArgs);\n }\n }\n };\n result.cancel = () => clearTimeout(timerId);\n return result;\n }\n /**\n * Create a \"debounced\" function which will call on the \"trailing edge\" of a timer period.\n * When first invoked will wait until the buffer period has expired to call the function, and\n * more calls within that time will restart the timer.\n *\n * This is useful for responding to keystrokes, but deferring action until the user pauses typing.\n *\n * @param {Function} fn The function to call.\n * @param {Number} buffer The milliseconds to wait after each execution before another execution takes place.\n * @param {Object} [thisObj] `this` reference for the function.\n * @param {Array} [args] The argument list to append to those passed to the function.\n * @returns {Function} A function which calls the passed `fn` when at least the passed `buffer`\n * milliseconds has elapsed since its last invocation.\n */\n static createBuffered(fn, buffer, thisObj, args) {\n let callArgs,\n timerId;\n const\n invoke = () => {\n timerId = 0;\n result.isPending = false;\n callArgs.push.apply(callArgs, args);\n fn.apply(thisObj, callArgs);\n },\n result = function(...args) {\n callArgs = args;\n // Cancel any impending invocation. It's pushed out for ms from each call\n if (timerId) {\n clearTimeout(timerId);\n }\n result.isPending = true;\n timerId = setTimeout(invoke, buffer);\n };\n result.cancel = () => {\n result.isPending = false;\n clearTimeout(timerId);\n };\n return result;\n }\n static decompile(fn) {\n if (!(decompiledSym in fn)) {\n const code = fn.toString();\n let m = fnRe1.exec(code),\n args, body, name, decompiled, t;\n if (m) {\n // [async] p => ...\n // [1] [2] [3]\n args = [m[2]];\n body = m[3];\n }\n else if ((m /* assignment */ = fnRe2.exec(code))) {\n // [async] (p1?[, px]*) => ...\n // [1] [2] [3]\n t = m[2].trim();\n args = t ? t.split(commaSepRe) : [];\n body = m[3];\n }\n else if ((m /* assignment */ = fnRe3.exec(code))) {\n // [async] [function] [name] (p1?[, px]*) ...\n // [1] [2] [3] [4]\n name = m[2];\n t = m[3].trim();\n args = t ? t.split(commaSepRe) : [];\n body = m[4];\n }\n body = body?.trim();\n fn[decompiledSym] = decompiled = m && {\n args,\n async : Boolean(m[1]),\n body : body?.startsWith('{') ? body.substring(1, body.length - 1).trim() : body\n };\n if (name) {\n decompiled.name = name;\n }\n }\n return fn[decompiledSym];\n }\n static hookMethod(object, method, hook) {\n hook.$nextHook = object[method];\n object[method] = hook;\n return () => {\n // Object will have no hooks on the instance if it is destroyed (perhaps other reasons too)\n if (hasOwnProperty.call(object, method)) {\n let f = object[method],\n next;\n if (f === hook) {\n // When this is the outermost hook, we may be the last hook. If $nextHook is found on the object's\n // prototype, simply delete the slot to expose it. Otherwise, there's another hook, so make it the\n // outermost.\n if (Object.getPrototypeOf(object)?.[method] === hook.$nextHook) {\n delete object[method];\n }\n else {\n object[method] = hook.$nextHook;\n }\n }\n else {\n // Not being the outermost hook means we have outer hooks that should chain to the one we want to\n // remove. Be cautious because the object could be destroyed.\n for (; (next = f?.$nextHook); f = next) {\n if (next === hook) {\n f.$nextHook = hook.$nextHook;\n break;\n }\n }\n }\n }\n };\n }\n /**\n * Protects the specified `method` on a given `object` such that calling it will not throw exceptions.\n * @param {Object} object The object whose method is to be protected.\n * @param {String} method The name of the method to protect.\n * @param {Function} [handler] An optional function to call for any thrown exceptions.\n * @internal\n */\n static noThrow(object, method, handler) {\n const fn = object[method];\n object[method] = (...args) => {\n try {\n return fn.apply(object, args);\n }\n catch (e) {\n return handler?.(e);\n }\n };\n }\n static returnTrue() {\n return true;\n }\n static animate(duration, fn, thisObj, easing = 'linear') {\n let cancel = false;\n const result = new Promise(resolve => {\n const start = performance.now(),\n iterate = () => {\n const progress = Math.min((performance.now() - start) / duration, 1),\n delayable = thisObj && thisObj.setTimeout ? thisObj : globalThis;\n if (!cancel) {\n if (fn.call(thisObj, this.easingFunctions[easing](progress)) === false) {\n resolve();\n }\n }\n if (cancel || progress === 1) {\n // Push resolution into the next animation frame so that\n // this frame completes before the resolution handler runs.\n delayable.requestAnimationFrame(() => resolve());\n }\n else {\n delayable.requestAnimationFrame(iterate);\n }\n };\n iterate();\n });\n result.cancel = () => {\n cancel = true;\n result.cancelled = true;\n return false;\n };\n return result;\n }\n}\nconst\n half = 0.5,\n e1 = 1.70158,\n e2 = 7.5625,\n e3 = 1.525,\n e4 = 2 / 2.75,\n e5 = 2.25 / 2.75,\n e6 = 1 / 2.75,\n e7 = 1.5 / 2.75,\n e8 = 2.5 / 2.75,\n e9 = 2.625 / 2.75,\n e10 = 0.75,\n e11 = 0.9375,\n e12 = 0.984375,\n s1 = 1.70158,\n s2 = 1.70158;\nFunctionHelper.easingFunctions = {\n linear : t => t,\n easeInQuad : t => Math.pow(t, 2),\n easeOutQuad : t => -(Math.pow((t - 1), 2) - 1),\n easeInOutQuad : t => (t /= half) < 1 ? half * Math.pow(t, 2) : -half * ((t -= 2) * t - 2),\n easeInCubic : t => Math.pow(t, 3),\n easeOutCubic : t => Math.pow((t - 1), 3) + 1,\n easeInOutCubic : t => (t /= half) < 1 ? half * Math.pow(t, 3) : half * (Math.pow((t - 2), 3) + 2),\n easeInQuart : t => Math.pow(t, 4),\n easeOutQuart : t => -(Math.pow((t - 1), 4) - 1),\n easeInOutQuart : t => (t /= half) < 1 ? half * Math.pow(t, 4) : -half * ((t -= 2) * Math.pow(t, 3) - 2),\n easeInQuint : t => Math.pow(t, 5),\n easeOutQuint : t => (Math.pow((t - 1), 5) + 1),\n easeInOutQuint : t => (t /= half) < 1 ? half * Math.pow(t, 5) : half * (Math.pow((t - 2), 5) + 2),\n easeInSine : t => -Math.cos(t * (Math.PI / 2)) + 1,\n easeOutSine : t => Math.sin(t * (Math.PI / 2)),\n easeInOutSine : t => -half * (Math.cos(Math.PI * t) - 1),\n easeInExpo : t => t === 0 ? 0 : Math.pow(2, 10 * (t - 1)),\n easeOutExpo : t => t === 1 ? 1 : -Math.pow(2, -10 * t) + 1,\n easeInOutExpo : t => (t === 0) ? 0 : (t === 1) ? 1 : ((t /= half) < 1) ? half * Math.pow(2, 10 * (t - 1)) : half * (-Math.pow(2, -10 * --t) + 2),\n easeInCirc : t => -(Math.sqrt(1 - (t * t)) - 1),\n easeOutCirc : t => Math.sqrt(1 - Math.pow((t - 1), 2)),\n easeInOutCirc : t => (t /= half) < 1 ? -half * (Math.sqrt(1 - t * t) - 1) : half * (Math.sqrt(1 - (t -= 2) * t) + 1),\n easeOutBounce : t => ((t) < e6) ? (e2 * t * t) : (t < e4) ? (e2 * (t -= e7) * t + e10) : (t < e8) ? (e2 * (t -= e5) * t + e11) : (e2 * (t -= e9) * t + e12),\n easeInBack : t => (t) * t * ((e1 + 1) * t - e1),\n easeOutBack : t => (t = t - 1) * t * ((e1 + 1) * t + e1) + 1,\n easeInOutBack : t => {\n let v1 = s1;\n return ((t /= half) < 1) ? half * (t * t * (((v1 *= (e3)) + 1) * t - v1)) : half * ((t -= 2) * t * (((v1 *= (e3)) + 1) * t + v1) + 2);\n },\n elastic : t => -1 * Math.pow(4, -8 * t) * Math.sin((t * 6 - 1) * (2 * Math.PI) / 2) + 1,\n swingFromTo : t => {\n let v2 = s2;\n return ((t /= half) < 1) ? half * (t * t * (((v2 *= (e3)) + 1) * t - v2)) : half * ((t -= 2) * t * (((v2 *= (e3)) + 1) * t + v2) + 2);\n },\n swingFrom : t => t * t * ((e1 + 1) * t - e1),\n swingTo : t => (t -= 1) * t * ((e1 + 1) * t + e1) + 1,\n bounce : t => (t < e6) ? (e2 * t * t) : (t < e4) ? (e2 * (t -= e7) * t + e10) : (t < e8) ? (e2 * (t -= e5) * t + e11) : (e2 * (t -= e9) * t + e12),\n bouncePast : t => (t < e6) ? (e2 * t * t) : (t < e4) ? 2 - (e2 * (t -= e7) * t + e10) : (t < e8) ? 2 - (e2 * (t -= e5) * t + e11) : 2 - (e2 * (t -= e9) * t + e12),\n easeFromTo : t => (t /= half) < 1 ? half * Math.pow(t, 4) : -half * ((t -= 2) * Math.pow(t, 3) - 2),\n easeFrom : t => Math.pow(t, 4),\n easeTo : t => Math.pow(t, 0.25)\n};\nFunctionHelper._$name = 'FunctionHelper';", "/* eslint-disable bryntum/no-listeners-in-lib,bryntum/no-on-in-lib */\nimport Base from '../Base.js';\nimport ArrayHelper from '../helper/ArrayHelper.js';\nimport StringHelper from '../helper/StringHelper.js';\nimport VersionHelper from '../helper/VersionHelper.js';\nimport BrowserHelper from '../helper/BrowserHelper.js';\nimport FunctionHelper from '../helper/FunctionHelper.js';\nimport Objects from '../helper/util/Objects.js';\n/**\n * @module Core/mixin/Events\n */\n/**\n * @typedef {Object.} BryntumListenerConfig\n * @property {Object} [thisObj] The `this` reference for all listeners. May be overridden if a handler is specified in object form.\n * @property {Boolean} [once] Specify as `true` to remove the listener as soon as it is invoked.\n * @property {Number|Object} [expires] The listener only waits for a specified time before\n * being removed. The value may be a number or an object containing an expiry handler.\n * @property {Number} [expires.delay] How long to wait for the event for.\n * @property {String|Function} [expires.alt] The function to call when the listener expires **without having been triggered**.\n * @property {Object[]} [args] An array of arguments to be passed to the handler before the event object.\n * @property {Number} [prio] The priority for all listeners; higher priority listeners are called before lower.\n * @property {Number} [buffer] A buffer time in milliseconds to wait after last event trigger to call the handler, to reduce the amount of handler calls for frequent events.\n * @property {Number} [throttle] A millisecond timeout value to throttle event triggering. With it specified a handler\n * will be called once immediately and then all following calls during the timeout period will be grouped together into one call once per throttle period.\n */\nconst\n // Used by the config system to flatten configs from the class hierarchy.\n // In this case, a pure merge is not wanted. Listener definitions from\n // every class level are collected up into an array.\n // addListener iterates any passed array, adding each element.\n { isArray } = Array,\n { hasOwnProperty } = Object.prototype,\n // Used to distinguish event names from listener options in addListener object config.\n specialProperties = {\n thisObj : 1,\n detachable : 1,\n once : 1,\n detacher : 1,\n prio : 1,\n args : 1,\n expires : 1,\n buffer : 1,\n throttle : 1,\n name : 1,\n $internal : 1\n },\n priorityComparator = (a, b) => b.prio - a.prio;\n/**\n * Mix this into another class to enable event handling.\n *\n * ## Basic usage\n * Listeners can be added either through config:\n *\n * ```javascript\n * let button = new Button({\n * listeners: {\n * click: () => {},\n * press: () => {},\n * ...\n * }\n * });\n * ```\n *\n * *NOTE*: Do not reuse listeners config object, use new every time:\n * ```javascript\n * // wrong\n * let config = { click : () => {} }\n * new Button({\n * listeners : config\n * })\n * new Button({\n * listeners : config\n * })\n * // right\n * new Button({\n * listeners : { click : () => {} }\n * })\n * new Button({\n * listeners : { click : () => {} }\n * })\n * ```\n *\n * Or by calling on()/addListener():\n *\n * ```javascript\n * let button = new Button();\n *\n * button.addListener('press', () => {});\n * // on is an alias for addListener\n * button.on('click', () => {});\n * ```\n *\n * This style also accepts multiple listeners in same way as when using config:\n *\n * ```javascript\n * button.on({\n * click: () => {},\n * press: () => {},\n * ...\n * });\n * ```\n *\n * ### Handlers as function name\n *\n * Event handlers may be specified as a function __name__. If a string is specified, it is the name\n * of the function in the `thisObj` object.\n *\n * If the string begins with `up.`, the owning object's ownership hierarchy\n * (if present) is scanned for an object which implements that function name:\n *\n * ```javascript\n * new Popup({\n * tbar : {\n * items : {\n * myCombo : {\n * type : 'combo',\n * editable : false,\n * label : 'Type',\n * listeners : {\n * // Look in owner chain for this function name\n * change : 'up.onFilterChange'\n * },\n * items : [\n * 'Event',\n * 'Task',\n * 'Appointment'\n * ]\n * }\n * }\n * },\n * items : {\n * ...\n * },\n * onFilterChange({ value }) {\n * // Handle event type selection here\n * }\n * });\n *```\n *\n * ## Listener options\n * ### Once\n * Listeners can be configured to automatically deregister after first trigger by specifying config option `once`:\n *\n * ```javascript\n * button.on({\n * click: () => {},\n * once: true\n * });\n * ```\n *\n * ### Priority\n * Specifying priority affects the order in which listeners are called when triggering an event. Higher priorities will be\n * called before lower. Default value is 0.\n *\n * ```javascript\n * button.on({\n * click: this.onClick,\n * prio: 1\n * });\n * ```\n *\n * ### This reference\n * If desired, you can specify thisObj when configuring listeners. There is no need if you are using arrow functions as\n * listeners, but might be handy in other cases. Of course, you can also use bind to set `this` reference.\n *\n * ```javascript\n * button.on({\n * click: this.onClick,\n * thisObj: this\n * });\n *\n * // or\n *\n * button.on({\n * click: this.onClick.bind(this)\n * });\n * ```\n *\n * ### Buffering\n * By specifying a `buffer` events that fire frequently can be grouped together and delayed. A handler for the event will be called once only, when no new event has been fired during the specified buffer time:\n *\n * ```javascript\n * button.on({\n * click : this.onClick,\n * buffer : 200 // in milliseconds\n * });\n * ```\n *\n * In this example, if a user clicked the button 6 times very fast (<200ms between each click),\n * the `this.onClick` handler would be called only once 200 milliseconds after the last click.\n *\n * ### Throttling\n * Create a \"debounced\" function which will call on the \"leading edge\" of a timer period.\n * When first invoked will call immediately, but invocations after that inside its buffer\n * period will be rejected, and *one* invocation will be made after the buffer period has expired.\n *\n * This is useful for responding immediately to a first mousemove, but from then on, only\n * calling the action function on a regular timer while the mouse continues to move.\n * ```javascript\n * button.on({\n * click : this.onClick,\n * throttle : 200 // in milliseconds\n * });\n * ```\n *\n * In this example, if a user clicked the button 6 times very fast, the `this.onClick` handler would be called once immediately on the first click and a second time 200 milliseconds after the **first** click.\n * So in reality the `click` event handler will be called every 200ms independent of amount of click in a middle, if the event was triggered at least once during the `throttle` timeout.\n *\n * ### Detacher\n * A convenient way of unregistering events is to use a detacher, a function returned when adding listeners that you\n * call later to deregister them. As of version 1.0, detachable defaults to true.\n *\n * ```javascript\n * let detacher = button.on({\n * click: () => {},\n * press: () => {},\n * detachable: true\n * });\n *\n * // when you want to detach, for example in destroy()\n * detacher();\n * ```\n *\n * ### Auto detaching\n * When listeners are bound to a class instance using `thisObj`, the `thisObj`'s `doDestroy` method\n * is overridden to remove the listeners before calling the overridden doDestroy.\n *\n * ```javascript\n * class MyClass extends Base {\n * construct() {\n * let button = new Button({\n * listeners: {\n * click: () => {},\n * thisObj: this\n * }\n * });\n * }\n *\n * doDestroy() {\n * // clean up stuff\n * }\n * }\n *\n * let myObj = new MyClass();\n * // clean up, also removes listeners\n * myObj.destroy();\n * ```\n *\n * ### On-functions\n * When mixing Events into another class it can be configured to call on-functions when events are triggered.\n * On-functions are functions named 'onEventName', for example 'onClick', 'onPress' declared on the class triggering\n * the event.\n *\n * ```javascript\n * // mix Events in with on-functions activated\n * let button = new Button({\n * callOnFunctions: true,\n *\n * onClick: () => {}\n * });\n *\n * // or add a getter in class declaration\n * ```\n *\n * Returning `false` from an on-function will prevent triggering listeners for the event.\n *\n * ### Catching all events\n * By specifying a listener for {@link #event-catchAll catchAll} a function can be notified when any event is triggered:\n *\n * ```javascript\n * const button = new Button({\n * listeners : {\n * catchAll(event) {\n * // All events on the button will pass through here\n * }\n * }\n * });\n * ```\n *\n * ## Preventable events\n *\n * By returning `false` from a listener for an event documented as `preventable` the action that would otherwise be\n * executed after the event is prevented. These events are usually named `beforeXX`, for example `beforeRemove`,\n * `beforeDragStart` etc.\n *\n *
Note that Angular does not support return values from listeners. Instead, assign to\n * event.returnValue as shown in the Angular snippet below
\n *\n * {@frameworktabs}\n * {@js}\n * ```javascript\n * taskBoard.on({\n * beforeColumnDrag({ columnRecord }) {\n * if (columnRecord.locked) {\n * return false;\n * }\n * }\n * });\n * ```\n *\n * {@endjs}\n * {@react}\n *\n * ```jsx\n * const App = props => {\n * function onBeforeColumnDrag({ columnRecord }) {\n * if (columnRecord.locked) {\n * return false;\n * }\n * }\n *\n * return (\n * <>\n * \n * \n * )\n * }\n * ```\n *\n * {@endreact}\n * {@vue}\n *\n * ```html\n * \n * ```\n *\n * ```javascript\n * export default {\n * methods : {\n * onBeforeColumnDrag({ columnRecord }) {\n * if (columnRecord.locked) {\n * return false;\n * }\n * }\n * }\n * }\n * ```\n *\n * {@endvue}\n * {@angular}\n *\n * ```html\n * \n * ```\n *\n * ```typescript\n * export class AppComponent {\n * onBeforeColumnDrag({ event }: { event: any }): void {\n * event.returnValue = !event.columnRecord.locked;\n * }\n * }\n * ```\n *\n * {@endangular}\n * {@endframeworktabs}\n *\n * @mixin\n */\nexport default Target => class Events extends (Target || Base) {\n eventsSuspended = null;\n static get $name() {\n return 'Events';\n }\n //region Events\n /**\n * Fires before an object is destroyed.\n * @event beforeDestroy\n * @param {Core.Base} source The Object that is being destroyed.\n */\n /**\n * Fires when an object is destroyed.\n * @event destroy\n * @param {Core.Base} source The Object that is being destroyed.\n */\n /**\n * Fires when any other event is fired from the object.\n *\n * **Note**: `catchAll` is fired for both public and private events. Please rely on the public events only.\n * @event catchAll\n * @param {Object} event The Object that contains event details\n * @param {String} event.type The type of the event which is caught by the listener\n * @typings event -> {{[key: string]: any, type: string}}\n */\n //endregion\n static get declarable() {\n return [\n /**\n * The list of deprecated events as an object, where `key` is an event name which is deprecated and\n * `value` is an object which contains values for\n * {@link Core.helper.VersionHelper#function-deprecate-static VersionHelper}:\n * - product {String} The name of the product;\n * - invalidAsOfVersion {String} The version where the offending code is invalid (when any compatibility\n * layer is actually removed);\n * - message {String} Warning message to show to the developer using a deprecated API;\n *\n * For example:\n *\n * ```javascript\n * return {\n * click : {\n * product : 'Grid',\n * invalidAsOfVersion : '1.0.0',\n * message : 'click is deprecated!'\n * }\n * }\n * ```\n *\n * @name deprecatedEvents\n * @returns {Object}\n * @static\n * @internal\n */\n 'deprecatedEvents'\n ];\n }\n static setupDeprecatedEvents(cls, meta) {\n const\n all = meta.getInherited('deprecatedEvents'),\n add = cls.deprecatedEvents;\n for (const eventName in add) {\n // Event names are case-insensitive so build our map using toLowerCased names (but keep true case too):\n all[eventName.toLowerCase()] = all[eventName] = add[eventName];\n }\n }\n //region Config\n static get configurable() {\n return {\n /**\n * Set to true to call onXXX method names (e.g. `onShow`, `onClick`), as an easy way to listen for events.\n *\n * ```javascript\n * const container = new Container({\n * callOnFunctions : true\n *\n * onHide() {\n * // Do something when the 'hide' event is fired\n * }\n * });\n * ```\n *\n * @config {Boolean} callOnFunctions\n * @category Misc\n * @default false\n */\n /**\n * The listener set for this object.\n *\n * An object whose property names are the names of events to handle, or options which modifiy\n * __how__ the handlers are called.\n *\n * See {@link #function-addListener} for details about the options.\n *\n * Listeners can be specified in target class config and they will be merged with any listeners specified in\n * the instantiation config. Class listeners will be fired first:\n *\n * ```javascript\n * class MyStore extends Store({\n * static get configurable() {\n * return {\n * listeners : {\n * myCustomEvent() {\n * },\n * load : {\n * prio : 10000,\n * fn() { // this load listener handles things first }\n * }\n * }\n * }\n * }\n * });\n *\n * let store = new MyStore({\n * listeners: {\n * load: () => { // This load listener runs after the class's },\n * ...\n * }\n * });\n * ```\n *\n * ### Handlers as function name\n *\n * Object event handlers may be specified as a function __name__. If a string is specified, it is the name\n * of the function in the `thisObj` object.\n *\n * If the string begins with `up.`, this object's ownership hierarchy\n * (if present) is scanned for an object which implements that function name:\n *\n * ```javascript\n * new Popup({\n * tbar : {\n * items : {\n * myCombo : {\n * type : 'combo',\n * editable : false,\n * label : 'Type',\n * listeners : {\n * // Look in owner chain for this function name\n * change : 'up.onFilterChange'\n * },\n * items : [\n * 'Event',\n * 'Task',\n * 'Appointment'\n * ]\n * }\n * }\n * },\n * items : {\n * ...\n * },\n * onFilterChange({ value }) {\n * // Handle event type selection here\n * }\n * });\n *```\n *\n * @config {Object}\n * @category Common\n */\n listeners : {\n value : null,\n $config : {\n merge(newValue, currentValue) {\n if (newValue !== null) {\n if (!newValue) {\n return currentValue;\n }\n if (currentValue) {\n newValue = newValue ? [newValue] : [];\n newValue.push[isArray(currentValue) ? 'apply' : 'call'](newValue, currentValue);\n }\n }\n return newValue;\n }\n }\n },\n /**\n * Internal listeners, that cannot be removed by the user.\n * @config {Object}\n * @internal\n */\n internalListeners : null,\n /**\n * An object where property names with a truthy value indicate which events should bubble up the ownership\n * hierarchy when triggered.\n *\n * ```javascript\n * const container = new Container({\n * items : [\n * { type : 'text', bubbleEvents : { change : true }}\n * ],\n *\n * listeners : {\n * change() {\n * // Will catch change event from the text field\n * }\n * }\n * });\n * ```\n *\n * @config {Object}\n * @category Misc\n */\n bubbleEvents : null\n };\n }\n destroy() {\n this.trigger('beforeDestroy');\n super.destroy();\n }\n //endregion\n //region Init\n construct(config, ...args) {\n // Configured listeners use this as the thisObj\n if ((this.configuredListeners /* assignment */ = config?.listeners)) {\n // We have to copy in case listeners have been forked\n config = Objects.assign({}, config);\n delete config.listeners;\n }\n super.construct(config, ...args);\n // Apply configured listeners after construction.\n // Note that some classes invoke this during parts of their construction.\n // Store invokes this prior to setting data so that observers are notified of data load.\n this.processConfiguredListeners();\n }\n processConfiguredListeners() {\n // This can only happen once\n if (this.configuredListeners) {\n const\n me = this,\n { isConfiguring } = me;\n // If called from config ingestion during configuration, listeners must be added\n // so temporarily clear the isConfiguring flag.\n me.isConfiguring = false;\n me.listeners = me.configuredListeners;\n me.configuredListeners = null;\n me.isConfiguring = isConfiguring;\n }\n }\n /**\n * Auto detaches listeners registered from start, if set as detachable\n * @internal\n */\n doDestroy() {\n this.trigger('destroy');\n this.removeAllListeners(false);\n super.doDestroy();\n }\n static setupClass(meta) {\n super.setupClass(meta);\n Events.prototype.onListen.$nullFn = true;\n Events.prototype.onUnlisten.$nullFn = true;\n }\n //endregion\n //region Listeners\n /**\n * Adds an event listener. This method accepts parameters in the following format:\n *\n * ```javascript\n * myObject.addListener({\n * thisObj : this, // The this reference for the handlers\n * eventname2 : 'functionName' // Resolved at invocation time using the thisObj,\n * otherevent : {\n * fn : 'handlerFnName',\n * once : true // Just this handler is auto-removed on fire\n * },\n * yetanother : {\n * fn : 'yetAnotherHandler',\n * args : [ currentState1, currentState2 ] // Capture info to be passed to handler\n * },\n * prio : 100 // Higher prio listeners are called before lower\n * });\n * ```\n *\n * When listeners have a `thisObj` option, they are linked to the lifecycle of that object.\n * When it is destroyed, those listeners are removed.\n *\n * The `config` parameter allows supplying options for the listener(s), for available options see {@link #typedef-BryntumListenerConfig}.\n *\n * A simpler signature may be used when only adding a listener for one event and no extra options\n * (such as `once` or `delay`) are required:\n *\n * ```javascript\n * myObject.addListener('click', myController.handleClicks, myController);\n * ```\n *\n * The args in this simple case are `eventName`, `handler` and `thisObj`\n *\n * @param {BryntumListenerConfig|String} config An object containing listener definitions, or the event name to listen for\n * @param {Object|Function} [thisObj] Default `this` reference for all listeners in the config object, or the handler\n * function to call if providing a string as the first arg.\n * @param {Object} [oldThisObj] The `this` reference if the old signature starting with a string event name is used..\n * @returns {Function} Returns a detacher function unless configured with `detachable: false`. Call detacher to remove listeners\n */\n addListener(config, thisObj, oldThisObj) {\n if (isArray(config)) {\n for (let i = 0, { length } = config; i < length; i++) {\n this.addListener(config[i], thisObj);\n }\n return;\n }\n const\n me = this,\n deprecatedEvents = me.$meta.getInherited('deprecatedEvents');\n if (typeof config === 'string') {\n // arguments[2] is thisObj if (eventName, handler, thisObj) form called.\n // Note that the other side of the if-statement compares to undefined, so this will work.\n return me.addListener({\n [config] : thisObj,\n detachable : thisObj.detachable !== false,\n thisObj : oldThisObj\n });\n }\n else {\n // Capture the default thisObj.\n thisObj = config.thisObj = config.thisObj !== undefined ? config.thisObj : thisObj;\n for (const key in config) {\n // Skip special properties or events without handlers (convenient syntax with optional handlers)\n if (!specialProperties[key] && config[key] != null) {\n const\n // Comparing should be case-insensitive\n eventName = key.toLowerCase(),\n deprecatedEvent = deprecatedEvents?.[eventName],\n events = me.eventListeners || (me.eventListeners = {}),\n // When cloning listeners, there might be multiple listeners for the same event\n specs = ArrayHelper.asArray(config[key]);\n if (deprecatedEvent) {\n const { product, invalidAsOfVersion, message } = deprecatedEvent;\n VersionHelper.deprecate(product, invalidAsOfVersion, message);\n }\n for (const listenerSpec of specs) {\n const\n expires = listenerSpec.expires || config.expires,\n listener = {\n fn : typeof listenerSpec === 'object' ? listenerSpec.fn : listenerSpec,\n thisObj : listenerSpec.thisObj !== undefined ? listenerSpec.thisObj : thisObj,\n args : listenerSpec.args || config.args,\n prio : listenerSpec.prio !== undefined ? listenerSpec.prio : config.prio !== undefined ? config.prio : 0,\n once : listenerSpec.once !== undefined ? listenerSpec.once : config.once !== undefined ? config.once : false,\n buffer : listenerSpec.buffer || config.buffer,\n throttle : listenerSpec.throttle || config.throttle,\n $internal : config.$internal,\n catchAll : key === 'catchAll'\n };\n if (expires) {\n // Extract expires : { delay : 100, alt : 'onExpireFn' }\n const\n { alt } = expires,\n delay = alt ? expires.delay : expires,\n name = config.name || key,\n fn = () => {\n me.un(eventName, listener);\n // If we make it here and the handler has not been called, invoke the alt handler\n if (alt && !listener.called) {\n me.callback(alt, thisObj);\n }\n };\n if (me.isDelayable) {\n me.setTimeout({\n fn,\n name,\n cancelOutstanding : true,\n delay\n });\n }\n else {\n globalThis.setTimeout(fn, delay);\n }\n }\n let listeners = events[eventName] || (events[eventName] = []);\n if (listeners.$firing) {\n events[eventName] = listeners = listeners.slice();\n }\n // Insert listener directly in prio order\n listeners.splice(\n ArrayHelper.findInsertionIndex(listener, listeners, priorityComparator, listeners.length),\n 0, listener);\n if (!me.onListen.$nullFn && listeners.length < 2) {\n me.onListen(eventName);\n }\n // Hook to call when a listener is added\n me.afterAddListener?.(eventName, listener);\n }\n }\n }\n if (config.relayAll) {\n me.relayAll(config.relayAll);\n }\n // Hook into the thisObj's destruction sequence to remove these listeners.\n // Pass the default thisObj in for use when it comes to destruction time.\n if (thisObj && thisObj !== me) {\n me.attachAutoDetacher(config, thisObj);\n }\n const\n detachable = config.detachable !== false,\n name = config.name,\n destroy = (config.expires || detachable || name) ? () => {\n // drop listeners if not destroyed yet\n if (!me.isDestroyed) {\n me.removeListener(config, thisObj);\n }\n } : null;\n if (destroy) {\n destroy.eventer = me;\n destroy.listenerName = name;\n if (name && thisObj?.trackDetacher) {\n thisObj.trackDetacher(name, destroy);\n }\n if (config.expires) {\n // handle expires : { alt : timeoutHandler, delay : 2000 }\n me.delay(destroy, isNaN(config.expires) ? config.expires.delay : config.expires, name);\n }\n if (detachable) {\n return destroy;\n }\n }\n }\n }\n /**\n * Alias for {@link #function-addListener}. Adds an event listener. This method accepts parameters in the following format:\n *\n * ```javascript\n * myObject.on({\n * thisObj : this, // The this reference for the handlers\n * eventname2 : 'functionName' // Resolved at invocation time using the thisObj,\n * otherevent : {\n * fn : 'handlerFnName',\n * once : true // Just this handler is auto-removed on fire\n * },\n * yetanother : {\n * fn : 'yetAnotherHandler',\n * args : [ currentState1, currentState2 ] // Capture info to be passed to handler\n * },\n * prio : 100 // Higher prio listeners are called before lower\n * });\n * ```\n *\n * When listeners have a `thisObj` option, they are linked to the lifecycle of that object.\n * When it is destroyed, those listeners are removed.\n *\n * The `config` parameter allows supplying options for the listener(s), for available options see {@link #typedef-BryntumListenerConfig}.\n *\n * A simpler signature may be used when only adding a listener for one event and no extra options\n * (such as `once` or `delay`) are required:\n *\n * ```javascript\n * myObject.on('click', myController.handleClicks, myController);\n * ```\n *\n * The args in this simple case are `eventName`, `handler` and `thisObj`\n *\n * @param {BryntumListenerConfig|String} config An object containing listener definitions, or the event name to listen for\n * @param {Object|Function} [thisObj] Default `this` reference for all listeners in the config object, or the handler\n * function to call if providing a string as the first arg.\n * @param {Object} [oldThisObj] The `this` reference if the old signature starting with a string event name is used..\n * @returns {Function} Returns a detacher function unless configured with `detachable: false`. Call detacher to remove listeners\n */\n on(config, thisObj, oldThisObj) {\n return this.addListener(config, thisObj, oldThisObj);\n }\n /**\n * Internal convenience method for adding an internal listener, that cannot be removed by the user.\n *\n * Alias for `on({ $internal : true, ... })`. Only supports single argument form.\n *\n * @internal\n */\n ion(config) {\n config.$internal = true;\n return this.on(config);\n }\n /**\n * Shorthand for {@link #function-removeListener}\n * @param {Object|String} config A config object or the event name\n * @param {Object|Function} [thisObj] `this` reference for all listeners, or the listener function\n * @param {Object} [oldThisObj] `this` The `this` object for the legacy way of adding listeners\n */\n un(...args) {\n this.removeListener(...args);\n }\n updateInternalListeners(internalListeners, oldInternalListeners) {\n oldInternalListeners?.detach();\n if (internalListeners) {\n internalListeners.detach = this.ion(internalListeners);\n }\n }\n get listeners() {\n return this.eventListeners;\n }\n changeListeners(listeners) {\n // If we are receiving class listeners, add them early, and they do not become\n // the configured listeners, and are not removed by setting listeners during the lifecycle.\n if (this.isConfiguring) {\n // Pull in internal listeners first\n this.getConfig('internalListeners');\n if (listeners) {\n this.on(listeners, this);\n }\n }\n // Setting listeners after config time clears the old set and adds the new.\n // This will initially happen at the tail end of the constructor when config\n // listeners are set.\n else {\n // Configured listeners use this as the thisObj by default.\n // Flatten using Objects.assign because it may have been part of\n // a prototype chained default configuration of another object.\n // eg: the tooltip config of a Widget.\n // listener object blocks from multiple configuration levels are pushed\n // onto an array (see listeners merge function in configurable block above).\n // If this has happened, each entry must be processed like this.\n if (Array.isArray(listeners)) {\n for (let i = 0, l = listeners[0], { length } = listeners; i < length; l = listeners[++i]) {\n if (!('thisObj' in l)) {\n listeners[i] = Objects.assign({ thisObj : this }, l);\n }\n }\n }\n else if (listeners && !('thisObj' in listeners)) {\n listeners = Objects.assign({ thisObj : this }, listeners);\n }\n return listeners;\n }\n }\n updateListeners(listeners, oldListeners) {\n // Only configured listeners get here. Class listeners are added by changeListeners.\n oldListeners && this.un(oldListeners);\n listeners && this.on(listeners);\n }\n /**\n * Removes an event listener. Same API signature as {@link #function-addListener}\n * @param {Object|String} config A config object or the event name\n * @param {Object|Function} thisObj `this` reference for all listeners, or the listener function\n * @param {Object} oldThisObj `this` The `this` object for the legacy way of adding listeners\n */\n removeListener(config, thisObj = config.thisObj, oldThisObj) {\n const me = this;\n if (typeof config === 'string') {\n return me.removeListener({ [config] : thisObj }, oldThisObj);\n }\n Object.entries(config).forEach(([eventName, listenerToRemove]) => {\n if (!specialProperties[eventName] && listenerToRemove != null) {\n eventName = eventName.toLowerCase();\n const\n { eventListeners } = me,\n index = me.findListener(eventName, listenerToRemove, thisObj);\n if (index >= 0) {\n let listeners = eventListeners[eventName];\n // Hook to call when a listener is removed (slightly before removing for now)\n me.afterRemoveListener?.(eventName, listeners[index]);\n if (listeners.length > 1) {\n if (listeners.$firing) {\n eventListeners[eventName] = listeners = listeners.slice();\n }\n // NOTE: we cannot untrack any detachers here because we may only be\n // removing some of its listeners\n listeners.splice(index, 1);\n }\n else {\n delete eventListeners[eventName];\n if (!me.onUnlisten.$nullFn) {\n me.onUnlisten(eventName);\n }\n }\n }\n }\n });\n if (config.thisObj && !config.thisObj.isDestroyed) {\n me.detachAutoDetacher(config);\n }\n }\n /**\n * Finds the index of a particular listener to the named event. Returns `-1` if the passed\n * function/thisObj listener is not present.\n * @param {String} eventName The name of an event to find a listener for.\n * @param {String|Function} listenerToFind The handler function to find.\n * @param {Object} defaultThisObj The `thisObj` for the required listener.\n * @internal\n */\n findListener(eventName, listenerToFind, defaultThisObj) {\n const\n eventListeners = this.eventListeners?.[eventName],\n fn = listenerToFind.fn || listenerToFind,\n thisObj = listenerToFind.thisObj || defaultThisObj;\n if (eventListeners) {\n for (let listenerEntry, i = 0, { length } = eventListeners; i < length; i++) {\n listenerEntry = eventListeners[i];\n if (listenerEntry.fn === fn && listenerEntry.thisObj === thisObj) {\n return i;\n }\n }\n }\n return -1;\n }\n /**\n * Check if any listener is registered for the specified eventName\n * @param {String} eventName\n * @returns {Boolean} `true` if listener is registered, otherwise `false`\n * @advanced\n */\n hasListener(eventName) {\n return Boolean(this.eventListeners?.[eventName?.toLowerCase()]);\n }\n /**\n * Relays all events through another object that also implements Events mixin. Adds a prefix to the event name\n * before relaying, for example add -> storeAdd\n * ```\n * // Relay all events from store through grid, will make it possible to listen for store events prefixed on grid:\n * 'storeLoad', 'storeChange', 'storeRemoveAll' etc.\n * store.relayAll(grid, 'store');\n *\n * grid.on('storeLoad', () => console.log('Store loaded');\n * ```\n * @param {Core.mixin.Events} through Object to relay the events through, needs to mix Events mixin in\n * @param {String} prefix Prefix to add to event name\n * @param {Boolean} [transformCase] Specify false to prevent making first letter of event name uppercase\n * @advanced\n */\n relayAll(through, prefix, transformCase = true) {\n if (!this.relayAllTargets) {\n this.relayAllTargets = [];\n }\n const { relayAllTargets } = this;\n through.ion({\n beforeDestroy : ({ source }) => {\n if (source === through) {\n const configs = relayAllTargets.filter(r => r.through === through);\n configs.forEach(config => ArrayHelper.remove(relayAllTargets, config));\n }\n }\n });\n relayAllTargets.push({ through, prefix, transformCase });\n }\n /**\n * Removes all listeners registered to this object by the application.\n */\n removeAllListeners(preserveInternal = true) {\n const listeners = this.eventListeners;\n let i, thisObj;\n for (const event in listeners) {\n const bucket = listeners[event];\n // We iterate backwards since we call removeListener which will splice out of\n // this array as we go...\n for (i = bucket.length; i-- > 0; /* empty */) {\n const cfg = bucket[i];\n if (!cfg.$internal || !preserveInternal) {\n this.removeListener(event, cfg);\n thisObj = cfg.thisObj;\n thisObj?.untrackDetachers?.(this);\n }\n }\n }\n }\n relayEvents(source, eventNames, prefix = '') {\n const listenerConfig = { detachable : true, thisObj : this };\n eventNames.forEach(eventName => {\n listenerConfig[eventName] = (event, ...params) => {\n return this.trigger(prefix + eventName, event, ...params);\n };\n });\n return source.on(listenerConfig);\n }\n /**\n * This method is called when the first listener for an event is added.\n * @param {String} eventName\n * @internal\n */\n onListen() {}\n /**\n * This method is called when the last listener for an event is removed.\n * @param {String} eventName\n * @internal\n */\n onUnlisten() {}\n destructorInterceptor() {\n const { autoDetachers, target, oldDestructor } = this;\n // Remove listeners first, so that they do not fire during destruction.\n // The observable being listened to by the thisObj may already have\n // been destroyed in a clean up sequence\n for (let i = 0; i < autoDetachers.length; i++) {\n const { dispatcher, config } = autoDetachers[i];\n if (!dispatcher.isDestroyed) {\n dispatcher.removeListener(config, target);\n }\n }\n oldDestructor.call(target);\n }\n /**\n * Internal function used to hook destroy() calls when using thisObj\n * @private\n */\n attachAutoDetacher(config, thisObj) {\n const\n target = config.thisObj || thisObj,\n // If it's a Bryntum Base subclass, hook doDestroy, otherwise, destroy\n destructorName = ('doDestroy' in target) ? 'doDestroy' : 'destroy';\n if (destructorName in target) {\n let { $autoDetachers } = target;\n if (!$autoDetachers) {\n target.$autoDetachers = $autoDetachers = [];\n }\n if (!target.$oldDestructor) {\n target.$oldDestructor = target[destructorName];\n // Binding instead of using closure (used to use FunctionHelper.createInterceptor) to not retain target\n // when detaching manually\n target[destructorName] = this.destructorInterceptor.bind({\n autoDetachers : $autoDetachers,\n oldDestructor : target.$oldDestructor,\n target\n });\n }\n $autoDetachers.push({ config, dispatcher : this });\n }\n else {\n target[destructorName] = () => {\n this.removeListener(config);\n };\n }\n }\n /**\n * Internal function used restore hooked destroy() calls when using thisObj\n * @private\n */\n detachAutoDetacher(config) {\n const target = config.thisObj;\n // Restore old destructor and remove from auto detachers only if we are not called as part of destruction.\n // (Altering $autoDetachers affects destruction iterating over them, breaking it. It is pointless to clean up\n // during destruction anyway, since everything gets removed)\n if (target.$oldDestructor && !target.isDestroying) {\n ArrayHelper.remove(\n target.$autoDetachers,\n target.$autoDetachers.find(detacher => detacher.config === config && detacher.dispatcher === this)\n );\n if (!target.$autoDetachers.length) {\n target['doDestroy' in target ? 'doDestroy' : 'destroy'] = target.$oldDestructor;\n target.$oldDestructor = null;\n }\n }\n }\n /**\n * Internal function used to run a callback function after an event is triggered\n * @private\n */\n once(eventName, callback) {\n return this.on({\n [eventName] : () => this.callback(callback),\n once : true\n });\n }\n //endregion\n //region Promise based workflow\n // experimental, used in tests to support async/await workflow\n await(eventName, options = { checkLog : true, resetLog : true, args : null }) {\n const me = this;\n if (options === false) {\n options = { checkLog : false };\n }\n const { args } = options;\n return new Promise(resolve => {\n // check if previously triggered?\n if (options.checkLog && me._triggered?.[eventName]) {\n // resolve immediately, no params though...\n resolve();\n // reset log to be able to await again\n if (options.resetLog) {\n me.clearLog(eventName);\n }\n }\n // This branch will listen for events until catches one with specific arguments\n if (args) {\n const detacher = me.on({\n [eventName] : (...params) => {\n // if args is a function use it to match arguments\n const argsOk = typeof args === 'function' ? args(...params) : Object.keys(args).every(key => {\n return key in params[0] && params[0][key] === args[key];\n });\n if (argsOk) {\n // resolve when event is fired with required arguments\n resolve(...params);\n // reset log to be able to await again\n if (options.resetLog) {\n me.clearLog(eventName);\n }\n detacher();\n }\n },\n prio : -10000 // Let others do their stuff first\n });\n }\n else {\n me.on({\n [eventName] : (...params) => {\n // resolve when event is caught\n resolve(...params);\n // reset log to be able to await again\n if (options.resetLog) {\n me.clearLog(eventName);\n }\n },\n prio : -10000, // Let others do their stuff first\n once : true // promises can only be resolved once anyway\n });\n }\n });\n }\n clearLog(eventName) {\n if (this._triggered) {\n if (eventName) {\n delete this._triggered[eventName];\n }\n else {\n this._triggered = {};\n }\n }\n }\n //endregion\n //region Trigger\n /**\n * Triggers an event, calling all registered listeners with the supplied arguments. Returning false from any listener\n * makes function return false.\n * @param {String} eventName Event name for which to trigger listeners\n * @param {Object} [param] Single parameter passed on to listeners, source property will be added to it (this)\n * @param {Boolean} [param.bubbles] Pass as `true` to indicate that the event will bubble up the widget\n * ownership hierarchy. For example up a `Menu`->`parent` Menu tree, or a `Field`->`Container` tree.\n * @typings param -> {{bubbles?: boolean, [key: string]: any}}\n * @returns {Boolean|Promise} Returns false if any listener returned `false`, or a `Promise` yielding\n * `true` / `false` based on what is returned from the async listener functions, otherwise `true`\n * @async\n * @advanced\n */\n trigger(eventName, param) {\n const\n me = this,\n name = eventName.toLowerCase(),\n {\n eventsSuspended,\n relayAllTargets,\n callOnFunctions\n } = me;\n let listeners = me.eventListeners?.[name],\n handlerPromises;\n // log trigger, used by experimental promise support to resolve immediately when needed\n if (!me._triggered) {\n me._triggered = {};\n }\n me._triggered[eventName] = true;\n if (eventsSuspended) {\n if (eventsSuspended.shouldQueue) {\n eventsSuspended.queue.push(arguments);\n }\n return true;\n }\n // Include catchall listener for all events.\n // Do not push the catchAll listeners onto the events own listener array.\n if (me.eventListeners?.catchall) {\n (listeners = (listeners ? listeners.slice() : [])).push(...me.eventListeners.catchall);\n // The catchAll listeners must honour their prio settings.\n listeners.sort(priorityComparator);\n }\n if (!listeners && !relayAllTargets && !callOnFunctions) {\n return true;\n }\n // default to include source : this in param\n if (param) {\n if (!('source' in param)) {\n if (Object.isExtensible(param)) {\n param.source = me;\n }\n else {\n param = Object.setPrototypeOf({\n source : me\n }, param);\n }\n }\n }\n else {\n param = {\n source : me\n };\n }\n // Lowercased event name should be the \"type\" property in keeping with DOM events.\n if (param.type !== name) {\n // Create instance property because \"type\" is read only\n if (param.constructor !== Object) {\n Reflect.defineProperty(param, 'type', { get : () => name });\n }\n else {\n param.type = name;\n }\n }\n param.eventName = eventName;\n // Bubble according to `bubbleEvents` config if `bubbles` is not explicitly set\n if (!('bubbles' in param) && me.bubbleEvents?.[eventName]) {\n param.bubbles = me.bubbleEvents[eventName];\n }\n if (callOnFunctions) {\n const fnName = 'on' + StringHelper.capitalize(eventName);\n if (fnName in me) {\n // Return true if the on[fnName] is not set to keep default behavior\n const result = me[fnName] ? me.callback(me[fnName], me, [param]) : true;\n let inhibit;\n if (Objects.isPromise(result)) {\n (handlerPromises || (handlerPromises = [])).push(result);\n }\n else {\n inhibit = result === false || inhibit;\n }\n // See if the called function was injected into the instance\n // masking an implementation in the prototype.\n // we must call the class's implementation after the injected one.\n // unless it's an injected chained function, in which case it will have been called above.\n // Note: The handler may have resulted in destruction.\n if (!me.isDestroyed && hasOwnProperty.call(me, fnName) && !me.pluginFunctionChain?.[fnName]) {\n const myProto = Object.getPrototypeOf(me);\n if (fnName in myProto) {\n const result = myProto[fnName].call(me, param);\n if (Objects.isPromise(result)) {\n (handlerPromises || (handlerPromises = [])).push(result);\n }\n else {\n inhibit = result === false || inhibit;\n }\n // A handler may have resulted in destruction.\n if (me.isDestroyed) {\n return;\n }\n }\n }\n // Returning false from an on-function prevents further triggering\n if (inhibit) {\n return false;\n }\n }\n }\n let ret;\n if (listeners) {\n let i = 0, internalAbort = false;\n // Let add/removeListener know that we're using the array to protect against a situation where an event\n // listener changes the listeners when triggering the event.\n listeners.$firing = true;\n // If any listener resulted in our destruction, abort.\n for (i; i < listeners.length && !me.isDestroyed && !internalAbort; i++) {\n const listener = listeners[i];\n // Previously, returning false would abort all further listeners. But now internal listeners\n // are allowed to run anyway\n if (ret === false && !listener.$internal) {\n continue;\n }\n let handler,\n thisObj = listener.thisObj;\n // Listeners that have thisObj are auto removed when thisObj is destroyed. If thisObj is destroyed from\n // a listener we might still end up here, since listeners are sliced and not affected by the removal\n if (!thisObj || !thisObj.isDestroyed) {\n // Flag for the expiry timer\n listener.called = true;\n if (listener.once) {\n me.removeListener(name, listener);\n }\n // prepare handler function\n if (typeof listener.fn === 'string') {\n if (thisObj) {\n handler = thisObj[listener.fn];\n }\n // keep looking for the callback in the hierarchy\n if (!handler) {\n const result = me.resolveCallback(listener.fn);\n handler = result.handler;\n thisObj = result.thisObj;\n }\n }\n else {\n handler = listener.fn;\n }\n // if `buffer` option is provided, the handler will be wrapped into buffer function,\n // but only once on the first call\n if (listener.buffer) {\n if (!listener.bufferFn) {\n const buffer = Number(listener.buffer);\n if (typeof buffer !== 'number' || isNaN(buffer)) {\n throw new Error(`Incorrect type for buffer, got \"${buffer}\" (expected a Number)`);\n }\n listener.bufferFn = FunctionHelper.createBuffered(handler, buffer, thisObj, listener.args);\n }\n handler = listener.bufferFn;\n }\n // if `throttle` option is provided, the handler will be called immediately, but all the rest calls\n // that happened during time specified in `throttle`, will be delayed and glued into 1 call\n if (listener.throttle) {\n const throttle = Number(listener.throttle);\n if (typeof throttle !== 'number' || isNaN(throttle)) {\n throw new Error(`Incorrect type for throttle, got \"${throttle}\" (expected a Number)`);\n }\n if (!listener.throttledFn) {\n listener.throttledFn = FunctionHelper.createThrottled(handler, throttle, thisObj, listener.args);\n }\n handler = listener.throttledFn;\n }\n const result = handler.call(thisObj || me, ...(listener.args || []), param);\n // Store result until we get a false return value, to mimic the old behavior from before we carried\n // on with calling internal listeners\n if (ret !== false) {\n ret = result;\n }\n if (listener.$internal && result === false) {\n internalAbort = true;\n }\n if (Objects.isPromise(result)) {\n result.$internal = listener.$internal;\n // If a handler is async (returns a Promise), then collect all Promises.\n // At the end we return a Promise which encapsulates all returned Promises\n // or, if only one handler was async, *the* Promise.\n // Don't allocate an Array until we have to.\n (handlerPromises || (handlerPromises = [])).push(result);\n }\n }\n }\n listeners.$firing = false;\n // An internal listener returned `false`, abort before relaying events etc.\n if (internalAbort) {\n return false;\n }\n }\n // relay all?\n relayAllTargets?.forEach(config => {\n let name = eventName;\n if (config.transformCase) {\n name = StringHelper.capitalize(name);\n }\n if (config.prefix) {\n name = config.prefix + name;\n }\n if (config.through.trigger(name, param) === false) {\n return false;\n }\n });\n // Use DOM standard event property name to indicate that the event\n // bubbles up the owner axis.\n // False from any handler cancels the bubble.\n // Must also avoid owner if any handlers destroyed the owner.\n if (param.bubbles && me.owner && !me.owner.isDestroyed) {\n return me.owner.trigger(eventName, param);\n }\n // Run internal promises even if external listener returned false\n handlerPromises = handlerPromises?.filter(p => ret !== false || p.$internal);\n // If any handlers were async functions (returned a Promise), then return a Promise\n // which resolves when they all resolve.\n if (handlerPromises?.length) {\n return new Promise(resolve => {\n Promise.all(handlerPromises).then(promiseResults => {\n const finalResult = !promiseResults.some(result => result === false);\n resolve(finalResult);\n });\n });\n }\n return ret !== false;\n }\n /**\n * Prevents events from being triggered until {@link #function-resumeEvents()} is called. Optionally queues events that are triggered while\n * suspended. Multiple calls stack to require matching calls to `resumeEvents()` before actually resuming.\n * @param {Boolean} queue Specify true to queue events triggered while suspended\n * @advanced\n */\n suspendEvents(queue = false) {\n const eventsSuspended = this.eventsSuspended || (this.eventsSuspended = { shouldQueue : queue, queue : [], count : 0 });\n eventsSuspended.count++;\n }\n /**\n * Resume event triggering after a call to {@link #function-suspendEvents()}. If any triggered events were queued they will be triggered.\n * @returns {Boolean} `true` if events have been resumed (multiple calls to suspend require an equal number of resume calls to resume).\n * @advanced\n */\n resumeEvents() {\n const suspended = this.eventsSuspended;\n if (suspended) {\n if (--suspended.count === 0) {\n this.eventsSuspended = null;\n if (suspended.shouldQueue) {\n for (const queued of suspended.queue) {\n this.trigger(...queued);\n }\n }\n }\n }\n return !Boolean(this.eventsSuspended);\n }\n //endregion\n};\n", "/**\n * @module Core/localization/LocaleHelper\n */\n/**\n * @typedef {Object} LocaleKeys\n * Object which contains `key: value` localization pairs.\n * Key value may have `String`, `Function`, `LocaleKeys` or `Object` type.\n *\n * Example:\n *\n * ```javascript\n * {\n * title : 'Title',\n * count : number => `Count is ${number}`,\n * MyClass : {\n * foo : 'bar'\n * }\n * }\n * ```\n *\n * @property {String|Function|LocaleKeys|Object} key localization key\n * @typings {[key: string]}:{string|number|Function|LocaleKeys|object}\n */\n/**\n * @typedef {LocaleKeys} Locale\n * Locale configuration object which contains locale properties alongside with localization pairs.\n *\n * Example:\n *\n * ```javascript\n {\n * localeName : 'En',\n * localeDesc : 'English (US)',\n * localeCode : 'en-US',\n * ... (localization key:value pairs)\n * }\n * ```\n *\n * @property {String} localeName Locale name. For example: \"En\"\n * @property {String} localeDesc Locale description to be shown in locale picker list. For example: \"English (US)\"\n * @property {String} localeCode Locale code. Two letter locale code or two letter locale and two letter country code.\n * For example: \"en\" or 'en_US'\n * @property {String} [localePath] Locale path for asynchronous loading using\n * AjaxHelper {@link Core.helper.AjaxHelper#function-get-static} request\n */\n/**\n * @typedef {Object} Locales\n * Object which contains locales. Each object key represents published locale by its `localeName`.\n *\n * Example:\n *\n * ```javascript\n * // This returns English locale.\n * const englishLocale = LocaleHelper.locales.En;\n * ```\n *\n * @property {Locale} key localization object\n * @typings {[key: string]}:{Locale}\n */\n/**\n * Thin class which provides locale management methods.\n * Class doesn't import other API classes and can be used separately for publishing locales before importing product classes.\n *\n * Locale should be published with {@link ##function-publishLocale-static} method before it is available for localizing of Bryntum API classes and widgets.\n *\n * Example:\n *\n * ```javascript\n * LocaleHelper.publishLocale({\n * localeName : 'En',\n * localeDesc : 'English (US)',\n * localeCode : 'en-US',\n * ... (localization key:value pairs)\n * });\n * ```\n *\n * or for asynchronous loading from remote path on applying locale\n *\n * ```javascript\n *LocaleHelper.publishLocale({\n * localeName : 'En',\n * localeDesc : 'English (US)',\n * localeCode : 'en-US',\n * localePath : 'https://my-server/localization/en.js'\n * });\n * ```\n */\nexport default class LocaleHelper {\n static skipLocaleIntegrityCheck = false;\n /**\n * Merges all properties of provided locale objects into new locale object.\n * Locales are merged in order they provided and locales which go later replace\n * same properties of previous locales.\n * @param {...Object} locales Locales to merge\n * @returns {Object} Merged locale\n */\n static mergeLocales(...locales) {\n const result = {};\n locales.forEach(locale => {\n Object.keys(locale).forEach(key => {\n if (typeof locale[key] === 'object') {\n result[key] = { ...result[key], ...locale[key] };\n }\n else {\n result[key] = locale[key];\n }\n });\n });\n return result;\n }\n /**\n * Removes all properties from `locale` that are present in the provided `toTrim`.\n * @param {Object} locale Locale to process\n * @param {Object} toTrim Object enumerating properties that should be removed.\n * When `false` throws exceptions in such cases.\n */\n static trimLocale(locale, toTrim) {\n const remove = (key, subKey) => {\n if (locale[key]) {\n if (subKey) {\n if (locale[key][subKey]) {\n delete locale[key][subKey];\n }\n }\n else {\n delete locale[key];\n }\n }\n };\n Object.keys(toTrim).forEach(key => {\n if (Object.keys(toTrim[key]).length > 0) {\n Object.keys(toTrim[key]).forEach(subKey => remove(key, subKey));\n }\n else {\n remove(key);\n }\n });\n }\n /**\n * Normalizes locale object to {@link Locale} type.\n *\n * Supported configs:\n *\n * ```javascript\n * LocaleHelper.normalizeLocale({\n * localeName : 'En',\n * localeDesc : 'English (US)',\n * localeCode : 'en-US',\n * ... (localization key:value pairs)\n * });\n * ```\n *\n * and for backward compatibility\n *\n * ```javascript\n * LocaleHelper.normalizeLocale('En', {\n * name : 'En',\n * desc : 'English (US)',\n * code : 'en-US',\n * locale : {\n * ... (localization key:value pairs)\n * }\n * });\n * ```\n * @param {String|Object} nameOrConfig String name of locale or locale object\n * @param {Object} [config] Locale object\n * @returns {Locale} Locale object\n * @internal\n */\n static normalizeLocale(nameOrConfig, config) {\n if (!nameOrConfig) {\n throw new Error(`\"nameOrConfig\" parameter can not be empty`);\n }\n if (typeof nameOrConfig === 'string') {\n if (!config) {\n throw new Error(`\"config\" parameter can not be empty`);\n }\n if (config.locale) {\n // Matches legacy locale type\n config.name = nameOrConfig || config.name;\n }\n else {\n config.localeName = nameOrConfig;\n }\n }\n else {\n config = nameOrConfig;\n }\n let locale = {};\n if (config.name || config.locale) {\n // Matches legacy locale type\n locale = Object.assign({\n localeName : config.name\n }, config.locale);\n config.desc && (locale.localeDesc = config.desc);\n config.code && (locale.localeCode = config.code);\n config.path && (locale.localePath = config.path);\n }\n else {\n if (!config.localeName) {\n throw new Error(`\"config\" parameter doesn't have \"localeName\" property`);\n }\n // Extract locale config from name object\n locale = Object.assign({}, config);\n }\n // Cleanup result\n for (const key of ['name', 'desc', 'code', 'path']) {\n if (locale[key]) {\n delete locale[key];\n }\n }\n if (!locale.localeName) {\n throw new Error(`Locale name can not be empty`);\n }\n return locale;\n }\n /**\n * Get/set currently published locales.\n * Returns an object with locales.\n *\n * Example:\n *\n * ```javascript\n * const englishLocale = LocaleHelper.locales.En;\n * ```\n *\n * `englishLocale` contains {@link Locale} object.\n *\n * @readonly\n * @member {Locales} locales\n * @static\n */\n static get locales() {\n return globalThis.bryntum.locales || {};\n }\n static set locales(locales) {\n globalThis.bryntum.locales = locales;\n }\n /**\n * Get/set current locale name. Defaults to \"En\"\n * @member {String} localeName\n * @static\n */\n static get localeName() {\n return globalThis.bryntum.locale || 'En';\n }\n static set localeName(localeName) {\n globalThis.bryntum.locale = localeName || LocaleHelper.localeName;\n }\n /**\n * Get current locale config specified by {@link ##property-localeName-static}.\n * If no current locale specified, returns default `En` locale or first published locale\n * or empty locale object if no published locales found.\n * @readonly\n * @member {Locales} locale\n * @static\n */\n static get locale() {\n return LocaleHelper.localeName && this.locales[LocaleHelper.localeName] || this.locales.En || Object.values(this.locales)[0] || { localeName : '', localeDesc : '', localeCoode : '' };\n }\n /**\n * Publishes a locale to make it available for applying.\n * Published locales are available in {@link ##property-locales-static}.\n *\n * Recommended usage:\n *\n * ```javascript\n * LocaleHelper.publishLocale({\n * localeName : 'En',\n * localeDesc : 'English (US)',\n * localeCode : 'en-US',\n * ... (localization key:value pairs)\n * });\n * ```\n *\n * for backward compatibility (prior to `5.3.0` version):\n *\n * ```javascript\n * LocaleHelper.publishLocale('En', {\n * name : 'En',\n * desc : 'English (US)',\n * code : 'en-US',\n * locale : {\n * ... (localization key:value pairs)\n * }\n * });\n * ```\n *\n * Publishing a locale will automatically merge it's localization keys with existing locale matching by locale name,\n * replacing existing one with new. To replace existing locale entirely pass `true` to optional `config` parameter.\n *\n * Example:\n *\n * ```javascript\n * LocaleHelper.publishLocale({\n * localeName : 'En',\n * localeDesc : 'English (US)',\n * localeCode : 'en-US',\n * ... (localization key:value pairs)\n * }, true);\n * ```\n *\n * @param {String|Locale} nameOrConfig String name of locale (for example `En` or `SvSE`) or locale object\n * @param {Locale|Boolean} [config] Locale object.\n * Not used if locale object is passed as first method parameter.\n * Path `true` value and locale object as first method parameter to publish locale without merging with existing one.\n * @returns {Locale} Locale object\n */\n static publishLocale(nameOrConfig, config) {\n const\n { locales } = globalThis.bryntum,\n locale = LocaleHelper.normalizeLocale(nameOrConfig, config),\n { localeName } = locale;\n if (!locales[localeName] || config === true) {\n locales[localeName] = locale;\n }\n else {\n locales[localeName] = this.mergeLocales(locales[localeName] || {}, locale || {});\n }\n return locales[localeName];\n }\n}\nglobalThis.bryntum = globalThis.bryntum || {};\nglobalThis.bryntum.locales = globalThis.bryntum.locales || {};\nLocaleHelper._$name = 'LocaleHelper';", "import Base from '../Base.js';\nimport AjaxHelper from '../helper/AjaxHelper.js';\nimport Events from '../mixin/Events.js';\nimport BrowserHelper from '../helper/BrowserHelper.js';\nimport LocaleHelper from '../localization/LocaleHelper.js';\nimport VersionHelper from '../helper/VersionHelper.js';\n/**\n * @module Core/localization/LocaleManager\n */\n// Documented at the export below, to work for singleton\nclass LocaleManager extends Events(Base) {\n static get defaultConfig() {\n return {\n // Enable strict locale checking by default for tests\n throwOnMissingLocale : VersionHelper.isTestEnv\n };\n }\n construct(...args) {\n const me = this;\n super.construct(...args);\n if (BrowserHelper.isBrowserEnv) {\n // Try get locale name from script's `default-locale` tag\n const scriptTag = document.querySelector('script[data-default-locale]');\n if (scriptTag) {\n me.applyLocale(scriptTag.dataset.defaultLocale);\n }\n else if (me.locale?.localeName) {\n me.applyLocale(me.locale.localeName);\n }\n }\n }\n /**\n * Get/set currently registered locales.\n * Alias for {@link Core.localization.LocaleHelper#property-locales-static LocaleHelper.locales}.\n * @readonly\n * @member {Locales} locales\n */\n get locales() {\n return LocaleHelper.locales;\n }\n set locales(locales) {\n LocaleHelper.locales = locales;\n }\n /**\n * Get/set currently used locale.\n * Setter calls {@link #function-applyLocale}.\n * @member {Locales} locale\n * @accepts {String|Locale}\n */\n set locale(nameOrConfig) {\n this.applyLocale(nameOrConfig);\n }\n get locale() {\n return LocaleHelper.locale;\n }\n /**\n * Publishes a locale to make it available for applying.\n * @deprecated Since 5.3.0. Use {@link Core.localization.LocaleHelper#function-publishLocale-static LocaleHelper.publishLocale} instead.\n *\n * @param {String|Locale} nameOrConfig String name of locale (for example `En` or `SvSE`) or locale object.\n * @param {Locale} [config] Locale object. Not used if object is passed as first method parameter\n * @returns {Locale} published locale object is passed as first method parameter\n * @function registerLocale\n */\n registerLocale(nameOrConfig, config) {\n VersionHelper.deprecate('Core', '6.0.0', 'LocaleManager.registerLocale deprecated, use LocaleHelper.publishLocale instead');\n LocaleHelper.publishLocale(nameOrConfig, config);\n }\n /**\n * Extends locale specified by name to add additional translations and applies it.\n * @deprecated Since 5.3.0. Use {@link ##function-applyLocale} instead.\n *\n * @param {String} name Name of locale (for example `En` or `SvSE`).\n * @param {Locale} config Locale object\n * @returns {Locale|Promise} locale object or Promise which resolves with locale object after it was loaded\n * @function extendLocale\n */\n extendLocale(name, config) {\n VersionHelper.deprecate('Core', '6.0.0', 'LocaleManager.extendLocale deprecated, use LocaleManager.applyLocale instead');\n const locale = LocaleHelper.publishLocale(name, config);\n return this.applyLocale(locale, true);\n }\n /**\n * Applies a locale by string name or publishes new locale configuration with\n * {@link Core.localization.LocaleHelper#function-publishLocale-static} and applies it.\n * If locale is specified by string name, like 'En', it must be published before applying it.\n *\n * @param {String|Locale} nameOrConfig String name of locale (for example `En` or `SvSE`) or locale object\n * @param {Locale|Boolean} [config] Locale object. Pass `true` to reapply locale which is passed as first method parameter.\n * @returns {Locale|Promise} locale object or Promise which resolves with locale object after it was loaded\n * @fires locale\n * @async\n * @function applyLocale\n */\n applyLocale(nameOrConfig, config, ignoreError = false) {\n const me = this;\n let localeConfig;\n if (typeof nameOrConfig === 'string') {\n if (typeof config !== 'object') {\n localeConfig = me.locales[nameOrConfig];\n if (!localeConfig) {\n if (ignoreError) {\n return true;\n }\n throw new Error(`Locale \"${nameOrConfig}\" is not published. Publish with LocaleHelper.publishLocale() before applying.`);\n }\n }\n else {\n localeConfig = LocaleHelper.publishLocale(nameOrConfig, config);\n }\n }\n else {\n localeConfig = LocaleHelper.publishLocale(nameOrConfig);\n }\n if (me.locale.localeName && me.locale.localeName === localeConfig.localeName && config !== true) {\n // no need to apply same locale again\n return me.locale;\n }\n // Set current locale name\n LocaleHelper.localeName = localeConfig.localeName;\n const triggerLocaleEvent = () => {\n /**\n * Fires when a locale is applied\n * @event locale\n * @param {Core.localization.LocaleManager} source The Locale manager instance.\n * @typings source -> {typeof LocaleManager}\n * @param {Locale} locale Locale configuration\n */\n me.trigger('locale', localeConfig);\n };\n if (localeConfig.localePath) {\n return new Promise((resolve, reject) => {\n me.loadLocale(localeConfig.localePath).then(response => {\n response.text().then(text => {\n const parseLocale = new Function(text);\n parseLocale();\n if (BrowserHelper.isBrowserEnv) {\n localeConfig = me.locales[localeConfig.localeName];\n // Avoid loading next time\n if (localeConfig) {\n delete localeConfig.localePath;\n }\n }\n triggerLocaleEvent();\n resolve(localeConfig);\n });\n }).catch(response => reject(response));\n });\n }\n triggerLocaleEvent();\n return localeConfig;\n }\n /**\n * Loads a locale using AjaxHelper {@link Core.helper.AjaxHelper#function-get-static} request.\n * @private\n * @param {String} path Path to locale file\n * @async\n */\n loadLocale(path) {\n return AjaxHelper.get(path);\n }\n /**\n * Specifies if {@link Core.localization.Localizable#function-L-static Localizable.L()} function would throw error if no localization found at runtime.\n *\n * @member {Boolean} throwOnMissingLocale\n * @default false\n */\n set throwOnMissingLocale(value) {\n this._throwOnMissingLocale = value;\n }\n get throwOnMissingLocale() {\n return this._throwOnMissingLocale;\n }\n}\nconst LocaleManagerSingleton = new LocaleManager();\n/**\n * Singleton that handles switching locale.\n * Locales can be included on page with `