/// <summary>
            /// Erzeugt eine neue Beschreibung.
            /// </summary>
            /// <param name="context">Vom Anwender der Schnittstelle zusätzlich bereitgestellte Daten.</param>
            /// <param name="name">Eine Name zur Identifikation der Aufzeichnung.</param>
            /// <param name="uniqueIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
            /// <param name="resources">Die Liste aller Geräte, die verwendet werden dürfen.</param>
            /// <param name="source">Die gewünschte Quelle.</param>
            /// <param name="start">Der Beginn der Aufzeichnung.</param>
            /// <param name="duration">Die Dauer der Aufzeichnung.</param>
            public _OneOffItem(UserDataType context, string name, Guid uniqueIdentifier, IScheduleResource[] resources, IScheduleSource source, DateTime start, TimeSpan duration)
            {
                // Validate
                if (source == null)
                {
                    throw new ArgumentNullException("source");
                }
                if (start.Year < 2000)
                {
                    throw new ArgumentOutOfRangeException("start", string.Format(Properties.InterfaceResources.Exception_StartYear, start));
                }
                if (duration.TotalSeconds <= 0)
                {
                    throw new ArgumentOutOfRangeException("duration", string.Format(Properties.InterfaceResources.Exception_Duration, duration));
                }
                if (resources != null)
                {
                    if (resources.Any(r => r == null))
                    {
                        throw new ArgumentNullException("resources");
                    }
                }

                // Create compound information
                m_Plan = new PlannedTime {
                    Start = start, Duration = duration
                };

                // Remember simple information
                Resources        = resources ?? new IScheduleResource[0];
                UniqueIdentifier = uniqueIdentifier;
                Context          = context;
                Source           = source;
                Name             = name;
            }
示例#2
0
 /// <summary>
 /// Erzeugt eine neue Beschreibung.
 /// </summary>
 /// <param name="map">Die zugehörige Verwaltung einer Ressource.</param>
 /// <param name="source">Die Quelle, die verwendet werden soll.</param>
 /// <param name="plan">Die ursprüngliche Planung.</param>
 /// <param name="index">Der erste Eintrag in der Verwaltung, der belegt werden soll.</param>
 public AllocationPlan(AllocationMap map, IScheduleSource source, SuggestedPlannedTime plan, int index)
 {
     // Remember
     m_allocationIndex = index;
     m_source          = source;
     m_plan            = plan;
     m_map             = map;
 }
示例#3
0
        /// <summary>
        /// Fordert eine Entschlüsselung an.
        /// </summary>
        /// <param name="source">Die zu verwendende Quelle.</param>
        /// <param name="timeHolder">Der Zeitraum, für den die Planung stattfinden soll.</param>
        /// <returns>Gesetzt, wenn eine Zuordnung überhaupt möglich ist. Gemeldet wird dann der Zeitversatz der Zuordnung.</returns>
        public AllocationPlan PrepareAllocation(IScheduleSource source, SuggestedPlannedTime timeHolder)
        {
            // Extract the time to use for plannung
            var time = timeHolder.Planned;

            // As long as needed
            for (var scanStart = 0; ;)
            {
                // See if there is at least one allocation area available
                var allocationIndex = m_Allocations.FindIndex(scanStart, a => a.Overlaps(time));
                if (allocationIndex < 0)
                {
                    return(null);
                }

                // On the start skip all having no recording left
                while (!m_Allocations[allocationIndex].CanAllocate(source))
                {
                    if (++allocationIndex == m_Allocations.Count)
                    {
                        return(null);
                    }
                    else if (!m_Allocations[allocationIndex].Overlaps(time))
                    {
                        return(null);
                    }
                }

                // Initial index - where we start the allocation
                var startIndex = allocationIndex;

                // Now make sure that we can record to the end - allocation maps from the beginning to the end of all times
                while (++allocationIndex < m_Allocations.Count)
                {
                    if (!m_Allocations[allocationIndex].Overlaps(time))
                    {
                        break;
                    }
                    else if (!m_Allocations[allocationIndex].CanAllocate(source))
                    {
                        // Prepare to rescan
                        scanStart = allocationIndex + 1;

                        // Do not end
                        startIndex = -1;

                        // Done with loop
                        break;
                    }
                }

                // Response
                if (startIndex >= 0)
                {
                    return(new AllocationPlan(this, source, timeHolder, startIndex));
                }
            }
        }
