diff --git a/api/src/main/kotlin/nebulosa/api/autofocus/AutoFocusJob.kt b/api/src/main/kotlin/nebulosa/api/autofocus/AutoFocusJob.kt index 644ac6550..f236ade10 100644 --- a/api/src/main/kotlin/nebulosa/api/autofocus/AutoFocusJob.kt +++ b/api/src/main/kotlin/nebulosa/api/autofocus/AutoFocusJob.kt @@ -1,9 +1,7 @@ package nebulosa.api.autofocus import nebulosa.api.cameras.* -import nebulosa.api.focusers.BacklashCompensationFocuserMoveTask -import nebulosa.api.focusers.BacklashCompensationMode -import nebulosa.api.focusers.FocuserEventAware +import nebulosa.api.focusers.* import nebulosa.api.message.MessageEvent import nebulosa.autofocus.AutoFocus import nebulosa.autofocus.AutoFocusListener @@ -46,7 +44,7 @@ data class AutoFocusJob( ) private val cameraExposureTask = CameraExposureTask(this, camera, cameraRequest) - private val backlashCompensationFocuserMoveTask = BacklashCompensationFocuserMoveTask(this, focuser, 0, request.backlashCompensation) + private val backlashCompensator = BacklashCompensator(request.backlashCompensation, focuser.maxPosition) private val reverse = request.backlashCompensation.mode == BacklashCompensationMode.OVERSHOOT && request.backlashCompensation.backlashIn > 0 private val finished = AtomicBoolean() @@ -57,6 +55,7 @@ data class AutoFocusJob( ) @Volatile private var initialFocusPosition = 0 + @Volatile private var focuserTask: FocuserTask? = null @JvmField val status = AutoFocusEvent(camera) @@ -74,8 +73,8 @@ data class AutoFocusJob( add(cameraExposureTask) } is AutoFocusResult.MoveFocuser -> { - backlashCompensationFocuserMoveTask.position = if (relative) focuser.position + position else position - add(backlashCompensationFocuserMoveTask) + val position = if (relative) focuser.position + position else position + add(BacklashCompensationFocuserMoveTask(this@AutoFocusJob, focuser, position, backlashCompensator)) } is AutoFocusResult.Completed -> { status.determinedFocusPoint = determinedFocusPoint @@ -102,7 +101,7 @@ data class AutoFocusJob( } override fun handleFocuserEvent(event: FocuserEvent) { - backlashCompensationFocuserMoveTask.handleFocuserEvent(event) + focuserTask?.handleFocuserEvent(event) } override fun beforeStart() { @@ -115,10 +114,12 @@ data class AutoFocusJob( } override fun beforeTask(task: Task) { - if (task === backlashCompensationFocuserMoveTask) { + if (task is FocuserTask) { + focuserTask = task status.state = AutoFocusState.MOVING status.send() } else if (task === cameraExposureTask) { + focuserTask = null status.state = AutoFocusState.EXPOSURING status.send() } @@ -201,15 +202,19 @@ data class AutoFocusJob( private fun restoringFocuserToInitialPosition() { finished.set(true) - backlashCompensationFocuserMoveTask.position = initialFocusPosition - backlashCompensationFocuserMoveTask.run() + + focuserTask = BacklashCompensationFocuserMoveTask(this, focuser, initialFocusPosition, backlashCompensator) + focuserTask!!.run() + cameraExposureTask.run() } private fun movingFocuserToDeterminedFocusPosition(position: CurvePoint) { finished.set(true) - backlashCompensationFocuserMoveTask.position = position.x.roundToInt() - backlashCompensationFocuserMoveTask.run() + + focuserTask = BacklashCompensationFocuserMoveTask(this, focuser, position.x.roundToInt(), backlashCompensator) + focuserTask!!.run() + cameraExposureTask.run() } diff --git a/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureRequest.kt b/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureRequest.kt index 8ed13cb0c..016b82ab9 100644 --- a/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureRequest.kt +++ b/api/src/main/kotlin/nebulosa/api/cameras/CameraStartCaptureRequest.kt @@ -41,6 +41,8 @@ data class CameraStartCaptureRequest( @JvmField val shutterPosition: Int = 0, // Focuser. @JvmField val focusOffset: Int = 0, + // Rotator. + @JvmField val angle: Double = -1.0, // deg // Others. @JvmField val namingFormat: CameraCaptureNamingFormat = CameraCaptureNamingFormat.DEFAULT, ) : Validatable { diff --git a/api/src/main/kotlin/nebulosa/api/focusers/AbstractFocuserMoveTask.kt b/api/src/main/kotlin/nebulosa/api/focusers/AbstractFocuserMoveTask.kt index 544186b2a..467866f16 100644 --- a/api/src/main/kotlin/nebulosa/api/focusers/AbstractFocuserMoveTask.kt +++ b/api/src/main/kotlin/nebulosa/api/focusers/AbstractFocuserMoveTask.kt @@ -3,6 +3,7 @@ package nebulosa.api.focusers import nebulosa.indi.device.focuser.FocuserEvent import nebulosa.indi.device.focuser.FocuserMoveFailed import nebulosa.indi.device.focuser.FocuserMovingChanged +import nebulosa.indi.device.focuser.FocuserPositionChanged import nebulosa.job.manager.Job import nebulosa.log.d import nebulosa.log.loggerFor @@ -22,7 +23,7 @@ sealed class AbstractFocuserMoveTask : FocuserTask, CancellationListener { if (event.device === focuser) { when (event) { is FocuserMovingChanged -> if (event.device.moving) moving = true else if (moving) latch.reset() - // is FocuserPositionChanged -> if (moving && !event.device.moving) latch.reset() + is FocuserPositionChanged -> if (moving && !event.device.moving) latch.reset() is FocuserMoveFailed -> latch.reset() } } @@ -36,6 +37,7 @@ sealed class AbstractFocuserMoveTask : FocuserTask, CancellationListener { if (!job.isCancelled && focuser.connected && !focuser.moving && canMove()) { LOG.d("Focuser move started. focuser={}", focuser) latch.countUp() + moving = true move() latch.await() moving = false diff --git a/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensationFocuserMoveTask.kt b/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensationFocuserMoveTask.kt index 2afff756f..c7bdd9e08 100644 --- a/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensationFocuserMoveTask.kt +++ b/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensationFocuserMoveTask.kt @@ -3,139 +3,54 @@ package nebulosa.api.focusers import nebulosa.indi.device.focuser.Focuser import nebulosa.indi.device.focuser.FocuserEvent import nebulosa.job.manager.Job -import nebulosa.log.d -import nebulosa.log.loggerFor -import nebulosa.log.w import nebulosa.util.concurrency.cancellation.CancellationSource /** - * This task will wrap an absolute backlash [compensation] model around the [focuser]. + * This task will wrap an absolute backlash [compensator] model around the [focuser]. * On each move an absolute backlash compensation value will be applied, if the focuser changes its moving direction * The returned position will then accommodate for this backlash and simulating the position without backlash. */ data class BacklashCompensationFocuserMoveTask( @JvmField val job: Job, override val focuser: Focuser, - @JvmField var position: Int, - @JvmField val compensation: BacklashCompensation, + @JvmField val position: Int, + @JvmField val compensator: BacklashCompensator, ) : FocuserTask { - enum class OvershootDirection { - NONE, - IN, - OUT, - } - - @Volatile private var offset = 0 - @Volatile private var lastDirection = OvershootDirection.NONE - - private val task = FocuserMoveAbsoluteTask(job, focuser, 0) + @Volatile private var task: FocuserTask? = null /** * Returns the adjusted position based on the amount of backlash compensation. */ val adjustedPosition - get() = focuser.position - offset + get() = compensator.adjustedPosition(focuser.position) override fun handleFocuserEvent(event: FocuserEvent) { - task.handleFocuserEvent(event) + task?.handleFocuserEvent(event) } override fun onCancel(source: CancellationSource) { - task.onCancel(source) + task?.onCancel(source) } override fun onPause(paused: Boolean) { - task.onPause(paused) + task?.onPause(paused) } override fun run() { if (!job.isCancelled && focuser.connected && !focuser.moving) { - val startPosition = focuser.position - - val newPosition = when (compensation.mode) { - BacklashCompensationMode.ABSOLUTE -> { - val adjustedTargetPosition = position + offset - - if (adjustedTargetPosition < 0) { - offset = 0 - 0 - } else if (adjustedTargetPosition > focuser.maxPosition) { - offset = 0 - focuser.maxPosition - } else { - val backlashCompensation = calculateAbsoluteBacklashCompensation(startPosition, adjustedTargetPosition) - offset += backlashCompensation - adjustedTargetPosition + backlashCompensation - } - } - BacklashCompensationMode.OVERSHOOT -> { - val backlashCompensation = calculateOvershootBacklashCompensation(startPosition, position) - - if (backlashCompensation != 0) { - val overshoot = position + backlashCompensation + val targetPositions = compensator.compute(position, focuser.position) - if (overshoot < 0) { - LOG.w("overshooting position is below minimum 0, skipping overshoot") - } else if (overshoot > focuser.maxPosition) { - LOG.w("overshooting position is above maximum {}, skipping overshoot", focuser.maxPosition) - } else { - LOG.d("overshooting from {} to overshoot position {} using a compensation of {}. Moving back to position {}", startPosition, overshoot, backlashCompensation, position) - moveFocuser(overshoot) - } - } - - position - } - else -> { - position - } + for (position in targetPositions) { + moveFocuser(position) } - - LOG.d("moving to position {} using {} backlash compensation", newPosition, compensation.mode) - - moveFocuser(newPosition) } } private fun moveFocuser(position: Int) { - if (position > 0 && position <= focuser.maxPosition) { - lastDirection = determineMovingDirection(focuser.position, position) - task.position = position - task.run() + if (!job.isCancelled && position in 0..focuser.maxPosition) { + task = FocuserMoveAbsoluteTask(job, focuser, position) + task!!.run() } } - - private fun determineMovingDirection(prevPosition: Int, newPosition: Int): OvershootDirection { - return if (newPosition > prevPosition) OvershootDirection.OUT - else if (newPosition < prevPosition) OvershootDirection.IN - else lastDirection - } - - private fun calculateAbsoluteBacklashCompensation(lastPosition: Int, newPosition: Int): Int { - val direction = determineMovingDirection(lastPosition, newPosition) - - return if (direction == OvershootDirection.IN && lastDirection == OvershootDirection.OUT) { - LOG.d("Focuser is reversing direction from outwards to inwards") - -compensation.backlashIn - } else if (direction == OvershootDirection.OUT && lastDirection === OvershootDirection.IN) { - LOG.d("Focuser is reversing direction from inwards to outwards") - compensation.backlashOut - } else { - 0 - } - } - - private fun calculateOvershootBacklashCompensation(lastPosition: Int, newPosition: Int): Int { - val direction = determineMovingDirection(lastPosition, newPosition) - - return if (direction == OvershootDirection.IN && compensation.backlashIn != 0) -compensation.backlashIn - else if (direction == OvershootDirection.OUT && compensation.backlashOut != 0) compensation.backlashOut - else 0 - } - - companion object { - - @JvmStatic private val LOG = loggerFor() - } } diff --git a/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensator.kt b/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensator.kt new file mode 100644 index 000000000..3dd8377d9 --- /dev/null +++ b/api/src/main/kotlin/nebulosa/api/focusers/BacklashCompensator.kt @@ -0,0 +1,118 @@ +package nebulosa.api.focusers + +import nebulosa.log.d +import nebulosa.log.loggerFor +import nebulosa.log.w +import kotlin.math.max +import kotlin.math.min + +// https://bitbucket.org/Isbeorn/nina + +data class BacklashCompensator( + @JvmField val compensation: BacklashCompensation, + @JvmField val maxPosition: Int, +) { + + enum class OvershootDirection { + NONE, + IN, + OUT, + } + + @Volatile var lastDirection = OvershootDirection.NONE + private set + + @Volatile var offset = 0 + private set + + fun compute(targetPosition: Int, currentPosition: Int): IntArray { + var newPosition = targetPosition + + when (compensation.mode) { + BacklashCompensationMode.ABSOLUTE -> { + val adjustedTargetPosition = targetPosition + offset + + if (adjustedTargetPosition < 0) { + offset = 0 + newPosition = 0 + } else if (adjustedTargetPosition > maxPosition) { + offset = 0 + newPosition = maxPosition + } else { + val backlashCompensation = calculateAbsoluteBacklashCompensation(currentPosition, adjustedTargetPosition) + offset += backlashCompensation + newPosition = max(0, min(adjustedTargetPosition + backlashCompensation, maxPosition)) + } + } + BacklashCompensationMode.OVERSHOOT -> { + val backlashCompensation = calculateOvershootBacklashCompensation(currentPosition, targetPosition) + + if (backlashCompensation != 0) { + val overshoot = targetPosition + backlashCompensation + + if (overshoot < 0) { + LOG.w("overshooting position is below minimum 0, skipping overshoot") + } else if (overshoot > maxPosition) { + LOG.w("overshooting position is above maximum {}, skipping overshoot", maxPosition) + } else { + LOG.d("overshooting from {} to overshoot position {} using a compensation of {}. Moving back to position {}", currentPosition, overshoot, backlashCompensation, newPosition) + + move(currentPosition, overshoot) + move(overshoot, newPosition) + + return intArrayOf(overshoot, newPosition) + } + } + } + BacklashCompensationMode.NONE -> Unit + } + + move(currentPosition, newPosition) + + return intArrayOf(newPosition) + } + + fun adjustedPosition(currentPosition: Int): Int { + return currentPosition - offset + } + + + @Suppress("NOTHING_TO_INLINE") + private inline fun move(currentPosition: Int, newPosition: Int) { + lastDirection = determineMovingDirection(currentPosition, newPosition) + LOG.d("moving to position {} using {} backlash compensation", newPosition, compensation.mode) + } + + private fun determineMovingDirection(prevPosition: Int, newPosition: Int): OvershootDirection { + return if (newPosition > prevPosition) OvershootDirection.OUT + else if (newPosition < prevPosition) OvershootDirection.IN + else lastDirection + } + + private fun calculateAbsoluteBacklashCompensation(lastPosition: Int, newPosition: Int): Int { + val direction = determineMovingDirection(lastPosition, newPosition) + + return if (direction == OvershootDirection.IN && lastDirection == OvershootDirection.OUT) { + LOG.d("focuser is reversing direction from outwards to inwards") + -compensation.backlashIn + } else if (direction == OvershootDirection.OUT && lastDirection === OvershootDirection.IN) { + LOG.d("focuser is reversing direction from inwards to outwards") + compensation.backlashOut + } else { + 0 + } + } + + private fun calculateOvershootBacklashCompensation(lastPosition: Int, newPosition: Int): Int { + val direction = determineMovingDirection(lastPosition, newPosition) + + return if (direction == OvershootDirection.IN && compensation.backlashIn != 0) -compensation.backlashIn + else if (direction == OvershootDirection.OUT && compensation.backlashOut != 0) compensation.backlashOut + else 0 + } + + companion object { + + @JvmStatic private val LOG = loggerFor() + } +} diff --git a/api/src/main/kotlin/nebulosa/api/focusers/FocuserMoveAbsoluteTask.kt b/api/src/main/kotlin/nebulosa/api/focusers/FocuserMoveAbsoluteTask.kt index 91692bf03..2832969ed 100644 --- a/api/src/main/kotlin/nebulosa/api/focusers/FocuserMoveAbsoluteTask.kt +++ b/api/src/main/kotlin/nebulosa/api/focusers/FocuserMoveAbsoluteTask.kt @@ -7,10 +7,10 @@ import kotlin.math.abs data class FocuserMoveAbsoluteTask( override val job: Job, override val focuser: Focuser, - @JvmField @Volatile var position: Int, + @JvmField val position: Int, ) : AbstractFocuserMoveTask() { - override fun canMove() = position != focuser.position && position > 0 && position < focuser.maxPosition + override fun canMove() = position != focuser.position && position in 0..focuser.maxPosition override fun move() { if (focuser.canAbsoluteMove) focuser.moveFocusTo(position) diff --git a/api/src/main/kotlin/nebulosa/api/rotators/RotatorMoveTask.kt b/api/src/main/kotlin/nebulosa/api/rotators/RotatorMoveTask.kt new file mode 100644 index 000000000..17ab82c70 --- /dev/null +++ b/api/src/main/kotlin/nebulosa/api/rotators/RotatorMoveTask.kt @@ -0,0 +1,46 @@ +package nebulosa.api.rotators + +import nebulosa.indi.device.rotator.* +import nebulosa.job.manager.Job +import nebulosa.job.manager.Task +import nebulosa.log.d +import nebulosa.log.loggerFor +import nebulosa.util.concurrency.latch.CountUpDownLatch + +data class RotatorMoveTask( + @JvmField val job: Job, + @JvmField val rotator: Rotator, + @JvmField val angle: Double, +) : Task, RotatorEventAware { + + private val latch = CountUpDownLatch() + + @Volatile private var moving = false + + override fun handleRotatorEvent(event: RotatorEvent) { + when (event) { + is RotatorMovingChanged -> if (event.device.moving) moving = true else if (moving) latch.reset() + is RotatorAngleChanged -> if (moving && !event.device.moving) latch.reset() + is RotatorMoveFailed -> latch.reset() + } + } + + override fun run() { + if (!job.isCancelled && rotator.connected && !rotator.moving && + angle != rotator.angle && angle in 0.0..rotator.maxAngle + ) { + LOG.d("Rotator move started. rotator={}", rotator) + latch.countUp() + moving = true + rotator.moveRotator(angle) + latch.await() + moving = false + LOG.d("Rotator move finished. rotator={}", rotator) + } + } + + companion object { + + @JvmStatic private val LOG = loggerFor() + } +} diff --git a/api/src/main/kotlin/nebulosa/api/sequencer/SequencerJob.kt b/api/src/main/kotlin/nebulosa/api/sequencer/SequencerJob.kt index 452bb0ca9..051894dd4 100644 --- a/api/src/main/kotlin/nebulosa/api/sequencer/SequencerJob.kt +++ b/api/src/main/kotlin/nebulosa/api/sequencer/SequencerJob.kt @@ -1,13 +1,16 @@ package nebulosa.api.sequencer -import nebulosa.api.calibration.CalibrationFrameProvider import nebulosa.api.cameras.* +import nebulosa.api.focusers.BacklashCompensationFocuserMoveTask +import nebulosa.api.focusers.BacklashCompensator import nebulosa.api.focusers.FocuserEventAware +import nebulosa.api.focusers.FocuserTask import nebulosa.api.guiding.DitherAfterExposureEvent import nebulosa.api.guiding.DitherAfterExposureTask import nebulosa.api.guiding.WaitForSettleTask import nebulosa.api.message.MessageEvent import nebulosa.api.rotators.RotatorEventAware +import nebulosa.api.rotators.RotatorMoveTask import nebulosa.api.wheels.WheelEventAware import nebulosa.api.wheels.WheelMoveTask import nebulosa.guiding.Guider @@ -45,9 +48,10 @@ data class SequencerJob( private val sequences = plan.sequences.filter { it.enabled } private val initialDelayTask = DelayTask(this, plan.initialDelay) private val waitForSettleTask = WaitForSettleTask(this, guider) - private val cameraCaptureEvents = - Array(plan.sequences.size + 1) { CameraCaptureEvent(camera, exposureAmount = plan.sequences.getOrNull(it - 1)?.exposureAmount ?: 0) } + private val cameraCaptureEvents = Array(plan.sequences.size + 1) { CameraCaptureEvent(camera, exposureAmount = plan.sequences.getOrNull(it - 1)?.exposureAmount ?: 0) } + private val backlashCompensator = BacklashCompensator(plan.backlashCompensation, focuser?.maxPosition ?: 0) + @Volatile private var initialFocuserPosition = 0 @Volatile private var estimatedCaptureTime = initialDelayTask.duration * 1000L @Volatile private var captureStartElapsedTime = 0L @@ -56,6 +60,8 @@ data class SequencerJob( init { require(sequences.isNotEmpty()) { "no entries found" } + initialFocuserPosition = focuser?.position ?: 0 + add(initialDelayTask) if (plan.captureMode == SequencerCaptureMode.FULLY || sequences.size == 1) { @@ -70,7 +76,13 @@ data class SequencerJob( add(SequencerIdTask(id)) // FILTER WHEEL. - request.wheelMoveTask()?.also(::add) + if (request.wheelMoveTask()?.also(::add) != null) { + // FOCUSER. + request.focuserMoveTask()?.also(::add) + } + + // ROTATOR. + request.rotatorMoveTask()?.also(::add) // DELAY. val delayTask = DelayTask(this, request.exposureDelay) @@ -97,6 +109,8 @@ data class SequencerJob( val requests = sequences.map { it.map() } val sequenceIdTasks = sequences.map { req -> SequencerIdTask(plan.sequences.indexOfFirst { it === req } + 1) } val wheelMoveTasks = requests.map { it.wheelMoveTask() } + val focuserMoveTasks = requests.map { it.focuserMoveTask() } + val rotatorMoveTasks = requests.map { it.rotatorMoveTask() } val cameraExposureTasks = requests.map { CameraExposureTask(this, camera, it) } val delayTasks = requests.map { DelayTask(this, it.exposureDelay) } val ditherAfterExposureTask = requests.map { DitherAfterExposureTask(this, guider, it.dither) } @@ -113,7 +127,13 @@ data class SequencerJob( add(sequenceIdTasks[i]) // FILTER WHEEL. - wheelMoveTasks[i]?.also(::add) + if (wheelMoveTasks[i]?.also(::add) != null) { + // FOCUSER. + focuserMoveTasks[i]?.also(::add) + } + + // ROTATOR. + rotatorMoveTasks[i]?.also(::add) // DELAY. if (!first) { @@ -146,9 +166,13 @@ data class SequencerJob( (currentTask as? WheelEventAware)?.handleFilterWheelEvent(event) } - override fun handleFocuserEvent(event: FocuserEvent) = Unit + override fun handleFocuserEvent(event: FocuserEvent) { + (currentTask as? FocuserEventAware)?.handleFocuserEvent(event) + } - override fun handleRotatorEvent(event: RotatorEvent) = Unit + override fun handleRotatorEvent(event: RotatorEvent) { + (currentTask as? RotatorEventAware)?.handleRotatorEvent(event) + } private fun CameraStartCaptureRequest.map() = copy( savePath = plan.savePath, @@ -161,16 +185,36 @@ data class SequencerJob( private fun CameraStartCaptureRequest.wheelMoveTask(): WheelMoveTask? { if (wheel != null) { - val filterPosition = if (frameType == FrameType.DARK) shutterPosition else filterPosition + val position = if (frameType == FrameType.DARK) shutterPosition else filterPosition - if (filterPosition in 1..wheel.count) { - return WheelMoveTask(this@SequencerJob, wheel, filterPosition) + if (position in 1..wheel.count) { + return WheelMoveTask(this@SequencerJob, wheel, position) } } return null } + private fun CameraStartCaptureRequest.focuserMoveTask(): FocuserTask? { + if (focuser != null && focusOffset != 0 && frameType != FrameType.DARK) { + val position = initialFocuserPosition + focusOffset + + if (position in 0..focuser.maxPosition) { + return BacklashCompensationFocuserMoveTask(this@SequencerJob, focuser, position, backlashCompensator) + } + } + + return null + } + + private fun CameraStartCaptureRequest.rotatorMoveTask(): RotatorMoveTask? { + if (rotator != null && angle.isFinite() && frameType != FrameType.DARK && angle in 0.0..rotator.maxAngle) { + return RotatorMoveTask(this@SequencerJob, rotator, angle) + } + + return null + } + private fun addFrameToLiveStacker(request: CameraStartCaptureRequest, path: Path?): Path? { return if (path != null && liveStackingManager != null && liveStackingManager.start(request, path)) { try { diff --git a/api/src/main/kotlin/nebulosa/api/sequencer/SequencerPlanRequest.kt b/api/src/main/kotlin/nebulosa/api/sequencer/SequencerPlanRequest.kt index 5b32fe6b5..d88e7ac3b 100644 --- a/api/src/main/kotlin/nebulosa/api/sequencer/SequencerPlanRequest.kt +++ b/api/src/main/kotlin/nebulosa/api/sequencer/SequencerPlanRequest.kt @@ -4,6 +4,7 @@ import nebulosa.api.cameras.AutoSubFolderMode import nebulosa.api.cameras.CameraCaptureNamingFormat import nebulosa.api.cameras.CameraStartCaptureRequest import nebulosa.api.converters.time.DurationUnit +import nebulosa.api.focusers.BacklashCompensation import nebulosa.api.guiding.DitherAfterExposureRequest import nebulosa.api.livestacker.LiveStackingRequest import nebulosa.api.validators.Validatable @@ -25,6 +26,7 @@ data class SequencerPlanRequest( @JvmField val autoFocus: AutoFocusAfterConditions = AutoFocusAfterConditions.DISABLED, @JvmField val liveStacking: LiveStackingRequest = LiveStackingRequest.DISABLED, @JvmField val namingFormat: CameraCaptureNamingFormat = CameraCaptureNamingFormat.DEFAULT, + @JvmField val backlashCompensation: BacklashCompensation = BacklashCompensation.EMPTY, ) : Validatable { override fun validate() { diff --git a/api/src/test/kotlin/BacklashCompensatorTest.kt b/api/src/test/kotlin/BacklashCompensatorTest.kt new file mode 100644 index 000000000..ba3dc2bfb --- /dev/null +++ b/api/src/test/kotlin/BacklashCompensatorTest.kt @@ -0,0 +1,50 @@ +import io.kotest.matchers.shouldBe +import nebulosa.api.focusers.BacklashCompensation +import nebulosa.api.focusers.BacklashCompensationMode +import nebulosa.api.focusers.BacklashCompensator +import org.junit.jupiter.api.Test + +class BacklashCompensatorTest { + + @Test + fun absoluteIn() { + val compensation = BacklashCompensation(BacklashCompensationMode.ABSOLUTE, 100, 0) + val compensator = BacklashCompensator(compensation, 10000) + + compensator.compute(1000, 0) shouldBe intArrayOf(1000) + compensator.compute(100, 1000) shouldBe intArrayOf(0) + } + + @Test + fun absoluteOut() { + val compensation = BacklashCompensation(BacklashCompensationMode.ABSOLUTE, 0, 100) + val compensator = BacklashCompensator(compensation, 10000) + + compensator.compute(1000, 0) shouldBe intArrayOf(1000) + compensator.compute(0, 1000) shouldBe intArrayOf(0) + compensator.compute(1000, 0) shouldBe intArrayOf(1100) + compensator.compute(0, 1100) shouldBe intArrayOf(100) + } + + @Test + fun overshootIn() { + val compensation = BacklashCompensation(BacklashCompensationMode.OVERSHOOT, 100, 0) + val compensator = BacklashCompensator(compensation, 10000) + + compensator.compute(1000, 0) shouldBe intArrayOf(1000) + compensator.compute(100, 1000) shouldBe intArrayOf(0, 100) + compensator.compute(1000, 0) shouldBe intArrayOf(1000) + compensator.compute(0, 1000) shouldBe intArrayOf(0) + } + + @Test + fun overshootOut() { + val compensation = BacklashCompensation(BacklashCompensationMode.OVERSHOOT, 0, 100) + val compensator = BacklashCompensator(compensation, 10000) + + compensator.compute(1000, 0) shouldBe intArrayOf(1100, 1000) + compensator.compute(0, 1000) shouldBe intArrayOf(0) + compensator.compute(1000, 0) shouldBe intArrayOf(1100, 1000) + compensator.compute(0, 1000) shouldBe intArrayOf(0) + } +} diff --git a/build.gradle.kts b/build.gradle.kts index a6da68a50..d8b61c18f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile buildscript { dependencies { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.21") - classpath("io.objectbox:objectbox-gradle-plugin:4.0.2") + classpath("io.objectbox:objectbox-gradle-plugin:4.0.3") classpath("com.gradleup.shadow:shadow-gradle-plugin:8.3.3") } diff --git a/desktop/README.md b/desktop/README.md index 4f2e23a1f..f08dab14f 100644 --- a/desktop/README.md +++ b/desktop/README.md @@ -77,7 +77,3 @@ The complete integrated solution for all of your astronomical imaging needs. ## Settings ![](settings.png) - -## Support me - -[![](src/assets/images/donate-with-paypal-blue.svg)](https://www.paypal.com/donate/?hosted_button_id=U8TGGJTKSZUCA) diff --git a/desktop/package-lock.json b/desktop/package-lock.json index c2dbacc27..346cb0356 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -37,15 +37,15 @@ }, "devDependencies": { "@angular-builders/custom-webpack": "18.0.0", - "@angular-devkit/build-angular": "18.2.8", - "@angular/cli": "18.2.8", + "@angular-devkit/build-angular": "18.2.9", + "@angular/cli": "18.2.9", "@angular/compiler-cli": "18.2.8", "@angular/language-service": "18.2.8", "@eslint/js": "9.12.0", "@types/eslint__js": "8.42.3", "@types/leaflet": "1.9.12", - "@types/node": "22.7.5", - "electron": "33.0.0", + "@types/node": "22.7.6", + "electron": "33.0.1", "electron-builder": "25.1.8", "eslint": "9.12.0", "node-polyfill-webpack-plugin": "4.0.0", @@ -111,13 +111,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1802.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.8.tgz", - "integrity": "sha512-/rtFQEKgS7LlB9oHr4NCBSdKnvP5kr8L5Hbd3Vl8hZOYK9QWjxKPEXnryA2d5+PCE98bBzZswCNXqELZCPTgIQ==", + "version": "0.1802.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1802.9.tgz", + "integrity": "sha512-fubJf4WC/t3ITy+tyjI4/CKKwUP4XJTmV+Y0nyPcrkcthVyUcIpZB74NlUOvg6WECiPQuIc+CtoAaA9X5+RQ5Q==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.8", + "@angular-devkit/core": "18.2.9", "rxjs": "7.8.1" }, "engines": { @@ -127,17 +126,16 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.8.tgz", - "integrity": "sha512-qK/iLk7A8vQp1CyiJV4DpwfLjPKoiOlTtFqoO5vD8Tyxmc+R06FQp6GJTsZ7JtrTLYSiH+QAWiY6NgF/Rj/hHg==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.2.9.tgz", + "integrity": "sha512-d4W6t9vBozFUmOP2VvihMcSg/zgr3AvJY6/b7OPuATlK+W3P6tmsqxGIQ6eKc1TxXeu3lWhi14mV2pPykfrwfA==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.8", - "@angular-devkit/build-webpack": "0.1802.8", - "@angular-devkit/core": "18.2.8", - "@angular/build": "18.2.8", + "@angular-devkit/architect": "0.1802.9", + "@angular-devkit/build-webpack": "0.1802.9", + "@angular-devkit/core": "18.2.9", + "@angular/build": "18.2.9", "@babel/core": "7.25.2", "@babel/generator": "7.25.0", "@babel/helper-annotate-as-pure": "7.24.7", @@ -148,7 +146,7 @@ "@babel/preset-env": "7.25.3", "@babel/runtime": "7.25.0", "@discoveryjs/json-ext": "0.6.1", - "@ngtools/webpack": "18.2.8", + "@ngtools/webpack": "18.2.9", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.20", @@ -409,13 +407,12 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1802.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.8.tgz", - "integrity": "sha512-uPpopkXkO66SSdjtVr7xCyQCPs/x6KUC76xkDc4j0b8EEHifTbi/fNpbkcZ6wBmoAfjKLWXfKvtkh0TqKK5Hkw==", + "version": "0.1802.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1802.9.tgz", + "integrity": "sha512-p7xNGo5ZTV/Z0Rk+q2/E68QQLw9VT33kauDh6s010jIeBLrOwMo74JpzXMSFttQo5O4bLKP8IORzIM+0q7Uzjg==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.8", + "@angular-devkit/architect": "0.1802.9", "rxjs": "7.8.1" }, "engines": { @@ -429,11 +426,10 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.8.tgz", - "integrity": "sha512-4o2T6wsmXGE/v53+F8L7kGoN2+qzt03C9rtjLVQpOljzpJVttQ8bhvfWxyYLWwcl04RWqRa+82fpIZtBkOlZJw==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.2.9.tgz", + "integrity": "sha512-bsVt//5E0ua7FZfO0dCF/qGGY6KQD34/bNGyRu5B6HedimpdU2/0PGDptksU5v3yKEc9gNw0xC6mT0UsY/R9pA==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -457,13 +453,12 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.8.tgz", - "integrity": "sha512-i/h2Oji5FhJMC7wDSnIl5XUe/qym+C1ZwScaATJwDyRLCUIynZkj5rLgdG/uK6l+H0PgvxigkF+akWpokkwW6w==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.2.9.tgz", + "integrity": "sha512-aIY5/IomDOINGCtFYi77uo0acDpdQNNCighfBBUGEBNMQ1eE3oGNGpLAH/qWeuxJndgmxrdKsvws9DdT46kLig==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.8", + "@angular-devkit/core": "18.2.9", "jsonc-parser": "3.3.1", "magic-string": "0.30.11", "ora": "5.4.1", @@ -491,14 +486,13 @@ } }, "node_modules/@angular/build": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.8.tgz", - "integrity": "sha512-ufuA4vHJSrL9SQW7bKV61DOoN1mm0t0ILTHaxSoCG3YF70cZJOX7+HNp3cK2uoldRMwbTOKSvCWBw54KKDRd5Q==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.2.9.tgz", + "integrity": "sha512-o1hOEM2e6ARy+ck2Pohl0d/RFgbbXTw6/hTLAj3CBKjtqAGStRaVF2UlJjhi+xOxlfsOPuJJc9IpzLBteku+Ag==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1802.8", + "@angular-devkit/architect": "0.1802.9", "@babel/core": "7.25.2", "@babel/helper-annotate-as-pure": "7.24.7", "@babel/helper-split-export-declaration": "7.24.7", @@ -577,18 +571,17 @@ } }, "node_modules/@angular/cli": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.8.tgz", - "integrity": "sha512-GKXG7F7z5rxwZ8/bnW/Bp8/zsfE/BpHmIP/icLfUIOwv2kaY5OD2tfQssWXPEuqZzYq2AYz+wjVSbWjxGoja8A==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.2.9.tgz", + "integrity": "sha512-ejTIqwvPABwK7MtVmI2qWbEaMhhbHNsq0NPzl1hwLtkrLbjdDrEVv0Wy+gN0xqrT9NyCPl4AmNLz/xuYTzgU5g==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.1802.8", - "@angular-devkit/core": "18.2.8", - "@angular-devkit/schematics": "18.2.8", + "@angular-devkit/architect": "0.1802.9", + "@angular-devkit/core": "18.2.9", + "@angular-devkit/schematics": "18.2.9", "@inquirer/prompts": "5.3.8", "@listr2/prompt-adapter-inquirer": "2.0.15", - "@schematics/angular": "18.2.8", + "@schematics/angular": "18.2.9", "@yarnpkg/lockfile": "1.1.0", "ini": "4.1.3", "jsonc-parser": "3.3.1", @@ -898,7 +891,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -1202,7 +1194,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.7" }, @@ -3268,7 +3259,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -3285,7 +3275,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3302,7 +3291,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3319,7 +3307,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -3336,7 +3323,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3353,7 +3339,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -3370,7 +3355,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3387,7 +3371,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -3404,7 +3387,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3421,7 +3403,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3438,7 +3419,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3455,7 +3435,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3472,7 +3451,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3489,7 +3467,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3506,7 +3483,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3523,7 +3499,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3540,7 +3515,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -3557,7 +3531,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -3574,7 +3547,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3591,7 +3563,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -3608,7 +3579,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -3625,7 +3595,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -3642,7 +3611,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -3659,7 +3627,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -4365,7 +4332,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/base64/-/base64-1.1.2.tgz", "integrity": "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -4382,7 +4348,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/json-pack/-/json-pack-1.1.0.tgz", "integrity": "sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/base64": "^1.1.1", "@jsonjoy.com/util": "^1.1.2", @@ -4405,7 +4370,6 @@ "resolved": "https://registry.npmjs.org/@jsonjoy.com/util/-/util-1.5.0.tgz", "integrity": "sha512-ojoNsrIuPI9g6o8UxhraZQSyF2ByJanAY4cTFbc8Mf2AXEF4aQRGY1dJxyJpuyav8r9FGflEt/Ff3u5Nt6YMPA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -4427,8 +4391,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@listr2/prompt-adapter-inquirer": { "version": "2.0.15", @@ -4454,7 +4417,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -4468,7 +4430,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -4482,7 +4443,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -4496,7 +4456,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -4510,7 +4469,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -4524,7 +4482,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -4617,7 +4574,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -4631,7 +4587,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -4645,7 +4600,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -4659,7 +4613,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -4673,7 +4626,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -4687,18 +4639,16 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@ngtools/webpack": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.8.tgz", - "integrity": "sha512-sq0kI8gEen4QlM6X8XqOYy7j4B8iLCYNo+iKxatV36ts4AXH0MuVkP56+oMaoH5oZNoSqd0RlfnotEHfvJAr8A==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.2.9.tgz", + "integrity": "sha512-/apDvs4qevjSWoYw3h3/c/mILFrf2EgCJfBy9f3E7PEgi2tjifOIszBRrLQkVpeHAaFgEH8zKS2ol0hAmOl8sw==", "dev": true, - "license": "MIT", "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", @@ -5342,7 +5292,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -5356,7 +5305,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -5370,7 +5318,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5384,7 +5331,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5398,7 +5344,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5412,7 +5357,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5426,7 +5370,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5440,7 +5383,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5454,7 +5396,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5468,7 +5409,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5482,7 +5422,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5496,7 +5435,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5510,7 +5448,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5524,7 +5461,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5538,7 +5474,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5552,7 +5487,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5587,14 +5521,13 @@ } }, "node_modules/@schematics/angular": { - "version": "18.2.8", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.8.tgz", - "integrity": "sha512-62Sr7/j/dlhZorxH4GzQgpJy0s162BVts0Q7knZuEacP4VL+IWOUE1NS9OFkh/cbomoyXBdoewkZ5Zd1dVX78w==", + "version": "18.2.9", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.2.9.tgz", + "integrity": "sha512-LlMHZQ6f8zrqSK24OBXi4u2MTNHNu9ZN6JXpbElq0bz/9QkUR2zy+Kk2wLpPxCwXYTZby7/xgHiTzXvG+zTdhw==", "dev": true, - "license": "MIT", "dependencies": { - "@angular-devkit/core": "18.2.8", - "@angular-devkit/schematics": "18.2.8", + "@angular-devkit/core": "18.2.9", + "@angular-devkit/schematics": "18.2.9", "jsonc-parser": "3.3.1" }, "engines": { @@ -6026,7 +5959,6 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -6037,7 +5969,6 @@ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6060,7 +5991,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6070,7 +6000,6 @@ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, - "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -6118,7 +6047,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -6131,7 +6059,6 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz", "integrity": "sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6144,7 +6071,6 @@ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -6189,8 +6115,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/http-proxy": { "version": "1.17.15", @@ -6233,8 +6158,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/minimatch": { "version": "5.1.2", @@ -6259,11 +6183,10 @@ } }, "node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "version": "22.7.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.6.tgz", + "integrity": "sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==", "dev": true, - "license": "MIT", "dependencies": { "undici-types": "~6.19.2" } @@ -6273,7 +6196,6 @@ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6293,15 +6215,13 @@ "version": "6.9.16", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/responselike": { "version": "1.0.3", @@ -6317,15 +6237,13 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -6336,7 +6254,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -6346,7 +6263,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -6358,7 +6274,6 @@ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6382,7 +6297,6 @@ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz", "integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6612,7 +6526,6 @@ "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.6.0" }, @@ -6841,7 +6754,6 @@ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, - "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -7055,7 +6967,6 @@ "engines": [ "node >= 0.8.0" ], - "license": "Apache-2.0", "bin": { "ansi-html": "bin/ansi-html" } @@ -7334,8 +7245,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", @@ -7612,8 +7522,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/bezier-easing": { "version": "2.1.0", @@ -7683,7 +7592,6 @@ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -7708,7 +7616,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7718,7 +7625,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -7728,7 +7634,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -7740,15 +7645,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/bonjour-service": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" @@ -7758,8 +7661,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/boolean": { "version": "3.2.0", @@ -8169,7 +8071,6 @@ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, - "license": "MIT", "dependencies": { "run-applescript": "^7.0.0" }, @@ -8185,7 +8086,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8738,7 +8638,6 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -8751,7 +8650,6 @@ "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -8770,7 +8668,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -8779,15 +8676,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/compression/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/concat-map": { "version": "0.0.1", @@ -8855,7 +8750,6 @@ "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.8" } @@ -8884,7 +8778,6 @@ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -8897,7 +8790,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8914,7 +8806,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -8923,8 +8814,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/copy-anything": { "version": "2.0.6", @@ -9108,7 +8998,6 @@ "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.24.tgz", "integrity": "sha512-Oyqew0FGM0wYUSNqR0L6AteO5MpMoUU0rhKRieXeiKs+PmRTxiJMyaunYB2KF6fQ3dzChXKCpbFOEJx3OQ1v/Q==", "dev": true, - "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^5.1.0", @@ -9124,7 +9013,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -9140,7 +9028,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9157,7 +9044,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9169,15 +9055,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -9187,7 +9071,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -9320,7 +9203,6 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -9356,7 +9238,6 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -9490,7 +9371,6 @@ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", "dev": true, - "license": "MIT", "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" @@ -9507,7 +9387,6 @@ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -9520,7 +9399,6 @@ "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "execa": "^5.0.0" }, @@ -9574,7 +9452,6 @@ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -9621,7 +9498,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9642,7 +9518,6 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -9833,7 +9708,6 @@ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -9846,7 +9720,6 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -9879,15 +9752,13 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ], - "license": "BSD-2-Clause" + ] }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.3.0" }, @@ -9903,7 +9774,6 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -9951,8 +9821,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/ejs": { "version": "3.1.10", @@ -9970,9 +9839,9 @@ } }, "node_modules/electron": { - "version": "33.0.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-33.0.0.tgz", - "integrity": "sha512-OdLLR/zAVuNfKahSSYokZmSi7uK2wEYTbCoiIdqWLsOWmCqO9j0JC2XkYQmXQcAk2BJY0ri4lxwAfc5pzPDYsA==", + "version": "33.0.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-33.0.1.tgz", + "integrity": "sha512-PipPnWH4gvf7o+P8jlKQZGgPfb5eHcLgTrnKkFzb98MXhyPjVJYCR7YWqcawZ8IfyJCut8vMxLuBFLT1Ag8TSQ==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -10359,7 +10228,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -10617,7 +10485,6 @@ "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -10678,8 +10545,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/escape-string-regexp": { "version": "1.0.5", @@ -10988,7 +10854,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11036,7 +10901,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11060,7 +10924,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -11073,7 +10936,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -11088,8 +10950,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/exponential-backoff": { "version": "3.1.1", @@ -11103,7 +10964,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -11146,7 +11006,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -11155,8 +11014,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/external-editor": { "version": "3.1.0", @@ -11290,7 +11148,6 @@ "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", "dev": true, - "license": "Apache-2.0", "dependencies": { "websocket-driver": ">=0.5.1" }, @@ -11360,7 +11217,6 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", @@ -11379,7 +11235,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -11388,8 +11243,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/find-cache-dir": { "version": "4.0.0", @@ -11524,7 +11378,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11554,7 +11407,6 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -11972,8 +11824,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/has-bigints": { "version": "1.0.2", @@ -12150,7 +12001,6 @@ "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, - "license": "MIT", "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", @@ -12162,15 +12012,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -12185,15 +12033,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -12212,8 +12058,7 @@ "type": "patreon", "url": "https://patreon.com/mdevils" } - ], - "license": "MIT" + ] }, "node_modules/htmlparser2": { "version": "8.0.2", @@ -12227,7 +12072,6 @@ "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -12246,15 +12090,13 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -12270,8 +12112,7 @@ "version": "0.5.8", "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-proxy": { "version": "1.18.1", @@ -12360,7 +12201,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -12379,7 +12219,6 @@ "resolved": "https://registry.npmjs.org/hyperdyperid/-/hyperdyperid-1.2.0.tgz", "integrity": "sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.18" } @@ -12613,7 +12452,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 10" } @@ -12780,7 +12618,6 @@ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, - "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -12845,7 +12682,6 @@ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, - "license": "MIT", "dependencies": { "is-docker": "^3.0.0" }, @@ -12911,7 +12747,6 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "dev": true, - "license": "MIT", "engines": { "node": ">=16" }, @@ -13009,7 +12844,6 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -13103,7 +12937,6 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" }, @@ -13547,7 +13380,6 @@ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", "dev": true, - "license": "MIT", "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" @@ -13899,7 +13731,6 @@ "integrity": "sha512-UGe+BbaSUQtAMZobTb4nHvFMrmvuAQKSeaqAX2meTEQjfsbpl5sxdHD8T72OnwD4GU9uwNhYXIVe4QGs8N9Zyw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "dependencies": { "msgpackr": "^1.10.2", "node-addon-api": "^6.1.0", @@ -13923,8 +13754,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/load-json-file": { "version": "4.0.0", @@ -14488,17 +14318,15 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/memfs": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.13.0.tgz", - "integrity": "sha512-dIs5KGy24fbdDhIAg0RxXpFqQp3RwL6wgSMRF9OSuphL/Uc9a4u2/SDJKPLj/zUgtOGKuHrRMrj563+IErj4Cg==", + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", + "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3", "@jsonjoy.com/util": "^1.3.0", @@ -14527,7 +14355,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" } @@ -14554,7 +14381,6 @@ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -14875,7 +14701,6 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -14892,7 +14717,6 @@ "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.0.tgz", "integrity": "sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==", "dev": true, - "license": "MIT", "optionalDependencies": { "msgpackr-extract": "^3.0.2" } @@ -14903,7 +14727,6 @@ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { "node-gyp-build-optional-packages": "5.2.2" @@ -14925,7 +14748,6 @@ "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -15032,7 +14854,6 @@ "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", "dev": true, "hasInstallScript": true, - "license": "MIT", "optional": true, "os": [ "!win32" @@ -15047,7 +14868,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "license": "MIT", "optional": true }, "node_modules/nice-try": { @@ -15090,7 +14910,6 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, - "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } @@ -15125,7 +14944,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", "dev": true, - "license": "MIT", "optional": true, "bin": { "node-gyp-build": "bin.js", @@ -15138,7 +14956,6 @@ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, - "license": "MIT", "dependencies": { "detect-libc": "^2.0.1" }, @@ -15779,7 +15596,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -15808,7 +15624,6 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -15888,15 +15703,13 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -15909,7 +15722,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -15945,7 +15757,6 @@ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", "dev": true, - "license": "MIT", "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", @@ -16131,8 +15942,7 @@ "version": "1.5.2", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.2.tgz", "integrity": "sha512-JTo+4+4Fw7FreyAvlSLjb1BBVaxEQAacmjD3jjuyPZclpbEghTvQZbXBb2qPd2LeIMxiHwXBZUcpmG2Gl/mDEA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/os-browserify": { "version": "0.3.0", @@ -16223,7 +16033,6 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, - "license": "MIT", "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -16241,7 +16050,6 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -16544,7 +16352,6 @@ "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", "dev": true, - "license": "MIT", "dependencies": { "entities": "^4.3.0", "parse5": "^7.0.0", @@ -16559,7 +16366,6 @@ "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", "dev": true, - "license": "MIT", "dependencies": { "parse5": "^7.0.0" }, @@ -16572,7 +16378,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -16658,8 +16463,7 @@ "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/path-type": { "version": "5.0.0", @@ -16761,7 +16565,6 @@ "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.6.1.tgz", "integrity": "sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==", "dev": true, - "license": "MIT", "optionalDependencies": { "nice-napi": "^1.0.2" } @@ -16959,8 +16762,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/postcss-modules-extract-imports": { "version": "3.1.0", @@ -17168,7 +16970,6 @@ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -17182,7 +16983,6 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.10" } @@ -17330,7 +17130,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -17340,7 +17139,6 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -17356,7 +17154,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -17366,7 +17163,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -17907,7 +17703,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz", "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==", "dev": true, - "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -17942,15 +17737,13 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -18173,8 +17966,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/selecto": { "version": "1.26.3", @@ -18199,7 +17991,6 @@ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node-forge": "^1.3.0", "node-forge": "^1" @@ -18234,7 +18025,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -18259,7 +18049,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -18268,15 +18057,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/send/node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -18286,7 +18073,6 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -18340,7 +18126,6 @@ "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, - "license": "MIT", "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", @@ -18359,7 +18144,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -18369,7 +18153,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -18379,7 +18162,6 @@ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, - "license": "MIT", "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -18394,29 +18176,25 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/serve-index/node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -18426,7 +18204,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, - "license": "MIT", "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -18488,8 +18265,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/sha.js": { "version": "2.4.11", @@ -18694,7 +18470,6 @@ "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", "dev": true, - "license": "MIT", "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", @@ -18845,7 +18620,6 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", @@ -18862,7 +18636,6 @@ "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", @@ -18905,7 +18678,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -19088,7 +18860,6 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -19388,7 +19159,6 @@ "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", "integrity": "sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==", "dev": true, - "license": "Unlicense", "engines": { "node": ">=10.18" }, @@ -19400,8 +19170,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/timers-browserify": { "version": "2.0.12", @@ -19475,7 +19244,6 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.6" } @@ -19485,7 +19253,6 @@ "resolved": "https://registry.npmjs.org/tree-dump/-/tree-dump-1.0.2.tgz", "integrity": "sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.0" }, @@ -19843,7 +19610,6 @@ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -20092,7 +19858,6 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -20191,7 +19956,6 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -20201,7 +19965,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -20239,7 +20002,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -20264,7 +20026,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz", "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==", "dev": true, - "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -20327,7 +20088,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -20344,7 +20104,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -20361,7 +20120,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -20378,7 +20136,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -20395,7 +20152,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -20412,7 +20168,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -20429,7 +20184,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -20446,7 +20200,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -20463,7 +20216,6 @@ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20480,7 +20232,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20497,7 +20248,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20514,7 +20264,6 @@ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20531,7 +20280,6 @@ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20548,7 +20296,6 @@ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20565,7 +20312,6 @@ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20582,7 +20328,6 @@ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20599,7 +20344,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -20616,7 +20360,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -20633,7 +20376,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -20650,7 +20392,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -20667,7 +20408,6 @@ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -20684,7 +20424,6 @@ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -20701,7 +20440,6 @@ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -20716,7 +20454,6 @@ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -20768,7 +20505,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.0", @@ -20824,7 +20560,6 @@ "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", "dev": true, - "license": "MIT", "dependencies": { "minimalistic-assert": "^1.0.0" } @@ -20843,8 +20578,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/webpack": { "version": "5.95.0", @@ -20899,7 +20633,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.2.tgz", "integrity": "sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", "memfs": "^4.6.0", @@ -20929,7 +20662,6 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, - "license": "MIT", "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -20989,7 +20721,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -21010,7 +20741,6 @@ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", @@ -21035,7 +20765,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -21051,7 +20780,6 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } @@ -21061,7 +20789,6 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, - "license": "ISC", "dependencies": { "glob": "^10.3.7" }, @@ -21215,7 +20942,6 @@ "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, - "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", @@ -21230,7 +20956,6 @@ "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=0.8.0" } @@ -21438,7 +21163,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.0.0" }, diff --git a/desktop/package.json b/desktop/package.json index d855fd70b..9b1aa0c72 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -62,15 +62,15 @@ }, "devDependencies": { "@angular-builders/custom-webpack": "18.0.0", - "@angular-devkit/build-angular": "18.2.8", - "@angular/cli": "18.2.8", + "@angular-devkit/build-angular": "18.2.9", + "@angular/cli": "18.2.9", "@angular/compiler-cli": "18.2.8", "@angular/language-service": "18.2.8", "@eslint/js": "9.12.0", "@types/eslint__js": "8.42.3", "@types/leaflet": "1.9.12", - "@types/node": "22.7.5", - "electron": "33.0.0", + "@types/node": "22.7.6", + "electron": "33.0.1", "electron-builder": "25.1.8", "eslint": "9.12.0", "node-polyfill-webpack-plugin": "4.0.0", diff --git a/desktop/src/app/about/about.component.html b/desktop/src/app/about/about.component.html index 7c59df1fe..f9286cbb8 100644 --- a/desktop/src/app/about/about.component.html +++ b/desktop/src/app/about/about.component.html @@ -83,5 +83,12 @@ src="assets/images/donate-with-paypal-blue.svg" style="height: 31px" /> + + + diff --git a/desktop/src/app/atlas/atlas.component.ts b/desktop/src/app/atlas/atlas.component.ts index 81dacb000..1077494b8 100644 --- a/desktop/src/app/atlas/atlas.component.ts +++ b/desktop/src/app/atlas/atlas.component.ts @@ -172,6 +172,16 @@ export class AtlasComponent implements OnInit, AfterContentInit, AfterViewInit, pointRadius: 0, pointHitRadius: 0, }, + // Now. + { + type: 'line', + fill: true, + backgroundColor: '#D50000', + borderColor: '#D50000', + data: [], + pointRadius: 0, + pointHitRadius: 0, + }, // Altitude. { type: 'line', @@ -201,6 +211,15 @@ export class AtlasComponent implements OnInit, AfterContentInit, AfterViewInit, if (context.datasetIndex <= 7 && context.dataIndex === 1) { return '' } + if (context.datasetIndex === 9) { + if (this.dateTimeAndLocation.manual) { + const hour = TWO_DIGITS_FORMATTER.format(this.dateTimeAndLocation.dateTime.getHours()) + const minute = TWO_DIGITS_FORMATTER.format(this.dateTimeAndLocation.dateTime.getMinutes()) + return `${hour}:${minute}` + } else { + return 'now' + } + } const hours = (context.parsed.x + 12) % 24 const minutes = (hours - Math.trunc(hours)) * 60 @@ -267,6 +286,7 @@ export class AtlasComponent implements OnInit, AfterContentInit, AfterViewInit, }, x: { type: 'linear', + position: 'bottom', min: 0, max: 24.0, border: { @@ -686,6 +706,8 @@ export class AtlasComponent implements OnInit, AfterContentInit, AfterViewInit, this.app.subTitle = `${location.name} · ${extractDate(dateTime)} ${extractTime(dateTime, false)}` + this.updateNow(dateTime) + try { // Sun. if (this.tab === BodyTabType.SUN) { @@ -846,12 +868,22 @@ export class AtlasComponent implements OnInit, AfterContentInit, AfterViewInit, } } + private updateNow(date: Date = new Date()) { + const hour = (date.getHours() + 12) % 24 + const minute = date.getMinutes() / 60 + + this.altitudeData.datasets[9].data = [ + [hour + minute - 0.0083333 * 4, 90.0], + [hour + minute + 0.0083333 * 4, 90.0], + ] + } + private updateAltitudeDataPoints(points?: AltitudeDataPoint[]) { if (points?.length) { AtlasComponent.removePointsBelowZero(points) - this.altitudeData.datasets[9].data = points + this.altitudeData.datasets[10].data = points } else { - this.altitudeData.datasets[9].data = [] + this.altitudeData.datasets[10].data = [] } } diff --git a/desktop/src/app/filterwheel/filterwheel.component.html b/desktop/src/app/filterwheel/filterwheel.component.html index af7ca77ad..609629f40 100644 --- a/desktop/src/app/filterwheel/filterwheel.component.html +++ b/desktop/src/app/filterwheel/filterwheel.component.html @@ -125,10 +125,15 @@ (onChange)="shutterToggled(filter, $event)" label="Shutter" /> + +
() private readonly filterSubscription?: Subscription @@ -47,6 +47,10 @@ export class FilterWheelComponent implements AfterContentInit, OnDestroy, Tickab return this.mode === 'CAPTURE' } + get canChangeFocusOffset() { + return this.mode === 'CAPTURE' + } + get canEdit() { return this.mode === 'CAPTURE' } @@ -98,7 +102,7 @@ export class FilterWheelComponent implements AfterContentInit, OnDestroy, Tickab }) electronService.on('FOCUSER.DETACHED', (event) => { - if (event.device.id === this.focuser?.id) { + if (this.mode === 'CAPTURE' && event.device.id === this.focuser?.id) { ngZone.run(() => { this.focuser = undefined this.updateFocusOffset() @@ -181,11 +185,13 @@ export class FilterWheelComponent implements AfterContentInit, OnDestroy, Tickab this.ticker.register(this, 30000) }) - this.focusers = await this.api.focusers() + if (this.mode === 'CAPTURE') { + this.focusers = await this.api.focusers() - if (this.focusers.length === 1) { - this.focuser = this.focusers[0] - await this.focuserChanged() + if (this.focusers.length === 1 && !this.focuser) { + this.focuser = this.focusers[0] + await this.focuserChanged() + } } } @@ -203,7 +209,14 @@ export class FilterWheelComponent implements AfterContentInit, OnDestroy, Tickab private async loadCameraStartCaptureForDialogMode(data?: WheelDialogInput) { if (data) { this.mode = data.mode + this.focuser = data.focuser + await this.wheelChanged(data.wheel) + + if (this.focuser) { + await this.focuserChanged() + } + Object.assign(this.request, data.request) } } @@ -369,18 +382,17 @@ export class FilterWheelComponent implements AfterContentInit, OnDestroy, Tickab } private makeCameraStartCapture(): CameraStartCapture { - return { - ...this.request, - filterPosition: this.filter?.position ?? 0, - } + const filterPosition = this.filter?.position ?? 0 + const focusOffset = this.filter ? this.focusOffsetForFilter(this.filter) : 0 + return { ...this.request, filterPosition, focusOffset } } protected apply() { return this.app.close(this.makeCameraStartCapture()) } - static async showAsDialog(service: BrowserWindowService, mode: WheelMode, wheel: Wheel, request: CameraStartCapture) { - const result = await service.openWheelDialog({ mode, wheel, request }) + static async showAsDialog(service: BrowserWindowService, mode: WheelDialogMode, wheel: Wheel, request: CameraStartCapture, focuser?: Focuser) { + const result = await service.openWheelDialog({ mode, wheel, request, focuser }) if (result) { Object.assign(request, result) diff --git a/desktop/src/app/home/home.component.ts b/desktop/src/app/home/home.component.ts index e8152d598..e2dbaa690 100644 --- a/desktop/src/app/home/home.component.ts +++ b/desktop/src/app/home/home.component.ts @@ -628,6 +628,8 @@ export class HomeComponent implements AfterContentInit { connection.id = status.id connection.type = status.type connection.connected = true + connection.connectedAt = Date.now() + this.savePreference() this.connection = connection break } diff --git a/desktop/src/app/rotator/rotator.component.html b/desktop/src/app/rotator/rotator.component.html index 04ce4ca45..602e68067 100644 --- a/desktop/src/app/rotator/rotator.component.html +++ b/desktop/src/app/rotator/rotator.component.html @@ -44,7 +44,7 @@
Reversed
@@ -79,7 +79,7 @@ [max]="rotator.maxAngle" [showButtons]="true" styleClass="p-inputtext-sm border-0 max-w-full" - [(ngModel)]="preference.angle" + [(ngModel)]="angle" (ngModelChange)="savePreference()" [allowEmpty]="false" locale="en" @@ -87,7 +87,7 @@
+
+
+ +
+
diff --git a/desktop/src/app/rotator/rotator.component.ts b/desktop/src/app/rotator/rotator.component.ts index 51c51ad4b..db3a1aea0 100644 --- a/desktop/src/app/rotator/rotator.component.ts +++ b/desktop/src/app/rotator/rotator.component.ts @@ -1,10 +1,12 @@ import { AfterViewInit, Component, HostListener, NgZone, OnDestroy } from '@angular/core' import { ActivatedRoute } from '@angular/router' import { ApiService } from '../../shared/services/api.service' +import { BrowserWindowService } from '../../shared/services/browser-window.service' import { ElectronService } from '../../shared/services/electron.service' import { PreferenceService } from '../../shared/services/preference.service' import { Tickable, Ticker } from '../../shared/services/ticker.service' -import { DEFAULT_ROTATOR, DEFAULT_ROTATOR_PREFERENCE, Rotator } from '../../shared/types/rotator.types' +import { CameraStartCapture, DEFAULT_CAMERA_START_CAPTURE } from '../../shared/types/camera.types' +import { DEFAULT_ROTATOR, DEFAULT_ROTATOR_PREFERENCE, Rotator, RotatorDialogInput, RotatorDialogMode } from '../../shared/types/rotator.types' import { AppComponent } from '../app.component' @Component({ @@ -13,8 +15,36 @@ import { AppComponent } from '../app.component' }) export class RotatorComponent implements AfterViewInit, OnDestroy, Tickable { protected readonly rotator = structuredClone(DEFAULT_ROTATOR) + protected readonly request = structuredClone(DEFAULT_CAMERA_START_CAPTURE) protected readonly preference = structuredClone(DEFAULT_ROTATOR_PREFERENCE) + protected angle = 0 + protected mode: RotatorDialogMode = 'CAPTURE' + + get canAbort() { + return this.mode === 'CAPTURE' && this.rotator.canAbort + } + + get canHome() { + return this.mode === 'CAPTURE' && this.rotator.canHome + } + + get canReverse() { + return this.mode === 'CAPTURE' && this.rotator.canReverse + } + + get canSync() { + return this.mode === 'CAPTURE' && this.rotator.canSync + } + + get canMove() { + return this.mode === 'CAPTURE' + } + + get canApply() { + return this.mode !== 'CAPTURE' + } + constructor( private readonly app: AppComponent, private readonly api: ApiService, @@ -46,8 +76,14 @@ export class RotatorComponent implements AfterViewInit, OnDestroy, Tickable { ngAfterViewInit() { this.route.queryParams.subscribe(async (e) => { - const data = JSON.parse(decodeURIComponent(e['data'] as string)) as Rotator - await this.rotatorChanged(data) + const data = JSON.parse(decodeURIComponent(e['data'] as string)) as unknown + + if (this.app.modal) { + await this.loadCameraStartCaptureForDialogMode(data as RotatorDialogInput) + } else { + await this.rotatorChanged(data as Rotator) + } + this.ticker.register(this, 30000) }) } @@ -64,6 +100,15 @@ export class RotatorComponent implements AfterViewInit, OnDestroy, Tickable { } } + private async loadCameraStartCaptureForDialogMode(data?: RotatorDialogInput) { + if (data) { + this.mode = data.mode + await this.rotatorChanged(data.rotator) + this.angle = Math.max(this.rotator.minAngle, Math.min(data.request.angle, this.rotator.maxAngle)) + Object.assign(this.request, data.request) + } + } + protected async rotatorChanged(rotator?: Rotator) { if (rotator?.id) { rotator = await this.api.rotator(rotator.id) @@ -107,14 +152,35 @@ export class RotatorComponent implements AfterViewInit, OnDestroy, Tickable { private update() {} private loadPreference() { - if (this.rotator.id) { + if (this.mode === 'CAPTURE' && this.rotator.id) { Object.assign(this.preference, this.preferenceService.rotator(this.rotator).get()) + this.angle = this.preference.angle } } protected savePreference() { - if (this.rotator.connected) { + if (this.mode === 'CAPTURE' && this.rotator.connected) { + this.preference.angle = this.angle this.preferenceService.rotator(this.rotator).set(this.preference) } } + + private makeCameraStartCapture(): CameraStartCapture { + return { ...this.request, angle: this.angle } + } + + protected apply() { + return this.app.close(this.makeCameraStartCapture()) + } + + static async showAsDialog(service: BrowserWindowService, mode: RotatorDialogMode, rotator: Rotator, request: CameraStartCapture) { + const result = await service.openRotatorDialog({ mode, rotator, request }) + + if (result) { + Object.assign(request, result) + return true + } else { + return false + } + } } diff --git a/desktop/src/app/sequencer/sequencer.component.html b/desktop/src/app/sequencer/sequencer.component.html index 038eb1802..914e07c23 100644 --- a/desktop/src/app/sequencer/sequencer.component.html +++ b/desktop/src/app/sequencer/sequencer.component.html @@ -130,14 +130,15 @@ [text]="true" (onClick)="showWheelDialog(sequence)" size="small" /> - + [text]="true" + (onClick)="showRotatorDialog(sequence)" + size="small" />
diff --git a/desktop/src/app/sequencer/sequencer.component.ts b/desktop/src/app/sequencer/sequencer.component.ts index 7a1e2b215..67236da68 100644 --- a/desktop/src/app/sequencer/sequencer.component.ts +++ b/desktop/src/app/sequencer/sequencer.component.ts @@ -25,6 +25,7 @@ import { deviceComparator, textComparator } from '../../shared/utils/comparators import { AppComponent } from '../app.component' import { CameraComponent } from '../camera/camera.component' import { FilterWheelComponent } from '../filterwheel/filterwheel.component' +import { RotatorComponent } from '../rotator/rotator.component' @Component({ selector: 'neb-sequencer', @@ -478,7 +479,13 @@ export class SequencerComponent implements AfterContentInit, OnDestroy, Tickable } protected async showWheelDialog(sequence: Sequence) { - if (this.plan.wheel && (await FilterWheelComponent.showAsDialog(this.browserWindowService, 'SEQUENCER', this.plan.wheel, sequence))) { + if (this.plan.wheel && (await FilterWheelComponent.showAsDialog(this.browserWindowService, 'SEQUENCER', this.plan.wheel, sequence, this.plan.focuser))) { + this.savePreference() + } + } + + protected async showRotatorDialog(sequence: Sequence) { + if (this.plan.rotator && (await RotatorComponent.showAsDialog(this.browserWindowService, 'SEQUENCER', this.plan.rotator, sequence))) { this.savePreference() } } @@ -635,12 +642,28 @@ export class SequencerComponent implements AfterContentInit, OnDestroy, Tickable this.savePreference() } + protected angleRemoved(sequence: Sequence) { + sequence.angle = -1 + this.savePreference() + } + protected async start() { if (this.plan.camera) { for (let i = 0; i < this.cameraExposures.length; i++) { this.cameraExposures.get(i)?.reset() } + // FOCUS OFFSET + if (this.plan.wheel && this.plan.focuser) { + const offsets = this.preferenceService.focusOffsets(this.plan.wheel, this.plan.focuser).get() + + for (const sequence of this.plan.sequences) { + if (sequence.filterPosition > 0) { + sequence.focusOffset = offsets[sequence.filterPosition - 1] || 0 + } + } + } + Object.assign(this.plan.liveStacking, this.preferenceService.settings.get().liveStacker[this.plan.liveStacking.type]) await this.browserWindowService.openCameraImage(this.plan.camera, 'SEQUENCER') diff --git a/desktop/src/shared/components/camera-info/camera-info.component.html b/desktop/src/shared/components/camera-info/camera-info.component.html index 7410541c1..8aa2004d4 100644 --- a/desktop/src/shared/components/camera-info/camera-info.component.html +++ b/desktop/src/shared/components/camera-info/camera-info.component.html @@ -49,16 +49,38 @@
+ class="flex flex-row gap-1 align-items-center relative">
{{ filter }}
+
+ + {{ info.focusOffset }} +
+
+
+ + {{ info.angle.toFixed(1) }}° +
+ +
diff --git a/desktop/src/shared/components/camera-info/camera-info.component.ts b/desktop/src/shared/components/camera-info/camera-info.component.ts index 5faa3942c..d0fc605ae 100644 --- a/desktop/src/shared/components/camera-info/camera-info.component.ts +++ b/desktop/src/shared/components/camera-info/camera-info.component.ts @@ -1,5 +1,7 @@ import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core' import type { CameraStartCapture } from '../../types/camera.types' +import type { Focuser } from '../../types/focuser.types' +import type { Rotator } from '../../types/rotator.types' import type { Wheel } from '../../types/wheel.types' @Component({ @@ -14,6 +16,12 @@ export class CameraInfoComponent { @Input() protected readonly wheel?: Wheel + @Input() + protected readonly focuser?: Focuser + + @Input() + protected readonly rotator?: Rotator + @Input() protected readonly hasType: boolean = true @@ -26,6 +34,12 @@ export class CameraInfoComponent { @Output() protected readonly filterRemoved = new EventEmitter() + @Input() + protected readonly canRemoveAngle = false + + @Output() + protected readonly angleRemoved = new EventEmitter() + @Input() protected readonly disabled?: boolean = false diff --git a/desktop/src/shared/services/browser-window.service.ts b/desktop/src/shared/services/browser-window.service.ts index e74e47959..d09b38da4 100644 --- a/desktop/src/shared/services/browser-window.service.ts +++ b/desktop/src/shared/services/browser-window.service.ts @@ -9,7 +9,7 @@ import { LoadFraming } from '../types/framing.types' import { ImageSource, OpenImage } from '../types/image.types' import { LightBox } from '../types/lightbox.types' import { Mount } from '../types/mount.types' -import { Rotator } from '../types/rotator.types' +import { Rotator, RotatorDialogInput } from '../types/rotator.types' import { Wheel, WheelDialogInput } from '../types/wheel.types' import { Undefinable } from '../utils/types' import { ElectronService } from './electron.service' @@ -40,12 +40,7 @@ export class BrowserWindowService { openCameraDialog(data: CameraDialogInput, preference: WindowPreference = {}) { Object.assign(preference, { icon: 'camera', width: 400, height: 424 }) - return this.openModal({ - preference, - data, - id: `camera.${data.camera.name}.modal`, - path: 'camera', - }) + return this.openModal({ preference, data, id: `camera.${data.camera.name}.modal`, path: 'camera' }) } openFocuser(data: Focuser, preference: WindowPreference = {}) { @@ -75,12 +70,12 @@ export class BrowserWindowService { openWheelDialog(data: WheelDialogInput, preference: WindowPreference = {}) { Object.assign(preference, { icon: 'filter-wheel', width: 300, height: 217 }) - return this.openModal({ - preference, - data, - id: `wheel.${data.wheel.name}.modal`, - path: 'wheel', - }) + return this.openModal({ preference, data, id: `wheel.${data.wheel.name}.modal`, path: 'wheel' }) + } + + openRotatorDialog(data: RotatorDialogInput, preference: WindowPreference = {}) { + Object.assign(preference, { icon: 'rotate', width: 280, height: 210 }) + return this.openModal({ preference, data, id: `rotator.${data.rotator.name}.modal`, path: 'rotator' }) } openGuider(preference: WindowPreference = {}) { diff --git a/desktop/src/shared/types/camera.types.ts b/desktop/src/shared/types/camera.types.ts index 2aa3ef784..533c45d7d 100644 --- a/desktop/src/shared/types/camera.types.ts +++ b/desktop/src/shared/types/camera.types.ts @@ -112,6 +112,7 @@ export interface CameraStartCapture { filterPosition: number shutterPosition: number focusOffset: number + angle: number calibrationGroup?: string liveStacking: LiveStackingRequest stackerGroupType: ImageFilterType @@ -317,6 +318,7 @@ export const DEFAULT_CAMERA_START_CAPTURE: CameraStartCapture = { filterPosition: 0, shutterPosition: 0, focusOffset: 0, + angle: 0, dither: DEFAULT_DITHER, liveStacking: DEFAULT_LIVE_STACKING_REQUEST, stackerGroupType: 'MONO', @@ -359,6 +361,7 @@ export function cameraStartCaptureWithDefault(request?: Partial, source: plan.autoFocus = autoFocusAfterConditionsWithDefault(plan.autoFocus, source.autoFocus) plan.liveStacking = liveStackingRequestWithDefault(plan.liveStacking, source.liveStacking) plan.namingFormat = cameraCaptureNamingFormatWithDefault(plan.namingFormat, source.namingFormat) + plan.backlashCompensation = backlashCompensationWithDefault(plan.backlashCompensation, source.backlashCompensation) + plan.sequences ??= source.sequences + + for (let i = 0; i < plan.sequences.length; i++) { + plan.sequences[i] = cameraStartCaptureWithDefault(plan.sequences[i]) + } + return plan as SequencerPlan } diff --git a/desktop/src/shared/types/wheel.types.ts b/desktop/src/shared/types/wheel.types.ts index a797424d6..6f5410594 100644 --- a/desktop/src/shared/types/wheel.types.ts +++ b/desktop/src/shared/types/wheel.types.ts @@ -1,7 +1,8 @@ import type { CameraStartCapture } from './camera.types' import type { Device } from './device.types' +import type { Focuser } from './focuser.types' -export type WheelMode = 'CAPTURE' | 'SEQUENCER' | 'FLAT_WIZARD' +export type WheelDialogMode = 'CAPTURE' | 'SEQUENCER' | 'FLAT_WIZARD' export interface Wheel extends Device { count: number @@ -11,8 +12,9 @@ export interface Wheel extends Device { } export interface WheelDialogInput { - mode: WheelMode + mode: WheelDialogMode wheel: Wheel + focuser?: Focuser request: CameraStartCapture } diff --git a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/rotator/INDIRotator.kt b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/rotator/INDIRotator.kt index 15ffea282..4cbe3f4e3 100644 --- a/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/rotator/INDIRotator.kt +++ b/nebulosa-indi-client/src/main/kotlin/nebulosa/indi/client/device/rotator/INDIRotator.kt @@ -77,6 +77,10 @@ internal open class INDIRotator( sender.fireOnEventReceived(RotatorMovingChanged(this)) } + if (message.state == PropertyState.ALERT) { + sender.fireOnEventReceived(RotatorMoveFailed(this)) + } + if (value != angle) { angle = value sender.fireOnEventReceived(RotatorAngleChanged(this)) diff --git a/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/rotator/RotatorMoveFailed.kt b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/rotator/RotatorMoveFailed.kt new file mode 100644 index 000000000..dcba7d9dd --- /dev/null +++ b/nebulosa-indi-device/src/main/kotlin/nebulosa/indi/device/rotator/RotatorMoveFailed.kt @@ -0,0 +1,5 @@ +package nebulosa.indi.device.rotator + +import nebulosa.indi.device.PropertyChangedEvent + +data class RotatorMoveFailed(override val device: Rotator) : RotatorEvent, PropertyChangedEvent