feat(scheduler): add create schedule command#192
Conversation
yordis
commented
May 29, 2026
- Enable scheduler command handling to build on the state schemas already introduced upstream.
- Keep this slice focused on creation so later lifecycle commands can land with separate review context.
PR SummaryMedium Risk Overview Adds a domain layer for schedule specs (at / every / cron / RRULE), NATS delivery routes, message content and headers (including reserved
Reviewed by Cursor Bugbot for commit 7de8e0d. Bugbot is set up for automated code reviews on this repo. Configure here. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR establishes the domain layer and command logic for schedule creation in the trogon-scheduler crate. It introduces validated domain types for messaging, scheduling specifications (one-time, interval, cron, recurrence-rule), delivery routing, and schedule identifiers; wires conversions to protobuf event types; implements state evolution logic; and provides a CreateScheduleCommand decider that gates creation on stream preconditions. ChangesScheduler domain and command implementation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ce2f437 to
4bf191f
Compare
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
4bf191f to
018fc2f
Compare
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs`:
- Around line 99-109: The domain type MessageContent currently accepts any
string but elsewhere conversion always sets "application/json", so make invalid
states unrepresentable by either (A) enforcing JSON validity in MessageContent:
change MessageContent::new and from_static to validate the input with
serde_json::from_str and return Result<MessageContent, Error> so only valid JSON
is constructed (update callers and conversions), or (B) make content-type
explicit by changing MessageContent to include a content_type field (e.g.,
MessageContent { body: String, content_type: String }) and update the conversion
logic that currently hardcodes "application/json" to read the content_type from
the instance; pick one approach and update all usages (constructors,
conversions, and serialization) accordingly so the domain invariant is
preserved.
- Around line 24-50: Replace the Vec<(String,String)> storage and combined
validation in MessageHeaders and MessageHeaders::new with domain value objects:
create HeaderName and HeaderValue newtypes that implement TryFrom<String> (or
TryFrom<&str>) and perform their respective validation (name rules and value
rules) inside their factories, then change MessageHeaders to contain
Vec<MessageHeader> or Vec<(HeaderName, HeaderValue)> and update
MessageHeaders::new to iterate the input, attempt to construct HeaderName and
HeaderValue for each pair (propagating the specific conversion errors), and push
the validated value objects into the collection rather than validating raw
strings in the aggregate constructor. Ensure unique error types map to
MessageHeadersError where appropriate and update any call sites that previously
expected (String,String) tuples to use the new types or to extract their inner
strings explicitly.
In
`@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs`:
- Around line 4-6: Replace the primitive String in the
ScheduleEventSamplingSource enum with the validated domain value object
SamplingSubject: change the variant LatestFromSubject { subject: String } to use
subject: SamplingSubject, import/bring SamplingSubject into scope, and update
all creation sites, pattern matches, and serde/derive usages for
ScheduleEventSamplingSource (constructors, matches, and any
serialization/deserialization) to accept/produce SamplingSubject instances so
invalid subjects become unrepresentable.
In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs`:
- Around line 80-83: The Display implementation for ScheduleIdError currently
prints "job id" which is misleading; update the message in impl fmt::Display for
ScheduleIdError so it says "schedule id '{}' is invalid: {}" instead, since this
error is emitted by ScheduleId::parse and serde failures; ensure any other
user-facing strings in the ScheduleIdError formatting remain consistent with
this rename.
In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs`:
- Around line 377-380: ScheduleTimezone::new currently only
strips/control-validates tokens via validate_timezone_token and must
additionally reject non-existent cron timezone IDs; update ScheduleTimezone::new
to attempt resolving the token to a real timezone (e.g., parse/lookup using the
same timezone registry used by RRuleTimezone, such as chrono_tz::Tz::from_str or
your project's timezone resolver) and return ScheduleSpecError on failure,
mirroring RRuleTimezone's behavior; apply the same validation change to the
other factory area referenced (the second ScheduleTimezone construction block)
so all Schedule::Cron constructors guarantee the timezone is real at
construction.
- Around line 14-21: The Job struct is a domain aggregate but is currently
deriving Deserialize; stop exposing domain types to the wire by removing
Deserialize from Job and introduce a new boundary type (e.g., JobInput or
JobWire) that derives Deserialize and mirrors the JSON shape (fields:
id/ScheduleId, status/JobStatus, schedule/Schedule, delivery/Delivery,
message/JobMessage). Implement an explicit conversion (e.g., From<JobInput> for
Job or TryFrom<JobInput> for Job) that validates or maps any wire types into the
domain Job (referencing Job, JobInput/JobWire, and the
JobStatus/Schedule/Delivery/JobMessage types) and update all deserialization
sites to parse into JobInput and then convert once into Job. Ensure serde
annotations move to the new JobInput and that domain code and tests use Job only
after that single conversion.
In `@rsworkspace/crates/trogon-scheduler/src/commands/state.rs`:
- Line 15: The Display message for the enum variant Self::UnsupportedEvent is
misleading ("job event"); update the string to reference "schedule event"
instead so it accurately reflects the handled type—locate the Display/fmt
implementation that contains Self::UnsupportedEvent in commands/state.rs and
replace the message "protobuf job event is not supported by command state" with
a clear "protobuf schedule event is not supported by command state" (or
equivalent wording), and run tests or adjust any assertions that depended on the
old message.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bee14602-23fb-4509-81d0-9854d846539b
📒 Files selected for processing (13)
rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/message.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_details.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rsrsworkspace/crates/trogon-scheduler/src/commands/mod.rsrsworkspace/crates/trogon-scheduler/src/commands/snapshot.rsrsworkspace/crates/trogon-scheduler/src/commands/state.rs
Schedule identity is a business concept; constraining it to NATS subject grammar let a transport detail dictate what a valid identifier is. Subject safety belongs at the subject-construction seam, not on the identity. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Schedule event representations re-admitted invariants the domain already proves (unbounded seconds, unvalidated subjects/expressions) by flattening value objects back to primitives. Keeping the value objects through to the proto boundary stops unvalidated values from being representable, and moves the create-event factory beside the command that emits it. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Domain-time to protobuf conversions were duplicated inside the scheduler; hosting them in the proto crate behind a chrono feature lets any crate reuse them without depending on scheduler internals. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs`:
- Around line 32-36: The current Display impl for CreateScheduleDecideError uses
Debug ("{self:?}") which leaks internals; replace the impl of std::fmt::Display
for CreateScheduleDecideError (the fn fmt) with a match on each enum variant and
return concise, user-facing messages for each case (including any inner error
messages where appropriate), e.g., map validation/permission/internal variants
to human-readable strings and include underlying error.display() when useful;
keep the Display implementation stable for logging and ensure the error type
still implements std::error::Error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 06e87181-2a0f-4d3a-9577-a8af83c8a552
📒 Files selected for processing (15)
rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/message.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_details.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rsrsworkspace/crates/trogon-scheduler/src/commands/mod.rsrsworkspace/crates/trogon-scheduler/src/commands/state.rsrsworkspace/crates/trogonai-proto/Cargo.tomlrsworkspace/crates/trogonai-proto/src/convert.rsrsworkspace/crates/trogonai-proto/src/lib.rs
✅ Files skipped from review due to trivial changes (2)
- rsworkspace/crates/trogonai-proto/src/lib.rs
- rsworkspace/crates/trogon-scheduler/src/commands/mod.rs
🚧 Files skipped from review as they are similar to previous changes (9)
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_details.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_delivery.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
- rsworkspace/crates/trogon-scheduler/src/commands/state.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs
483dade to
f39e1c5
Compare
f39e1c5 to
01b4b90
Compare
Code Coverage SummaryDetailsDiff against mainResults for commit: 7de8e0d Minimum allowed coverage is ♻️ This comment has been updated with latest results |
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
01b4b90 to
271aba5
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs (1)
224-227:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReplace
std::io::Error::other/format!in RRULE validation with a typed error source
ScheduleSpecError::InvalidRRule { source: Box<dyn std::error::Error> }is currently populated withstd::io::Error::other(...)(andformat!(...)) at lines 224-227, 251-254, 260-265, and 272-275, making the failure reasons opaque/stringly-typed. Use a dedicatedRRuleValidationErrorenum (implementsDisplay+Error) and box that intoInvalidRRule.sourcefor these branches.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs` around lines 224 - 227, Replace the ad-hoc std::io::Error::other/format!-based sources used when constructing ScheduleSpecError::InvalidRRule with a new typed RRuleValidationError enum (implementing std::fmt::Display + std::error::Error) and box that into InvalidRRule.source; add variants that match the four failing cases (e.g., EmptyOrMultiLine, InvalidProperty(String), ParseError(String), etc.), implement Display/Error for RRuleValidationError, and in the existing places that return Err(ScheduleSpecError::InvalidRRule { rrule: raw, source: Box::new(...) }) (the branches around the current returns) replace Box::new(std::io::Error::other(...)) / Box::new(format!(...)) with Box::new(RRuleValidationError::YourVariant(...)) so the error source is strongly typed and descriptive.rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs (1)
6-9:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPreserve typed header validation errors in
MessageHeaders::newinstead of flattening to strings.
MessageHeadersErrorstoresInvalidName/InvalidValueas{ name: String }, andMessageHeaders::newcollapsesHeaderNameError/HeaderValueErrorby extracting onlysource.nameor discarding the source entirely—dropping the typed cause. The localHeaderNameError/HeaderValueErrorin this module also don’t implementDisplay/std::error::Error, so they can’t be chained per the error guidelines.Update
MessageHeadersErrorto wrap the source errors (and useHeaderNameas the typed header-name field), implementDisplay+std::error::ErrorforHeaderNameError/HeaderValueError, and adjustMessageHeadersError’sDisplayplus themap_errcalls accordingly.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs` around lines 6 - 9, Change MessageHeadersError to carry the typed causes and header-name type instead of plain strings: make its variants like InvalidName { name: HeaderName, source: HeaderNameError } and InvalidValue { name: HeaderName, source: HeaderValueError }, update MessageHeaders::new map_err calls to wrap the original HeaderNameError/HeaderValueError (preserving them as source) and supply the parsed HeaderName for name; implement Display and std::error::Error for the local HeaderNameError and HeaderValueError types so they can be chained; and update MessageHeadersError’s Display impl to render a message plus use std::error::Error::source() to return the wrapped source so chained errors are preserved.rsworkspace/crates/trogon-scheduler/src/commands/state.rs (1)
48-58:⚠️ Potential issue | 🟠 Major | ⚡ Quick winReject
ScheduleCreatedevents that omit status.If
inner.statusorstatus.kindis missing, this branch currently materializes the schedule asSTATE_VALUE_PRESENT_ENABLED. That silently turns a malformed wire event into a live schedule instead of surfacing bad input.Proposed fix
Some(ScheduleEventCase::ScheduleCreated(inner)) => { + let Some(kind) = inner.status.as_option().and_then(|status| status.kind.as_ref()) else { + return Err(EvolveError::UnsupportedEvent); + }; + if current_state == state_v1::StateValue::STATE_VALUE_DELETED { state_v1::StateValue::STATE_VALUE_DELETED - } else if matches!( - inner.status.as_option().and_then(|status| status.kind.as_ref()), - Some(ScheduleStatusKind::Paused(_)) - ) { + } else if matches!(kind, ScheduleStatusKind::Paused(_)) { state_v1::StateValue::STATE_VALUE_PRESENT_DISABLED } else { state_v1::StateValue::STATE_VALUE_PRESENT_ENABLED } }As per coding guidelines, "Untrusted input must use distinct
*Input/*Wire/*Requesttypes. Convert those boundary types into domain types exactly once."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rsworkspace/crates/trogon-scheduler/src/commands/state.rs` around lines 48 - 58, The ScheduleCreated branch currently treats missing inner.status or status.kind as STATE_VALUE_PRESENT_ENABLED; instead detect when inner.status.as_option() is None or status.kind is None and reject the event (return an error) rather than materializing it. Update the ScheduleEventCase::ScheduleCreated handling to explicitly pattern-match inner.status.as_option().and_then(|s| s.kind.as_ref()); if that yields None return a domain-level error (e.g. Err(InvalidWireEvent(...)) from the function that maps events to state) so malformed wire input is surfaced, and adjust callers/signature (propagate Result) as needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rsworkspace/crates/trogonai-proto/src/convert.rs`:
- Around line 10-17: The function duration_from_seconds currently panics via
expect; change it to return Result<Duration, DurationConversionError> and add a
DurationConversionError enum (e.g., OutOfRange { seconds: u64 }) with Display
and std::error::Error impls, then replace the try_from/ok/filter chain with
ok_or to return DurationConversionError::OutOfRange when seconds is not
representable or exceeds PROTOBUF_DURATION_MAX_SECONDS, and finally return
Ok(Duration::from_secs(converted_seconds_i64)); alternatively, if callers
already validate (e.g., EverySeconds), document the precondition and keep the
function infallible.
---
Outside diff comments:
In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/message.rs`:
- Around line 6-9: Change MessageHeadersError to carry the typed causes and
header-name type instead of plain strings: make its variants like InvalidName {
name: HeaderName, source: HeaderNameError } and InvalidValue { name: HeaderName,
source: HeaderValueError }, update MessageHeaders::new map_err calls to wrap the
original HeaderNameError/HeaderValueError (preserving them as source) and supply
the parsed HeaderName for name; implement Display and std::error::Error for the
local HeaderNameError and HeaderValueError types so they can be chained; and
update MessageHeadersError’s Display impl to render a message plus use
std::error::Error::source() to return the wrapped source so chained errors are
preserved.
In `@rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rs`:
- Around line 224-227: Replace the ad-hoc std::io::Error::other/format!-based
sources used when constructing ScheduleSpecError::InvalidRRule with a new typed
RRuleValidationError enum (implementing std::fmt::Display + std::error::Error)
and box that into InvalidRRule.source; add variants that match the four failing
cases (e.g., EmptyOrMultiLine, InvalidProperty(String), ParseError(String),
etc.), implement Display/Error for RRuleValidationError, and in the existing
places that return Err(ScheduleSpecError::InvalidRRule { rrule: raw, source:
Box::new(...) }) (the branches around the current returns) replace
Box::new(std::io::Error::other(...)) / Box::new(format!(...)) with
Box::new(RRuleValidationError::YourVariant(...)) so the error source is strongly
typed and descriptive.
In `@rsworkspace/crates/trogon-scheduler/src/commands/state.rs`:
- Around line 48-58: The ScheduleCreated branch currently treats missing
inner.status or status.kind as STATE_VALUE_PRESENT_ENABLED; instead detect when
inner.status.as_option() is None or status.kind is None and reject the event
(return an error) rather than materializing it. Update the
ScheduleEventCase::ScheduleCreated handling to explicitly pattern-match
inner.status.as_option().and_then(|s| s.kind.as_ref()); if that yields None
return a domain-level error (e.g. Err(InvalidWireEvent(...)) from the function
that maps events to state) so malformed wire input is surfaced, and adjust
callers/signature (propagate Result) as needed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 446a90db-706b-4aac-af5c-88236b52ef71
⛔ Files ignored due to path filters (1)
rsworkspace/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (14)
rsworkspace/crates/trogon-scheduler/Cargo.tomlrsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/message.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_sampling_source.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rsrsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rsrsworkspace/crates/trogon-scheduler/src/commands/state.rsrsworkspace/crates/trogon-scheduler/src/error.rsrsworkspace/crates/trogon-scheduler/src/lib.rsrsworkspace/crates/trogon-scheduler/tests/create_schedule_errors.rsrsworkspace/crates/trogonai-proto/src/convert.rs
🚧 Files skipped from review as they are similar to previous changes (5)
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_status.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/mod.rs
- rsworkspace/crates/trogon-scheduler/src/commands/create_schedule.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_id.rs
- rsworkspace/crates/trogon-scheduler/src/commands/domain/schedule_event_schedule.rs
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Align create-schedule command and domain naming with schedule terminology by replacing JobStatus, JobHeaders, and JobMessage with ScheduleEventStatus, ScheduleHeaders, and ScheduleMessage. Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
2ce160a to
38a4fd5
Compare
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 599c911. Configure here.
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
