local function X(X,...)local N={}local K=#X for K=1,K,1 do N[K]=X[K]end for X=1,select("\035",...),1 do N[K+X]=select(X,...)end return N end local function N(X,N)local K={}for V=1,#X,1 do if X[V]~=N then table.insert(K,X[V])end end return K end local K={}K.__index=K function K.new(X)local N={_listeners={};_store=X}setmetatable(N,K)return N end function K.connect(V,K)if typeof(K)~="\102\117\110\099\116\105\111\110"then error("\069\120\112\101\099\116\101\100 \116\104\101 \108\105\115\116\101\110\101\114 \116\111 \098\101 \097 \102\117\110\099\116\105\111\110\046")end if V._store and V._store._isDispatching then error("\089\111\117 \109\097\121 \110\111\116 \099\097\108\108 \115\116\111\114\101\046\099\104\097\110\103\101\100\058\099\111\110\110\101\099\116\040\041 \119\104\105\108\101 \116\104\101 \114\101\100\117\099\101\114 \105\115 \101\120\101\099\117\116\105\110\103\046 \073\102 \121\111\117 \119\111\117\108\100 \108\105\107\101 \116\111 \098\101 \110\111\116\105\102\105\101\100 \097\102\116\101\114 \116\104\101 \115\116\111\114\101 \104\097\115 \098\101\101\110 \117\112\100\097\116\101\100\044 \115\117\098\115\099\114\105\098\101 \102\114\111\109 \097 \099\111\109\112\111\110\101\110\116 \097\110\100 \105\110\118\111\107\101 \115\116\111\114\101\058\103\101\116\083\116\097\116\101\040\041 \105\110 \116\104\101 \099\097\108\108\098\097\099\107 \116\111 \097\099\099\101\115\115 \116\104\101 \108\097\116\101\115\116 \115\116\097\116\101\046 ")end local f={callback=K;disconnected=false,connectTraceback=debug.traceback(),disconnectTraceback=nil}V._listeners=X(V._listeners,f)local function q()if f.disconnected then error(("\076\105\115\116\101\110\101\114 \099\111\110\110\101\099\116\101\100 \097\116\058 \n\037\115\n\119\097\115 \097\108\114\101\097\100\121 \100\105\115\099\111\110\110\101\099\116\101\100 \097\116\058 \n\037\115\n"):format(tostring(f.connectTraceback),tostring(f.disconnectTraceback)))end if V._store and V._store._isDispatching then error("\089\111\117 \109\097\121 \110\111\116 \117\110\115\117\098\115\099\114\105\098\101 \102\114\111\109 \097 \115\116\111\114\101 \108\105\115\116\101\110\101\114 \119\104\105\108\101 \116\104\101 \114\101\100\117\099\101\114 \105\115 \101\120\101\099\117\116\105\110\103\046")end f.disconnected=true f.disconnectTraceback=debug.traceback()V._listeners=N(V._listeners,f)end return{disconnect=q}end function K.fire(X,...)for X,N in ipairs(X._listeners)do if not N.disconnected then N.callback(...)end end end return K
--[[
	A limited, simple implementation of a Signal.

	Handlers are fired in order, and (dis)connections are properly handled when
	executing an event.
]]
local function immutableAppend(list, ...)
	local new = {}
	local len = #list

	for key = 1, len do
		new[key] = list[key]
	end

	for i = 1, select("#", ...) do
		new[len + i] = select(i, ...)
	end

	return new
end

local function immutableRemoveValue(list, removeValue)
	local new = {}

	for i = 1, #list do
		if list[i] ~= removeValue then
			table.insert(new, list[i])
		end
	end

	return new
end

local Signal = {}

Signal.__index = Signal

function Signal.new(store)
	local self = {
		_listeners = {},
		_store = store,
	}

	setmetatable(self, Signal)

	return self
end

function Signal:connect(callback)
	if typeof(callback) ~= "function" then
		error("Expected the listener to be a function.")
	end

	if self._store and self._store._isDispatching then
		error(
			"You may not call store.changed:connect() while the reducer is executing. "
				.. "If you would like to be notified after the store has been updated, subscribe from a "
				.. "component and invoke store:getState() in the callback to access the latest state. "
		)
	end

	local listener = {
		callback = callback,
		disconnected = false,
		connectTraceback = debug.traceback(),
		disconnectTraceback = nil,
	}

	self._listeners = immutableAppend(self._listeners, listener)

	local function disconnect()
		if listener.disconnected then
			error(
				("Listener connected at: \n%s\n" .. "was already disconnected at: \n%s\n"):format(
					tostring(listener.connectTraceback),
					tostring(listener.disconnectTraceback)
				)
			)
		end

		if self._store and self._store._isDispatching then
			error("You may not unsubscribe from a store listener while the reducer is executing.")
		end

		listener.disconnected = true
		listener.disconnectTraceback = debug.traceback()
		self._listeners = immutableRemoveValue(self._listeners, listener)
	end

	return {
		disconnect = disconnect,
	}
end

function Signal:fire(...)
	for _, listener in ipairs(self._listeners) do
		if not listener.disconnected then
			listener.callback(...)
		end
	end
end

return Signal
