Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More rundown metadata #1429

Merged
merged 24 commits into from
Jan 9, 2025
Merged

More rundown metadata #1429

merged 24 commits into from
Jan 9, 2025

Conversation

alex-Arc
Copy link
Collaborator

@alex-Arc alex-Arc commented Jan 5, 2025

No description provided.

Copy link
Contributor

coderabbitai bot commented Jan 5, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This pull request introduces two new properties, dayOffset and gap, to various event-related components across the application. The changes span multiple files in the client and server directories, focusing on enhancing event management and timing calculations. The modifications include updating type definitions, modifying utility functions, and refactoring how events are processed, particularly in scenarios involving multi-day events and time gaps.

Changes

File Path Change Summary
apps/client/src/common/utils/eventsManager.ts Added dayOffset and gap to ClonedEvent type
apps/client/src/features/rundown/* Updated components to handle new dayOffset and gap properties, removed previousStart and previousEnd
apps/server/src/models/demoProject.ts Added dayOffset: 0 and gap: 0 to event objects
apps/server/src/models/eventsDefinition.ts Added dayOffset: 0 and gap: 0 to event constant
packages/utils/src/date-utils/* Refactored getTimeFromPrevious and isNewLatest functions to use object-based parameters

Possibly related PRs

Suggested reviewers

  • cpvalente

Finishing Touches

  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@alex-Arc alex-Arc added the priority Issue or PR to be prioritised label Jan 5, 2025
@alex-Arc alex-Arc marked this pull request as draft January 5, 2025 14:43
@alex-Arc alex-Arc force-pushed the more-rundown-metadata branch from 470e55c to d4397c3 Compare January 5, 2025 15:04
@alex-Arc
Copy link
Collaborator Author

alex-Arc commented Jan 5, 2025

@coderabbitai review

Copy link
Contributor

coderabbitai bot commented Jan 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (10)
packages/utils/src/date-utils/isNewLatest.test.ts (1)

4-4: TODO note
A note indicates this test might be tricked by any function returning true. Consider adding negative or boundary test cases to ensure correctness.

apps/server/src/services/rundown-service/rundownCache.ts (2)

60-60: Use docstring or comments
You've introduced a global totalDays variable to track day increments. Consider adding a brief docstring explaining its usage to ensure clarity for future maintainers.


132-138: Day offset logic
This block increments totalDays if an event crosses midnight or if checkIsNextDay evaluates to true. It appears correct, but please address the //TODO about whether to count in days or milliseconds for better clarity.

apps/client/src/common/utils/eventsManager.ts (1)

28-29: Consider referencing relevant design docs or usage patterns for dayOffset and gap.

It's good that you've added clear defaults (0) for the new properties. If there's additional business rationale for these fields, add inline code comments or references to design docs to ease future maintenance and highlight their purpose across the codebase.

apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts (2)

16-16: Clarify negative gap usage vs. overlap.

You’re calling formatGap(-30 * MILLIS_PER_SECOND, false), then validating 'Overlap 30s'. A negative gap suggests an overlap, but consider updating naming or comments to avoid confusion—especially since the function is named formatGap.


23-25: Consider adding more tests for multi-day scenarios.

Verifying 'Gap 30s (next day)' is great. Extend coverage to handle edge cases: multiple consecutive next-day events, very large multi-day offsets, etc.

apps/client/src/features/rundown/time-input-flow/TimeInputFlow.tsx (1)

49-49: Revisit the “Over midnight” warning threshold.

Currently, “Over midnight” is flagged when timeStart + duration > dayInMs. Consider user scenarios where crossing midnight by a second is acceptable vs. needing a distinct warning. You might add an adjustable threshold or an alternative label to clarify whether it’s a strict limit or a cautionary notice.

apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts (1)

187-188: More gap and dayOffset properties
Extends the coverage for events that might skip days or times. Keep an eye on how correlation with other fields might impact these values.

apps/server/src/services/rundown-service/__tests__/delayUtils.test.ts (2)

190-191: Applying multi-hour gaps alongside dayOffset
This test clarifies that time-based calculations account for both day offsets and hour-level gaps. Looks solid.


Line range hint 223-224: Zero-gap event in a multi-day scenario
This scenario is helpful to differentiate truly consecutive events from day transitions. Keep the tests flexible for real-world scheduling.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 891c43b and d4397c3.

⛔ Files ignored due to path filters (1)
  • packages/types/src/definitions/core/OntimeEvent.type.ts is excluded by none and included by none
📒 Files selected for processing (21)
  • apps/client/src/common/utils/eventsManager.ts (1 hunks)
  • apps/client/src/features/rundown/Rundown.tsx (5 hunks)
  • apps/client/src/features/rundown/RundownEntry.tsx (3 hunks)
  • apps/client/src/features/rundown/event-block/EventBlock.tsx (3 hunks)
  • apps/client/src/features/rundown/event-block/EventBlock.utils.ts (2 hunks)
  • apps/client/src/features/rundown/event-block/RundownIndicators.tsx (1 hunks)
  • apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts (2 hunks)
  • apps/client/src/features/rundown/time-input-flow/TimeInputFlow.tsx (2 hunks)
  • apps/client/src/views/timeline/timeline.utils.ts (2 hunks)
  • apps/server/src/models/demoProject.ts (14 hunks)
  • apps/server/src/models/eventsDefinition.ts (1 hunks)
  • apps/server/src/services/rundown-service/__tests__/delayUtils.test.ts (3 hunks)
  • apps/server/src/services/rundown-service/__tests__/rundownCache.test.ts (12 hunks)
  • apps/server/src/services/rundown-service/delayUtils.ts (2 hunks)
  • apps/server/src/services/rundown-service/rundownCache.ts (4 hunks)
  • apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts (6 hunks)
  • apps/server/src/utils/parser.ts (1 hunks)
  • packages/utils/src/date-utils/getTimeFromPrevious.test.ts (1 hunks)
  • packages/utils/src/date-utils/getTimeFromPrevious.ts (1 hunks)
  • packages/utils/src/date-utils/isNewLatest.test.ts (1 hunks)
  • packages/utils/src/date-utils/isNewLatest.ts (1 hunks)
🔇 Additional comments (65)
packages/utils/src/date-utils/isNewLatest.ts (4)

1-3: Imports look consistent
No issues found with these imports. They reflect a standard usage of type imports and utility constants.


13-13: Sensible default return
Returning true when no previousEvent exists is straightforward and self-explanatory. No issues found.


17-20: Clear day offset handling
Using dayOffset * dayInMs integrates well with the concept of multi-day events. The comparison logic is straightforward, and the use of >= to determine the “latest” event is easy to follow.


8-11: Improved function signature
The shift to accepting object parameters rather than multiple numeric arguments makes the code more expressive and easier to maintain. This aligns well with best practices for handling related data as a single entity. Ensure all references to this function in the codebase have been updated accordingly.

✅ Verification successful

Function signature change is properly implemented across the codebase

Based on the search results, all current usages of isNewLatest() in the codebase are already using the new object parameter signature. The function is called in three different locations:

  • apps/server/src/services/rundown-service/rundownCache.ts
  • apps/client/src/views/timeline/timeline.utils.ts
  • apps/client/src/features/rundown/Rundown.tsx

And all test cases in isNewLatest.test.ts also use the new object parameter format. No instances of the old signature (with multiple numeric arguments) were found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Searching the entire repo for calls to isNewLatest that may use the old signature
ast-grep --pattern $'isNewLatest($_, $_, $_, $_)' 

Length of output: 50


Script:

#!/bin/bash
# Let's search for any usage of isNewLatest function
rg "isNewLatest\(" -A 2

Length of output: 3140


Script:

#!/bin/bash
# Let's check the git history of this file to see the previous implementation
git log -p packages/utils/src/date-utils/isNewLatest.ts | head -n 50

Length of output: 0

packages/utils/src/date-utils/getTimeFromPrevious.ts (7)

1-2: Imports look good
The new type import aligns with the refactored function signature.


10-11: Enhanced readability with object-based parameters
Transitioning from multiple numeric parameters to an object-based approach promotes clearer usage and is more robust. Great improvement.


14-14: Proper handling of no-previous scenario
Returning 0 makes logical sense when there is no previous event. Straightforward and unambiguous.


18-19: Consistent calculation of adjusted times
The approach to handle multi-day events (via day offset) avoids confusion inherent in separate day-check logic. It’s both readable and flexible.


22-22: Equality check for consecutive events
Comparing start/end times for exact matches is good for identifying back-to-back events.


27-29: Logical gap calculation
When the current start is after the previous end, returning the positive difference is appropriate.


33-33: Negative overlap scenario
Falling back to the difference captures overlap in a single statement. This keeps the logic simple.

packages/utils/src/date-utils/isNewLatest.test.ts (1)

8-8: Comprehensive test coverage
Each test scenario methodically verifies the function behavior under different time, duration, and dayOffset settings. These tests are well structured and illustrate multi-day logic thoroughly.

Also applies to: 12-17, 21-26, 30-35, 39-44, 48-53

packages/utils/src/date-utils/getTimeFromPrevious.test.ts (2)

1-1: New constant import
Importing MILLIS_PER_MINUTE is consistent with the test’s usage.


7-12: Improved object-based test inputs
Switching to object parameters in the tests aligns with the updated function signature. The coverage for gap calculation, overlap, next-day logic, and partial overlaps is well demonstrated.

Also applies to: 16-19, 23-26, 30-36, 41-46, 51-56

apps/client/src/views/timeline/timeline.utils.ts (2)

145-145: Clarity in getTimeFromPrevious usage
Passing the currentEntry and lastEntry as object parameters demonstrates the object-based refactor. This reduces confusion about argument order and fosters maintainability.


154-154: Robust check with isNewLatest
Using the new structured parameters keeps the code consistent across the application. The straightforward if-statement ensures we only update lastEntry when the current event is indeed more recent.

apps/server/src/services/rundown-service/rundownCache.ts (8)

23-24: Imports for day-based calculations
The new checkIsNextDay and dayInMs imports expand the logic for multi-day event handling. Good addition.


113-113: Reset total days upon generate
Re-initializing totalDays at the start of generate() is consistent with the other counters. Looks good.


124-124: Initialize gap
Setting currentEntry.gap to 0 ensures a default value, preventing undefined behavior in subsequent calculations.


146-146: Gap assignment
Using getTimeFromPrevious to assign currentEntry.gap keeps event timing calculations consistent and streamlined.


148-154: Gap-based duration logic
Treating zero, positive, and negative gaps distinctly is a clear way to handle concurrency, overlaps, or breaks. Consider adding edge-case tests (e.g., extremely large negative overlaps).


158-158: Safe overlap handling
Using Math.max(currentEntry.duration + currentEntry.gap, 0) ensures total duration never goes below zero.


163-164: Delay reduction logic
Subtracting a positive gap from the accumulated delay makes sense, preventing the carry-over of unused delays.


170-170: Identify latest event
Using isNewLatest to set lastEntry is a clean approach for tracking events ending last, ensuring accurate next-calculation logic.

apps/server/src/services/rundown-service/__tests__/rundownCache.test.ts (12)

580-581: New event properties
Introducing dayOffset and gap ensures thorough multi-day testing for events.


610-611: Added dayOffset and gap
This aligns tested events with new rundown logic for multi-day spans.


640-641: dayOffset and gap
Their inclusion in test objects affirms coverage of these properties in runtime evaluations.


670-671: Initialize dayOffset/gap
Ensures each test event has a defined baseline for multi-day or overlapping calculations.


712-713: Default zero dayOffset/gap
Having both properties set to 0 by default avoids uninitialized values in test scenarios.


738-739: Insertion of dayOffset/gap
Reinforces test coverage for new scheduling properties introduced in the rundown logic.


768-769: Test event properties
Adding dayOffset and gap keeps the test event structure consistent with the updated model.


798-799: Consistent new fields
Ensures that multi-day logic (dayOffset, gap) is exercised during testing.


854-855: Further dayOffset/gap usage
These properties are crucial for verifying correct day transitions and spacing.


884-885: Partial dayOffset/gap setups
Maintaining consistency in test data aligns with the real event model across files.


914-915: Ensure uniform usage
Retaining dayOffset and gap here solidifies your multi-day event coverage.


944-945: Comprehensive coverage
Specifying dayOffset and gap for this block further ensures the logic is fully tested under different day scenarios.

apps/client/src/features/rundown/event-block/EventBlock.utils.ts (1)

13-17: New gap formatting function
Swapping out formatOverlap for formatGap simplifies the logic for presenting day-spanning or overlapping intervals, especially with the isNextDay flag.

apps/client/src/features/rundown/event-block/RundownIndicators.tsx (3)

1-1: Updated import
Replaces formatOverlap with formatGap to support new event gap logic.


7-9: Extended interface
Adding isNextDay and gap aligns with multi-day awareness and gap-based calculations, removing reliance on previous event timing.


13-15: Using formatGap
Destructuring gap and isNextDay clarifies how gaps and next-day transitions are displayed in these indicators.

apps/server/src/models/eventsDefinition.ts (1)

28-29: New event fields
Adding dayOffset and gap reflects the expanded multi-day coverage in your event model, keeping it in sync with runtime logic.

apps/client/src/features/rundown/event-block/__tests__/EventBlock.utils.test.ts (2)

1-3: Adapt existing test coverage to encompass edge cases for both negative and positive gap values.

Importing MILLIS_PER_SECOND is fine, but also consider testing boundary conditions (e.g., extremely large gap values or zero gap) to ensure that your logic gracefully handles these extremes.


19-21: Confirm consistent naming: 'Recognizes a gap' vs. 'Overlaps'.

This test checks for a gap instead of an overlap, but make sure the test descriptions and logic match the function’s behavior. If your domain terms are “gap” and “overlap,” keep them consistent throughout.

apps/server/src/services/rundown-service/delayUtils.ts (1)

142-143: Re-evaluate applying gap deduction before checking if delayValue is zero.

The logic delayValue = Math.max(delayValue - currentEntry.gap, 0) is useful, but if delayValue becomes zero prematurely, subsequent events may not get the intended partial delay. Verify if this is the correct design or if you need a more granular approach.

apps/client/src/features/rundown/time-input-flow/TimeInputFlow.tsx (1)

9-9: Centralize constants for daily thresholds.

Importing dayInMs here is good. Keep any related constants (e.g., hourInMs, etc.) in the same place to maintain consistency and discoverability in your time-related calculations.

apps/client/src/features/rundown/RundownEntry.tsx (3)

35-35: Added isNextDay prop in RundownEntryProps
This new boolean prop effectively captures whether the event spills over into the following day. Looks good for clarifying day boundaries. Ensure that all downstream components handle day transitions as intended.


54-54: Destructured isNextDay from props
Ensure that any business logic reliant on the next-day condition properly references this extracted boolean. If other files or components also need to check day transitions, consider offering a shared utility.


174-175: Passing gap and isNextDay to EventBlock
Providing both gap and isNextDay here promotes consistency with the updated event model. Verify that related components and logic support the new properties without side effects.

apps/server/src/services/sheet-service/__tests__/sheetUtils.test.ts (5)

40-41: Introduced gap and dayOffset in the test event
These newly added properties are tested effectively. Confirm that coverage is comprehensive for all edge cases involving day offsets and gaps.


89-90: Added gap and dayOffset
Ensures the test scenario now reflects multi-day or spaced events. Good for consistency.


139-140: Testing gap and dayOffset for boolean coverage
Properly aligns with the new event schema. Make sure further negative or large gap scenarios are tested to ensure robust coverage.


223-224: Extending the coverage for offset events
Confirm that date/time calculations remain correct, especially around boundary transitions or large offsets.


259-260: Deployment of gap and dayOffset in final scenario
Allows the test to confirm successful usage in the typical sheet setup as well. Looks consistent with the rest of the tests.

apps/client/src/features/rundown/event-block/EventBlock.tsx (3)

50-51: Added gap and isNextDay to EventBlockProps
This clarifies event spacing and future-day transitions. Perfect synergy with the newly updated schema.


88-89: Destructuring gap and isNextDay
Reflects the revised props. If multiple components handle similar logic, consider abstracting it for consistency.


276-276: Passing new props to RundownIndicators
Enhances event visuals by factoring in gap and next-day notices. Ensure UI changes remain consistent in different user locales and timezones.

apps/server/src/services/rundown-service/__tests__/delayUtils.test.ts (3)

153-157: Adding gap to event definitions
Including the extra gap logic is crucial for correct timing adjustments. Good to see negative or zero-gap cases tested.


168-168: Retaining gap in the updated rundown
Ensures that upon applying delay, the event’s gap remains recognized. Confirm no unintended side effects where gap + linkStart might conflict.


181-182: New gap and dayOffset fields
These fields support multi-day events. Validate that negative offsets or large transitions do not break existing delay logic.

apps/server/src/models/demoProject.ts (1)

24-25: Consistent addition of dayOffset & gap properties.

All these newly introduced properties (dayOffset and gap) are uniform across the different event objects. Since both are currently set to zero, ensure there is clarity around whether these values will be updated during runtime and if they need to be persisted or recalculated. Otherwise, there is no functional issue with adding them upfront.

Also applies to: 52-53, 80-81, 108-109, 136-137, 169-170, 197-198, 225-226, 253-254, 281-282, 314-315, 342-343, 370-371, 398-399

apps/client/src/features/rundown/Rundown.tsx (4)

16-16: Good use of dayInMs for day-boundary logic.

Importing dayInMs from ontime-utils clarifies the day boundary checks. This is concise and avoids hardcoding magic numbers.


271-271: Explicit initialization of isNextDay.

Setting isNextDay = false at the start of the iteration ensures a clean default. Confirm that all usage paths properly update the variable when day changes are detected.


Line range hint 290-307: Refined day-over-day logic.

Lines 299-305 check if the new entry is on the next day by comparing (lastEvent.timeStart + lastEvent.duration) <= dayInMs and entry.dayOffset > lastEvent.dayOffset. Carefully verify that this approach is always accurate for multi-day events or entries shifting across midnight boundaries. If events can span beyond a single day, consider comparing actual day boundaries in the code or adjusting for time zones.


339-339: Passing isNextDay prop to child.

Introducing the isNextDay indicator in the <RundownEntry> increases clarity when rendering day transitions. This looks good.

apps/server/src/utils/parser.ts (1)

387-389: Set dayOffset, gap, and delay to 0 by default.

Hardcoding these values to zero makes sense if the rundown cache or a subsequent process recalculates them. If these fields must always be regenerated externally, confirm that no code path relies on a non-zero default here.

@alex-Arc alex-Arc force-pushed the more-rundown-metadata branch from d4397c3 to 6eb318f Compare January 5, 2025 23:40
@alex-Arc alex-Arc marked this pull request as ready for review January 5, 2025 23:43
@alex-Arc alex-Arc force-pushed the more-rundown-metadata branch from 5fc7876 to 7d013d5 Compare January 7, 2025 11:12
packages/utils/src/date-utils/checkIsNextDay.ts Outdated Show resolved Hide resolved
packages/utils/src/date-utils/checkIsNextDay.ts Outdated Show resolved Hide resolved
@@ -1,45 +1,34 @@
import { checkIsNextDay } from './checkIsNextDay.js';
import type { OntimeEvent } from 'ontime-types';

import { dayInMs } from './conversionUtils.js';

/**
* Utility returns the time elapsed (gap or overlap) from the previous
* It uses deconstructed parameters to simplify implementation in UI
*/
export function getTimeFromPrevious(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: do we still need this function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used in rundownCache and timeline.utils.ts
might be able to remove it from timeline at some point...

packages/utils/src/date-utils/getTimeFromPrevious.ts Outdated Show resolved Hide resolved
alex-Arc and others added 3 commits January 8, 2025 22:26
Co-authored-by: Carlos Valente <34649812+cpvalente@users.noreply.github.com>
@alex-Arc alex-Arc merged commit e9a7cd0 into master Jan 9, 2025
4 checks passed
@alex-Arc alex-Arc deleted the more-rundown-metadata branch January 9, 2025 12:35
@coderabbitai coderabbitai bot mentioned this pull request Jan 24, 2025
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority Issue or PR to be prioritised
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants