if not bin then
	print('Warning the \'bin\' library wasn\'t required! multi:tofile(path) and the multi:fromfile(path,int) features will not work!')
end
if table.unpack then
	unpack=table.unpack
end
function table.merge(t1, t2)
    for k,v in pairs(t2) do
    	if type(v) == 'table' then
    		if type(t1[k] or false) == 'table' then
    			table.merge(t1[k] or {}, t2[k] or {})
    		else
    			t1[k] = v
    		end
    	else
    		t1[k] = v
    	end
    end
    return t1
end
multi = {}
multi.Version={'A',2,0}-- History: EventManager,EventManager+,MultiManager <-- Current After 6.3.0 Versioning scheme was altered. A.0.0
multi.help=[[
For a list of features do print(multi.Features)
For a list of changes do print(multi.changelog)
For current version do print(multi.Version)
For current stage do print(multi.stage)
For help do print(multi.help) :D
]]
multi.stage='stable'
multi.Features='Current Version: '..multi.Version[1]..'.'..multi.Version[2]..'.'..multi.Version[3]..' '..multi.stage..[[
MultiManager has 19 Objects: # indicates most commonly used 1-19 1 being the most used by me
+Events			#7
+Alarms			#2
+Loops			#3
+Steps			#4
+TSteps			#6
+Triggers		#16
+Tasks			#12
+Connections	#1  -- This is a rather new feature of this library, but has become the most useful for async handling. Knowing this is already 50% of this library
+Timers			#14 -- this was tricky because these make up both Alarms and TSteps, but in purly using this standalone is almost non existent
+Jobs			#11
+Process		#10
+Conditions		#15
+Ranges			#8
+Threads		#13
+Functions		#5
+Queuers		#17
+Updaters		#9
+Watchers		#18
+CustomObjects	#19

Constructors [Runners]
---------------------- Note: multi is the main Processor Obj It cannot be paused or destroyed (kinda)
intObj=multi:newProcess([string: FILE defualt: nil])
intObj=multi:newQueuer([string: FILE defualt: nil])

Constructors [ACTORS]
--------------------- Note: everything is a multiObj!
eventObj=multi:newEvent([function: TASK defualt: function() end])
alarmObj=multi:newAlarm([number: SET defualt: 0])
loopObj=multi:newLoop([function: FUNC])
stepObj=multi:newStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SKIP defualt: 0])
tstepObj=multi:newTStep([number: START defualt: 0],[number: RESET defualt: inf],[number: COUNT defualt: 1],[number: SET defualt: 1])
updaterObj=multi:newUpdater([number: SKIP defualt: 0])
watcherObj=multi:newWatcher(table: NAMESPACE,string: NAME)
multiObj=multi:newCustomObject([table: OBJREF],[string: T='process'])
void=multi:newThread(string: name,function: func)

Constructors [Semi-ACTORS]
--------------------------
multi:newJob(function: func,[string: name])
multi:newRange(number: a,number: b,[number: c])
multi:newCondition(func)

