Exemplo n.º 1
0
        private void checkNodeAvoidNegatives(option location, ruleNode LNode, node hostNode)
        {
            if (!nodeMatches(LNode, hostNode, location) && !nodeMatchRelaxed(LNode, hostNode, location))
            {
                return;
            }
            location.nodes[L.nodes.IndexOf(LNode)] = hostNode;
            var newLArc = LNode.arcs.FirstOrDefault(a =>
                                                    (((a is ruleHyperarc) && ((ruleHyperarc)a).MustExist) ||
                                                     ((a is ruleArc) && ((ruleArc)a).MustExist)) &&
                                                    (location.findLMappedElement(a) == null));

            if (newLArc == null)
            {
                FindPositiveStartElementAvoidNegatives(location);
            }
            else if (newLArc is ruleHyperarc)
            {
                checkHyperArcAvoidNegatives(location, LNode, hostNode, (ruleHyperarc)newLArc);
            }
            else if (newLArc is ruleArc)
            {
                checkArcAvoidNegatives(location, LNode, hostNode, (ruleArc)newLArc);
            }
        }
Exemplo n.º 2
0
        private void checkForNegativeNode(option location, ruleNode LNode, node hostNode)
        {
            if (!nodeMatches(LNode, hostNode, location))
            {
                return;
            }
            location.nodes[L.nodes.IndexOf(LNode)] = hostNode;
            var newLArc = LNode.arcs.FirstOrDefault(a => (location.findLMappedElement(a) == null));

            if (newLArc == null)
            {
                findNegativeStartElement(location);
            }
            else if (newLArc is ruleHyperarc)
            {
                checkForNegativeHyperArc(location, LNode, hostNode, (ruleHyperarc)newLArc);
            }
            else if (newLArc is ruleArc)
            {
                checkForNegativeArc(location, LNode, hostNode, (ruleArc)newLArc);
            }
        }
