Exemplo n.º 1
0
        /// <summary>
        /// Aktualisiert einen Auftrag oder legt einen neue an.
        /// </summary>
        /// <param name="job">Der betroffene Auftrag.</param>
        /// <param name="scheduleIdentifier">Die eindeutige Kennung der veränderten Aufzeichnung.</param>
        public void UpdateJob(VCRJob job, Guid?scheduleIdentifier)
        {
            // Client is talking to us - do not hibernate after update
            m_PendingHibernation = false;

            // Cleanup
            if (scheduleIdentifier.HasValue)
            {
                foreach (var schedule in job.Schedules)
                {
                    if (schedule.UniqueID.HasValue)
                    {
                        if (schedule.UniqueID.Value.Equals(scheduleIdentifier.Value))
                        {
                            schedule.NoStartBefore = null;
                        }
                    }
                }
            }

            // Add to job manager
            JobManager.Update(job, scheduleIdentifier);

            // Recalculate
            BeginNewPlan();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Aktualisiert einen Auftrag oder legt einen Auftrag neu an.
        /// </summary>
        /// <param name="job">Der neue oder veränderte Auftrag.</param>
        /// <param name="scheduleIdentifier">Die eindeutige Kennung der veränderten Aufzeichnung.</param>
        public void Update(VCRJob job, Guid?scheduleIdentifier)
        {
            // Report
            if (job != null)
            {
                Tools.ExtendedLogging("Updating Job {0}", job.UniqueID);
            }

            // Load default profile name
            job.SetProfile();

            // Validate
            job.Validate(scheduleIdentifier);

            // Cleanup schedules
            job.CleanupExceptions();

            // Remove from archive - if job has been recovered
            job.Delete(ArchiveDirectory);

            // Try to store to disk - actually this is inside the lock because the directory virtually is part of our map
            lock (m_Jobs)
                if (job.Save(JobDirectory).GetValueOrDefault())
                {
                    m_Jobs[job.UniqueID.Value] = job;
                }
                else
                {
                    throw new ArgumentException(string.Format(Properties.Resources.SaveJobFailed, job.UniqueID), "job");
                }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Entfernt einen Auftrag.
        /// </summary>
        /// <param name="job">Der betroffene Auftrag.</param>
        public void DeleteJob(VCRJob job)
        {
            // Client is talking to us - do not hibernate after change
            m_PendingHibernation = false;

            // Remove from job manager
            JobManager.Delete(job);

            // Recalculate
            BeginNewPlan();
        }
Exemplo n.º 4
0
        /// <summary>
        /// Erstellt einen passenden Auftrag für die persistente Ablage.
        /// </summary>
        /// <param name="jobIdentifier">Die eindeutige Kennung des Auftrags.</param>
        /// <returns>Der zugehörige Auftrag.</returns>
        public VCRJob CreateJob(Guid jobIdentifier)
        {
            // Create core
            var job =
                new VCRJob
            {
                AutomaticResourceSelection = !UseProfileForRecording,
                Directory = RecordingDirectory,
                UniqueID  = jobIdentifier,
                Name      = Name,
            };

            // Check source
            var profile = Profile;

            if (string.IsNullOrEmpty(profile))
            {
                return(job);
            }

            // Get the name of the source
            var sourceName = Source;

            if (string.IsNullOrEmpty(sourceName))
            {
                // Create profile reference
                job.Source = new SourceSelection {
                    ProfileName = profile
                };

                // Done
                return(job);
            }

            // Locate the source
            job.Source = ServerRuntime.VCRServer.FindSource(profile, sourceName);
            if (job.Source == null)
            {
                return(job);
            }

            // Configure streams
            job.Streams = new StreamSelection();

            // Set all - oder of audio settings is relevant, dolby MUST come last
            job.Streams.SetUsesAllAudio(AllLanguages);
            job.Streams.SetUsesDolbyAudio(DolbyDigital);
            job.Streams.SetUsesSubtitles(DVBSubtitles);
            job.Streams.SetUsesVideotext(Videotext);
            job.Streams.ProgramGuide = true;

            // Report
            return(job);
        }
Exemplo n.º 5
0
 /// <summary>
 /// Legt eine neue Information an.
 /// </summary>
 /// <param name="job">Der Auftrag.</param>
 /// <param name="schedule">Die Aufzeichnung.</param>
 /// <param name="guide">Ein Eintrag der Programmzeitschrift.</param>
 /// <param name="profile">Vorgabe für das Geräteprofil.</param>
 /// <returns>Die Information.</returns>
 public static JobScheduleInfo Create(VCRJob job, VCRSchedule schedule, ProgramGuideEntry guide, string profile)
 {
     // Process
     return
         (new JobScheduleInfo
     {
         ScheduleIdentifier = (schedule == null) ? null : schedule.UniqueID.Value.ToString("N"),
         JobIdentifier = (job == null) ? null : job.UniqueID.Value.ToString("N"),
         Schedule = EditSchedule.Create(schedule, job, guide),
         Job = EditJob.Create(job, guide, profile),
     });
 }
Exemplo n.º 6
0
 /// <summary>
 /// Erstellt eine neue Beschreibung.
 /// </summary>
 /// <param name="job">Ein Auftrag.</param>
 /// <param name="active">Gesetzt, wenn es sich um einen aktiven Auftrag handelt.</param>
 /// <returns>Die gewünschte Beschreibung.</returns>
 public static InfoJob Create(VCRJob job, bool active)
 {
     // Report
     return
         (new InfoJob
     {
         Schedules = job.Schedules.Select(schedule => InfoSchedule.Create(schedule, job)).OrderBy(schedule => schedule.Name ?? string.Empty, StringComparer.InvariantCultureIgnoreCase).ToArray(),
         WebId = ServerRuntime.GetUniqueWebId(job, null),
         ProfileName = job.Source.ProfileName,
         SourceName = job.Source.DisplayName,
         IsActive = active,
         Name = job.Name,
     });
 }
Exemplo n.º 7
0
 /// <summary>
 /// Meldet die Daten zu einer Aufzeichnung.
 /// </summary>
 /// <param name="schedule">Die Aufzeichnung.</param>
 /// <param name="job">Der zugehörige Auftrag.</param>
 /// <returns></returns>
 public static InfoSchedule Create(VCRSchedule schedule, VCRJob job)
 {
     // Create
     return
         (new InfoSchedule
     {
         Source = (schedule.Source ?? job.Source).GetUniqueName(),
         WebId = ServerRuntime.GetUniqueWebId(job, schedule),
         StartTime = schedule.FirstStart,
         RepeatPattern = schedule.Days,
         Duration = schedule.Duration,
         Name = schedule.Name,
     });
 }
Exemplo n.º 8
0
        /// <summary>
        /// Erstellt die Beschreibung der Aufzeichnung für die persistente Ablage.
        /// </summary>
        /// <param name="scheduleIdentifier">Die eindeutige Kennung der Aufzeichnung.</param>
        /// <param name="job">Der zugehörige Auftrag.</param>
        /// <returns>Die gewünschte Beschreibung.</returns>
        public VCRSchedule CreateSchedule(Guid scheduleIdentifier, VCRJob job)
        {
            // Create
            var schedule =
                new VCRSchedule
            {
                UniqueID   = scheduleIdentifier,
                FirstStart = FirstStart,
                Days       = RepeatPattern,
                Duration   = Duration,
                LastDay    = LastDay,
                Name       = Name,
            };

            // See if we have a source
            var sourceName = Source;

            if (string.IsNullOrEmpty(sourceName))
            {
                return(schedule);
            }

            // See if there is a profile
            var jobSource = job.Source;

            if (jobSource == null)
            {
                return(schedule);
            }

            // Locate the source
            schedule.Source = ServerRuntime.VCRServer.FindSource(jobSource.ProfileName, sourceName);
            if (schedule.Source == null)
            {
                return(schedule);
            }

            // Configure streams
            schedule.Streams = new StreamSelection();

            // Set all - oder of audio settings is relevant, dolby MUST come last
            schedule.Streams.SetUsesAllAudio(AllLanguages);
            schedule.Streams.SetUsesDolbyAudio(DolbyDigital);
            schedule.Streams.SetUsesSubtitles(DVBSubtitles);
            schedule.Streams.SetUsesVideotext(Videotext);
            schedule.Streams.ProgramGuide = true;

            // Report
            return(schedule);
        }
Exemplo n.º 9
0
 /// <summary>
 /// Erzeugt eine Beschreibung.
 /// </summary>
 /// <param name="job">Ein Auftrag.</param>
 /// <param name="active">Gesetzt, wenn es sich um einen aktiven Auftrag handel.</param>
 /// <returns>Die gewünschte Beschreibung.</returns>
 public static ProfileJobInfo Create(VCRJob job, bool active)
 {
     // Process
     if (active)
     {
         return new ProfileJobInfo {
                    Profile = job.Source.ProfileName, Name = job.Name, JobIdentifier = job.UniqueID.Value.ToString("N").ToLower()
         }
     }
     ;
     else
     {
         return(null);
     }
 }
Exemplo n.º 10
0
 /// <summary>
 /// Ermittelt eine Referenz für eine bestimmte Aufzeichung in einem Auftrag, so dass diese
 /// auch in einer URL verwendet werden kann.
 /// </summary>
 /// <param name="job">Ein Auftrag.</param>
 /// <param name="schedule">Eine Aufzeichnung.</param>
 /// <returns>Die eindeutige Referenz.</returns>
 public static string GetUniqueWebId(VCRJob job, VCRSchedule schedule)
 {
     // Forward
     if (job == null)
     {
         return("*");
     }
     else if (schedule == null)
     {
         return(string.Format("*{0:N}", job.UniqueID.Value));
     }
     else
     {
         return(GetUniqueWebId(job.UniqueID.Value, schedule.UniqueID.Value));
     }
 }
Exemplo n.º 11
0
        /// <summary>
        /// Erstellt eine neue Beschreibung.
        /// </summary>
        /// <param name="job">Der konkrete Auftag.</param>
        /// <param name="guide">Ein Eintrag der Programmzeitschrift.</param>
        /// <param name="profile">Vorgabe für das Geräteprofil.</param>
        /// <returns>Die zugehörige Beschreibung.</returns>
        public static EditJob Create(VCRJob job, ProgramGuideEntry guide, string profile)
        {
            // Process
            if (job == null)
            {
                // No hope
                if (guide == null)
                {
                    return(null);
                }

                // Create from program guide
                return
                    (new EditJob
                {
                    Source = ServerRuntime.VCRServer.GetUniqueName(new SourceSelection {
                        ProfileName = profile, Source = guide.Source
                    }),
                    DVBSubtitles = UserProfileSettings.UseSubTitles,
                    DolbyDigital = UserProfileSettings.UseAC3,
                    AllLanguages = UserProfileSettings.UseMP2,
                    Videotext = UserProfileSettings.UseTTX,
                    UseProfileForRecording = false,
                    Name = guide.Name.MakeValid(),
                    Profile = profile,
                });
            }

            // Optionen ermitteln
            var streams    = job.Streams;
            var sourceName = ServerRuntime.VCRServer.GetUniqueName(job.Source);

            // Report
            return
                (new EditJob
            {
                UseProfileForRecording = !job.AutomaticResourceSelection,
                DolbyDigital = streams.GetUsesDolbyAudio(),
                AllLanguages = streams.GetUsesAllAudio(),
                DVBSubtitles = streams.GetUsesSubtitles(),
                Videotext = streams.GetUsesVideotext(),
                RecordingDirectory = job.Directory,
                Profile = job.Source.ProfileName,
                Source = sourceName,
                Name = job.Name,
            });
        }
Exemplo n.º 12
0
        /// <summary>
        /// Rekonstruiert einen Auftrag und eine Aufzeichnung aus einer Textdarstellung.
        /// </summary>
        /// <param name="id">Die Textdarstellung.</param>
        /// <param name="job">Der ermittelte Auftrag.</param>
        /// <returns>Die zugehörige Aufzeichnung im Auftrag.</returns>
        public static VCRSchedule ParseUniqueWebId(string id, out VCRJob job)
        {
            ParseUniqueWebId(id, out Guid jobID, out Guid scheduleID);

            // Find the job
            job = VCRServer.FindJob(jobID);

            // Report schedule if job exists
            if (job == null)
            {
                return(null);
            }
            else
            {
                return(job[scheduleID]);
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Ermittelt einen Auftrag nach seiner eindeutigen Kennung.
        /// </summary>
        /// <param name="jobIdentifier">Die Kennung des Auftrags.</param>
        /// <returns>Der gewünschte Auftrag oder <i>null</i>, wenn kein derartiger
        /// Auftrag existiert.</returns>
        public VCRJob FindJob(Guid jobIdentifier)
        {
            // The result
            VCRJob result = null;

            // Synchronize
            lock (m_Jobs)
            {
                // Try map
                if (m_Jobs.TryGetValue(jobIdentifier, out result))
                {
                    return(result);
                }

                // Create file name
                var jobFile = new FileInfo(Path.Combine(ArchiveDirectory.FullName, jobIdentifier.ToString("N").ToUpper() + VCRJob.FileSuffix));
                if (!jobFile.Exists)
                {
                    return(null);
                }

                // Load
                result = SerializationTools.Load <VCRJob>(jobFile);
                if (result == null)
                {
                    return(null);
                }
            }

            // Check identifier and finalize settings - for pre-3.0 files
            if (!result.UniqueID.HasValue)
            {
                return(null);
            }
            if (!jobIdentifier.Equals(result.UniqueID.Value))
            {
                return(null);
            }

            // Finish
            result.SetProfile();

            // Found in archive
            return(result);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Ergänz die Abbildung von einer Aufzeichnung auf einen Auftrag.
        /// </summary>
        /// <param name="schedule">Eine Aufzeichnung.</param>
        /// <param name="job">Der zugehörige Auftrag.</param>
        public void RegisterSchedule(VCRSchedule schedule, VCRJob job)
        {
            // Validate
            if (schedule == null)
            {
                throw new ArgumentNullException(nameof(schedule));
            }
            if (job == null)
            {
                throw new ArgumentNullException(nameof(job));
            }

            // Skip on missing identifier
            var scheduleIdentifier = schedule.UniqueID;

            if (scheduleIdentifier.HasValue)
            {
                m_jobsBySchedule.Add(scheduleIdentifier.Value, job);
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Löscht einen aktiven oder archivierten Auftrag.
        /// </summary>
        /// <param name="job">Der zu löschende Auftrag.</param>
        public void Delete(VCRJob job)
        {
            // Check unique identifier
            if (!job.UniqueID.HasValue)
            {
                throw new InvalidJobDataException(Properties.Resources.BadUniqueID);
            }

            // Report
            Tools.ExtendedLogging("Deleting Job {0}", job.UniqueID);

            // Must synchronize
            lock (m_Jobs)
            {
                // Load from the map
                var internalJob = this[job.UniqueID.Value];

                // See if this is active
                if (internalJob != null)
                {
                    // Delete it
                    internalJob.Delete(JobDirectory);

                    // Remove from map
                    m_Jobs.Remove(internalJob.UniqueID.Value);

                    // Save to file
                    internalJob.Save(ArchiveDirectory);
                }
                else
                {
                    // Report
                    Tools.ExtendedLogging("Job not found in Active Directory - trying Archive");

                    // Must be archived
                    job.Delete(ArchiveDirectory);
                }
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Erzeugt eine neue Verwaltungsinstanz und lädt die aktuellen Auftragsliste.
        /// </summary>
        /// <param name="rootDirectory">Meldet das Verzeichnis, unterhalb dessen alle
        /// Aufträge und Protokolle angelegt werden.</param>
        /// <param name="server">Die VCR.NET Instanz, der diese Verwaltung zugeordnet ist.</param>
        internal JobManager(DirectoryInfo rootDirectory, VCRServer server)
        {
            // Remember
            RootDirectory = rootDirectory;
            Server        = server;

            // Create root directory
            RootDirectory.Create();

            // Create working directories
            CollectorDirectory.Create();
            ArchiveDirectory.Create();
            JobDirectory.Create();
            LogDirectory.Create();

            // Load all jobs
            foreach (var job in VCRJob.Load(JobDirectory))
            {
                if (job.UniqueID.HasValue)
                {
                    m_Jobs[job.UniqueID.Value] = job;
                }
            }
        }
Exemplo n.º 17
0
 /// <summary>
 /// Erstellt die Beschreibung der Aufzeichnung für die persistente Ablage.
 /// </summary>
 /// <param name="job">Der zugehörige Auftrag.</param>
 /// <returns>Die gewünschte Beschreibung.</returns>
 public VCRSchedule CreateSchedule(VCRJob job)
 {
     // Forward
     return(CreateSchedule(Guid.NewGuid(), job));
 }
Exemplo n.º 18
0
        /// <summary>
        /// Erstellt eine Beschreibung zu dieser Aufzeichnung.
        /// </summary>
        /// <param name="schedule">Eine Aufzeichnung.</param>
        /// <param name="job">Der bereits vorhandene Auftrag.</param>
        /// <param name="guide">Ein Eintrag aus der Programmzeitschrift.</param>
        /// <returns>Die gewünschte Beschreibung.</returns>
        public static EditSchedule Create(VCRSchedule schedule, VCRJob job, ProgramGuideEntry guide)
        {
            // None
            if (schedule == null)
            {
                // No hope
                if (guide == null)
                {
                    return(null);
                }

                // Calculate
                var start    = guide.StartTime - TimeSpan.FromMinutes(UserProfileSettings.EPGPreTime);
                var duration = checked ((int)(UserProfileSettings.EPGPreTime + (guide.Duration / 60) + UserProfileSettings.EPGPostTime));

                // Partial - we have a brand new job which is pre-initialized with the source
                if (job == null)
                {
                    return new EditSchedule {
                               FirstStart = start, Duration = duration
                    }
                }
                ;

                // Full monty - we have to overwrite the jobs settings since we are not the first schedule
                return
                    (new EditSchedule
                {
                    Source = ServerRuntime.VCRServer.GetUniqueName(new SourceSelection {
                        ProfileName = job.Source.ProfileName, Source = guide.Source
                    }),
                    DVBSubtitles = UserProfileSettings.UseSubTitles,
                    DolbyDigital = UserProfileSettings.UseAC3,
                    AllLanguages = UserProfileSettings.UseMP2,
                    Videotext = UserProfileSettings.UseTTX,
                    Name = guide.Name.MakeValid(),
                    Duration = duration,
                    FirstStart = start,
                });
            }

            // Consolidate exceptions
            schedule.CleanupExceptions();

            // Optionen ermitteln
            var streams    = schedule.Streams;
            var sourceName = ServerRuntime.VCRServer.GetUniqueName(schedule.Source);

            // Create
            return
                (new EditSchedule
            {
                Exceptions = schedule.Exceptions.Select(exception => PlanException.Create(exception, schedule)).ToArray(),
                LastDay = schedule.LastDay.GetValueOrDefault(VCRSchedule.MaxMovableDay),
                DolbyDigital = streams.GetUsesDolbyAudio(),
                DVBSubtitles = streams.GetUsesSubtitles(),
                AllLanguages = streams.GetUsesAllAudio(),
                Videotext = streams.GetUsesVideotext(),
                FirstStart = schedule.FirstStart,
                RepeatPattern = schedule.Days,
                Duration = schedule.Duration,
                Name = schedule.Name,
                Source = sourceName,
            });
        }
Exemplo n.º 19
0
        /// <summary>
        /// Erstellt einen neuen Eintrag.
        /// </summary>
        /// <param name="schedule">Die zugehörige Beschreibung der geplanten Aktivität.</param>
        /// <param name="context">Die Abbildung auf die Aufträge.</param>
        /// <param name="profiles">Die Verwaltung der Geräteprofile.</param>
        /// <returns>Die angeforderte Repräsentation.</returns>
        public static PlanActivity Create(IScheduleInformation schedule, PlanContext context, ProfileStateCollection profiles)
        {
            // Request context information
            var definition   = schedule.Definition;
            var runningInfo  = context.GetRunState(definition.UniqueIdentifier);
            var isAllocation = definition is IResourceAllocationInformation;

            // Maybe it's an resource allocation
            if (isAllocation)
            {
                if (runningInfo != null)
                {
                    definition = runningInfo.Schedule.Definition;
                }
                else
                {
                    return(null);
                }
            }

            // Create initial entry
            var time     = schedule.Time;
            var start    = time.Start;
            var end      = time.End;
            var activity =
                new PlanActivity
            {
                IsHidden = (schedule.Resource == null),
                IsLate   = schedule.StartsLate,
            };

            // May need some correction
            if (runningInfo != null)
            {
                if (end == runningInfo.Schedule.Time.End)
                {
                    // Only report the allocation itself
                    if (!isAllocation)
                    {
                        return(null);
                    }

                    // Reload the real start and times - just in case someone manipulated
                    start = runningInfo.Schedule.Time.Start;
                    end   = runningInfo.RealTime.End;

                    // Never report as late - actually since we have some spin up time most of the time the recording is late
                    activity.IsLate = false;
                }
            }

            // Get the beautified range
            start = PlanCurrent.RoundToSecond(start);
            end   = PlanCurrent.RoundToSecond(end);

            // Set times
            activity.Duration  = end - start;
            activity.StartTime = start;

            // Set name
            if (definition != null)
            {
                activity.FullName = definition.Name;
            }

            // Set resource
            var resource = schedule.Resource;

            if (resource != null)
            {
                activity.Device = resource.Name;
            }

            // Schedule to process
            VCRSchedule vcrSchedule = null;
            VCRJob      vcrJob      = null;

            // Analyse definition
            var scheduleDefinition = definition as IScheduleDefinition <VCRSchedule>;

            if (scheduleDefinition != null)
            {
                // Regular plan
                vcrSchedule = scheduleDefinition.Context;
                vcrJob      = context.TryFindJob(vcrSchedule);
            }

            // Process if we found one
            if (vcrSchedule != null)
            {
                // See if we have a job
                if (vcrJob != null)
                {
                    activity.LegacyReference = ServerRuntime.GetUniqueWebId(vcrJob, vcrSchedule);
                }

                // Find the source to use - stream selection is always bound to the context of the source
                var streams = vcrSchedule.Streams;
                var source  = vcrSchedule.Source;
                if (source == null)
                {
                    if (vcrJob != null)
                    {
                        // Try job
                        source = vcrJob.Source;

                        // Adjust stream flags to use
                        if (source == null)
                        {
                            streams = null;
                        }
                        else
                        {
                            streams = vcrJob.Streams;
                        }
                    }
                }

                // Copy station name
                if (source != null)
                {
                    // Remember
                    activity.Source  = SourceIdentifier.ToString(source.Source).Replace(" ", "");
                    activity.Station = source.DisplayName;

                    // Load the profile
                    var profile = profiles[activity.GuideEntryDevice = source.ProfileName];
                    if (profile != null)
                    {
                        activity.HasGuideEntry = profile.ProgramGuide.HasEntry(source.Source, activity.StartTime, activity.StartTime + activity.Duration);
                    }
                }

                // Apply special settings
                activity.CurrentProgramGuide = streams.GetUsesProgramGuide();
                activity.AllLanguages        = streams.GetUsesAllAudio();
                activity.SubTitles           = streams.GetUsesSubtitles();
                activity.VideoText           = streams.GetUsesVideotext();
                activity.Dolby = streams.GetUsesDolbyAudio();

                // Check for exception rule on the day
                var exception = vcrSchedule.FindException(time.End);
                if (exception != null)
                {
                    activity.ExceptionRule = PlanException.Create(exception, vcrSchedule);
                }

                // May want to add end time checks
                if (!isAllocation)
                {
                    if (!activity.IsLate)
                    {
                        if (!activity.IsHidden)
                        {
                            if ((exception == null) || exception.IsEmpty)
                            {
                                activity.EndTimeCouldBeWrong = activity.CheckEndTime(vcrSchedule.FirstStart);
                            }
                        }
                    }
                }
            }
            else if (definition is ProgramGuideTask)
            {
                activity.Station = VCRJob.ProgramGuideName;
            }
            else if (definition is SourceListTask)
            {
                activity.Station = VCRJob.SourceScanName;
            }

            // Report
            return(activity);
        }
Exemplo n.º 20
0
        static void Main1(string[] args)
        {
            // Attach to job manager
            VCRServer  server = new VCRServer(new DirectoryInfo(@"C:\temp\VCR.NET 3.9 Alpha\Jobs"));
            JobManager jobs   = server.JobManager;

            // Process all profiles
            foreach (Profile profile in VCRProfiles.Profiles)
            {
                // Report
                Console.WriteLine(profile.Name);

                // Start time
                DateTime start = DateTime.UtcNow;

                // Process a bit
                for (int i = 10; i-- > 0;)
                {
                    // Helper data
                    VCRRecordingInfo[] included;
                    bool inComplete;

                    // Find the recording
                    FullInfo         info  = jobs.FindNextRecording(start, profile, out inComplete, out included);
                    VCRRecordingInfo rec   = info.Recording;
                    VCRJob           job   = jobs[rec.JobUniqueID.Value];
                    VCRSchedule      sched = job[rec.ScheduleUniqueID.Value];

                    // Report
                    Console.WriteLine("\t{0} {1} {2} ({3}) {4} {5} {6} {7}", rec.StartsAt.Value.ToLocalTime(), rec.EndsAt.ToLocalTime().TimeOfDay, job.Name, sched.Name, inComplete, included.Length, rec.JobUniqueID, rec.ScheduleUniqueID);

                    // Report
                    foreach (VCRRecordingInfo include in included)
                    {
                        Console.WriteLine("\t\t{0} {1} {2} {3} {4}", include.Source.GetUniqueName(), include.StartsAt.Value.ToLocalTime(), include.EndsAt.ToLocalTime().TimeOfDay, include.JobUniqueID, include.ScheduleUniqueID);
                    }

                    // Report
                    foreach (StreamInfo stream in info.Streams)
                    {
                        foreach (ScheduleInfo schedule in stream.Schedules)
                        {
                            Console.WriteLine("\t\t{0} {1} {2} {3}", schedule.JobUniqueID, schedule.ScheduleUniqueID, schedule.StartsAt.ToLocalTime(), schedule.EndsAt.ToLocalTime().TimeOfDay);
                        }
                    }

                    // Advance
                    start = rec.EndsAt;
                }

                // Helper data
                VCRRecordingInfo[] incDummy;
                bool dummyFlag;

                // Start timer
                Stopwatch timer = Stopwatch.StartNew();

                // Measure
                for (int n = 0; ++n > 0;)
                {
                    // Find the recording
                    jobs.FindNextRecording(DateTime.UtcNow, profile, out dummyFlag, out incDummy);

                    // Get the time
                    TimeSpan delta = timer.Elapsed;
                    if (delta.TotalSeconds >= 5)
                    {
                        // Report
                        Console.WriteLine("{0}ms", delta.TotalMilliseconds / n);

                        // Done
                        break;
                    }
                }
            }

            // Get the profile
            Profile nexus = VCRProfiles.FindProfile("Nexus");

            // Find the next recording
            VCRRecordingInfo rec2 = jobs.FindNextJob(new DateTime(2009, 2, 19, 20, 0, 0), null, nexus);

            if (null != rec2)
            {
                if (rec2.StartsAt.HasValue)
                {
                    using (RecordingRequest recording = jobs.CreateRecording(rec2, rec2.StartsAt.Value, nexus))
                    {
                        // Get the information
                        FullInfo info0 = recording.CreateFullInformation();

#if EXEC
                        // Start it
                        recording.BeginExecute(false);

                        // Report
                        Console.WriteLine("Recording...");
                        Console.ReadLine();

                        // Get the information
                        FullInfo info1 = recording.CreateFullInformation();
#endif
                    }
                }
            }

            // Done
            Console.WriteLine("Done");
            Console.ReadLine();
        }