示例#4
0
            /// <summary>
            /// Aktiviert eine Aufzeichnung auf einem Gerät.
            /// </summary>
            /// <param name="resource">Eines der verwalteten Geräte.</param>
            /// <param name="source">Optional eine Quelle, die auf dem Gerät angesteuert werden kann.</param>
            /// <param name="scheduleIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
            /// <param name="scheduleName">Der Anzeigename der Aufzeichnung.</param>
            /// <param name="plannedStart">Der ursprüngliche Start der Aufzeichnung in UTC / GMT Notation.</param>
            /// <param name="currentEnd">Das aktuelle Ende der Aufzeichnung in UTC / GMT Notation.</param>
            /// <returns>Gesetzt, wenn die Aufzeichnung auf dem gewünschten Gerät aktiviert werden kann.</returns>
            /// <exception cref="ArgumentNullException">Es wurde kein Gerät angegeben.</exception>
            /// <exception cref="ArgumentException">Das Gerät ist nicht bekannt oder kann die Quelle nicht empfangen.</exception>
            /// <exception cref="ArgumentOutOfRangeException">Die Laufzeit der Aufzeichnung ist nicht positiv.</exception>
            public bool Start(IScheduleResource resource, IScheduleSource source, Guid scheduleIdentifier, string scheduleName, DateTime plannedStart, DateTime currentEnd)
            {
                // Validate
                if (resource == null)
                {
                    throw new ArgumentNullException("resource");
                }
                if (!m_Resources.Contains(resource))
                {
                    throw new ArgumentException(resource.Name, "resource");
                }
                if (plannedStart >= currentEnd)
                {
                    throw new ArgumentOutOfRangeException("currentEnd");
                }
                if (m_Recordings.Any(r => r.UniqueIdentifier == scheduleIdentifier))
                {
                    throw new ArgumentException("resource");
                }

                // Create helper entry
                m_Recordings.Add(new ResourceAllocationInformation(resource, source, scheduleIdentifier, scheduleName, plannedStart, currentEnd - plannedStart));

                // May require cleanup
                try
                {
                    // Create the new plan
                    var plan = CreateSchedulePlan();

                    // Did it
                    if (plan != null)
                    {
                        // Remember as current
                        m_CurrentPlan = plan;

                        // Report
                        return(true);
                    }
                }
                catch
                {
                    // Cleanup
                    m_Recordings.RemoveAt(m_Recordings.Count - 1);

                    // Report
                    throw;
                }

                // Cleanup
                m_Recordings.RemoveAt(m_Recordings.Count - 1);

                // Add to list
                return(false);
            }
        /// <summary>
        /// Erzeugt eine neue Beschreibung.
        /// </summary>
        /// <param name="resource">Das zugehörige Gerät.</param>
        /// <param name="source">Optional die zu verwendende Quelle.</param>
        /// <param name="identifier">Die eindeutige Kennung der zugehörigen Aufzeichnung oder Aufgabe.</param>
        /// <param name="name">Der Name der Aufzeichnung.</param>
        /// <param name="start">Der Startzeitpunkt.</param>
        /// <param name="duration">Die Dauer der Aufzeichnung.</param>
        /// <exception cref="ArgumentOutOfRangeException">Die Dauer der Aufzeichnung ist negativ.</exception>
        public ResourceAllocationInformation( IScheduleResource resource, IScheduleSource source, Guid identifier, string name, DateTime start, TimeSpan duration )
        {
            // Validate
            if (duration.TotalSeconds <= 0)
                throw new ArgumentOutOfRangeException( "duration" );

            // Remember all
            Time = new PlannedTime { Start = start, Duration = duration };
            Resources = new[] { resource };
            UniqueIdentifier = identifier;
            Source = source;
            Name = name;
        }
示例#6
0
            /// <summary>
            /// Reserviert eine Quelle.
            /// </summary>
            /// <param name="source">Die Quelle, die nun verwendet werden soll.</param>
            /// <exception cref="ArgumentNullException">Es wurde keine Quelle angegeben.</exception>
            public void Allocate(IScheduleSource source)
            {
                // Validate
                if (source == null)
                {
                    throw new ArgumentNullException("source");
                }

                // Remember
                if (!Sources.Any(s => s.IsSameAs(source)))
                {
                    Sources.Add(source);
                }
            }