Exemplo n.º 3
0
        /* this is similar for rules with nonexistence graph elements*/
        private void FindPositiveStartElementAvoidNegatives(option location)
        {
            #region Case #1: Location found! No empty slots left in the location
            /* this is the only way to properly exist the recursive loop. */
            if (!L.nodes.Any(n => ((ruleNode)n).MustExist && location.findLMappedNode(n) == null) &&
                !L.arcs.Any(a => ((ruleArc)a).MustExist && location.findLMappedArc(a) == null) &&
                !L.hyperarcs.Any(n => ((ruleHyperarc)n).MustExist && location.findLMappedHyperarc(n) == null))
            {
                /* as a recursive function, we first check how the recognition process terminates. If all nodes,
                 * hyperarcs and arcs within location have been filled with references to elements in the host,
                 * then we've found a location...well maybe. More details are described in the LocationFound function. */
                if (!FinalRuleChecks(location) && !FinalRuleCheckRelaxed(location))
                {
                    return;
                }
                Boolean resultNegativeNotFulfilled;
                lock (AllNegativeElementsFound)
                {
                    AllNegativeElementsFound = false;
                    negativeRelaxation       = location.Relaxations.copy();
                    findNegativeStartElement(location);
                    resultNegativeNotFulfilled = !(bool)AllNegativeElementsFound;
                }
                if (resultNegativeNotFulfilled)
                {
                    var locCopy = location.copy();
                    locCopy.Relaxations = negativeRelaxation;
                    lock (options) { options.Add(locCopy); }
                }
                return;
            }
            #endregion
            #region Case #2: build off of a hyperarc found so far - by looking for unfulfilled nodes

            /* the quickest approach to finding a new element in the LHS to host subgraph matching is to build
             * directly off of elements found so far. This is because we don't need to check amongst ALL elements in the
             * host (as is the case in the last three cases below). In this case we start with any hyperarcs
             * that have already been matched to one in the host, and see if it connects to any nodes that
             * have yet to be matched. */
            var startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => ((ruleHyperarc)ha).MustExist &&
                                                                         ((location.findLMappedHyperarc(ha) != null) &&
                                                                          (ha.nodes.Any(n => ((ruleNode)n).MustExist &&
                                                                                        (location.findLMappedNode(n) == null)))));
            if (startHyperArc != null)
            {
                var hostHyperArc = location.findLMappedHyperarc(startHyperArc);
                var newLNode     = (ruleNode)startHyperArc.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist &&
                                                                                (location.findLMappedNode(n) == null));
                foreach (var n in hostHyperArc.nodes.Where(n => !location.nodes.Contains(n)))
                {
                    checkNodeAvoidNegatives(location.copy(), newLNode, n);
                }
                return;
            }
            #endregion
            #region Case #3: build off of a node found so far - by looking for unfulfilled arcs

            /* as stated above, the quickest approach is to build from elements that have already been found.
             * Therefore, we see if there are any nodes already matched to a node in L that has an arc in L
             * that has yet to be matched with a host arc. This is more efficient than the last 3 cases
             * because they look through the entire host, which is potentially large. */
            var startNode = (ruleNode)L.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist &&
                                                             ((location.findLMappedNode(n) != null) &&
                                                              (n.arcs.Any(a =>
                                                                          (((a is ruleHyperarc) && ((ruleHyperarc)a).MustExist) ||
                                                                           ((a is ruleArc) && ((ruleArc)a).MustExist)) &&
                                                                          (location.findLMappedElement(a) == null)))));

            /* is there a node already matched (which would only occur if your recursed to get here) that has an
             * unrecognized arc attaced to it. If yes, try all possible arcs in the host with the one that needs
             * to be fulfilled in L. */
            if (startNode != null)
            {
                var newLArc = startNode.arcs.FirstOrDefault(a =>
                                                            (((a is ruleHyperarc) && ((ruleHyperarc)a).MustExist) ||
                                                             ((a is ruleArc) && ((ruleArc)a).MustExist)) &&
                                                            (location.findLMappedElement(a) == null));
                if (newLArc is ruleHyperarc)
                {
                    checkHyperArcAvoidNegatives(location, startNode, location.findLMappedNode(startNode), (ruleHyperarc)newLArc);
                }
                else if (newLArc is ruleArc)
                {
                    checkArcAvoidNegatives(location, startNode, location.findLMappedNode(startNode), (ruleArc)newLArc);
                }
                return;
            }
            #endregion
            #region Case 4: Check entire host for a matching hyperarc

            /* if the above cases didn't match we try to match a hyperarc in the L to any in the host. Since the
             * prior three cases have conditions which require some non-nulls in the location, this is likely where the
             * process will start when invoked from line 79 of recognize above. Hyperarcs are most efficient to start from
             * since there are likely fewer hyperarcs in the host than nodes, or arcs. */
            startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => ((ruleHyperarc)ha).MustExist &&
                                                                     (location.findLMappedHyperarc(ha) == null));
            if (startHyperArc != null)
            {
                if (_in_parallel_)
                {
                    Parallel.ForEach(host.hyperarcs, hostHyperArc =>
                    {
                        if (!location.hyperarcs.Contains(hostHyperArc))
                        {
                            checkHyperArcAvoidNegatives(location.copy(), startHyperArc, hostHyperArc);
                        }
                    });
                }
                else
                {
                    foreach (var hostHyperArc in
                             host.hyperarcs.Where(hostHyperArc => !location.hyperarcs.Contains(hostHyperArc)))
                    {
                        checkHyperArcAvoidNegatives(location.copy(), startHyperArc, hostHyperArc);
                    }
                }
                return;
            }
            #endregion
            #region Case 5: Check entire host for a matching node

            /* If no other hyperarcs to recognize look to a unlocated node. If one gets here then none of the above
             * three conditions were met (obviously) but this also implies that there are multiple components in the
             * LHS, and we are now jumping to a new one with this. This is potentially time intensive if there are
             * a lot of nodes in the host. We allow for the possibility that this recognition can be done in parallel. */
            startNode = (ruleNode)L.nodes.FirstOrDefault(n => ((ruleNode)n).MustExist && (location.findLMappedNode(n) == null));
            if (startNode != null)
            {
                if (_in_parallel_)
                {
                    Parallel.ForEach(host.nodes, hostNode =>
                    {
                        if (!location.nodes.Contains(hostNode))
                        {
                            checkNodeAvoidNegatives(location.copy(), startNode, hostNode);
                        }
                    });
                }
                else
                {
                    foreach (var hostNode in host.nodes
                             .Where(hostNode => !location.nodes.Contains(hostNode)))
                    {
                        checkNodeAvoidNegatives(location.copy(), startNode, hostNode);
                    }
                }
                return;
            }
            #endregion
            #region Case 6: Check entire host for a matching arc
            var looseArc = (ruleArc)L.arcs.FirstOrDefault(a => ((ruleArc)a).MustExist && (location.findLMappedArc(a) == null));

            /* the only way one can get here is if there are one or more arcs NOT connected to any nodes
             * in L - a floating arc, dangling on both sides, like an eyelash. */
            if (looseArc != null)
            {
                if (_in_parallel_)
                {
                    Parallel.ForEach(host.arcs, hostArc =>
                    {
                        if ((!location.arcs.Contains(hostArc)) && (!location.nodes.Contains(hostArc.From)) &&
                            (!location.nodes.Contains(hostArc.To)) &&
                            (arcMatches(looseArc, hostArc) || arcMatchRelaxed(looseArc, hostArc, location)))
                        {
                            var newLocation = location.copy();
                            newLocation.arcs[L.arcs.IndexOf(looseArc)] = hostArc;
                            FindPositiveStartElementAvoidNegatives(newLocation);
                        }
                    });
                }
                else
                {
                    foreach (var hostArc in host.arcs)
                    {
                        if ((!location.arcs.Contains(hostArc)) && (!location.nodes.Contains(hostArc.From)) &&
                            (!location.nodes.Contains(hostArc.To)) &&
                            (arcMatches(looseArc, hostArc) || arcMatchRelaxed(looseArc, hostArc, location)))
                        {
                            var newLocation = location.copy();
                            newLocation.arcs[L.arcs.IndexOf(looseArc)] = hostArc;
                            FindPositiveStartElementAvoidNegatives(newLocation);
                        }
                    }
                }
            }
            #endregion
        }