Constructors [NON-ACTORS]
-------------------------
multi:newTrigger(function: func)
multi:newTask(function: func)
multi:newConnection()
multi:newTimer()
multi:newFunction(function: func)
]]
multi.changelog=[[Changelog starts at Version A.0.0
New in A.0.0
	Nothing really however a changelog will now be recorded! Feel free to remove this extra strings if space is a requriment
	version.major.minor
New in A.1.0
	Changed: multi:newConnection(protect) method
		Changed the way you are able to interact with it by adding the __call metamethod
		Old usage:
		OnUpdate=multi:newConnection()
			OnUpdate:connect(function(...)
				print("Updating",...)
			end)
		OnUpdate:Fire(1,2,3)
		New usage: notice that connect is no longer needed! Both ways still work! and always will work :)
		OnUpdate=multi:newConnection()
			OnUpdate(function(...)
				print("Updating",...)
			end)
		OnUpdate:Fire(1,2,3)
New in A.2.0 (12/31/2016)
	Added:
		connectionobj.getConnection(name)
		returns a list of an instance (or instances) of a single connect made with connectionobj:connect(func,name) or connectionobj(func,name)
		if you can orginize data before hand you can route info to certain connections thus saving a lot of cpu time. NOTE: only one name per each connection... you can't have 2 of the same names in a dictonary... the last one will be used
	Changed: obj=multi:newConnection()
		obj:connect(func,name) and obj(func,name)
		Added the name argument to allow indexing specific connection objects... Useful when creating an async library
]]
multi.__index = multi
multi.Mainloop={}
multi.Tasks={}
multi.Tasks2={}
multi.Garbage={}
multi.ender={}
multi.Children={}
multi.Paused={}
multi.Active=true
multi.fps=60
multi.Id=-1
multi.Type='mainprocess'
multi.Rest=0
multi._type=type
multi.Jobs={}
multi.queue={}
multi.jobUS=2
multi.clock=os.clock
multi.time=os.time
multi.LinkedPath=multi
multi.queuefinal=function(self)
	self:Destroy()
	if self.Parent.Mainloop[#self.Parent.Mainloop] then
		self.Parent.Mainloop[#self.Parent.Mainloop]:Resume()
	else
		for i=1,#self.Parent.funcE do
			self.Parent.funcE[i](self)
		end
		self.Parent:Remove()
	end
end
--Do not change these ever...Any other number will not work (Unless you are using enablePriority2() then change can be made. Just ensure that Priority_Idle is the greatest and Priority_Core is 1!)
multi.Priority_Core=1
multi.Priority_High=4
multi.Priority_Above_Normal=16
multi.Priority_Normal=64
multi.Priority_Below_Normal=256
multi.Priority_Low=1024
multi.Priority_Idle=4096
multi.PList={multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle}
multi.PStep=1
--^^^^
multi.PriorityTick=1 -- Between 1 and 4 any greater and problems arise
multi.Priority=multi.Priority_Core
function multi:setDomainName(name)
	self[name]={}
end
function multi:linkDomain(name)
	return self[name]
end
function multi:_Pause()
	self.Active=false
end
function multi:setPriority(s)
	if type(s)==number then
		self.Priority=s
	elseif type(s)=='string' then
		if s:lower()=='core' or s:lower()=='c' then
			self.Priority=self.Priority_Core
		elseif s:lower()=='high' or s:lower()=='h' then
			self.Priority=self.Priority_High
		elseif s:lower()=='above' or s:lower()=='an' then
			self.Priority=self.Priority_Above_Normal
		elseif s:lower()=='normal' or s:lower()=='n' then
			self.Priority=self.Priority_Normal
		elseif s:lower()=='below' or s:lower()=='bn' then
			self.Priority=self.Priority_Below_Normal
		elseif s:lower()=='low' or s:lower()=='l' then
			self.Priority=self.Priority_Low
		elseif s:lower()=='idle' or s:lower()=='i' then
			self.Priority=self.Priority_Idle
		end
	end
end
-- System
function os.getOS()
	if package.config:sub(1,1)=='\\' then
		return 'windows'
	else
		return 'unix'
	end
end
if os.getOS()=='windows' then
	function os.sleep(n)
		if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end
	end
else
	function os.sleep(n)
		os.execute('sleep ' .. tonumber(n))
	end
end
function multi:getParentProcess()
	return self.Mainloop[self.CID]
end
function multi:Stop()
	self.Active=false
end
function multi:condition(cond)
	if not self.CD then
		self:Pause()
		self.held=true
		self.CD=cond.condition
	elseif not(cond.condition()) then
		self.held=false
		self:Resume()
		self.CD=nil
		return false
	end
	self.Parent:Do_Order()
	return true
end
function multi:isHeld()
	return self.held
end
function multi.executeFunction(name,...)
	if type(_G[name])=='function' then
		_G[name](...)
	else
		print('Error: Not a function')
	end
end
function multi:waitFor(obj)
	self:hold(function() return obj:isActive() end)
end
function multi:reboot(r)
	local before=collectgarbage('count')
	self.Mainloop={}
	self.Tasks={}
	self.Tasks2={}
	self.Garbage={}
	self.Children={}
	self.Paused={}
	self.Active=true
	self.Id=-1
	if r then
		for i,v in pairs(_G) do
			if type(i)=='table' then
				if i.Parent and i.Id and i.Act then
					i={}
				end
			end
		end
	end
	collectgarbage()
	local after=collectgarbage('count')
	print([[Before rebooting total Ram used was ]]..before..[[Kb
After rebooting total Ram used is ]]..after..[[ Kb
A total of ]]..(before-after)..[[Kb was cleaned up]])
end
function multi:getChildren()
	return self.Mainloop
end
--Processor
function multi:getError()
	if self.error then
		return self.error
	end
end
function multi:Do_Order()
	local Loop=self.Mainloop
	_G.ID=0
	for _D=#Loop,1,-1 do
		if Loop[_D] then
			if Loop[_D].Active then
				Loop[_D].Id=_D
				self.CID=_D
				Loop[_D]:Act()
			end
		end
	end
end
function multi:enablePriority()
	function self:Do_Order()
		local Loop=self.Mainloop
		_G.ID=0
		local PS=self
		for _D=#Loop,1,-1 do
			if Loop[_D] then
				if (PS.PList[PS.PStep])%Loop[_D].Priority==0 then
					if Loop[_D].Active then
						Loop[_D].Id=_D
						self.CID=_D
						Loop[_D]:Act()
					end
				end
			end
		end
		PS.PStep=PS.PStep+1
		if PS.PStep>7 then
			PS.PStep=1
		end
	end
end
function multi:enablePriority2()
	function self:Do_Order()
		local Loop=self.Mainloop
		_G.ID=0
		local PS=self
		for _D=#Loop,1,-1 do
			if Loop[_D] then
				if (PS.PStep)%Loop[_D].Priority==0 then
					if Loop[_D].Active then
						Loop[_D].Id=_D
						self.CID=_D
						Loop[_D]:Act()
					end
				end
			end
		end
		PS.PStep=PS.PStep+1
		if PS.PStep>self.Priority_Idle then
			PS.PStep=1
		end
	end
end
multi.disablePriority=multi.unProtect
function multi:fromfile(path,int)
	int=int or self
	local test2={}
	local test=bin.load(path)
	local tp=test:getBlock('s')
	if tp=='event' then
		test2=int:newEvent(test:getBlock('f'))
		local t=test:getBlock('t')
		for i=1,#t do
			test2:OnEvent(t[i])
		end
	elseif tp=='alarm' then
		test2=int:newAlarm(test:getBlock('n'))
	elseif tp=='loop' then
		test2=int:newLoop(test:getBlock('t')[1])
	elseif tp=='step' or tp=='tstep' then
		local func=test:getBlock('t')
		local funcE=test:getBlock('t')
		local funcS=test:getBlock('t')
		local tab=test:getBlock('t')
		test2=int:newStep()
		table.merge(test2,tab)
		test2.funcE=funcE
		test2.funcS=funcS
		test2.func=func
	elseif tp=='trigger' then
		test2=int:newTrigger(test:getBlock('f'))
	elseif tp=='connector' then
		test2=int:newConnection()
		test2.func=test:getBlock('t')
	elseif tp=='timer' then
		test2=int:newTimer()
		test2.count=tonumber(test:getBlock('n'))
	else
		print('Error: The file you selected is not a valid multi file object!')
		return false
	end
	return test2
end
function multi:benchMark(sec,p)
	local temp=self:newLoop(function(t,self)
		if self.clock()-self.init>self.sec then
			print(self.c..' steps in '..self.sec..' second(s)')
			self.tt(self.sec)
			self:Destroy()
		else
			self.c=self.c+1
		end
	end)
	temp.Priority=p or 1
	function temp:OnBench(func)
		self.tt=func
	end
	self.tt=function() end
	temp.sec=sec
	temp.init=self.clock()
	temp.c=0
	return temp
end
function multi:tofile(path)
	local items=self:getChildren()
	io.mkDir(io.getName(path))
	for i=1,#items do
		items[i]:tofile(io.getName(path)..'\\item'..item[i]..'.dat')
	end
	local int=bin.new()
	int:addBlock('process')
	int:addBlock(io.getName(path))
	int:addBlock(#self.Mainloop)
	int:addBlock(self.Active)
	int:addBlock(self.Rest)
	int:addBlock(self.Jobs)
	int:tofile()
end
function multi.startFPSMonitior()
	if not multi.runFPS then
		multi.doFPS(s)
		multi.runFPS=true
	end
end
function multi.doFPS(s)
	multi:benchMark(1):OnBench(doFPS)
	if s then
		multi.fps=s
	end
end
--Helpers
function multi:OnMainConnect(func)
	table.insert(self.func,func)
end
function multi:protect()
	function self:Do_Order()
		local Loop=self.Mainloop
		for _D=#Loop,1,-1 do
			if Loop[_D]~=nil then
				Loop[_D].Id=_D
				self.CID=_D
				local status, err=pcall(Loop[_D].Act,Loop[_D])
				if err and not(Loop[_D].error) then
					Loop[_D].error=err
					self.OnError:Fire(err,Loop[_D])
				end
			end
		end
	end
end
function multi:unProtect()
	local Loop=self.Mainloop
	_G.ID=0
	for _D=#Loop,1,-1 do
		if Loop[_D] then
			if Loop[_D].Active then
				Loop[_D].Id=_D
				self.CID=_D
				Loop[_D]:Act()
			end
		end
	end
end
function multi:setJobSpeed(n)
	self.jobUS=n
end
function multi:hasJobs()
	return #self.Jobs>0,#self.Jobs
end
function multi:getJobs()
	return #self.Jobs
end
function multi:removeJob(name)
	for i=#self.Jobs,1,-1 do
		if self.Jobs[i][2]==name then
			table.remove(self.Jobs,i)
		end
	end
end
function multi:FreeMainEvent()
	self.func={}
end
function multi:connectFinal(func)
	if self.Type=='event' then
		self:OnEvent(func)
	elseif self.Type=='alarm' then
		self:OnRing(func)
	elseif self.Type=='step' or self.Type=='tstep' then
		self:OnEnd(func)
	else
		print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(function) to trigger it's final event!")
		self:OnBreak(func)
	end
end
function multi:Break()
	self:Pause()
	self.Active=nil
	for i=1,#self.ender do
		if self.ender[i] then
			self.ender[i](self)
		end
	end
end
function multi:OnBreak(func)
	table.insert(self.ender,func)
end
function multi:isPaused()
	return not(self.Active)
end
function multi:isActive()
	return self.Active
end
function multi:getType()
	return self.Type
end
function multi:Sleep(n)
	self:hold(n)
end
function multi:Pause()
	if self.Type=='mainprocess' then
		print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()")
	else
		self.Active=false
		if self.Parent.Mainloop[self.Id]~=nil then
			table.remove(self.Parent.Mainloop,self.Id)
			table.insert(self.Parent.Paused,self)
			self.PId=#self.Parent.Paused
		end
	end
end
function multi:Resume()
	if self.Type=='process' or self.Type=='mainprocess' then
		self.Active=true
		local c=self:getChildren()
		for i=1,#c do
			c[i]:Resume()
		end
	else
		if self:isPaused() then
			table.remove(self.Parent.Paused,self.PId)
			table.insert(self.Parent.Mainloop,self)
			self.Id=#self.Parent.Mainloop
			self.Active=true
		end
	end
end
function multi:resurrect()
	table.insert(self.Parent.Mainloop,self)
	self.Active=true
end
function multi:Destroy()
	if self.Type=='process' or self.Type=='mainprocess' then
		local c=self:getChildren()
		for i=1,#c do
			self.OnObjectDestroyed:Fire(c[i])
			c[i]:Destroy()
		end
	else
		for i=1,#self.Parent.Mainloop do
			if self.Parent.Mainloop[i]==self then
				self.Parent.OnObjectDestroyed:Fire(self)
				table.remove(self.Parent.Mainloop,i)
				break
			end
		end
		self.Active=false
	end
end

function multi:hold(task)
	self:Pause()
	self.held=true
	if type(task)=='number' then
		local alarm=self.Parent:newAlarm(task)
		while alarm.Active==true do
			if love then
				self.Parent:lManager()
			else
				self.Parent:Do_Order()
			end
		end
		alarm:Destroy()
		self:Resume()
		self.held=false
	elseif type(task)=='function' then
		local env=self.Parent:newEvent(task)
		env:OnEvent(function(envt) envt:Pause() envt.Active=false end)
		while env.Active do
			if love then
				self.Parent:lManager()
			else
				self.Parent:Do_Order()
			end
		end
		env:Destroy()
		self:Resume()
		self.held=false
	else
		print('Error Data Type!!!')
	end
end
function multi:oneTime(func,...)
	if not(self.Type=='mainprocess' or self.Type=='process') then
		for _k=1,#self.Parent.Tasks2 do
			if self.Parent.Tasks2[_k]==func then
				return false
			end
		end
		table.insert(self.Parent.Tasks2,func)
		func(...)
		return true
	else
		for _k=1,#self.Tasks2 do
			if self.Tasks2[_k]==func then
				return false
			end
		end
		table.insert(self.Tasks2,func)
		func(...)
		return true
	end
end
function multi:Reset(n)
	self:Resume()
end
function multi:isDone()
	return self.Active~=true
end
function multi:create(ref)
	multi.OnObjectCreated:Fire(ref)
end
--Constructors [CORE]
function multi:newBase(ins)
	if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end
	local c = {}
    if self.Type=='process' or self.Type=='queue' then
		setmetatable(c, self.Parent)
	else
		setmetatable(c, self)
	end
	c.Active=true
	c.func={}
	c.ender={}
	c.Id=0
	c.PId=0
	c.Act=function() end
	c.Parent=self
	c.held=false
	if ins then
		table.insert(self.Mainloop,ins,c)
	else
		table.insert(self.Mainloop,c)
	end
	return c
end
function multi:newProcess(file)
	if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end
	local c = {}
    setmetatable(c, self)
	c.Parent=self
	c.Active=true
	c.func={}
	c.Id=0
	c.Type='process'
	c.Mainloop={}
	c.Tasks={}
	c.Tasks2={}
	c.Garbage={}
	c.Children={}
	c.Paused={}
	c.Active=true
	c.Id=-1
	c.Rest=0
	c.Jobs={}
	c.queue={}
	c.jobUS=2
	function c:Start()
		if self.l then
			self.l:Resume()
		else
			self.l=self.Parent:newLoop(function(dt) c:uManager(dt) end)
		end
	end
	function c:Pause()
		if self.l then
			self.l:Pause()
		end
	end
	function c:Remove()
		self:Destroy()
		self.l:Destroy()
	end
	if file then
		self.Cself=c
		loadstring('local interface=multi.Cself '..io.open(file,'rb'):read('*all'))()
	end
	self:create(c)
	return c
end
function multi:newQueuer(file)
	local c=self:newProcess()
	c.Type='queue'
	c.last={}
	c.funcE={}
	function c:OnQueueCompleted(func)
		table.insert(self.funcE,func)
	end
	if file then
		self.Cself=c
		loadstring('local queue=multi.Cself '..io.open(file,'rb'):read('*all'))()
	end
	self:create(c)
	return c
end
--Constructors [ACTORS]
function multi:newCustomObject(objRef,t)
	local c={}
	if t=='process' then
		if self.Type=='queue' then
			c=self:newBase(1)
			self.last=c
			print("This Custom Object was created on a queue! Ensure that it has a way to end! All objects have a obj:Break() method!")
		else
			c=self:newBase()
		end
		if type(objRef)=='table' then
			table.merge(c,objRef)
		end
		if not c.Act then
			function c:Act()
				-- Empty function
			end
		end
	else
		c=objRef or {}
	end
	if not c.Type then
		c.Type='coustomObject'
	end
	if self.Type=='queue' then
		if #self.Mainloop>1 then
			c:Pause()
		end
		c:connectFinal(multi.queuefinal)
	end
	self:create(c)
	return c
end
function multi:newEvent(task)
	local c={}
	if self.Type=='queue' then
		c=self:newBase(1)
		self.last=c
	else
		c=self:newBase()
	end
	c.Type='event'
	c.Task=task or function() end
	function c:Act()
		if self.Task(self) then
			self:Pause()
			for _E=1,#self.func do
				self.func[_E](self)
			end
		end
	end
	function c:OnEvent(func)
		table.insert(self.func,func)
	end
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.Task)
		m:addBlock(self.func)
		m:addBlock(self.Active)
		m:tofile(path)
	end
	if self.Type=='queue' then
		if #self.Mainloop>1 then
			c:Pause()
		end
		c:connectFinal(multi.queuefinal)
	end
	self:create(c)
	return c
end
function multi:newAlarm(set)
	local c={}
	if self.Type=='queue' then
		c=self:newBase(1)
		self.last=c
	else
		c=self:newBase()
	end
	c.Type='alarm'
	c.Priority=self.Priority_Low
	c.timer=self:newTimer()
	c.set=set or 0
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.set)
		m:addBlock(self.Active)
		m:tofile(path)
	end
	function c:Act()
		if self.timer:Get()>=self.set then
			self:Pause()
			self.Active=false
			for i=1,#self.func do
				self.func[i](self)
			end
		end
	end
	function c:Resume()
		self.Parent.Resume(self)
		self.timer:Resume()
	end
	function c:Reset(n)
		if n then self.set=n end
		self:Resume()
		self.timer:Reset()
	end
	function c:OnRing(func)
		table.insert(self.func,func)
	end
	function c:Pause()
		self.timer:Pause()
		self.Parent.Pause(self)
	end
	if self.Type=='queue' then
		c:Pause()
		c:connectFinal(multi.queuefinal)
	else
		c.timer:Start()
	end
	self:create(c)
	return c
end
function multi:newLoop(func)
	local c={}
	if self.Type=='queue' then
		c=self:newBase(1)
		self.last=c
	else
		c=self:newBase()
	end
	c.Type='loop'
	c.Start=self.clock()
	if func then
		c.func={func}
	end
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.func)
		m:addBlock(self.Active)
		m:tofile(path)
	end
	function c:Act()
		for i=1,#self.func do
			self.func[i](self.Parent.clock()-self.Start,self)
		end
	end
	function c:OnLoop(func)
		table.insert(self.func,func)
	end
	if self.Type=='queue' then
		if #self.Mainloop>1 then
			c:Pause()
		end
		c:connectFinal(multi.queuefinal)
	end
	self:create(c)
	return c
