public ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(IBasicActivateItems activator, CatalogueCombineable catalogueCombineable, CohortAggregateContainer targetCohortAggregateContainer) : this(activator, targetCohortAggregateContainer)
        {
            _catalogueCombineable           = catalogueCombineable;
            _targetCohortAggregateContainer = targetCohortAggregateContainer;

            UpdateIsImpossibleFor(catalogueCombineable);
        }
Exemplo n.º 2
0
 public void Remove(CohortAggregateContainer parent, CohortAggregateContainer child)
 {
     CatalogueRepository.Delete("DELETE FROM CohortAggregateSubContainer WHERE CohortAggregateContainer_ChildID = @CohortAggregateContainer_ChildID", new Dictionary <string, object>
     {
         { "CohortAggregateContainer_ChildID", child.ID }
     });
 }
Exemplo n.º 3
0
        public void Container_Subcontainering()
        {
            var container = new CohortAggregateContainer(CatalogueRepository, SetOperation.UNION);

            var container2 = new CohortAggregateContainer(CatalogueRepository, SetOperation.INTERSECT);

            try
            {
                Assert.AreEqual(0, container.GetSubContainers().Length);


                Assert.AreEqual(0, container.GetSubContainers().Length);

                //set container to parent
                container.AddChild(container2);

                //container 1 should now contain container 2
                Assert.AreEqual(1, container.GetSubContainers().Length);
                Assert.Contains(container2, container.GetSubContainers());

                //container 2 should not have any children
                Assert.AreEqual(0, container2.GetSubContainers().Length);
            }
            finally
            {
                container.DeleteInDatabase();

                //container 2 was contained within container 1 so should have also been deleted
                Assert.Throws <KeyNotFoundException>(
                    () => CatalogueRepository.GetObjectByID <CohortAggregateContainer>(container2.ID));
            }
        }
        public ExecuteCommandUnMergeCohortIdentificationConfiguration(IBasicActivateItems activator, CohortAggregateContainer container) : base(activator)
        {
            _target = container;

            if (_target == null)
            {
                SetImpossible("No root container");
                return;
            }

            if (!_target.IsRootContainer())
            {
                SetImpossible("Only root containers can be unmerged");
                return;
            }

            if (_target.GetAggregateConfigurations().Any())
            {
                SetImpossible("Container must contain only subcontainers (i.e. no aggregate sets)");
                return;
            }

            if (_target.GetSubContainers().Count() <= 1)
            {
                SetImpossible("Container must have 2 or more immediate subcontainers for unmerging");
                return;
            }
        }