Exemplo n.º 4
0
        private Boolean InvalidateWithRelaxation(option location)
        {
            if (negativeRelaxation.NumberAllowable == 0)
            {
                return(false);
            }
            var ruleNegElts = new List <graphElement>();

            ruleNegElts.AddRange(L.nodes.FindAll(n => ((ruleNode)n).NotExist));
            ruleNegElts.AddRange(L.arcs.FindAll(a => ((ruleArc)a).NotExist));
            ruleNegElts.AddRange(L.hyperarcs.FindAll(h => ((ruleHyperarc)h).NotExist));
            foreach (var ruleElt in ruleNegElts)
            {
                var hostElt = location.findLMappedElement(ruleElt);
                if (ruleElt.localLabels.Count < hostElt.localLabels.Count)
                {
                    var rContainsAll =
                        negativeRelaxation.FirstOrDefault(
                            r => r.Matches(Relaxations.Contains_All_Local_Labels_Imposed, ruleElt));
                    if (rContainsAll != null)
                    {
                        negativeRelaxation.NumberAllowable--;
                        rContainsAll.NumberAllowed--;
                        negativeRelaxation.FulfilledItems.Add(
                            new RelaxItem(Relaxations.Contains_All_Local_Labels_Imposed, 1, ruleElt,
                                          hostElt.localLabels.Count.ToString(CultureInfo.InvariantCulture)));
                        return(true);
                    }
                }
                if ((ruleElt is ruleNode) && (!((ruleNode)ruleElt).strictDegreeMatch) && ((node)ruleElt).degree != ((node)hostElt).degree)
                {
                    var rStrictDegree =
                        negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Strict_Degree_Match_Imposed, ruleElt));
                    if (rStrictDegree != null)
                    {
                        negativeRelaxation.NumberAllowable--;
                        rStrictDegree.NumberAllowed--;
                        negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Strict_Degree_Match_Imposed, 1,
                                                                            ruleElt,
                                                                            ((node)hostElt).degree.ToString(
                                                                                CultureInfo.InvariantCulture)));
                        return(true);
                    }
                }
                if ((ruleElt is ruleHyperarc) && (!((ruleHyperarc)ruleElt).strictNodeCountMatch) && ((hyperarc)ruleElt).degree != ((hyperarc)hostElt).degree)
                {
                    var rStrictDegree =
                        negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Strict_Node_Count_Imposed, ruleElt));
                    if (rStrictDegree != null)
                    {
                        negativeRelaxation.NumberAllowable--;
                        rStrictDegree.NumberAllowed--;
                        negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Strict_Node_Count_Imposed, 1,
                                                                            ruleElt,
                                                                            ((hyperarc)hostElt).degree.ToString(
                                                                                CultureInfo.InvariantCulture)));
                        return(true);
                    }
                }
                if (ruleElt is arc)
                {
                    var rulearc = (ruleArc)ruleElt;
                    var hostarc = (arc)hostElt;
                    if (!rulearc.nullMeansNull && ((rulearc.To == null && hostarc.To != null) ||
                                                   (rulearc.From == null && hostarc.From != null)))
                    {
                        var rNullMeansNull =
                            negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Null_Means_Null_Imposed, ruleElt));
                        if (rNullMeansNull != null)
                        {
                            negativeRelaxation.NumberAllowable--;
                            rNullMeansNull.NumberAllowed--;
                            negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Null_Means_Null_Imposed, 1,
                                                                                ruleElt,
                                                                                (rulearc.To == null)
                                                                                      ? hostarc.To.name
                                                                                      : hostarc.From.name));
                            return(true);
                        }
                    }
                    if (!rulearc.directionIsEqual &&
                        ((rulearc.doublyDirected != hostarc.doublyDirected) || (rulearc.directed != hostarc.directed)))
                    {
                        var rDir =
                            negativeRelaxation.FirstOrDefault(
                                r => r.Matches(Relaxations.Direction_Is_Equal_Imposed, ruleElt));
                        if (rDir != null)
                        {
                            negativeRelaxation.NumberAllowable--;
                            rDir.NumberAllowed--;
                            negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Direction_Is_Equal_Imposed, 1,
                                                                                ruleElt));
                            return(true);
                        }
                    }
                }
                var ruleNegLabels = (ruleElt is ruleNode)
                                        ? ((ruleNode)ruleElt).negateLabels
                                        : (ruleElt is ruleArc)
                                              ? ((ruleArc)ruleElt).negateLabels
                                              : ((ruleHyperarc)ruleElt).negateLabels;
                foreach (var negLabel in ruleNegLabels)
                {
                    var rLabel =
                        negativeRelaxation.FirstOrDefault(
                            r => r.Matches(Relaxations.Label_Imposed, ruleElt, negLabel));
                    if (rLabel != null)
                    {
                        negativeRelaxation.NumberAllowable--;
                        rLabel.NumberAllowed--;
                        negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Label_Imposed, 1, ruleElt,
                                                                            negLabel));
                        return(true);
                    }
                }
                foreach (var lab in ruleElt.localLabels)
                {
                    var rNegLabel =
                        negativeRelaxation.FirstOrDefault(
                            r => r.Matches(Relaxations.Negate_Label_Imposed, ruleElt, lab));
                    if (rNegLabel != null)
                    {
                        negativeRelaxation.NumberAllowable--;
                        rNegLabel.NumberAllowed--;
                        negativeRelaxation.FulfilledItems.Add(new RelaxItem(Relaxations.Negate_Label_Imposed, 1, ruleElt,
                                                                            lab));
                        return(true);
                    }
                }
            }
            var localNumAllowable       = negativeRelaxation.NumberAllowable;
            var usedRelaxItems          = new List <RelaxItem>();
            var usedFulfilledRelaxItems = new List <RelaxItem>();

            foreach (var elt in ruleNegElts)
            {
                var rNotExist =
                    negativeRelaxation.FirstOrDefault(r => r.Matches(Relaxations.Element_Made_Positive, elt)
                                                      &&
                                                      usedRelaxItems.Count(ur => ur == r) <
                                                      r.NumberAllowed);
                if (rNotExist == null)
                {
                    break;
                }
                localNumAllowable--;
                usedRelaxItems.Add(rNotExist);
                usedFulfilledRelaxItems.Add(new RelaxItem(Relaxations.Element_Made_Positive, 1, elt));
            }
            if ((localNumAllowable >= 0) && usedFulfilledRelaxItems.Count == ruleNegElts.Count)
            {
                negativeRelaxation.NumberAllowable = localNumAllowable;
                foreach (var r in usedRelaxItems)
                {
                    r.NumberAllowed--;
                }
                negativeRelaxation.FulfilledItems.AddRange(usedFulfilledRelaxItems);
                return(true);
            }
            return(false);
        }
