local A="\078\101\120\117\115\067\111\110\116\097\105\110\101\114"local b=5 local O=(require(script.Parent.Parent:WaitForChild("\078\101\120\117\115\080\108\117\103\105\110\070\114\097\109\101\119\111\114\107\080\114\111\106\101\099\116"))):GetContext(script)local w=O:GetResource("\066\097\115\101\046\079\118\101\114\114\105\100\097\098\108\101\073\110\100\101\120\073\110\115\116\097\110\099\101")local X=O:GetResource("\078\101\120\117\115\073\110\115\116\097\110\099\101\046\069\118\101\110\116\046\078\101\120\117\115\069\118\101\110\116\067\114\101\097\116\111\114")local D=O:GetResource("\078\101\120\117\115\073\110\115\116\097\110\099\101\046\069\118\101\110\116\046\078\101\120\117\115\067\111\110\110\101\099\116\105\111\110")local E=w:Extend()E:SetClassName(A)O:SetContextResource(E)function E.__new(A)A:InitializeSuper()A.__Children={}A.__DescendantEvents={}A.__EventsToClear={}A.__ConnectionsToClear={}A.Name=A.ClassName A.Archivable=true A.Hidden=false A.AncestryChanged=X:CreateEvent()table.insert(A.__EventsToClear,A.AncestryChanged)A.ChildAdded=X:CreateEvent()table.insert(A.__EventsToClear,A.ChildAdded)A.ChildRemoved=X:CreateEvent()table.insert(A.__EventsToClear,A.ChildRemoved)A.DescendantAdded=X:CreateEvent()table.insert(A.__EventsToClear,A.DescendantAdded)A.DescendantRemoving=X:CreateEvent()table.insert(A.__EventsToClear,A.DescendantRemoving)A.__ChangedProperties={}table.insert(A.__ConnectionsToClear,A.Changed:Connect(function(b)A.__ChangedProperties[b]=A[b]end))A:__InitParentChanges()end function E.__InitParentChanges(b)b=b.object local O,w table.insert(b.__ConnectionsToClear,(b:GetPropertyChangedSignal("\080\097\114\101\110\116")):Connect(function()local X=b.Parent if w then w:Disconnect()w=nil end if X and X:IsA(A)then X:__ChildAdded(b)w=X.AncestryChanged:Connect(function(A,O)b.AncestryChanged:Fire(A,O)end)end if O and O:IsA(A)then O:__ChildRemoved(b)end b.AncestryChanged:Fire(b,X)O=X end))end function E.__tostring(A)return tostring(A.Name)end function E.__getindex(O,A,b)if b==nil and(A~="\095\095\067\104\105\108\100\114\101\110"and A~="\078\097\109\101")then for b,O in pairs(O.__Children or{})do if O.Name==A then return O end end end return E.super.__getindex(O.super,A,b)end function E.__CloneProperties(w,b,O)for w,X in pairs(w.__ChangedProperties)do if w~="\080\097\114\101\110\116"and string.sub(w,1,2)~="\095\095"then if typeof(X)=="\116\097\098\108\101"and(X.IsA and X:IsA(A))then b[w]=O[X]or X else b[w]=X end end end end function E.__PreInitializeClone(A)return E.new()end function E.__RecursiveClone(A)if A.Archivable==false then return nil,{}end local b={}local O=A:__PreInitializeClone()b[A]=O for A,w in pairs(A:GetChildren())do if b[w]then error("\083\116\114\117\099\116\117\114\101 \105\115 \114\101\099\117\114\115\105\118\101\046 \067\108\111\110\105\110\103 \119\105\108\108 \110\111\116 \119\111\114\107\046")end local X,D=w:__RecursiveClone()if X then X.Parent=O end for A,O in pairs(D)do b[A]=O end end return O,b end function E.__ChildAdded(b,A)for b,O in pairs(b.__Children)do if A==O then return end end table.insert(b.__Children,A)if not A.Hidden then b.ChildAdded:Fire(A)b.DescendantAdded:Fire(A)end local O=A.DescendantAdded:Connect(function(O)if not A.Hidden then b.DescendantAdded:Fire(O)end end)local w=A.DescendantRemoving:Connect(function(O)if not A.Hidden then b.DescendantRemoving:Fire(O)end end)b.__DescendantEvents[A]={O;w}end function E.__ChildRemoved(b,A)local O for b,w in pairs(b.__Children)do if A==w then O=b end end if O then table.remove(b.__Children,O)end if not A.Hidden then b.ChildRemoved:Fire(A)b.DescendantRemoving:Fire(A)for A,O in pairs(A:GetDescendants())do b.DescendantRemoving:Fire(O)end end local w=b.__DescendantEvents[A]if w then for A,b in pairs(w)do b:Disconnect()end b.__DescendantEvents[A]=nil end end function E.ClearAllChildren(A)for A,b in pairs(A:GetChildren())do b:Destroy()end end function E.Clone(A)if A.Archivable==false then return end local b,O=A:__RecursiveClone()for A,b in pairs(O)do A:__CloneProperties(b,O)end return b end function E.Destroy(A)A.Parent=nil A:LockProperty("\080\097\114\101\110\116")for A,b in pairs(A.__EventsToClear)do b:Disconnect()end for A,b in pairs(A.__ConnectionsToClear)do b:Disconnect()end A.__EventsToClear={}A.__ConnectionsToClear={}A:ClearAllChildren()end function E.FindFirstAncestor(b,A)if b.Parent==nil then return nil end local O=b.Parent if O.Name==A then return O end return O:FindFirstAncestor(A)end function E.FindFirstAncestorOfClass(b,A)if b.Parent==nil then return nil end local O=b.Parent if O.ClassName==A then return O end return O:FindFirstAncestorOfClass(A)end function E.FindFirstAncestorWhichIsA(b,A)if b.Parent==nil then return nil end local O=b.Parent if O:IsA(A)then return O end return O:FindFirstAncestorWhichIsA(A)end function E.FindFirstChild(O,A,b)for b,O in pairs(O:GetChildren())do if O.Name==A then return O end end if b then for O,w in pairs(O:GetChildren())do local X=w:FindFirstChild(A,b)if X then return X end end end end function E.FindFirstChildOfClass(b,A)for b,O in pairs(b:GetChildren())do if O.ClassName==A then return O end end end function E.FindFirstChildWhichIsA(O,A,b)for b,O in pairs(O:GetChildren())do if O:IsA(A)then return O end end if b then for O,w in pairs(O:GetChildren())do local X=w:FindFirstChildWhichIsA(A,b)if X then return X end end end end function E.GetChildren(A)local b={}for A,O in pairs(A.__Children)do if not O.Hidden then table.insert(b,O)end end return b end function E.GetDescendants(A)local b={}for A,O in pairs(A.__Children)do if not O.Hidden then table.insert(b,O)for A,O in pairs(O:GetDescendants())do table.insert(b,O)end end end return b end function E.GetFullName(A)if A.Parent then return A.Parent:GetFullName()..("\046"..A.Name)else return A.Name end end function E.IsAncestorOf(b,A)if not A or not A.Parent then return false end if A.Parent==b then return true end return b:IsAncestorOf(A.Parent)end function E.IsDescendantOf(b,A)if not A or not b.Parent then return false end if b.Parent==A then return true end return b.Parent:IsDescendantOf(A)end function E.WaitForChild(w,A,O)local X=tick()local D=false while true do local E=w:FindFirstChild(A)if E then return E end if O then if tick()-X>=O then return nil end elseif not D and tick()-X>=b then D=true warn("\073\110\102\105\110\105\116\101 \121\105\101\108\100 \112\111\115\115\105\098\108\101 \111\110 \'"..(w:GetFullName()..("\058\087\097\105\116\070\111\114\067\104\105\108\100\040\""..(A.."\"\041\'"))))end wait()end end function E.ConnectToHighestParent(O,A,b)local w=D.new(nil,b)local X local function E(O)local w,D=pcall(function()local w=O[A]if not w then return false else X=w:Connect(b)return true end end)if w then return D end return false end local function N(A)if not w.Connected then return false end local b=A.Parent if not b then return E(A)end if b and N(b)then return true end return E(A)end O.AncestryChanged:Connect(function()if X then X:Disconnect()X=nil end N(O)end)N(O)return w end return E
--[[
TheNexusAvenger

Mirrors the API of Roblox Instances for containing children and being parented.
--]]