示例#7
0
        /// <summary>
        /// Meldet, ob eine Quelle zu einer Liste von Quellen passt.
        /// </summary>
        /// <param name="source">Die Quelle.</param>
        /// <param name="sources">Die Liste der Quellen.</param>
        /// <returns>Gesetzt, wenn die Quelle passt.</returns>
        private bool CanMerge(IScheduleSource source, IEnumerable <IScheduleSource> sources)
        {
            // Check it
            var mergeTest = m_MergeTest;

            if (mergeTest == null)
            {
                return(true);
            }
            else
            {
                return(mergeTest(source, sources));
            }
        }
示例#8
0
        /// <summary>
        /// Prüft ob zwei Quellen identisch sind.
        /// </summary>
        /// <param name="source">Eine andere Quelle.</param>
        /// <returns>Gesetzt, wenn die Quellen identisch sind.</returns>
        public bool IsSameAs(IScheduleSource source)
        {
            // Pre-test
            if (!BelongsToSameSourceGroupAs(source))
            {
                return(false);
            }

            // Can now safe cast
            var typedSource = source as SourceMock;

            // Just test the identification
            return(Equals(Name, typedSource.Name));
        }
示例#9
0
        /// <summary>
        /// Prüft, ob diese Quelle mit einer anderen parallel aufgezeichnet werden kann.
        /// </summary>
        /// <param name="source">Eine andere Quelle.</param>
        /// <returns>Gesetzt, wenn eine parallele Aufzeichnung theoretisch möglich ist.</returns>
        public bool BelongsToSameSourceGroupAs(IScheduleSource source)
        {
            // Check type first
            var typedSource = source as SourceMock;

            if (typedSource == null)
            {
                return(false);
            }
            else
            {
                return(SourceGroup == typedSource.SourceGroup);
            }
        }
示例#10
0
        /// <summary>
        /// Prüft, ob eine Quelle zu einer Liste von Quellen hinzugefügt werden darf.
        /// </summary>
        /// <param name="source">Eine neue Quelle.</param>
        /// <param name="sources">Eine Liste von Quellen, durch genau diese Methode aller auf der
        /// selben Quellgruppe.</param>
        /// <returns>Gesetzt, wenn die Quelle die korrekte Quellgruppe verwendet.</returns>
        private static bool CheckForSourceGroupMatch(IScheduleSource source, IEnumerable <IScheduleSource> sources)
        {
            // Process
            var any = sources.FirstOrDefault();

            if (any == null)
            {
                return(true);
            }
            else
            {
                return(any.BelongsToSameSourceGroupAs(source));
            }
        }
示例#11
0
 /// <summary>
 /// Prüft, ob eine Quelle reserviert werden kann.
 /// </summary>
 /// <param name="source">Die zu prüfende Quelle.</param>
 /// <returns>Gesetzt, wenn eine Reservierung möglich ist.</returns>
 public bool CanAllocate(IScheduleSource source)
 {
     // Test
     if (Sources.Any(s => s.IsSameAs(source)))
     {
         return(true);
     }
     else if (!m_Map.CanMerge(source, Sources))
     {
         return(false);
     }
     else
     {
         return(Sources.Count < m_Map.TotalNumberOfSources);
     }
 }
        /// <summary>
        /// Prüft, ob eine bestimmte Quelle über dieses Gerät angesprochen werden kann.
        /// </summary>
        /// <param name="source">Die gewünschte Quelle.</param>
        /// <returns>Gesetzt, wenn die Quelle angesprochen werden kann.</returns>
        /// <exception cref="ArgumentNullException">Es wurde keine Quelle angegeben.</exception>
        /// <exception cref="ArgumentException">Die Quelle passt nicht zu dieser Art von Gerät.</exception>
        public bool CanAccess(IScheduleSource source)
        {
            // Validate
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }

            // Check type
            var typedSource = source as SourceType;

            if (typedSource == null)
            {
                throw new ArgumentException(source.GetType().FullName, "source");
            }

            // Report
            return(TestAccess(typedSource));
        }
            /// <summary>
            /// Prüft, ob diese Quelle mit einer anderen parallel aufgezeichnet werden kann.
            /// </summary>
            /// <param name="source">Eine andere Quelle.</param>
            /// <returns>Gesetzt, wenn eine parallele Aufzeichnung theoretisch möglich ist.</returns>
            public bool BelongsToSameSourceGroupAs(IScheduleSource source)
            {
                // Check type first
                var typedSource = source as _Source;

                if (typedSource == null)
                {
                    return(false);
                }

                // Check groups
                if (Equals(Source.Group, typedSource.Source.Group))
                {
                    return(Equals(Source.Location, typedSource.Source.Location));
                }
                else
                {
                    return(false);
                }
            }
