local loader = function(loader, ...)
	local core = require"_cqueues"
	local errno = require"_cqueues.errno"
	local monotime = core.monotime
	local running = core.running
	local strerror = errno.strerror
	local unpack = assert(table.unpack or unpack) -- 5.1 compat

	-- lazily load auxlib to prevent circular or unused dependencies
	local auxlib = setmetatable({}, { __index = function (t, k)
		local v = require"cqueues.auxlib"[k]
		rawset(t, k, v)
		return v
	end })

	-- load deprecated APIs into shadow table to keep hidden unless used
	local notsupp = {}
	setmetatable(core, { __index = notsupp })

	function core.new()
		local cq, err = core.create()
		if not cq then
			error("unable to initialize continuation queue: " .. err)
		end
		return cq
	end

	--
	-- core.poll
	--
	-- Wrap the cqueues yield protocol to support polling across
	-- multilevel resume/yield. Requires explicit or implicit use
	-- (through monkey patching of coroutine.resume and coroutine.wrap)
	-- of auxlib.resume or auxlib.wrap.
	--
	-- Also supports polling from outside of a running event loop using
	-- a cheap hack. NOT RECOMMENDED.
	--
	local _POLL = core._POLL
	local yield = coroutine.yield
	local poller

	function core.poll(...)
		if running() then
			return yield(_POLL, ...)
		else
			local tuple

			poller = poller or auxlib.assert3(core.new())

			poller:wrap(function (...)
				tuple = { core.poll(...) }
			end, ...)

			-- NOTE: must step twice, once to call poll and
			-- again to wake up
			auxlib.assert3(poller:step())
			auxlib.assert3(poller:step())

			return unpack(tuple or {})
		end
	end -- core.poll

	--
	-- core.sleep
	--
	-- Sleep primitive.
	--
	function core.sleep(timeout)
		core.poll(timeout)
	end -- core.sleep

	--
	-- core:step
	--
	-- Wrap the low-level :step interface to make managing event loops
	-- slightly easier.
	--
	local step; step = core.interpose("step", function (self, timeout)
		if core.running() then
			core.poll(self, timeout)

			return step(self, 0.0)
		else
			return step(self, timeout)
		end
	end)
	--
	-- Lua 5.1 doesn't allow continuations in C
	-- so we have to emulate them in lua.
	--
	if _VERSION == "Lua 5.1" then
		local function checkstep(self, ok, ...)
			if ok == "yielded" then
				return checkstep(self, self:step_resume(coroutine.yield(...)))
			else
				return ok, ...
			end
		end
		local step_; step_ = core.interpose("step", function (self, timeout)
			return checkstep(self, step_(self, timeout))
		end)
	end -- core:step

	--
	-- core:loop
	--
	-- Step until an error is encountered.
	--
	local function todeadline(timeout)
		-- special case 0 timeout to avoid monotime call in totimeout
		return timeout and (timeout > 0 and monotime() + timeout or 0) or nil
	end -- todeadline

	local function totimeout(deadline)
		if not deadline then
			return nil, false
		elseif deadline == 0 then
			return 0, true
		else
			local curtime = monotime()

			if curtime < deadline then
				return deadline - curtime, false
			else
				return  0, true
			end
		end
	end -- totimeout

	core.interpose("loop", function (self, timeout)
		local function checkstep(self, deadline, ok, ...)
			local timeout, expired = totimeout(deadline)

			if not ok then
				return false, ...
			elseif expired or self:empty() then
				return true
			else
				return checkstep(self, deadline, self:step(timeout))
			end
		end

		local deadline = todeadline(timeout)
		return checkstep(self, deadline, self:step(timeout))
	end) -- core:loop

	--
	-- core:errors
	--
	-- Return iterator over core:loop.
	--
	core.interpose("errors", function (self, timeout)
		local deadline = todeadline(timeout)

		return function ()
			local timeout = totimeout(deadline)
			return select(2, self:loop(timeout))
		end
	end) -- core:errors

	--
	-- core.assert
	--
	-- DEPRECATED. See auxlib.assert.
	--
	function notsupp.assert(...)
		return auxlib.assert(...)
	end -- notsupp.assert

	--
	-- core.resume
	--
	-- DEPRECATED. See auxlib.resume.
	--
	function notsupp.resume(...)
		return auxlib.resume(...)
	end -- notsupp.resume

	--
	-- core.wrap
	--
	-- DEPRECATED. See auxlib.wrap.
	--
	function notsupp.wrap(...)
		return auxlib.wrap(...)
	end -- notsupp.wrap

	core.loader = loader

	return core
end -- loader

return loader(loader, ...)