local CLASS_NAME = "NexusContainer"

local INFINITE_YEILD_DELAY = 5



local NexusPluginFramework = require(script.Parent.Parent:WaitForChild("NexusPluginFrameworkProject")):GetContext(script)
local OverridableIndexInstance = NexusPluginFramework:GetResource("Base.OverridableIndexInstance")
local NexusEventCreator = NexusPluginFramework:GetResource("NexusInstance.Event.NexusEventCreator")
local NexusConnection = NexusPluginFramework:GetResource("NexusInstance.Event.NexusConnection")

local NexusContainer = OverridableIndexInstance:Extend()
NexusContainer:SetClassName(CLASS_NAME)
NexusPluginFramework:SetContextResource(NexusContainer)



--[[
Creates a Nexus Container object.
--]]
function NexusContainer:__new()
	self:InitializeSuper()
	
	self.__Children = {}
	self.__DescendantEvents = {}
	self.__EventsToClear = {}
	self.__ConnectionsToClear = {}
	self.Name = self.ClassName
	self.Archivable = true
	self.Hidden = false
	
	--Create the events.
	self.AncestryChanged = NexusEventCreator:CreateEvent()
	table.insert(self.__EventsToClear,self.AncestryChanged)
	self.ChildAdded = NexusEventCreator:CreateEvent()
	table.insert(self.__EventsToClear,self.ChildAdded)
	self.ChildRemoved = NexusEventCreator:CreateEvent()
	table.insert(self.__EventsToClear,self.ChildRemoved)
	self.DescendantAdded = NexusEventCreator:CreateEvent()
	table.insert(self.__EventsToClear,self.DescendantAdded)
	self.DescendantRemoving = NexusEventCreator:CreateEvent()
	table.insert(self.__EventsToClear,self.DescendantRemoving)
	
	--Set up changed property tracking.
	self.__ChangedProperties = {}
	table.insert(self.__ConnectionsToClear,self.Changed:Connect(function(Property)
		self.__ChangedProperties[Property] = self[Property]
	end))
	
	--Set up parent changes.
	self:__InitParentChanges()
