/// <summary>
        /// Ermittelt die Geräteabstraktion zu einer Quellinformation.
        /// </summary>
        /// <param name="selection">Die betroffene Quellinformation.</param>
        /// <returns>Die zugehörige Geräteabstraktion.</returns>
        /// <exception cref="ArgumentNullException">Es wurde keine Quellinformation angegeben.</exception>
        public static Hardware GetHardware(this SourceSelection selection)
        {
            // Validate
            if (null == selection)
            {
                throw new ArgumentNullException("selection");
            }

            // Forward
            using (HardwareManager.Open())
                return(HardwareManager.OpenHardware(selection.ProfileName));
        }
 /// <summary>
 /// Erzeugt einen Aufzeichnungskontext für eine Quelle.
 /// </summary>
 /// <param name="selection">Die Informationen zur Quelle.</param>
 /// <param name="streams">Die gewünschten Aufzeichnungsparameter.</param>
 /// <returns>Eine Kontrollinstanz für die Aufzeichnung. Diese muss mittels <see cref="IDisposable.Dispose"/>
 /// freigegeben werden.</returns>
 public static SourceStreamsManager Open(this SourceSelection selection, StreamSelection streams)
 {
     // Validate
     if (selection == null)
     {
         throw new ArgumentNullException("selection");
     }
     else
     {
         return(selection.Source.Open(selection.GetHardware(), selection.GetLeafProfile(), streams));
     }
 }
        /// <summary>
        /// Aktiviert eine Quellinformation.
        /// </summary>
        /// <param name="selection">Die gewünschte Quellinformation.</param>
        /// <exception cref="ArgumentNullException">Es wurden keine Informationen zur
        /// Quelle angegeben.</exception>
        public static void SelectGroup(this SourceSelection selection)
        {
            // Validate
            if (null == selection)
            {
                throw new ArgumentNullException("selection");
            }

            // Forward
            using (HardwareManager.Open())
                selection.SelectGroup(selection.GetHardware());
        }
            /// <summary>
            /// Wählt eine Quellgruppe an.
            /// </summary>
            /// <param name="source">Eine der Quellen der Gruppe.</param>
            /// <returns>Die Liste aller Quellen der Gruppe.</returns>
            public CancellableTask<SourceSelection[]> Activate( SourceSelection source )
            {
                // Map to indicated device
                var localSource = m_profile.FindSource( source.Source ).FirstOrDefault();
                if (localSource == null)
                    throw new ArgumentException( "bad source", "source" );

                // Create task
                return
                    CancellableTask<SourceSelection[]>.Run( cancel =>
                    {
                        // Check for cancel
                        if (cancel.IsCancellationRequested)
                            return _NoSources;

                        // Start the hardware on first call - this may take some time
                        var device = localSource.GetHardware();

                        // Check for cancel
                        if (cancel.IsCancellationRequested)
                            return _NoSources;

                        // Select the group - again this may last a bit
                        localSource.SelectGroup( device );

                        // Check for cancel
                        if (cancel.IsCancellationRequested)
                            return _NoSources;

                        // Validate
                        var groupReader = device.GroupReader;
                        if (groupReader == null)
                            return _NoSources;
                        if (!groupReader.CancellableWait( cancel ))
                            return _NoSources;

                        // Load the map
                        var groupInformation = groupReader.Result;
                        if (groupInformation == null)
                            return _NoSources;

                        // Use profile to map to full source information
                        return
                            groupInformation
                                .Sources
                                .Select( s => m_profile.FindSource( s ).FirstOrDefault() )
                                .Where( s => s != null )
                                .ToArray();
                    } );
            }
        /// <summary>
        /// Ermittelt das Geräteprofile mit der Senderliste für eine Quellinformation.
        /// </summary>
        /// <param name="selection">Die betroffene Quellinformation.</param>
        /// <returns>Das zugehörige Profil mit der Senderliste, das durchaus von <see cref="GetProfile"/>
        /// abweichen kann.</returns>
        /// <exception cref="ArgumentNullException">Es wurde keine Quellinformation angegeben.</exception>
        public static Profile GetLeafProfile(this SourceSelection selection)
        {
            // Forward
            Profile profile = selection.GetProfile();

            // Check result
            if (null == profile)
            {
                return(null);
            }
            else
            {
                return(profile.LeafProfile);
            }
        }
        /// <summary>
        /// Aktiviert eine Quellinformation auf einer bestimmten Hardware.
        /// </summary>
        /// <param name="selection">Die gewünschte Quellinformation.</param>
        /// <param name="hardware">Die Hardware, die für den Empfang zu verwenden ist.</param>
        /// <exception cref="ArgumentNullException">Es wurden keine Informationen zur
        /// Quelle angegeben.</exception>
        public static void SelectGroup(this SourceSelection selection, Hardware hardware)
        {
            // Validate
            if (null == selection)
            {
                throw new ArgumentNullException("selection");
            }

            // Nothing to do
            if (null == hardware)
            {
                return;
            }

            // Forward
            hardware.SelectGroup(selection);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Stellt sicher, dass eine Aufzeichnung gestartet werden kann.
        /// </summary>
        /// <param name="source">Der gewünschte Sender.</param>
        /// <param name="tx">Die aktuelle Änderungsumgebung.</param>
        /// <returns>Gesetzt, wenn die Aufzeichnung möglich war.</returns>
        private Device EnsureRecordingFeed( SourceSelection source, FeedTransaction tx )
        {
            // Make sure we can receive it
            var device = EnsurePrimaryFeed( source, tx );
            if (device != null)
                return device;

            // See if there is a primary
            var primary = PrimaryView;
            if (primary == null)
                return null;

            // Switch off primary
            tx.DisablePrimaryView( primary );

            // Try again - may fail
            return EnsurePrimaryFeed( source, tx );
        }
        /// <summary>
        /// Ermittelt das Geräteprofile für eine Quellinformation.
        /// </summary>
        /// <param name="selection">Die betroffene Quellinformation.</param>
        /// <returns>Das zugehörige Profil.</returns>
        /// <exception cref="ArgumentNullException">Es wurde keine Quellinformation angegeben.</exception>
        public static Profile GetProfile(this SourceSelection selection)
        {
            // Validate
            if (null == selection)
            {
                throw new ArgumentNullException("selection");
            }

            // Forward
            if (string.IsNullOrEmpty(selection.ProfileName))
            {
                return(null);
            }
            else
            {
                return(ProfileManager.FindProfile(selection.ProfileName));
            }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen.
        /// </summary>
        /// <param name="other">Die andere Quelle.</param>
        /// <param name="transponderOnly">Gesetzt, wenn die eigentliche Quelle bei der Prüfung
        /// nicht berücksichtigt werden soll</param>
        /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns>
        public bool CompareTo(SourceSelection other, bool transponderOnly)
        {
            // Not possible
            if (null == other)
            {
                return(false);
            }

            // Profile
            if (0 != string.Compare(ProfileName, other.ProfileName, true))
            {
                return(false);
            }

            // Source
            if (!transponderOnly)
            {
                if (!Equals(Source, other.Source))
                {
                    return(false);
                }
            }

            // Use semantic compare
            if (!Equals(Location, other.Location))
            {
                return(false);
            }

            // Group pre-test
            if ((null == Group) || (null == other.Group))
            {
                return(false);
            }

            // Group tame test - more or less frequency only
            return(Group.CompareTo(other.Group, true));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Versucht einen Sender für die primäre Anzeige zu aktivieren.
        /// </summary>
        /// <param name="source">Der gewünschte Sender.</param>
        /// <param name="tx">Die aktuelle Änderungsumgebung.</param>
        /// <returns>Gesetzt, wenn die Aktivierung erfolgreich war.</returns>
        private Device EnsurePrimaryFeed( SourceSelection source, FeedTransaction tx )
        {
            // Make sure we can receive it
            var device = EnsureFeed( source );
            if (device != null)
                return device;

            // See if there is any device we can free
            var availableDevice =
                m_devices
                    .Where( cancidate => cancidate.ReusePossible )
                    .Aggregate( default( Device ), ( best, test ) => ((best != null) && (best.SecondaryFeeds.Count() <= test.SecondaryFeeds.Count())) ? best : test );

            // None
            if (availableDevice == null)
                return null;

            // Stop all secondaries
            foreach (var secondaryFeed in availableDevice.SecondaryFeeds)
                tx.DisableSecondaryView( secondaryFeed );

            // Run test again - can not fail
            return EnsureFeed( source );
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen.
 /// </summary>
 /// <param name="other">Die andere Quelle.</param>
 /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns>
 public bool CompareTo(SourceSelection other)
 {
     // Forward
     return(CompareTo(other, false));
 }
 /// <summary>
 /// Beginnt mit dem Auslesen der Quelldaten.
 /// </summary>
 /// <param name="source">Alle Informationen zur Quelle.</param>
 /// <returns>Die Hintergrundaufgabe zum Auslesen der Quelldaten.</returns>
 public static CancellableTask <SourceInformation> GetSourceInformationAsync(this SourceSelection source)
 {
     return(source.GetHardware().GetSourceInformationAsync(source.Source, source.GetProfile()));
 }
Ejemplo n.º 13
0
        /// <summary>
        /// Stellt sicher, dass ein Sender empfangen wird.
        /// </summary>
        /// <param name="source">Der gewünschte Sender.</param>
        /// <returns>Gesetzt, wenn ein Empfang möglich ist.</returns>
        private Device EnsureFeed( SourceSelection source )
        {
            // First see if there is a device handling the source
            var feed = FindFeed( source );
            if (feed != null)
                return feed.Device;

            // See if there is any device activated but idle and then reuse it - better than starting a brand new device
            foreach (var device in m_devices)
                if (device.IsIdle)
                {
                    // Tune it
                    device.EnsureFeed( source );

                    // Report success
                    return device;
                }

            // See if there is any device not yet activated
            foreach (var device in m_devices)
                if (!device.IsAllocated)
                {
                    // Tune it
                    device.EnsureFeed( source );

                    // Report success
                    return device;
                }

            // All devices are in use
            return null;
        }
Ejemplo n.º 14
0
 /// <summary>
 /// Ermittelt einen Sender.
 /// </summary>
 /// <param name="source">Die zugehörige Quelle.</param>
 /// <returns>Der Sender, sofern dieser verfügbar ist.</returns>
 public Feed FindFeed( SourceSelection source )
 {
     return Feeds.SingleOrDefault( feed => ReferenceEquals( feed.Source, source ) );
 }
Ejemplo n.º 15
0
        /// <summary>
        /// Ermittelt die aktuelle Konfiguration einer Quelle.
        /// </summary>
        /// <param name="source">Die gewünschte Quelle.</param>
        /// <returns>Die aktuelle Auswahl oder <i>null</i>.</returns>
        public static SourceSelection FindSource( SourceSelection source )
        {
            // Never
            if (source == null)
                return null;
            if (source.Source == null)
                return null;

            // Find the source
            return FindSource( source.ProfileName, source.Source );
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Ermittelt den eindeutigen Namen einer Quelle.
        /// </summary>
        /// <param name="source">Die gewünschte Quelle.</param>
        /// <returns>Der eindeutige Name oder <i>null</i>, wenn die Quelle nicht
        /// bekannt ist..</returns>
        public static string GetUniqueName( SourceSelection source )
        {
            // Map to current
            var active = FindSource( source );
            if (active == null)
                return null;

            // Find the name
            string name;
            if (!CurrentState.UniqueNameBySelectionMap.TryGetValue( active.SelectionKey, out name ))
                return null;

            // Report it
            return name;
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Stellt sicher, dass für diesen Auftrag ein Geräteprprofil ausgewählt ist.
        /// </summary>
        internal void SetProfile()
        {
            // No need
            if (!string.IsNullOrEmpty( Source?.ProfileName ))
                return;

            // Attach to the default profile
            var defaultProfile = VCRProfiles.DefaultProfile;
            if (defaultProfile == null)
                return;

            // Process
            if (Source == null)
                Source = new SourceSelection { ProfileName = defaultProfile.Name };
            else
                Source.ProfileName = defaultProfile.Name;
        }
Ejemplo n.º 18
0
 /// <summary>
 /// Stellt sicher, dass für diesen Auftrag ein Geräteprprofil ausgewählt ist.
 /// </summary>
 /// <param name="defaultProfileName">Der Name des bevorzugten Geräteprofils.</param>
 internal void SetProfile( string defaultProfileName )
 {
     // No source at all
     if (Source == null)
         Source = new SourceSelection { ProfileName = defaultProfileName };
     else if (string.IsNullOrEmpty( Source.ProfileName ))
         Source.ProfileName = defaultProfileName;
 }
Ejemplo n.º 19
0
 /// <summary>
 /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen.
 /// </summary>
 /// <param name="other">Die andere Quelle.</param>
 /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns>
 public bool CompareTo( SourceSelection other )
 {
     // Forward
     return CompareTo( other, false );
 }
Ejemplo n.º 20
0
        /// <summary>
        /// Zeigt den Zustand des <i>Card Servers</i> an.
        /// </summary>
        /// <param name="result">Gesamtinformationen zum Zustand.</param>
        private void ProcessState( object result )
        {
            // Convert
            ServerInformation info = (ServerInformation) result;

            // Reconstruct the selection
            SourceSelection selection = new SourceSelection { SelectionKey = info.Selection };

            // Fill
            txLocation.Text = ((null == selection) || (null == selection.Location)) ? null : selection.Location.ToString();
            txGroup.Text = ((null == selection) || (null == selection.Group)) ? null : selection.Group.ToString();
            txProfile.Text = (null == selection) ? null : selection.ProfileName;
            txEPGItems.Text = info.CurrentProgramGuideItems.ToString();
            epgProgress.Visible = info.ProgramGuideProgress.HasValue;
            txPSISources.Text = info.UpdateSourceCount.ToString();
            psiProgress.Visible = info.UpdateProgress.HasValue;

            // Set error mode
            txLocation.BackColor = info.HasGroupInformation ? txProfile.BackColor : Color.Yellow;
            txGroup.BackColor = txLocation.BackColor;

            // Show 
            pnlState.Visible = true;

            // Set the progress values
            if (epgProgress.Visible)
                epgProgress.Value = Math.Max( 0, Math.Min( epgProgress.Maximum, (int) (info.ProgramGuideProgress.Value * epgProgress.Maximum) ) );
            if (psiProgress.Visible)
                psiProgress.Value = Math.Max( 0, Math.Min( psiProgress.Maximum, (int) (info.UpdateProgress.Value * psiProgress.Maximum) ) );

            // Reset service list
            selServices.Items.Clear();

            // Fill service list
            if (null != info.Services)
            {
                // Helper
                List<string> services = new List<string>();

                // Fill
                foreach (ServiceInformation service in info.Services)
                    services.Add( string.Format( "{0} ({1})", service.UniqueName, service.Service ) );

                // Sort and use
                selServices.Items.AddRange( services.OrderBy( s => int.Parse( s.Split( ',' )[0] ) ).ToArray() );
            }

            // Finish service list
            selServices.Enabled = (selServices.Items.Count > 0);

            // Select first
            if (selServices.Enabled)
                selServices.SelectedIndex = 0;

            // Load streams
            LoadStreams( info.Streams, selection );
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Füllt die Informationen über die aktiven Quellen.
        /// </summary>
        /// <param name="streams">Die Liste der aktiven Quellen.</param>
        /// <param name="selection">Die aktive Quellgruppe.</param>
        private void LoadStreams( IEnumerable<StreamInformation> streams, SourceSelection selection )
        {
            // Reset
            lstStreams.Items.Clear();

            // Find the profile
            Profile profile = (null == selection) ? null : selection.GetProfile();

            // Process all
            foreach (StreamInformation stream in streams)
            {
                // Create the item
                ListViewItem item = lstStreams.Items.Add( stream.Source.ToString() );

                // No profile
                if (null != profile)
                    foreach (SourceSelection match in profile.FindSource( stream.Source ))
                    {
                        // Check for location match
                        if (null != selection.Location)
                            if (!Equals( selection.Location, match.Location ))
                                continue;

                        // Check for group match
                        if (null != selection.Group)
                            if (!Equals( selection.Group, match.Group ))
                                continue;

                        // Update name
                        item.Text = match.DisplayName;
                        // Skip the rest
                        break;
                    }

                // Add additional data
                item.SubItems.Add( (null == stream.Streams) ? null : string.Join( ", ", stream.Streams.MP2Tracks.Languages.ToArray() ) );
                item.SubItems.Add( (null == stream.Streams) ? null : string.Join( ", ", stream.Streams.AC3Tracks.Languages.ToArray() ) );
                item.SubItems.Add( (null == stream.Streams) ? null : string.Join( ", ", stream.Streams.SubTitles.Languages.ToArray() ) );
                item.SubItems.Add( (null == stream.Streams) ? null : (stream.Streams.Videotext ? "x" : null) );
                item.SubItems.Add( (null == stream.Streams) ? null : (stream.Streams.ProgramGuide ? "x" : null) );
                item.SubItems.Add( string.Format( "{0} ({1})", stream.BytesReceived, stream.CurrentAudioVideoBytes ) );
                item.SubItems.Add( stream.IsDecrypting ? "x" : null );
                item.SubItems.Add( stream.StreamTarget );
                item.SubItems.Add( stream.TargetPath );
                item.SubItems.Add( stream.ConsumerCount.ToString() );
                item.SubItems.Add( string.Join( ", ", stream.AllFiles.Select( f => string.Format( "{0} ({1})", f.FilePath, f.VideoType ) ).ToArray() ) );
            }

            // Set columns
            foreach (ColumnHeader column in lstStreams.Columns)
            {
                // First
                column.AutoResize( ColumnHeaderAutoResizeStyle.ColumnContent );

                // Remember
                int w = column.Width;

                // Second
                column.AutoResize( ColumnHeaderAutoResizeStyle.HeaderSize );

                // Both
                column.Width = Math.Max( column.Width, w );
            }
        }
Ejemplo n.º 22
0
 /// <summary>
 /// Stellt den Empfang auf die Quellgruppe der bezeichneten Quelle ein.
 /// </summary>
 /// <param name="source">Die Informationen zur gewünschten Quelle.</param>
 public void SelectGroup(SourceSelection source)
 {
     // Forward
     SelectGroup((source == null) ? null : source.Location, (source == null) ? null : source.Group);
 }
 /// <summary>
 /// Prüft eine Quelle und bringt sie auf den aktuellen Stand.
 /// </summary>
 /// <param name="source">Die gewünschte Quelle.</param>
 /// <returns>Die überprüfte Quelle.</returns>
 private SourceSelection FindSource( SourceSelection source )
 {
     // Forward
     return ProfileManager.FindProfile( source.ProfileName ).FindSource( source.Source ).Single();
 }
 /// <summary>
 /// Erzeugt eine Hintergrundaufgabe zum Ermitteln von Quelldaten.
 /// </summary>
 /// <param name="source">Die gewünschte Quelle.</param>
 /// <returns>Eine neue passende Hintergrundaufgabe.</returns>
 public CancellableTask<SourceInformation> GetSourceInformationAsync( SourceSelection source )
 {
     // Make sure this device can map the source
     var localSource = m_profile.FindSource( source.Source ).FirstOrDefault();
     if (localSource == null)
         throw new ArgumentException( "bad source", "source" );
     else
         return SourceInformationReader.GetSourceInformationAsync( localSource );
 }
Ejemplo n.º 25
0
 /// <summary>
 /// Erstellt eine neue Beschreibung.
 /// </summary>
 /// <param name="source">Die zugehörige Quelle.</param>
 /// <param name="device">Das zugehörige Gerät.</param>
 public Feed( SourceSelection source, Device device )
 {
     Device = device;
     Source = source;
 }
Ejemplo n.º 26
0
        /// <summary>
        /// Registriert diese Aufzeichnung in einer Planungsinstanz.
        /// </summary>
        /// <param name="scheduler">Die zu verwendende Planungsinstanz.</param>
        /// <param name="job">Der zugehörige Auftrag.</param>
        /// <param name="devices">Die Liste der Geräte, auf denen die Aufzeichnung ausgeführt werden darf.</param>
        /// <param name="findSource">Dient zum Prüfen einer Quelle.</param>
        /// <param name="disabled">Alle deaktivierten Aufträge.</param>
        /// <param name="context">Die aktuelle Planungsumgebung.</param>
        /// <exception cref="ArgumentNullException">Es wurden nicht alle Parameter angegeben.</exception>
        public void AddToScheduler( RecordingScheduler scheduler, VCRJob job, IScheduleResource[] devices, Func<SourceSelection, SourceSelection> findSource, Func<Guid, bool> disabled, PlanContext context )
        {
            // Validate
            if (scheduler == null)
                throw new ArgumentNullException( nameof( scheduler ) );
            if (job == null)
                throw new ArgumentNullException( nameof( job ) );
            if (findSource == null)
                throw new ArgumentNullException( nameof( findSource ) );

            // Let VCR.NET choose a profile to do the work
            if (job.AutomaticResourceSelection)
                devices = null;

            // Create the source selection
            var persistedSource = Source ?? job.Source;
            var selection = findSource( persistedSource );

            // Station no longer available
            if (selection == null)
                if (persistedSource != null)
                    selection =
                        new SourceSelection
                        {
                            DisplayName = persistedSource.DisplayName,
                            ProfileName = persistedSource.ProfileName,
                            Location = persistedSource.Location,
                            Group = persistedSource.Group,
                            Source =
                                new Station
                                {
                                    TransportStream = persistedSource.Source?.TransportStream ?? 0,
                                    Network = persistedSource.Source?.Network ?? 0,
                                    Service = persistedSource.Source?.Service ?? 0,
                                    Name = persistedSource.DisplayName,
                                },
                        };

            // See if we are allowed to process
            var identifier = UniqueID.Value;
            if (disabled != null)
                if (disabled( identifier ))
                    return;

            // Load all
            var name = string.IsNullOrEmpty( Name ) ? job.Name : $"{job.Name} ({Name})";
            var source = ProfileScheduleResource.CreateSource( selection );
            var duration = TimeSpan.FromMinutes( Duration );
            var noStartBefore = NoStartBefore;
            var start = FirstStart;

            // Check repetition
            var repeat = CreateRepeatPattern();
            if (repeat == null)
            {
                // Only if not being recorded
                if (!noStartBefore.HasValue)
                    scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration ) );
            }
            else
            {
                // See if we have to adjust the start day
                if (noStartBefore.HasValue)
                {
                    // Attach to the limit - actually we shift it a bit further assuming that we did have no large exception towards the past and the duration is moderate
                    var startAfter = noStartBefore.Value.AddHours( 12 );
                    var startAfterDay = startAfter.ToLocalTime().Date;

                    // Localize the start time
                    var startTime = start.ToLocalTime().TimeOfDay;

                    // First adjust
                    start = (startAfterDay + startTime).ToUniversalTime();

                    // One more day
                    if (start < startAfter)
                        start = (startAfterDay.AddDays( 1 ) + startTime).ToUniversalTime();
                }

                // Read the rest
                var exceptions = Exceptions.Select( e => e.ToPlanException( duration ) ).ToArray();
                var endDay = LastDay.GetValueOrDefault( MaxMovableDay );

                // A bit more complex
                if (start.Date <= endDay.Date)
                    scheduler.Add( RecordingDefinition.Create( this, name, identifier, devices, source, start, duration, endDay, repeat ), exceptions );
            }
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Prüft, ob zwei Quellauswahlen die selbe Quelle bezeichnen.
        /// </summary>
        /// <param name="other">Die andere Quelle.</param>
        /// <param name="transponderOnly">Gesetzt, wenn die eigentliche Quelle bei der Prüfung
        /// nicht berücksichtigt werden soll</param>
        /// <returns>Gesetzt, wenn beide Auswahlen die selbe Quelle bezeichnen.</returns>
        public bool CompareTo( SourceSelection other, bool transponderOnly )
        {
            // Not possible
            if (null == other)
                return false;

            // Profile
            if (0 != string.Compare( ProfileName, other.ProfileName, true ))
                return false;

            // Source
            if (!transponderOnly)
                if (!Equals( Source, other.Source ))
                    return false;

            // Use semantic compare
            if (!Equals( Location, other.Location ))
                return false;

            // Group pre-test
            if ((null == Group) || (null == other.Group))
                return false;

            // Group tame test - more or less frequency only
            return Group.CompareTo( other.Group, true );
        }