local u={}u.__index=u function u.new(z,C)return setmetatable({event=z,connected=true,_handler=C},u)end function u.disconnect(u)if u.connected then u.connected=false for z,C in pairs(u.event._connections)do if C==u then table.remove(u.event._connections,z)return end end end end local z={}z.__index=z function z.new()return setmetatable({_connections={},_threads={}},z)end function z.fire(u,...)for u,z in pairs(u._connections)do z._handler(...)end for u,z in pairs(u._threads)do coroutine.resume(z,...)end u._threads={}end function z.connect(C,z)local N=u.new(C,z)table.insert(C._connections,N)return N end function z.wait(u)table.insert(u._threads,coroutine.running())return coroutine.yield()end return z
local Connection = {}
Connection.__index = Connection

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

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

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

local Event = {}
Event.__index = Event

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

function Event: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 Event:connect(handler)
	local connection = Connection.new(self, handler)
	table.insert(self._connections, connection)
	return connection
end

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

return Event