end

--[[
Initializes changes to teh parent structure.
--]]
function NexusContainer:__InitParentChanges()
	--Set self as the root object.
	self = self.object
	
	--Set up changing the parent.
	local LastParent,LastAncestryChangedEvent
	table.insert(self.__ConnectionsToClear,self:GetPropertyChangedSignal("Parent"):Connect(function()
		local NewParent = self.Parent
		
		--Disconnect the last event.
		if LastAncestryChangedEvent then
			LastAncestryChangedEvent:Disconnect()
			LastAncestryChangedEvent = nil
		end
		
		--Register the new parent.
		if NewParent and NewParent:IsA(CLASS_NAME) then
			NewParent:__ChildAdded(self)
			
			LastAncestryChangedEvent = NewParent.AncestryChanged:Connect(function(Child,Parent)
				self.AncestryChanged:Fire(Child,Parent)
			end)
		end
		
		--Unregister the old parent.
		if LastParent and LastParent:IsA(CLASS_NAME) then
			LastParent:__ChildRemoved(self)
		end
		
		--Fire the ancestry changed event.
		self.AncestryChanged:Fire(self,NewParent)
		
		--Set the last parent as the new parent.
		LastParent = NewParent
	end))
end

--[[
Returns the object as a string.
--]]
function NexusContainer:__tostring()
	return tostring(self.Name)
end

--[[
Returns the value for a custom index. If the second
value returned is true, it will force return the
returned value, even if it is nil. If not, regular
indexing will be used.
--]]
function NexusContainer:__getindex(IndexName,OriginalReturn)
	--Return a child if one exists.
	if OriginalReturn == nil and IndexName ~= "__Children" and IndexName ~= "Name" then
		for _,Child in pairs(self.__Children or {}) do
			if Child.Name == IndexName then
				return Child
			end
		end
	end
	
	--Return the parent.
	return NexusContainer.super.__getindex(self.super,IndexName,OriginalReturn)
end

