local v=require((game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")):WaitForChild("\078\101\118\101\114\109\111\114\101"))local E=v("\066\097\115\101\079\098\106\101\099\116")local F=v("\083\105\103\110\097\108")local N=setmetatable({},E)N.ClassName="\066\111\117\110\100\067\104\105\108\100\067\111\108\108\101\099\116\105\111\110"N.__index=N function N.new(v,Q)local c=setmetatable(E.new(),N)c._binder=v or error("\078\111 \098\105\110\100\101\114")c._parent=Q or error("\078\111 \112\097\114\101\110\116")c.ClassAdded=F.new()c._maid:GiveTask(c.ClassAdded)c.ClassRemoved=F.new()c._maid:GiveTask(c.ClassRemoved)c._classes={}c._size=0 c._maid:GiveTask((c._binder:GetClassAddedSignal()):Connect(function(...)c:_handleNewClassBound(...)end))c._maid:GiveTask((c._binder:GetClassRemovingSignal()):Connect(function(v)c:_removeClass(v)end))c:_startTracking()return c end function N.HasClass(E,v)return E._classes[v]end function N.GetSize(v)return v._size end function N.GetSet(v)return v._classes end function N.GetClasses(v)local E={}for v,F in pairs(v._classes)do table.insert(E,v)end return E end function N._startTracking(v)v._maid:GiveTask(v._parent.ChildAdded:Connect(function(E)v:_addChild(E)end))v._maid:GiveTask(v._parent.ChildRemoved:Connect(function(E)v:_removeChild(E)end))for E,F in pairs(v._parent:GetChildren())do v:_addChild(F,true)end end function N._addChild(F,v,E)local N=F._binder:Get(v)if not N then return end F:_addClass(N,E)end function N._handleNewClassBound(F,v,E)if E.Parent~=F._parent then return end F:_addClass(v)end function N._removeChild(E,v)local F=E._binder:Get(v)if not F then return end E:_removeClass(F)end function N._addClass(F,v,E)if F._classes[v]then return end F._classes[v]=true F._size=F._size+1 if not E then F.ClassAdded:Fire(v)end end function N._removeClass(E,v)if not E._classes[v]then return end E._classes[v]=nil E._size=E._size-1 E.ClassRemoved:Fire(v)end return N
--- Tracks child of type
-- @classmod BoundChildCollection

local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Nevermore"))

local BaseObject = require("BaseObject")
local Signal = require("Signal")

local BoundChildCollection = setmetatable({}, BaseObject)
BoundChildCollection.ClassName = "BoundChildCollection"
BoundChildCollection.__index = BoundChildCollection

function BoundChildCollection.new(binder, parent)
	local self = setmetatable(BaseObject.new(), BoundChildCollection)

	self._binder = binder or error("No binder")
	self._parent = parent or error("No parent")

	--- Fires on class addition
	self.ClassAdded = Signal.new() -- :Fire(class)
	self._maid:GiveTask(self.ClassAdded)

	--- Fires on class removal
	self.ClassRemoved = Signal.new() -- :Fire(class)
	self._maid:GiveTask(self.ClassRemoved)

	self._classes = {} -- [class] = true
	self._size = 0

	self._maid:GiveTask(self._binder:GetClassAddedSignal():Connect(function(...)
		self:_handleNewClassBound(...)
	end))
	self._maid:GiveTask(self._binder:GetClassRemovingSignal():Connect(function(class)
		self:_removeClass(class)
	end))

	self:_startTracking()

	return self
end

--- Returns whether the track has the class
-- @return true if the class exists, nil otherwise
function BoundChildCollection:HasClass(class)
	return self._classes[class]
end

function BoundChildCollection:GetSize()
	return self._size
end

--- Returns the raw classes variable as [class] = true
-- @return The set
function BoundChildCollection:GetSet()
	return self._classes
end

--- Slow than :GetSet(), but adds them in an ordered list
-- @return The list
function BoundChildCollection:GetClasses()
	local list = {}
	for class, _ in pairs(self._classes) do
		table.insert(list, class)
	end
	return list
end

function BoundChildCollection:_startTracking()
	self._maid:GiveTask(self._parent.ChildAdded:Connect(function(child)
		self:_addChild(child)
	end))

	self._maid:GiveTask(self._parent.ChildRemoved:Connect(function(child)
		self:_removeChild(child)
	end))

	for _, child in pairs(self._parent:GetChildren()) do
		-- Specifically do not fire on init because nothing is listening
		self:_addChild(child, true)
	end
end

function BoundChildCollection:_addChild(inst, doNotFire)
	local class = self._binder:Get(inst)
	if not class then
		return
	end

	self:_addClass(class, doNotFire)
end

function BoundChildCollection:_handleNewClassBound(class, inst)
	if inst.Parent ~= self._parent then
		return
	end

	self:_addClass(class)
end

function BoundChildCollection:_removeChild(inst)
	local class = self._binder:Get(inst)
	if not class then
		return
	end

	self:_removeClass(class)
end

function BoundChildCollection:_addClass(class, doNotFire)
	if self._classes[class] then
		return
	end

	self._classes[class] = true
	self._size = self._size + 1
	if not doNotFire then
		self.ClassAdded:Fire(class)
	end
end

function BoundChildCollection:_removeClass(class)
	if not self._classes[class] then
		return
	end

	self._classes[class] = nil
	self._size = self._size - 1
	self.ClassRemoved:Fire(class)
end

return BoundChildCollection