示例#14
0
 /// <summary>
 /// Prüft, ob diese Quelle mit einer anderen parallel aufgezeichnet werden kann.
 /// </summary>
 /// <param name="source">Eine andere Quelle.</param>
 /// <returns>Gesetzt, wenn eine parallele Aufzeichnung theoretisch möglich ist.</returns>
 public bool BelongsToSameSourceGroupAs( IScheduleSource source )
 {
     // Check type first
     var typedSource = source as SourceMock;
     if (typedSource == null)
         return false;
     else
         return (SourceGroup == typedSource.SourceGroup);
 }
示例#15
0
            /// <summary>
            /// Aktiviert eine Aufzeichnung auf einem Gerät.
            /// </summary>
            /// <param name="resource">Eines der verwalteten Geräte.</param>
            /// <param name="source">Optional eine Quelle, die auf dem Gerät angesteuert werden kann.</param>
            /// <param name="scheduleIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
            /// <param name="scheduleName">Der Anzeigename der Aufzeichnung.</param>
            /// <param name="plannedStart">Der ursprüngliche Start der Aufzeichnung in UTC / GMT Notation.</param>
            /// <param name="currentEnd">Das aktuelle Ende der Aufzeichnung in UTC / GMT Notation.</param>
            /// <returns>Gesetzt, wenn die Aufzeichnung auf dem gewünschten Gerät aktiviert werden kann.</returns>
            /// <exception cref="ArgumentNullException">Es wurde kein Gerät angegeben.</exception>
            /// <exception cref="ArgumentException">Das Gerät ist nicht bekannt oder kann die Quelle nicht empfangen.</exception>
            /// <exception cref="ArgumentOutOfRangeException">Die Laufzeit der Aufzeichnung ist nicht positiv.</exception>
            public bool Start( IScheduleResource resource, IScheduleSource source, Guid scheduleIdentifier, string scheduleName, DateTime plannedStart, DateTime currentEnd )
            {
                // Validate
                if (resource == null)
                    throw new ArgumentNullException( "resource" );
                if (!m_Resources.Contains( resource ))
                    throw new ArgumentException( resource.Name, "resource" );
                if (plannedStart >= currentEnd)
                    throw new ArgumentOutOfRangeException( "currentEnd" );
                if (m_Recordings.Any( r => r.UniqueIdentifier == scheduleIdentifier ))
                    throw new ArgumentException( "resource" );

                // Create helper entry
                m_Recordings.Add( new ResourceAllocationInformation( resource, source, scheduleIdentifier, scheduleName, plannedStart, currentEnd - plannedStart ) );

                // May require cleanup
                try
                {
                    // Create the new plan
                    var plan = CreateSchedulePlan();

                    // Did it
                    if (plan != null)
                    {
                        // Remember as current
                        m_CurrentPlan = plan;

                        // Report
                        return true;
                    }
                }
                catch
                {
                    // Cleanup
                    m_Recordings.RemoveAt( m_Recordings.Count - 1 );

                    // Report
                    throw;
                }

                // Cleanup
                m_Recordings.RemoveAt( m_Recordings.Count - 1 );

                // Add to list
                return false;
            }