--[[
Clones the properties to another object.
--]]
function NexusContainer:__CloneProperties(TargetContainer,InstanceMap)
	for Name,Value in pairs(self.__ChangedProperties) do
		if Name ~= "Parent" and string.sub(Name,1,2) ~= "__" then
			if typeof(Value) == "table" and Value.IsA and Value:IsA(CLASS_NAME) then
				TargetContainer[Name] = InstanceMap[Value] or Value
			else
				TargetContainer[Name] = Value
			end
		end
	end
end

--[[
Returns a pre-initialized clone. Only the constructor
should be run with all properties added afterwards
except those starting with "__".
--]]
function NexusContainer:__PreInitializeClone()
	return NexusContainer.new()
end

--[[
Recursively clones the instance and
returns the new instance and a map of the
old instances to the new ones.
--]]
function NexusContainer:__RecursiveClone()
	--Return if Archivable is false.
	if self.Archivable == false then
		return nil,{}
	end
	
	--Clone the instance.
	local InstanceMap = {}
	local NewContainer = self:__PreInitializeClone()
	InstanceMap[self] = NewContainer
	
	--Clone the children.
	for _,Child in pairs(self:GetChildren()) do
		--Throw an error if the child already exists.
		if InstanceMap[Child] then
			error("Structure is recursive. Cloning will not work.")
		end
		
		--Add the clone.
		local Clone,CloneMap = Child:__RecursiveClone()
		if Clone then
			Clone.Parent = NewContainer 
		end
		
		--Add the mirror instances.
		for OldInstance,NewInstance in pairs(CloneMap) do
			InstanceMap[OldInstance] = NewInstance
		end
	end
	
	--Return the new instance and the map.
	return NewContainer,InstanceMap
end

--[[
Invoked when a child is added.
--]]
function NexusContainer:__ChildAdded(Child)
	--Return if the child exists.
	for i,OtherChild in pairs(self.__Children) do
		if Child == OtherChild then
			return
		end
	end
	
	--Add the child.
	table.insert(self.__Children,Child)
	
	--Fire the events.
	if not Child.Hidden then
		self.ChildAdded:Fire(Child)
		self.DescendantAdded:Fire(Child)
	end
	
	--Set up the descendant events for the child.
	local ChildDescendantAddedEvent = Child.DescendantAdded:Connect(function(OtherChild)
		if not Child.Hidden then
			self.DescendantAdded:Fire(OtherChild)
		end
	end)
	local ChildDescendantRemovingEvent = Child.DescendantRemoving:Connect(function(OtherChild)
		if not Child.Hidden then
			self.DescendantRemoving:Fire(OtherChild)
		end
	end)
	
	self.__DescendantEvents[Child] = {ChildDescendantAddedEvent,ChildDescendantRemovingEvent}
end

--[[
Invoked when a child is removed.
--]]
function NexusContainer:__ChildRemoved(Child)
	--Remove the child.
	local IndexToRemove 
	for i,OtherChild in pairs(self.__Children) do
		if Child == OtherChild then
			IndexToRemove = i
		end
	end
	if IndexToRemove then
		table.remove(self.__Children,IndexToRemove)
	end
	
	--Fire the events.
	if not Child.Hidden then
		self.ChildRemoved:Fire(Child)
		self.DescendantRemoving:Fire(Child)
		
		--Fire the DescendantRemoving for the children.
		for _,SubChild in pairs(Child:GetDescendants()) do
			self.DescendantRemoving:Fire(SubChild)
		end
	end
	
	--Disconnect the child descendant events.
	local ChildEvents = self.__DescendantEvents[Child]
	if ChildEvents then
		for _,Event in pairs(ChildEvents) do
			Event:Disconnect()
		end
		
		self.__DescendantEvents[Child] = nil
	end
end

--[[
This function destroys all of an NexusContainer's children.
--]]
function NexusContainer:ClearAllChildren()
	--Destroy the children.
	for _,Child in pairs(self:GetChildren()) do
		Child:Destroy()
	end
end

