local Q={}Q.__index=Q function Q.new(R,w)return setmetatable({signal=R;connected=true;_handler=w},Q)end function Q.disconnect(Q)if Q.connected then Q.connected=false for R,w in pairs(Q.signal._connections)do if w==Q then table.remove(Q.signal._connections,R)return end end end end local R={}R.__index=R function R.new()return setmetatable({_connections={};_threads={}},R)end function R.fire(Q,...)for Q,R in pairs(Q._connections)do R._handler(...)end for Q,R in pairs(Q._threads)do coroutine.resume(R,...)end Q._threads={}end function R.connect(w,R)local S=Q.new(w,R)table.insert(w._connections,S)return S end function R.wait(Q)table.insert(Q._threads,coroutine.running())return coroutine.yield()end return R
local Connection = {}
Connection.__index = Connection

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

function Connection:disconnect()
	if self.connected then
		self.connected = false

		for index, connection in pairs(self.signal._connections) do
			if connection == self then
				table.remove(self.signal._connections, index)
				return
			end
		end
	end
end

local Signal = {}
Signal.__index = Signal

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

function Signal:fire(...)
	for _, connection in pairs(self._connections) do
		connection._handler(...)
	end

	for _, thread in pairs(self._threads) do
		coroutine.resume(thread, ...)
	end
	
	self._threads = {}
end

function Signal:connect(handler)
	local connection = Connection.new(self, handler)
	table.insert(self._connections, connection)
	return connection
end

function Signal:wait()
	table.insert(self._threads, coroutine.running())
	return coroutine.yield()
end

return Signal
