local z={}z.__index=z function z.new(a,h)return setmetatable({signal=a;connected=true;_handler=h},z)end function z.disconnect(z)if z.connected then z.connected=false for a,h in pairs(z.signal._connections)do if h==z then table.remove(z.signal._connections,a)return end end end end local a={}a.__index=a function a.new()return setmetatable({_connections={};_threads={}},a)end function a.fire(z,...)for z,a in pairs(z._connections)do a._handler(...)end for z,a in pairs(z._threads)do coroutine.resume(a,...)end z._threads={}end function a.connect(h,a)local n=z.new(h,a)table.insert(h._connections,n)return n end function a.wait(z)table.insert(z._threads,coroutine.running())return coroutine.yield()end return a
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