end
function multi:newUpdater(skip)
	local c={}
	if self.Type=='queue' then
		c=self:newBase(1)
		self.last=c
	else
		c=self:newBase()
	end
	c.Type='updater'
	c.pos=1
	c.skip=skip or 1
	function c:Act()
		if self.pos>=self.skip then
			self.pos=0
			for i=1,#self.func do
				self.func[i](self)
			end
		end
		self.pos=self.pos+1
	end
	function c:setSkip(n)
		self.skip=n
	end
	c.OnUpdate=self.OnMainConnect
	if self.Type=='queue' then
		if #self.Mainloop>1 then
			c:Pause()
		end
		c:connectFinal(multi.queuefinal)
	end
	self:create(c)
	return c
end
function multi:newStep(start,reset,count,skip)
	local c={}
	if self.Type=='queue' then
		c=self:newBase(1)
		self.last=c
	else
		c=self:newBase()
	end
	think=1
	c.Type='step'
	c.pos=start or 1
	c.endAt=reset or math.huge
	c.skip=skip or 0
	c.spos=0
	c.count=count or 1*think
	c.funcE={}
	c.funcS={}
	c.start=start or 1
	if start~=nil and reset~=nil then
		if start>reset then
			think=-1
		end
	end
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.func)
		m:addBlock(self.funcE)
		m:addBlock(self.funcS)
		m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,spos=self.spos,count=self.count,start=self.start})
		m:addBlock(self.Active)
		m:tofile(path)
	end
	function c:Act()
		if self~=nil then
			if self.spos==0 then
				if self.pos==self.start then
					for fe=1,#self.funcS do
						self.funcS[fe](self)
					end
				end
				for i=1,#self.func do
					self.func[i](self.pos,self)
				end
				self.pos=self.pos+self.count
				if self.pos-self.count==self.endAt then
					self:Pause()
					for fe=1,#self.funcE do
						self.funcE[fe](self)
					end
					self.pos=self.start
				end
			end
		end
		self.spos=self.spos+1
		if self.spos>=self.skip then
			self.spos=0
		end
	end
	c.Reset=c.Resume
	function c:OnStart(func)
		table.insert(self.funcS,func)
	end
	function c:OnStep(func)
		table.insert(self.func,1,func)
	end
	function c:OnEnd(func)
		table.insert(self.funcE,func)
	end
	function c:Break()
		self.Active=nil
	end
	function c:Update(start,reset,count,skip)
		self.start=start or self.start
		self.endAt=reset or self.endAt
		self.skip=skip or self.skip
		self.count=count or self.count
		self:Resume()
	end
	if self.Type=='queue' then
		if #self.Mainloop>1 then
			c:Pause()
		end
		c:connectFinal(multi.queuefinal)
	end
	self:create(c)
	return c