--[[
Create a deep copy of a NexusContainer and
descendants where Archivable = true.
--]]
function NexusContainer:Clone()
	--Return if Archivable is false.
	if self.Archivable == false then
		return
	end
	
	--Clone the instances.
	local NewInstance,InstanceMap = self:__RecursiveClone()
	
	--Apply the properties.
	for OldInstance,NewInstance in pairs(InstanceMap) do
		OldInstance:__CloneProperties(NewInstance,InstanceMap)
	end
	
	--Return the new container.
	return NewInstance
end

--[[
Sets the NexusContainer.Parent property to nil,
locks the NexusContainer.Parent property,
and calls Destroy on all children.
--]]
function NexusContainer:Destroy()
	--Set the parent to nil and lock the property.
	self.Parent = nil
	self:LockProperty("Parent")
	
	--Disconnect the events.
	for _,Event in pairs(self.__EventsToClear) do
		Event:Disconnect()
	end
	for _,Connection in pairs(self.__ConnectionsToClear) do
		Connection:Disconnect()
	end
	self.__EventsToClear = {}
	self.__ConnectionsToClear = {}
	
	--Destroy the children.
	self:ClearAllChildren()
end

--[[
Returns the first ancestor of the NexusContainer
whose NexusContainer.Name is equal to the given
name.
--]]
function NexusContainer:FindFirstAncestor(Name)
	--Return nil if the parent is nil.
	if self.Parent == nil then
		return nil
	end
	
	--Return the parent if the parent matches the name.
	local Parent = self.Parent
	if Parent.Name == Name then
		return Parent
	end
	
	--Return the parent.
	return Parent:FindFirstAncestor(Name)
end

--[[
Returns the first ancestor of the NexusContainer
whose NexusContainer.ClassName is equal to the
given className.
--]]
function NexusContainer:FindFirstAncestorOfClass(ClassName)
	--Return nil if the parent is nil.
	if self.Parent == nil then
		return nil
	end
	
	--Return the parent if the parent matches the class name.
	local Parent = self.Parent
	if Parent.ClassName == ClassName then
		return Parent
	end
	
	--Return the parent.
	return Parent:FindFirstAncestorOfClass(ClassName)
end

--[[
Returns the first ancestor of the NexusContainer for whom
NexusContainer:IsA returns true for the given ClassName.
--]]
function NexusContainer:FindFirstAncestorWhichIsA(ClassName)
	--Return nil if the parent is nil.
	if self.Parent == nil then
		return nil
	end
	
	--Return the parent if the parent matches the class name.
	local Parent = self.Parent
	if Parent:IsA(ClassName) then
		return Parent
	end
	
	--Return the parent.
	return Parent:FindFirstAncestorWhichIsA(ClassName)
end

--[[
Returns the first child of the NexusContainer found with
the given name.
--]]
function NexusContainer:FindFirstChild(Name,Recursive)
	--Return if a direct child has the name.
	for _,Child in pairs(self:GetChildren()) do
		if Child.Name == Name then
			return Child
		end
	end
	
	--If it is recursive, return a subchild.
	if Recursive then
		for _,Child in pairs(self:GetChildren()) do
			local Match = Child:FindFirstChild(Name,Recursive)
			if Match then
				return Match
			end
		end
	end
end

--[[
Returns the first child of the NexusContainer whose ClassName
is equal to the given ClassName.
--]]
function NexusContainer:FindFirstChildOfClass(ClassName)
	--Return if a direct child has the class name.
	for _,Child in pairs(self:GetChildren()) do
		if Child.ClassName == ClassName then
			return Child
		end
	end
end

--[[
Returns the first child of the NexusContainer for whom 
NexusContainer:IsA returns true for the given ClassName.
--]]
function NexusContainer:FindFirstChildWhichIsA(ClassName,Recursive)
	--Return if a direct child has the class.
	for _,Child in pairs(self:GetChildren()) do
		if Child:IsA(ClassName) then
			return Child
		end
	end
	
	--If it is recursive, return a subchild.
	if Recursive then
		for _,Child in pairs(self:GetChildren()) do
			local Match = Child:FindFirstChildWhichIsA(ClassName,Recursive)
			if Match then
				return Match
			end
		end
	end
end

--[[
Returns an array containing all of the NexusContainers's
children.
--]]
function NexusContainer:GetChildren()
	local Children = {}
	
	--Clone the non-hidden children table.
	for _,Child in pairs(self.__Children) do
		if not Child.Hidden then
			table.insert(Children,Child)
		end
	end
	
	--Return the children.
	return Children