Exemplo n.º 5
0
        private void findNegativeStartElement(option location)
        {
            if ((bool)AllNegativeElementsFound)
            {
                return;                                 /* another sub-branch found a match to the negative elements.
                                                         * There's no point in finding more than one, so this statement
                                                         * aborts the search down this branch. */
            }
            #region Case #1: Location found! No empty slots left in the location
            /* this is the only way to properly exit the recursive loop. */
            if (!location.nodes.Contains(null) && !location.arcs.Contains(null) && !location.hyperarcs.Contains(null))
            {
                if (FinalRuleChecks(location))
                {
                    if (!InvalidateWithRelaxation(location))
                    {
                        AllNegativeElementsFound = true;
                    }
                }
                return;
            }
            #endregion
            #region Case #2: build off of a hyperarc found so far - by looking for unfulfilled nodes

            /* the quickest approach to finding a new element in the LHS to host subgraph matching is to build
             * directly off of elements found so far. This is because we don't need to check amongst ALL elements in the
             * host (as is the case in the last three cases below). In this case we start with any hyperarcs
             * that have already been matched to one in the host, and see if it connects to any nodes that
             * have yet to be matched. */
            var startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => ((location.findLMappedHyperarc(ha) != null) &&
                                                                                (ha.nodes.Any(n => (location.findLMappedNode(n) == null)))));
            if (startHyperArc != null)
            {
                var hostHyperArc = location.findLMappedHyperarc(startHyperArc);
                var newLNode     = (ruleNode)startHyperArc.nodes.FirstOrDefault(n => (location.findLMappedNode(n) == null));
                foreach (var n in hostHyperArc.nodes.Where(n => !location.nodes.Contains(n)))
                {
                    checkForNegativeNode(location.copy(), newLNode, n);
                    if ((bool)AllNegativeElementsFound)
                    {
                        return;
                    }
                }
                return;
            }
            #endregion
            #region Case #2.5: build off of a partially matched arc

            /* unlike the other renditions of this function (findNewStartElement,
             * findPositiveStartElementAvoidNegatives) this has a situation in which an arc has only been
             * partially matched but the connected nodes were not touched because they were negative elements.*/
            var startArc = (ruleArc)L.arcs.FirstOrDefault(a => (location.findLMappedArc(a) != null) &&
                                                          a.To != null && location.findLMappedNode(a.To) == null);
            if (startArc != null)
            {
                var hostArc = location.findLMappedArc(startArc);
                if ((hostArc.To != null) && !location.nodes.Contains(hostArc.To))
                {
                    checkForNegativeNode(location.copy(), (ruleNode)startArc.To, hostArc.To);
                }
                else if (!startArc.directionIsEqual && hostArc.From != null &&
                         !location.nodes.Contains(hostArc.From))
                {
                    checkForNegativeNode(location.copy(), (ruleNode)startArc.To, hostArc.From);
                }
                return;
            }
            startArc = (ruleArc)L.arcs.FirstOrDefault(a => (location.findLMappedArc(a) != null) &&
                                                      a.From != null && location.findLMappedNode(a.From) == null);
            if (startArc != null)
            {
                var hostArc = location.findLMappedArc(startArc);
                if ((hostArc.From != null) && !location.nodes.Contains(hostArc.From))
                {
                    checkForNegativeNode(location.copy(), (ruleNode)startArc.From, hostArc.From);
                }
                else if (!startArc.directionIsEqual && hostArc.To != null &&
                         !location.nodes.Contains(hostArc.To))
                {
                    checkForNegativeNode(location.copy(), (ruleNode)startArc.From, hostArc.To);
                }
                return;
            }
            #endregion
            #region Case #3: build off of a node found so far - by looking for unfulfilled arcs

            /* as stated above, the quickest approach is to build from elements that have already been found.
             * Therefore, we see if there are any nodes already matched to a node in L that has an arc in L
             * that has yet to be matched with a host arc. This is more efficient than the last 3 cases
             * because they look through the entire host, which is potentially large. */
            var startNode = (ruleNode)L.nodes.FirstOrDefault(n => ((location.findLMappedNode(n) != null) &&
                                                                   (n.arcs.Any(a => (location.findLMappedElement(a) == null)))));

            /* is there a node already matched (which would only occur if your recursed to get here) that has an
             * unrecognized arc attaced to it. If yes, try all possible arcs in the host with the one that needs
             * to be fulfilled in L. */
            if (startNode != null)
            {
                var newLArc = startNode.arcs.FirstOrDefault(a => (location.findLMappedElement(a) == null));
                if (newLArc is ruleHyperarc)
                {
                    checkForNegativeHyperArc(location, startNode, location.findLMappedNode(startNode), (ruleHyperarc)newLArc);
                }
                else if (newLArc is ruleArc)
                {
                    checkForNegativeArc(location, startNode, location.findLMappedNode(startNode), (ruleArc)newLArc);
                }
                return;
            }
            #endregion
            #region Case 4: Check entire host for a matching hyperarc

            /* if the above cases didn't match we try to match a hyperarc in the L to any in the host. Since the
             * prior three cases have conditions which require some non-nulls in the location, this is likely where the
             * process will start when invoked from line 87 of recognize above. Hyperarcs are most efficient to start from
             * since there are likely fewer hyperarcs in the host than nodes, or arcs. */
            startHyperArc = (ruleHyperarc)L.hyperarcs.FirstOrDefault(ha => (location.findLMappedHyperarc(ha) == null));
            if (startHyperArc != null)
            {
                foreach (var hostHyperArc in
                         host.hyperarcs.Where(hostHyperArc => !location.hyperarcs.Contains(hostHyperArc)))
                {
                    checkForNegativeHyperArc(location.copy(), startHyperArc, hostHyperArc);
                    if ((bool)AllNegativeElementsFound)
                    {
                        return;
                    }
                }
                return;
            }
            #endregion
            #region Case 5: Check entire host for a matching node

            /* If no other hyperarcs can be recognized, then look to a unlocated node. If one gets here then none of the above
             * three conditions were met (obviously) but this also implies that there are multiple components in the
             * LHS, and we are now jumping to a new one with this. This is potentially time intensive if there are
             * a lot of nodes in the host. We allow for the possibility that this recognition can be done in parallel. */
            startNode = (ruleNode)L.nodes.FirstOrDefault(n => (location.findLMappedNode(n) == null));
            if (startNode != null)
            {
                foreach (var hostNode in host.nodes.Where(hostNode => !location.nodes.Contains(hostNode)))
                {
                    checkForNegativeNode(location.copy(), startNode, hostNode);
                    if ((bool)AllNegativeElementsFound)
                    {
                        return;
                    }
                }
                return;
            }
            #endregion
            #region Case 6: Check entire host for a matching arc
            var looseArc = (ruleArc)L.arcs.FirstOrDefault(a => (location.findLMappedArc(a) == null));

            /* the only way one can get here is if there are one or more arcs NOT connected to any nodes
             * in L - a floating arc, dangling on both sides, like an eyelash. */
            if (looseArc != null)
            {
                foreach (var hostArc in host.arcs)
                {
                    if (!location.arcs.Contains(hostArc) && !location.nodes.Contains(hostArc.From) &&
                        !location.nodes.Contains(hostArc.To) && arcMatches(looseArc, hostArc))
                    {
                        var newLocation = location.copy();
                        newLocation.arcs[L.arcs.IndexOf(looseArc)] = hostArc;
                        findNegativeStartElement(newLocation);
                    }
                    if ((bool)AllNegativeElementsFound)
                    {
                        return;
                    }
                }
            }
            #endregion
        }