local D={}D.WILDCARD="\042"D.DEFERRED=0 D.SUCCEEDED=1 D.NO_TRANSITION=2 D.PENDING=3 D.CANCELLED=4 local function K(D,K)if D then return D(unpack(K))end end local function n(D,n,b,Z,k)local f=K(D["\111\110\095\098\101\102\111\114\101\095"..n],k)local R=K(D.on_before_event,k)if f==false or R==false then return false end end local function b(n,b,Z,k,f)local R=K(n["\111\110\095\108\101\097\118\101\095"..Z],f)local W=K(n.on_leave_state,f)if R==false or W==false then return false end if R==D.DEFERRED or W==D.DEFERRED then return D.DEFERRED end end local function Z(D,n,b,Z,k)K(D["\111\110\095\101\110\116\101\114\095"..Z]or D["\111\110\095"..Z],k)K(D.on_enter_state or D.on_state,k)end local function k(D,n,b,Z,k)K(D["\111\110\095\097\102\116\101\114\095"..n]or D["\111\110\095"..n],k)K(D.on_after_event or D.on_event,k)end local function f(K,f,R)return function(...)local W=K.current local g=R[W]or R[D.WILDCARD]or W local h={K,f;W;g,...}assert(not K.is_pending(),"\112\114\101\118\105\111\117\115 \116\114\097\110\115\105\116\105\111\110 \115\116\105\108\108 \112\101\110\100\105\110\103")assert(K.can(f),"\105\110\118\097\108\105\100 \116\114\097\110\115\105\116\105\111\110 \102\114\111\109 \115\116\097\116\101 \'"..(W..("\' \119\105\116\104 \101\118\101\110\116 \'"..(f.."\'"))))local s=n(K,f,W,g,h)if s==false then return D.CANCELLED end if W==g then k(K,f,W,g,h)return D.NO_TRANSITION end K.confirm=function()K.confirm=nil K.cancel=nil K.current=g Z(K,f,W,g,h)k(K,f,W,g,h)return D.SUCCEEDED end K.cancel=function()K.confirm=nil K.cancel=nil k(K,f,W,g,h)return D.CANCELLED end local l=b(K,f,W,g,h)if l==false then return D.CANCELLED end if l==D.DEFERRED then return D.PENDING end if K.confirm then return K.confirm()end end end function D.create(K,n)local b=n or{}local Z=K.initial Z=type(Z)=="\115\116\114\105\110\103"and{state=Z}or Z local k=Z and Z.event or"\115\116\097\114\116\117\112"local R=K.terminal local W=K.events or{}local g=K.callbacks or{}local h={}local s={}local function l(K)local n=type(K.from)=="\116\097\098\108\101"and K.from or K.from and{K.from}or{D.WILDCARD}local b=K.to local Z=K.name h[Z]=h[Z]or{}for D,K in ipairs(n)do s[K]=s[K]or{}table.insert(s[K],Z)h[Z][K]=b or K end end if Z then l({name=k,from="\110\111\110\101",to=Z.state})end for D,K in ipairs(W)do l(K)end for D,K in pairs(h)do b[D]=f(b,D,K)end for D,K in pairs(g)do b[D]=K end b.current="\110\111\110\101"function b.is(D)if type(D)=="\116\097\098\108\101"then for D,K in ipairs(D)do if b.current==K then return true end end return false end return b.current==D end function b.can(K)local n=h[K]local Z=n[b.current]or n[D.WILDCARD]return Z~=nil end function b.cannot(D)return not b.can(D)end function b.transitions()return s[b.current]end function b.is_pending()return b.confirm~=nil end function b.is_finished()return b.is(R)end if Z and not Z.defer then b[k]()end return b end return D
 --
local Fsm = {}
Fsm.WILDCARD = "*"
Fsm.DEFERRED = 0
Fsm.SUCCEEDED = 1
Fsm.NO_TRANSITION = 2
Fsm.PENDING = 3
Fsm.CANCELLED = 4
local function do_callback(handler, args)
	if handler then
		return handler(unpack(args))
	end
end
local function before_event(self, event, _, _, args)
	local specific = do_callback(self["on_before_" .. event], args)
	local general = do_callback(self["on_before_event"], args)
	if specific == false or general == false then
		return false
	end
