local u={}u.__index=u local W={}W.__index=W function W.new(u,O)return setmetatable({_handler=O;_signal=u},W)end function W.Disconnect(u)u._signal[u]=nil end function u.new()return setmetatable({},u)end function u.Connect(O,u)local Q=W.new(O,u)O[Q]=true return Q end function u.DisconnectAll(u)table.clear(u)end function u.Fire(u,...)if next(u)then for u,W in pairs(u)do u._handler(...)end end end function u.Wait(u)local W=coroutine.running()local O O=u:Connect(function(...)O:Disconnect()task.spawn(W,...)end)return coroutine.yield()end function u.Once(W,u)local O O=W:Connect(function(...)O:Disconnect()u(...)end)return O end return u


local Signal = {}
Signal.__index = Signal

local Connection = {}
Connection.__index = Connection

function Connection.new(signal, handler)
	return setmetatable({
		_handler = handler,
		_signal = signal,
	}, Connection)
end

function Connection:Disconnect()
	self._signal[self] = nil
end

function Signal.new()
	return setmetatable({}, Signal)
end

function Signal:Connect(fn)
	local connection = Connection.new(self, fn)
	self[connection] = true
	return connection
end

function Signal:DisconnectAll()
	table.clear(self)
end

function Signal:Fire(...)
	if next(self) then
		for handler, _ in pairs(self) do
			handler._handler(...)
		end
	end
end

function Signal:Wait()
	local waitingCoroutine = coroutine.running()
	local cn;
	cn = self:Connect(function(...)
		cn:Disconnect()
		task.spawn(waitingCoroutine, ...)
	end)
	return coroutine.yield()
end

function Signal:Once(fn)
	local cn;
	cn = self:Connect(function(...)
		cn:Disconnect()
		fn(...)
	end)
	return cn
end

return Signal