end

--[[
Returns an array containing all of the descendants of the
NexusContainer.
--]]
function NexusContainer:GetDescendants()
	local Children = {}
	
	--Add the children and descendants.
	for _,Child in pairs(self.__Children) do
		if not Child.Hidden then
			table.insert(Children,Child)
			for _,SubChild in pairs(Child:GetDescendants()) do
				table.insert(Children,SubChild)
			end
		end
	end
	
	--Return the children.
	return Children
end

--[[
Returns a string describing the NexusContainer's ancestry.
--]]
function NexusContainer:GetFullName()
	if self.Parent then
		return self.Parent:GetFullName().."."..self.Name
	else
		return self.Name
	end
end

--[[
Returns true if an NexusContainer is an ancestor of the given
descendant.
--]]
function NexusContainer:IsAncestorOf(OtherContainer)
	--Return false if the parent is nil.
	if not OtherContainer or not OtherContainer.Parent then
		return false
	end
	
	--Return true if the parent is the false.
	if OtherContainer.Parent == self then
		return true
	end
	
	--Return if the parent is an ancestor.
	return self:IsAncestorOf(OtherContainer.Parent)
end

--[[
Returns true if an NexusContainer is a descendant of the given
ancestor.
--]]
function NexusContainer:IsDescendantOf(OtherContainer)
	--Return false if the parent is nil.
	if not OtherContainer or not self.Parent then
		return false
	end
	
	--Return true if the parent is the false.
	if self.Parent == OtherContainer then
		return true
	end
	
	--Return if the parent is an ancestor.
	return self.Parent:IsDescendantOf(OtherContainer)
end

--[[
Returns the child of the NexusContainer with the given name.
If the child does not exist, it will yield the current thread
until it does.
--]]
function NexusContainer:WaitForChild(Name,TimeOut)
	local StartTime = tick()
	local WarningDisplayed = false
	
	--Run the loop until it returns.
	while true do
		--Return if the patch exists.
		local Child = self:FindFirstChild(Name)
		if Child then
			return Child
		end
		
		--Handle a timeout or infinite yield.
		if TimeOut then
			if tick() - StartTime >= TimeOut then
				return nil
			end
		elseif not WarningDisplayed and tick() - StartTime >= INFINITE_YEILD_DELAY then
			WarningDisplayed = true
			warn("Infinite yield possible on '"..self:GetFullName()..":WaitForChild(\""..Name.."\")'")
		end
		wait()
	end
end

--[[
Connects an event to the highest parent. If the ancestry
changes, the connected event changes. Returns a connection. 
--]]
function NexusContainer:ConnectToHighestParent(EventName,ConnectionFunction)
	--Create the connection.
	local Connection = NexusConnection.new(nil,ConnectionFunction)
	local CurrentConnection
	
	--[[
	Attempts to connect the event to the object.
	--]]
	local function AttemptConnection(Object)
		--Connect the event.
		local Worked,Return = pcall(function()
			local Event = Object[EventName]
			if not Event then
				return false
			else
				CurrentConnection = Event:Connect(ConnectionFunction)
				return true
			end
		end)
		if Worked then return Return end
			
		--Return false (failed).
		return false
	end
	
	--[[
	Returns true if the parent was connected.
	--]]
	local function ConnectParent(Object)
		--Return false if the event is disconnected.
		if not Connection.Connected then
			return false
		end
		
		--Return false, attempt connecting.
		local Parent = Object.Parent
		if not Parent then
			return AttemptConnection(Object)
		end
		
		--Return if the parent was connected.
		if Parent and ConnectParent(Parent) then
			return true
		end
		
		--Connect the event.
		return AttemptConnection(Object)
	end
	
	self.AncestryChanged:Connect(function()
		--Disconnect the current connection.
		if CurrentConnection then
			CurrentConnection:Disconnect()
			CurrentConnection = nil
		end
		
		--Reconnect the event.
		ConnectParent(self)
	end)
	ConnectParent(self)
	
	--Return the connection.
	return Connection
end



return NexusContainer