end
function multi:newTStep(start,reset,count,set)
	local c={}
	if self.Type=='queue' then
		c=self:newBase(1)
		self.last=c
	else
		c=self:newBase()
	end
	think=1
	c.Type='tstep'
	c.Priority=self.Priority_Low
	c.start=start or 1
	local reset = reset or math.huge
	c.endAt=reset
	c.pos=start or 1
	c.skip=skip or 0
	c.count=count or 1*think
	c.funcE={}
	c.timer=self.clock()
	c.set=set or 1
	c.funcS={}
	function c:Update(start,reset,count,set)
		self.start=start or self.start
		self.pos=self.start
		self.endAt=reset or self.endAt
		self.set=set or self.set
		self.count=count or self.count or 1
		self.timer=self.clock()
		self:Resume()
	end
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.func)
		m:addBlock(self.funcE)
		m:addBlock(self.funcS)
		m:addBlock({pos=self.pos,endAt=self.endAt,skip=self.skip,timer=self.timer,count=self.count,start=self.start,set=self.set})
		m:addBlock(self.Active)
		m:tofile(path)
	end
	function c:Act()
		if self.clock()-self.timer>=self.set then
			self:Reset()
			if self.pos==self.start then
				for fe=1,#self.funcS do
					self.funcS[fe](self)
				end
			end
			for i=1,#self.func do
				self.func[i](self.pos,self)
			end
			self.pos=self.pos+self.count
			if self.pos-self.count==self.endAt then
				self:Pause()
				for fe=1,#self.funcE do
					self.funcE[fe](self)
				end
				self.pos=self.start
			end
		end
	end
	function c:OnStart(func)
		table.insert(self.funcS,func)
	end
	function c:OnStep(func)
		table.insert(self.func,func)
	end
	function c:OnEnd(func)
		table.insert(self.funcE,func)
	end
	function c:Break()
		self.Active=nil
	end
	function c:Reset(n)
		if n then self.set=n end
		self.timer=self.clock()
		self:Resume()
	end
	if self.Type=='queue' then
		if #self.Mainloop>1 then
			c:Pause()
		end
		c:connectFinal(multi.queuefinal)
	end
	self:create(c)
	return c