Exemplo n.º 5
0
        public void BuildFor(CohortAggregateContainer container, ParameterManager parameterManager)
        {
            ThrowIfAlreadyBuilt();
            IsForContainer = true;

            _log.AppendLine("Starting Build for " + container);
            //gather dependencies
            foreach (var cohortSet in ChildProvider.GetAllChildrenRecursively(container).OfType <AggregateConfiguration>().Where(IsEnabled).OrderBy(ac => ac.Order))
            {
                AddDependency(cohortSet);
            }

            if (!Dependencies.Any())
            {
                throw new QueryBuildingException($"There are no AggregateConfigurations under the SET container '{container}'");
            }

            LogDependencies();

            BuildDependenciesSql(parameterManager.ParametersFoundSoFarInQueryGeneration[ParameterLevel.Global].ToArray());

            MakeCacheDecision();

            Sql = BuildSql(container, parameterManager);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Rebuilds the CohortCompiler diagram which shows all the currently configured tasks
        /// </summary>
        /// <param name="cancelTasks"></param>
        private void RecreateAllTasks(bool cancelTasks = true)
        {
            if (cancelTasks)
            {
                Compiler.CancelAllTasks(false);
            }

            tlvConfiguration.ClearObjects();

            tlvConfiguration.Enabled = true;

            _cic.CreateRootContainerIfNotExists();
            //if there is no root container,create one
            _root    = _cic.RootCohortAggregateContainer;
            _globals = _cic.GetAllParameters();

            //Could have configured/unconfigured a joinable state
            foreach (var j in Compiler.Tasks.Keys.OfType <JoinableTask>())
            {
                j.RefreshIsUsedState();
            }

            try
            {
                tlvConfiguration.AddObject(new CohortIdentificationHeader());
                tlvConfiguration.AddObject(new JoinableCollectionNode(_cic, _cic.GetAllJoinables()));
                tlvConfiguration.ExpandAll();
            }
            catch (Exception e)
            {
                tlvConfiguration.Enabled = false;
                ExceptionViewer.Show("Failed to populate tree of Tasks", e);
            }
        }
Exemplo n.º 7
0
        public CohortAggregateContainerCommand(CohortAggregateContainer aggregateContainer)
        {
            AggregateContainer          = aggregateContainer;
            AllSubContainersRecursively = AggregateContainer.GetAllSubContainersRecursively();

            ParentContainerIfAny = AggregateContainer.GetParentContainerIfAny();
        }
Exemplo n.º 8
0
        private CohortIdentificationConfiguration CreateCohortIdentificationConfiguration(ExtractionFilter inclusionFilter1)
        {
            //Create the top level configuration object
            var cic = new CohortIdentificationConfiguration(_repos.CatalogueRepository, "Tayside Lung Cancer Cohort");

            //create a UNION container for Inclusion Criteria
            var container = new CohortAggregateContainer(_repos.CatalogueRepository, SetOperation.UNION);

            container.Name = "Inclusion Criteria";
            container.SaveToDatabase();

            cic.RootCohortAggregateContainer_ID = container.ID;
            cic.SaveToDatabase();

            //Create a new cohort set to the 'Inclusion Criteria' based on the filters Catalogue
            var cata = inclusionFilter1.ExtractionInformation.CatalogueItem.Catalogue;
            var ac   = cic.CreateNewEmptyConfigurationForCatalogue(cata, (a, b) => { throw new Exception("Problem encountered with chi column(s)"); }, false);

            container.AddChild(ac, 0);

            //Add the filter to the WHERE logic of the cohort set
            var whereContainer = new AggregateFilterContainer(_repos.CatalogueRepository, FilterContainerOperation.OR);

            ac.Name = "People with " + inclusionFilter1.Name;
            ac.RootFilterContainer_ID = whereContainer.ID;
            cic.EnsureNamingConvention(ac); //this will put cicx at the front and cause implicit SaveToDatabase

            FilterImporter filterImporter = new FilterImporter(new AggregateFilterFactory(_repos.CatalogueRepository), null);
            var            cloneFilter    = filterImporter.ImportFilter(inclusionFilter1, null);

            whereContainer.AddChild(cloneFilter);

            return(cic);
        }
Exemplo n.º 9
0
        public CohortQueryBuilder(CohortAggregateContainer c, IEnumerable <ISqlParameter> globals, ICoreChildProvider childProvider) : this(globals, childProvider)
        {
            //set ourselves up to run with the root container
            container = c;

            SetChildProviderIfNull();
        }
Exemplo n.º 10
0
        public string DescribeProblem(CohortAggregateContainer container)
        {
            //if it's a root container don't check
            if (_childProvider.AllCohortIdentificationConfigurations.Any(c =>
                                                                         c.RootCohortAggregateContainer_ID == container.ID))
            {
                return(null);
            }

            //count children that are not disabled, there should be at least 2
            var children        = _childProvider.GetChildren(container);
            var enabledChildren = children.Where(o => !(o is IDisableable d) || !d.IsDisabled).ToArray();

            if (enabledChildren.Length == 0)
            {
                return("Empty SET containers have no effect (and will be ignored)");
            }

            if (enabledChildren.Length == 1)
            {
                return("SET container operations have no effect if there is only one child within");
            }

            //are there any children with the same order in this container?
            if (children.OfType <IOrderable>().GroupBy(o => o.Order).Any(g => g.Count() > 1))
            {
                return("Child order is ambiguous, show the Order column and reorder contents");
            }

            return(null);
        }
Exemplo n.º 11
0
        public CohortAggregateContainer CreateCohortAggregateContainer(CohortAggregateContainer rootContainer)
        {
            var operation = GetSetOperation();

            if (rootContainer.Operation != SetOperation.EXCEPT)
            {
                throw new ArgumentException("rootContainer");
            }

            var container = new CohortAggregateContainer(_activator.RepositoryLocator.CatalogueRepository, operation);

            if (_isInclusionCriteria)
            {
                container.Order = 1;
                container.Name  = operation + " - Inclusion Criteria";
            }
            else
            {
                container.Order = 2;
                container.Name  = operation + " - Exclusion Criteria";
            }

            container.SaveToDatabase();
            rootContainer.AddChild(container);

            return(container);
        }
Exemplo n.º 12
0
        private string WriteContainers(CohortAggregateContainer container, IQuerySyntaxHelper syntaxHelper,
                                       Dictionary <CohortQueryBuilderDependency, string> sqlDictionary, int tabs)
        {
            string sql = "";

            //Things we need to output
            var toWriteOut = container.GetOrderedContents().Where(IsEnabled).ToArray();

            if (toWriteOut.Any())
            {
                sql += Environment.NewLine + TabIn("(", tabs) + Environment.NewLine;
            }
            else
            {
                throw new QueryBuildingException($"Container '{container}' is empty, Disable it if you don't want it run'");
            }

            bool firstEntityWritten = false;

            foreach (IOrderable toWrite in toWriteOut)
            {
                if (firstEntityWritten)
                {
                    sql += Environment.NewLine + TabIn(GetSetOperationSql(container.Operation, syntaxHelper.DatabaseType) + Environment.NewLine + Environment.NewLine, tabs);
                }

                if (toWrite is AggregateConfiguration)
                {
                    sql += TabIn(sqlDictionary.Single(kvp => Equals(kvp.Key.CohortSet, toWrite)).Value, tabs);
                }

                if (toWrite is CohortAggregateContainer sub)
                {
                    sql += WriteContainers(sub, syntaxHelper, sqlDictionary, tabs + 1);
                }

                //we have now written the first thing at this level of recursion - all others will need to be separated by the OPERATION e.g. UNION
                firstEntityWritten = true;

                if (StopContainerWhenYouReach != null && StopContainerWhenYouReach.Equals(toWrite))
                {
                    if (tabs != 0)
                    {
                        throw new NotSupportedException("Stopping prematurely only works when the aggregate to stop at is in the top level container");
                    }
                    else
                    {
                        break;
                    }
                }
            }

            //if we outputted anything
            if (toWriteOut.Any())
            {
                sql += Environment.NewLine + TabIn(")", tabs) + Environment.NewLine;
            }

            return(sql);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Adds all AggregateConfigurations and CohortAggregateContainers in the specified container or subcontainers. Passing addSubcontainerTasks false will still process the subcontainers
        /// but will only add AggregateConfigurations to the task list
        /// </summary>
        /// <param name="globals"></param>
        /// <param name="container"></param>
        /// <param name="addSubcontainerTasks">The root container is always added to the task list but you could skip subcontainer totals if all you care about is the final total for the cohort
        /// and you don't have a dependant UI etc.  Passing false will add all joinables, subqueries etc and the root container (final answer for who is in cohort) only.</param>
        /// <returns></returns>
        public List <ICompileable> AddTasksRecursively(ISqlParameter[] globals, CohortAggregateContainer container, bool addSubcontainerTasks = true)
        {
            var toReturn = new List <ICompileable>();

            //if it is the root container or we are adding tasks for all containers including subcontainers
            if (CohortIdentificationConfiguration.RootCohortAggregateContainer_ID == container.ID || addSubcontainerTasks)
            {
                toReturn.Add(AddTask(container, globals));
            }

            foreach (IOrderable c in container.GetOrderedContents())
            {
                var aggregateContainer = c as CohortAggregateContainer;
                var aggregate          = c as AggregateConfiguration;

                if (aggregateContainer != null)
                {
                    toReturn.AddRange(AddTasksRecursively(globals, aggregateContainer, addSubcontainerTasks));
                }

                if (aggregate != null)
                {
                    toReturn.Add(AddTask(aggregate, globals));
                }
            }

            return(toReturn);
        }
Exemplo n.º 14
0
 public void Remove(CohortAggregateContainer parent, AggregateConfiguration child)
 {
     CatalogueRepository.Delete("DELETE FROM CohortAggregateContainer_AggregateConfiguration WHERE CohortAggregateContainer_ID = @CohortAggregateContainer_ID AND AggregateConfiguration_ID = @AggregateConfiguration_ID", new Dictionary <string, object>
     {
         { "CohortAggregateContainer_ID", parent.ID },
         { "AggregateConfiguration_ID", child.ID }
     });
 }
Exemplo n.º 15
0
 public void Add(CohortAggregateContainer parent, CohortAggregateContainer child)
 {
     CatalogueRepository.Insert("INSERT INTO CohortAggregateSubContainer(CohortAggregateContainer_ParentID,CohortAggregateContainer_ChildID) VALUES (@CohortAggregateContainer_ParentID, @CohortAggregateContainer_ChildID)", new Dictionary <string, object>
     {
         { "CohortAggregateContainer_ParentID", parent.ID },
         { "CohortAggregateContainer_ChildID", child.ID }
     });
 }
        /// <summary>
        /// Asserts that the given <paramref name="container"/> ran successfully and fetched it's results from the cache (if any) with the
        /// given <paramref name="expectedCacheUsageCount"/>
        /// </summary>
        /// <param name="compiler"></param>
        /// <param name="container"></param>
        /// <param name="expectedCacheUsageCount">The amount you expect to be used of the cache e.g. "2/2" </param>
        private void AssertCacheUsed(CohortCompiler compiler, CohortAggregateContainer container, string expectedCacheUsageCount)
        {
            //cache should have been used
            var containerResult = compiler.Tasks.Single(t => t.Key is AggregationContainerTask c && c.Container.Equals(container));

            Assert.AreEqual(CompilationState.Finished, containerResult.Key.State);
            Assert.AreEqual(expectedCacheUsageCount, containerResult.Key.GetCachedQueryUseCount());
        }
Exemplo n.º 17
0
        private string BuildSql(CohortAggregateContainer container, ParameterManager parameterManager)
        {
            Dictionary <CohortQueryBuilderDependency, string> sqlDictionary;

            //if we are fully cached on everything
            if (Dependencies.All(d => d.SqlFullyCached != null))
            {
                SetTargetServer(GetCacheServer(), "all dependencies are fully cached"); //run on the cache server

                //all are cached
                CountOfCachedSubQueries = CountOfSubQueries;

                sqlDictionary = Dependencies.ToDictionary(k => k, v => v.SqlFullyCached.Use(parameterManager)); //run the fully cached sql
            }
            else
            {
                string uncached = "CacheUsageDecision is " + CacheUsageDecision +
                                  " and the following were not cached:" + string.Join(Environment.NewLine,
                                                                                      Dependencies.Where(d => d.SqlFullyCached == null));

                switch (CacheUsageDecision)
                {
                case CacheUsage.MustUse:
                    throw new QueryBuildingException(
                              "Could not build final SQL because some queries are not fully cached and " + uncached);

                case CacheUsage.Opportunistic:

                    //The cache and dataset are on the same server so run it
                    SetTargetServer(DependenciesSingleServer.GetDistinctServer(), "not all dependencies are cached while " + uncached);

                    CountOfCachedSubQueries = Dependencies.Count(d => d.SqlFullyCached != null);

                    sqlDictionary =
                        Dependencies.ToDictionary(k => k,
                                                  v => v.SqlFullyCached?.Use(parameterManager) ??
                                                  v.SqlPartiallyCached?.Use(parameterManager) ??
                                                  v.SqlCacheless.Use(parameterManager)); //run the fully cached sql
                    break;

                case CacheUsage.AllOrNothing:

                    //It's not fully cached so we have to run it entirely uncached
                    SetTargetServer(DependenciesSingleServer.GetDistinctServer(), "not all dependencies are cached while " + uncached);

                    //cannot use any of the caches because it's all or nothing
                    CountOfCachedSubQueries = 0;
                    sqlDictionary           =
                        Dependencies.ToDictionary(k => k, v => v.SqlCacheless.Use(parameterManager));     //run the fully uncached sql
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }

            return(WriteContainers(container, TargetServer.GetQuerySyntaxHelper(), sqlDictionary, 0));
        }
Exemplo n.º 18
0
        public void Test_AggregateConfigurationOrder_MovingAggregatesBetweenContainers()
        {
            GetObjects(out Catalogue cata, out CohortIdentificationConfiguration cic);

            //we should be able to add it to root container
            var cmd = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(ItemActivator, new CatalogueCommand(cata), cic.RootCohortAggregateContainer);

            cmd.Execute();


            //create a subcontainer
            var subcontainer = new CohortAggregateContainer(Repository, SetOperation.INTERSECT);

            cic.RootCohortAggregateContainer.AddChild(subcontainer);

            //add the second ac to the subcontainer
            var cmd2 = new ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(ItemActivator, new CatalogueCommand(cata), subcontainer);

            cmd2.Execute();

            //should now look like this:
            //Root
            //  INTERSECT
            //      Ac2
            //  Ac 1
            //

            var all = cic.RootCohortAggregateContainer.GetOrderedContents().ToArray();

            var ac1       = (AggregateConfiguration)all[1];
            var ac2       = (AggregateConfiguration)subcontainer.GetOrderedContents().Single();
            var intersect = (CohortAggregateContainer)all[0];

            Assert.AreEqual(0, intersect.Order);
            Assert.AreEqual(1, ac1.Order);
            Assert.AreEqual(0, ac2.Order);

            //now move the Ac2 to Root (problematic since both Ac 2 and the INTERSECT have Order 0 - in their own separate containers)
            var cmd3 = new ExecuteCommandMoveAggregateIntoContainer(ItemActivator, new AggregateConfigurationCommand(ac2), cic.RootCohortAggregateContainer);

            cmd3.Execute();

            all = cic.RootCohortAggregateContainer.GetOrderedContents().ToArray();

            //should now look like this
            //Root
            //  Ac2
            //  INTERSECT (empty)
            //  Ac 1

            ac2       = (AggregateConfiguration)all[0];
            intersect = (CohortAggregateContainer)all[1];
            ac1       = (AggregateConfiguration)all[2];

            Assert.AreEqual(0, ac2.Order);
            Assert.AreEqual(1, intersect.Order);
            Assert.AreEqual(2, ac1.Order);
        }
Exemplo n.º 19
0
        public AggregationContainerTask(CohortAggregateContainer container, CohortCompiler compiler) : base(compiler)
        {
            Container = container;

            SubContainers           = Container.GetSubContainers();
            ContainedConfigurations = Container.GetAggregateConfigurations();

            _parentContainers = Container.GetAllParentContainers().ToArray();
        }
        public ExecuteCommandAddCohortSubContainer(IBasicActivateItems activator, CohortAggregateContainer container) : base(activator)
        {
            this._container = container;

            if (container.ShouldBeReadOnly(out string reason))
            {
                SetImpossible(reason);
            }
        }
        /// <summary>
        /// Returns cached answers without running database queries
        /// </summary>
        /// <param name="parent"></param>
        /// <returns></returns>
        public override IOrderable[] GetChildren(CohortAggregateContainer parent)
        {
            if (_contents.ContainsKey(parent.ID))
            {
                return(_contents[parent.ID].ToArray());
            }

            return(new IOrderable[0]);
        }
        public override void Execute()
        {
            base.Execute();

            var newContainer = new CohortAggregateContainer(Activator.RepositoryLocator.CatalogueRepository, SetOperation.UNION);

            _container.AddChild(newContainer);
            Publish(_container);
        }
Exemplo n.º 23
0
 public CohortAggregateContainer GetParent(CohortAggregateContainer child)
 {
     return(CatalogueRepository.SelectAllWhere <CohortAggregateContainer>("SELECT CohortAggregateContainer_ParentID FROM CohortAggregateSubContainer WHERE CohortAggregateContainer_ChildID=@CohortAggregateContainer_ChildID",
                                                                          "CohortAggregateContainer_ParentID",
                                                                          new Dictionary <string, object>
     {
         { "CohortAggregateContainer_ChildID", child.ID }
     }).SingleOrDefault());
 }
Exemplo n.º 24
0
        private ExecuteCommandAddAggregateConfigurationToCohortIdentificationSetContainer(IBasicActivateItems activator, CohortAggregateContainer targetCohortAggregateContainer) : base(activator)
        {
            _targetCohortAggregateContainer = targetCohortAggregateContainer;

            if (targetCohortAggregateContainer.ShouldBeReadOnly(out string reason))
            {
                SetImpossible(reason);
            }
        }
        public ExecuteCommandAddCatalogueToCohortIdentificationSetContainer(IActivateItems activator, CatalogueCommand catalogueCommand, CohortAggregateContainer targetCohortAggregateContainer) : base(activator)
        {
            _catalogueCommand = catalogueCommand;
            _targetCohortAggregateContainer = targetCohortAggregateContainer;

            if (!catalogueCommand.ContainsAtLeastOneExtractionIdentifier)
            {
                SetImpossible("Catalogue " + catalogueCommand.Catalogue + " does not contain any IsExtractionIdentifier columns");
            }
        }
Exemplo n.º 26
0
        public AggregationContainerTask(CohortAggregateContainer container, CohortCompiler compiler) : base(compiler)
        {
            Container = container;

            SubContainers           = compiler.CoreChildProvider.GetChildren(Container).OfType <CohortAggregateContainer>().ToArray();
            ContainedConfigurations = compiler.CoreChildProvider.GetChildren(Container).OfType <AggregateConfiguration>().ToArray();

            var d = compiler.CoreChildProvider.GetDescendancyListIfAnyFor(Container);

            _parentContainers = d?.Parents?.OfType <CohortAggregateContainer>()?.ToArray() ?? new CohortAggregateContainer[0];
        }
Exemplo n.º 27
0
        public ExecuteCommandReOrderAggregate(IActivateItems activator, AggregateConfigurationCombineable sourceAggregateCommand, CohortAggregateContainer targetCohortAggregateContainer, InsertOption insertOption) : this(activator, targetCohortAggregateContainer, insertOption)
        {
            _sourceAggregateCommand = sourceAggregateCommand;
            _parentContainer        = targetCohortAggregateContainer.GetParentContainerIfAny();

            if (!sourceAggregateCommand.ContainerIfAny.Equals(_parentContainer))
            {
                SetImpossible("Cannot ReOrder, you should first move both objects into the same container (UNION / EXCEPT / INTERSECT)");
                return;
            }
        }
Exemplo n.º 28
0
        /// <summary>
        /// Creates a new AggregateConfiguration based on the Catalogue and returns it as an AggregateConfigurationCommand, you should only use this method during EXECUTE as you do not
        /// want to be randomly creating these as the user waves an object around over the user interface trying to decide where to drop it.
        /// </summary>
        /// <param name="cohortAggregateContainer"></param>
        /// <param name="importMandatoryFilters"></param>
        /// <param name="caller"></param>
        /// <returns></returns>
        public AggregateConfigurationCommand GenerateAggregateConfigurationFor(CohortAggregateContainer cohortAggregateContainer, bool importMandatoryFilters = true, [CallerMemberName] string caller = null)
        {
            var cic = cohortAggregateContainer.GetCohortIdentificationConfiguration();

            if (cic == null)
            {
                return(null);
            }

            return(GenerateAggregateConfigurationFor(cic, importMandatoryFilters));
        }
Exemplo n.º 29
0
 public void Add(CohortAggregateContainer parent, AggregateConfiguration child, int order)
 {
     CatalogueRepository.Insert(
         "INSERT INTO CohortAggregateContainer_AggregateConfiguration (CohortAggregateContainer_ID, AggregateConfiguration_ID, [Order]) VALUES (@CohortAggregateContainer_ID, @AggregateConfiguration_ID, @Order)",
         new Dictionary <string, object>
     {
         { "CohortAggregateContainer_ID", parent.ID },
         { "AggregateConfiguration_ID", child.ID },
         { "Order", order }
     });
 }
Exemplo n.º 30
0
        public ExecuteCommandReOrderAggregateContainer(IActivateItems activator, CohortAggregateContainerCombineable sourceCohortAggregateContainerCombineable, AggregateConfiguration targetAggregate, InsertOption insertOption) : this(activator, targetAggregate, insertOption)
        {
            _sourceCohortAggregateContainerCombineable = sourceCohortAggregateContainerCombineable;
            _targetParent = targetAggregate.GetCohortAggregateContainerIfAny();

            //if they do not share the same parent container
            if (!_sourceCohortAggregateContainerCombineable.ParentContainerIfAny.Equals(_targetParent))
            {
                SetImpossible("First move objects into the same parent container");
            }
        }