end
local function leave_state(self, _, from, _, args)
	local specific = do_callback(self["on_leave_" .. from], args)
	local general = do_callback(self["on_leave_state"], args)
	if specific == false or general == false then
		return false
	end
	if specific == Fsm.DEFERRED or general == Fsm.DEFERRED then
		return Fsm.DEFERRED
	end
end
local function enter_state(self, _, _, to, args)
	do_callback(self["on_enter_" .. to] or self["on_" .. to], args)
	do_callback(self["on_enter_state"] or self["on_state"], args)
end
local function after_event(self, event, _, _, args)
	do_callback(self["on_after_" .. event] or self["on_" .. event], args)
	do_callback(self["on_after_event"] or self["on_event"], args)
end
local function build_transition(self, event, states)
	return function(...)
		local from = self.current
		local to = states[from] or states[Fsm.WILDCARD] or from
		local args = {self, event, from, to, ...}
		assert(not self.is_pending(), "previous transition still pending")
		assert(self.can(event), "invalid transition from state '" .. from .. "' with event '" .. event .. "'")
		local before = before_event(self, event, from, to, args)
		if before == false then
			return Fsm.CANCELLED
		end
		if from == to then
			after_event(self, event, from, to, args)
			return Fsm.NO_TRANSITION
		end
		self.confirm = function()
			self.confirm = nil
			self.cancel = nil
			self.current = to
			enter_state(self, event, from, to, args)
			after_event(self, event, from, to, args)
			return Fsm.SUCCEEDED
		end
		self.cancel = function()
			self.confirm = nil
			self.cancel = nil
			after_event(self, event, from, to, args)
			return Fsm.CANCELLED
		end
		local leave = leave_state(self, event, from, to, args)
		if leave == false then
			return Fsm.CANCELLED
		end
		if leave == Fsm.DEFERRED then
			return Fsm.PENDING
		end
		if self.confirm then
			return self.confirm()
		end
	end
end
function Fsm.create(cfg, target)
	local self = target or {}
	-- Initial state.
	local initial = cfg.initial
	-- Allow for a string, or a map like `{state = "foo", event = "setup"}`.
	initial = type(initial) == "string" and {state = initial} or initial
	-- Initial event.
	local initial_event = initial and initial.event or "startup"
	-- Terminal state.
	local terminal = cfg.terminal
	-- Events.
	local events = cfg.events or {}
	-- Callbacks.
	local callbacks = cfg.callbacks or {}
	-- Track state transitions allowed for an event.
	local states_for_event = {}
	-- Track events allowed from a state.
	local events_for_state = {}
	local function add(e)
		-- Allow wildcard transition if `from` is not specified.
		local from = type(e.from) == "table" and e.from or (e.from and {e.from} or {Fsm.WILDCARD})
		local to = e.to
		local event = e.name
		states_for_event[event] = states_for_event[event] or {}
		for _, fr in ipairs(from) do
			events_for_state[fr] = events_for_state[fr] or {}
			table.insert(events_for_state[fr], event)
			-- Allow no-op transition if `to` is not specified.
			states_for_event[event][fr] = to or fr
		end
	end
	if initial then
		add({name = initial_event, from = "none", to = initial.state})
	end
	for _, event in ipairs(events) do
		add(event)
	end
	for event, states in pairs(states_for_event) do
		self[event] = build_transition(self, event, states)
	end
	for name, callback in pairs(callbacks) do
		self[name] = callback
	end
	self.current = "none"
	function self.is(state)
		if type(state) == "table" then
			for _, s in ipairs(state) do
				if self.current == s then
					return true
				end
			end
			return false
		end
		return self.current == state
	end
	function self.can(event)
		local states = states_for_event[event]
		local to = states[self.current] or states[Fsm.WILDCARD]
		return to ~= nil
	end
	function self.cannot(event)
		return not self.can(event)
	end
	function self.transitions()
		return events_for_state[self.current]
	end
	function self.is_pending()
		return self.confirm ~= nil
	end
	function self.is_finished()
		return self.is(terminal)
	end
	if initial and not initial.defer then
		self[initial_event]()
	end
	return self
end
return Fsm