end
function multi:newWatcher(namespace,name)
	local function WatcherObj(ns,n)
		if self.Type=='queue' then
			print("Cannot create a watcher on a queue! Creating on 'multi' instead!")
			self=multi
		end
		local c=self:newBase()
		c.Type='watcher'
		c.ns=ns
		c.n=n
		c.cv=ns[n]
		function c:OnValueChanged(func)
			table.insert(self.func,func)
		end
		function c:Act()
			if self.cv~=self.ns[self.n] then
				for i=1,#self.func do
					self.func[i](self,self.cv,self.ns[self.n])
				end
				self.cv=self.ns[self.n]
			end
		end
		self:create(c)
		return c
	end
	if type(namespace)~='table' and type(namespace)=='string' then
		return WatcherObj(_G,namespace)
	elseif type(namespace)=='table' and (type(name)=='string' or 'number') then
		return WatcherObj(namespace,name)
	else
		print('Warning, invalid arguments! Nothing returned!')
	end
end
function multi:newThread(name,func)
	local c={}
	c.ref={}
	c.Name=name
	c.thread=coroutine.create(func)
	c.sleep=1
	c.firstRunDone=false
	c.timer=multi.scheduler:newTimer()
	c.ref.Globals=self:linkDomain("Globals")
	function c.ref:send(name,val)
		ret=coroutine.yield({Name=name,Value=val})
		self:syncGlobals(ret)
	end
	function c.ref:get(name)
		return self.Globals[name]
	end
	function c.ref:kill()
		err=coroutine.yield({"_kill_"})
		if err then
			error("Failed to kill a thread! Exiting...")
		end
	end
	function c.ref:sleep(n)
		n = tonumber(n) or 0
		ret=coroutine.yield({"_sleep_",n})
		self:syncGlobals(ret)
	end
	function c.ref:syncGlobals(v)
		self.Globals=v
	end
	table.insert(self:linkDomain("Threads"),c)
	if not multi.scheduler:isActive() then
		multi.scheduler:Resume()
	end