示例#16
0
        /// <summary>
        /// Korrigiert einen Abruf einer Entschlüsselung.
        /// </summary>
        /// <param name="allocationIndex">Die laufende Nummer des zu belegenden Eintrags.</param>
        /// <param name="source">Die zu verwendende Quelle.</param>
        /// <param name="time">Der Zeitraum, in dem eine Entschlüsselung aktiv ist.</param>
        private void Allocate(int allocationIndex, IScheduleSource source, ref PlannedTime time)
        {
            // Reset all caches - just in case...
            m_cachedResourceStartTimes = null;
            m_sourceUsage = null;

            // We are now using the source
            if (!m_Sources.Any(s => s.IsSameAs(source)))
            {
                m_Sources.Add(source);
            }

            // Localize time - can not use ref parameters inside a delegate
            var timeCopy = time;

            // Find the one the prepare analysis gave us - no further tests will be made!
            var allocation = m_Allocations[allocationIndex];

            // See if we have to clip
            if (time.Start < allocation.Start)
            {
                // Do the clip
                time.Duration = time.End - allocation.Start;
                time.Start    = allocation.Start;
            }

            // Correct it all
            for (; ;)
            {
                // On change we must create a clone
                var allocationIsPrivate = false;

                // Create a new starter
                if (time.Start > allocation.Start)
                {
                    // Create a new allocation entry
                    var split = allocation.Clone(allocation.Start, time.Start);

                    // Add it just in front of the current one
                    m_Allocations.Insert(allocationIndex++, split);

                    // Must create a brand new one
                    allocation = allocation.Clone(time.Start, allocation.End);

                    // Update in our private list
                    m_Allocations[allocationIndex] = allocation;

                    // We can now safely overwrite it
                    allocationIsPrivate = true;
                }

                // Create a new trailer
                if (time.End < allocation.End)
                {
                    // Create a new allocation entry
                    var split = allocation.Clone(time.End, allocation.End);

                    // Add it just behind the current one
                    m_Allocations.Insert(allocationIndex + 1, split);

                    // Update the allocation
                    if (allocationIsPrivate)
                    {
                        // We are allowed to change it
                        allocation.End = time.End;
                    }
                    else
                    {
                        // Must create a brand new one
                        allocation = allocation.Clone(allocation.Start, time.End);

                        // Update in our private list
                        m_Allocations[allocationIndex] = allocation;

                        // We are now allowed to write to it
                        allocationIsPrivate = true;
                    }
                }

                // Update the allocation
                if (allocationIsPrivate)
                {
                    // Just count down
                    allocation.Allocate(source);
                }
                else
                {
                    // Must create a brand new one
                    allocation = allocation.Clone(allocation.Start, allocation.End);

                    // Correct
                    allocation.Allocate(source);

                    // Update in our private list
                    m_Allocations[allocationIndex] = allocation;
                }

                // See if we are done
                if (time.End <= allocation.End)
                {
                    break;
                }

                // Load the next allocation area
                allocation = m_Allocations[++allocationIndex];
            }
        }