end
-- Constructors [SEMI-ACTORS]
function multi:newJob(func,name)
	if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end
	local c = {}
    if self.Type=='process' then
		setmetatable(c, self.Parent)
	else
		setmetatable(c, self)
	end
	c.Active=true
	c.func={}
	c.Id=0
	c.PId=0
	c.Parent=self
	c.Type='job'
	c.trigfunc=func or function() end
	function c:Act()
		self:trigfunc(self)
	end
	table.insert(self.Jobs,{c,name})
	if self.JobRunner==nil then
		self.JobRunner=self:newAlarm(self.jobUS)
		self.JobRunner:OnRing(function(self)
			if #self.Parent.Jobs>0 then
				if self.Parent.Jobs[1] then
					self.Parent.Jobs[1][1]:Act()
					table.remove(self.Parent.Jobs,1)
				end
			end
			self:Reset(self.Parent.jobUS)
		end)
	end
end
function multi:newRange()
	local selflink=self
	local temp={
		getN = function(self) selflink:Do_Order() self.n=self.n+self.c if self.n>self.b then self.Link.held=false self.Link:Resume() return nil end return self.n end,
	}
	setmetatable(temp,{
		__call=function(self,a,b,c)
			self.c=c or 1
			self.n=a-self.c
			self.a=a
			self.b=b
			self.Link=selflink--.Parent.Mainloop[selflink.CID] or
			self.Link:Pause()
			self.Link.held=true
			return function() return self:getN() end
		end
	})
	self:create(temp)
	return temp
end
function multi:newCondition(func)
	local c={['condition']=func}
	self:create(c)
	return c
end
-- Constructors [NON-ACTORS]
function multi:newFunction(func)
	local c={}
	c.func=func
	mt={
		__index=multi,
		__call=function(self,...) if self.Active then return self:func(...) end local t={...} return "PAUSED" end
	}
	c.Parent=self
	function c:Pause()
		self.Active=false
	end
	function c:Resume()
		self.Active=true
	end
	setmetatable(c,mt)
	self:create(c)
	return c
end
function multi:newTimer()
	local c={}
	c.Type='timer'
	c.time=0
	c.count=0
	function c:Start()
		self.time=os.clock()
	end
	function c:Get()
		return (os.clock()-self.time)+self.count
	end
	c.Reset=c.Start
	function c:Pause()
		self.time=self:Get()
	end
	function c:Resume()
		self.time=os.clock()-self.time
	end
	function c:tofile(path)
		local m=bin.new()
		self.count=self.count+self:Get()
		m:addBlock(self.Type)
		m:addBlock(self.count)
		m:tofile(path)
	end
	self:create(c)
	return c
end
function multi:newTask(func)
	table.insert(self.Tasks,func)
end
function multi:newTrigger(func)
	local c={}
	c.Type='trigger'
	c.trigfunc=func or function() end
	function c:Fire(...)
		self:trigfunc(self,...)
	end
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.trigfunc)
		m:tofile(path)
	end
	self:create(c)
	return c