示例#17
0
        /// <summary>
        /// Prüft ob zwei Quellen identisch sind.
        /// </summary>
        /// <param name="source">Eine andere Quelle.</param>
        /// <returns>Gesetzt, wenn die Quellen identisch sind.</returns>
        public bool IsSameAs( IScheduleSource source )
        {
            // Pre-test
            if (!BelongsToSameSourceGroupAs( source ))
                return false;

            // Can now safe cast
            var typedSource = source as SourceMock;

            // Just test the identification
            return Equals( Name, typedSource.Name );
        }
            /// <summary>
            /// Erzeugt eine neue Beschreibung.
            /// </summary>
            /// <param name="context">Vom Anwender der Schnittstelle zusätzlich bereitgestellte Daten.</param>
            /// <param name="name">Eine Name zur Identifikation der Aufzeichnung.</param>
            /// <param name="uniqueIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
            /// <param name="resources">Die Liste aller Geräte, die verwendet werden dürfen.</param>
            /// <param name="source">Die gewünschte Quelle.</param>
            /// <param name="start">Der Beginn der Aufzeichnung.</param>
            /// <param name="end">Der Tag der letzten Aufzeichnung.</param>
            /// <param name="duration">Die Dauer der Aufzeichnung.</param>
            /// <param name="pattern">Die Liste der Tage, an denen die Aufzeichnung stattfinden soll.</param>
            public _RepeatingItem(UserDataType context, string name, Guid uniqueIdentifier, IScheduleResource[] resources, IScheduleSource source, DateTime start, DateTime end, TimeSpan duration, IEnumerable <DayOfWeek> pattern)
                : base(context, name, uniqueIdentifier, resources, source, start, duration)
            {
                // Unmap
                var localStartDate = start.ToLocalTime().Date;
                var days           = pattern.ToArray();

                // Remember
                m_Pattern = new HashSet <DayOfWeek>(days);
                m_End     = end;

                // Validate
                if (end.TimeOfDay != TimeSpan.Zero)
                {
                    throw new ArgumentException(string.Format(Properties.InterfaceResources.Exception_EndNotDay, end), "end");
                }
                if (end < localStartDate)
                {
                    throw new ArgumentException(string.Format(Properties.InterfaceResources.Exception_EndDay, localStartDate, end), "end");
                }
                if (m_Pattern.Count < 1)
                {
                    throw new ArgumentException(Properties.InterfaceResources.Exception_EmptyPattern, "pattern");
                }
                if (m_Pattern.Count != days.Length)
                {
                    throw new ArgumentException(Properties.InterfaceResources.Exception_BadPattern, "pattern");
                }
            }
 /// <summary>
 /// Erzeugt eine einmalige Aufzeichnung.
 /// </summary>
 /// <param name="context">Vom Anwender zusätzlich bereitgestellte Daten.</param>
 /// <param name="name">Eine Name zur Identifikation der Aufzeichnung.</param>
 /// <param name="uniqueIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
 /// <param name="resources">Die Liste aller Geräte, die verwendet werden dürfen.</param>
 /// <param name="source">Die zu verwendende Quelle.</param>
 /// <param name="start">Der Beginn der Aufzeichnung in UTC / GMT Notation.</param>
 /// <param name="duration">Die Dauer der Aufzeichnung.</param>
 /// <typeparam name="UserDataType">Vom Benutzer zusätzlich bereitgestellte Informationen.</typeparam>
 /// <returns>Die Beschreibung der Aufzeichnung.</returns>
 /// <exception cref="ArgumentNullException">Es wurde keine Quelle angegeben.</exception>
 /// <exception cref="ArgumentOutOfRangeException">Der Startzeitpunkt liegt vor dem Jahr 2000 oder
 /// die Dauer ist nicht positiv.</exception>
 public static IRecordingDefinition <UserDataType> Create <UserDataType>(UserDataType context, string name, Guid uniqueIdentifier, IScheduleResource[] resources, IScheduleSource source, DateTime start, TimeSpan duration)
 {
     // Use the simple implementation
     return(new _OneOffItem <UserDataType>(context, name, uniqueIdentifier, resources, source, start, duration));
 }
 /// <summary>
 /// Erzeugt eine sich wiederholende Aufzeichnung.
 /// </summary>
 /// <param name="context">Vom Anwender zusätzlich bereitgestellte Daten.</param>
 /// <param name="name">Eine Name zur Identifikation der Aufzeichnung.</param>
 /// <param name="uniqueIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
 /// <param name="resources">Die Liste aller Geräte, die verwendet werden dürfen.</param>
 /// <param name="source">Die zu verwendende Quelle.</param>
 /// <param name="start">Der Beginn der Aufzeichnung in UTC / GMT Notation.</param>
 /// <param name="duration">Die Dauer der Aufzeichnung.</param>
 /// <param name="end">Der Tag in der lokalen Zeitzone, an dem die Aufzeichnung letztmalig ausgeführt werden soll.</param>
 /// <param name="dayPattern">Die Tage in der lokalen Zeitzone, an denen eine Aufzeichnung stattfinden soll.</param>
 /// <typeparam name="UserDataType">Vom Benutzer zusätzlich bereitgestellte Informationen.</typeparam>
 /// <returns>Die Beschreibung der Aufzeichnung.</returns>
 /// <exception cref="ArgumentNullException">Es wurde keine Quelle angegeben.</exception>
 /// <exception cref="ArgumentOutOfRangeException">Der Startzeitpunkt liegt vor dem Jahr 2000 oder
 /// die Dauer ist nicht positiv.</exception>
 public static IRecordingDefinition <UserDataType> Create <UserDataType>(UserDataType context, string name, Guid uniqueIdentifier, IScheduleResource[] resources, IScheduleSource source, DateTime start, TimeSpan duration, DateTime end, params DayOfWeek[] dayPattern)
 {
     // Use the repeating implementation which will do some more tests
     return(new _RepeatingItem <UserDataType>(context, name, uniqueIdentifier, resources, source, start, end, duration, dayPattern ?? Enumerable.Empty <DayOfWeek>()));
 }