end
function multi:newConnection(protect)
	local c={}
	setmetatable(c,{__call=function(self,...) self:connect(...) end})
	c.Type='connector'
	c.func={}
	c.ID=0
	c.protect=protect or true
	c.connections={}
	c.fconnections={}
	c.FC=0
	function c:fConnect(func)
		local temp=self:connect(func)
		table.insert(self.fconnections,temp)
		self.FC=self.FC+1
	end
	function c:getConnection(name,ingore)
		if ingore then
			return self.connections[name] or {
				Fire=function() end -- if the connection doesn't exist lets call all of them or silently ingore
			}
		else
			return self.connections[name] or self
		end
	end
	function c:Fire(...)
		local ret={}
		for i=#self.func,1,-1 do
			if self.protect then
				local temp={pcall(self.func[i][1],...)}
				if temp[1] then
					table.remove(temp,1)
					table.insert(ret,temp)
				else
					print(temp[2])
				end
			else
				table.insert(ret,{self.func[i][1](...)})
			end
		end
		return ret
	end
	function c:bind(t)
		self.func=t
	end
	function c:remove()
		self.func={}
	end
	function c:connect(func,name)
		self.ID=self.ID+1
		table.insert(self.func,1,{func,self.ID})
		local temp = {
			Link=self.func,
			func=func,
			ID=self.ID,
			Parent=self,
			Fire=function(self,...)
				if self.Parent.FC>0 then
					for i=1,#self.Parent.FC do
						self.Parent.FC[i]:Fire(...)
					end
				end
				if self.Parent.protect then
					local t=pcall(self.func,...)
					if t then
						return t
					end
				else
					return self.func(...)
				end
			end,
			remove=function(self)
				for i=1,#self.Link do
					if self.Link[i][2]~=nil then
						if self.Link[i][2]==self.ID then
							table.remove(self.Link,i)
							self.remove=function() end
							self.Link=nil
							self.ID=nil
							return true
						end
					end
				end
			end
		}
		if name then
			self.connections[name]=temp
		end
		return temp
	end
	function c:tofile(path)
		local m=bin.new()
		m:addBlock(self.Type)
		m:addBlock(self.func)
		m:tofile(path)
	end
	return c
end
multi.OnObjectCreated=multi:newConnection()
multi.OnObjectDestroyed=multi:newConnection()
--Managers
function multi:mainloop()
	for i=1,#self.Tasks do
		self.Tasks[i](self)
	end
	rawset(self,'Start',self.clock())
	while self.Active do
		self:Do_Order()
	end
	print("Did you call multi:Stop()? This method should not be used when using multi:mainloop()! You now need to restart the multiManager, by using multi:reboot() and calling multi:mainloop() again or by using multi:uManager()")
end
function multi._tFunc(self,dt)
	for i=1,#self.Tasks do
		self.Tasks[i](self)
	end
	if dt then
		self.pump=true
	end
	self.pumpvar=dt
	rawset(self,'Start',self.clock())
end
function multi:uManager(dt)
	if self.Active then
		self:oneTime(self._tFunc,self,dt)
		function self:uManager(dt)
			self:Do_Order()
		end
		self:Do_Order()
	end
end
--Thread Setup Stuff
multi:setDomainName("Threads")
multi:setDomainName("Globals")
-- Scheduler
multi.scheduler=multi:newUpdater()
multi.scheduler.Type="scheduler"
function multi.scheduler:setStep(n)
	self.skip=tonumber(n) or 24
end
multi.scheduler.Threads=multi:linkDomain("Threads")
multi.scheduler.Globals=multi:linkDomain("Globals")
multi.scheduler:OnUpdate(function(self)
	for i=#self.Threads,1,-1 do
		ret={}
		if coroutine.status(self.Threads[i].thread)=="dead" then
			table.remove(self.Threads,i)
		else
			if self.Threads[i].timer:Get()>=self.Threads[i].sleep then
				if self.Threads[i].firstRunDone==false then
					self.Threads[i].firstRunDone=true
					self.Threads[i].timer:Start()
					_,ret=coroutine.resume(self.Threads[i].thread,self.Threads[i].ref)
				else
					_,ret=coroutine.resume(self.Threads[i].thread,self.Globals)
				end
				if ret==true or ret==false then
					print("Thread Ended!!!")
					ret={}
				end
			end
			if ret then
				if ret[1]=="_kill_" then
					table.remove(self.Threads,i)
				elseif ret[1]=="_sleep_" then
					self.Threads[i].timer:Reset()
					self.Threads[i].sleep=ret[2]
				elseif ret.Name then
					self.Globals[ret.Name]=ret.Value
				end
			end
		end
	end
end)
multi.scheduler:setStep()
multi.scheduler:Pause()
multi.OnError=multi:newConnection()
