<NME> thread.lua
<BEF> --[[

Copyright 2014 The Luvit Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS-IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

--]]

--- luvit thread management
local uv = require('uv')
local base = require('luvi').bundle.base

exports.name = "luvit/thread"
exports.version = "0.1.0"
  description = "thread module for luvit"
  tags = {"luvit", "thread","threadpool","work"}
  dependencies = {
    "luvit/core@1.0.5",
  }
exports.start = function(thread_func, ...)
  local dumped = string.dump(thread_func)

  function thread_entry(dumped, base,...)
    --- set thread luvit enviroment, mainly copy from luvi/src/init.lua
    local os = require('ffi').os
    local env = require('env')
    local uv = require('uv')
    local luvi = require('luvi')
    local miniz = require('miniz')

    local getPrefix, splitPath, joinParts

    local tmpBase = os == "Windows" and (env.get("TMP") or uv.cwd()) or
                                        (env.get("TMPDIR") or '/tmp')

    if os == "Windows" then
      -- Windows aware path utilities
      function getPrefix(path)
        return path:match("^%a:\\") or
               path:match("^/") or
               path:match("^\\+")
      end
      function splitPath(path)
        local parts = {}
        for part in string.gmatch(path, '([^/\\]+)') do
          table.insert(parts, part)
        end
        return parts
      end
      function joinParts(prefix, parts, i, j)
        if not prefix then
          return table.concat(parts, '/', i, j)
        elseif prefix ~= '/' then
          return prefix .. table.concat(parts, '\\', i, j)
        else
          return prefix .. table.concat(parts, '/', i, j)
        end
      end
    else
      -- Simple optimized versions for UNIX systems
      function getPrefix(path)
        return path:match("^/")
      end
      function splitPath(path)
        local parts = {}
        for part in string.gmatch(path, '([^/]+)') do
          table.insert(parts, part)
        end
        return parts
      end
      function joinParts(prefix, parts, i, j)
        if prefix then
          return prefix .. table.concat(parts, '/', i, j)
        end
        return table.concat(parts, '/', i, j)
      end
    end

    local function pathJoin(...)
      local inputs = {...}
      local l = #inputs

      -- Find the last segment that is an absolute path
      -- Or if all are relative, prefix will be nil
      local i = l
      local prefix
      while true do
        prefix = getPrefix(inputs[i])
        if prefix or i <= 1 then break end
        i = i - 1
      end

      -- If there was one, remove its prefix from its segment
      if prefix then
        inputs[i] = inputs[i]:sub(#prefix)
      end

      -- Split all the paths segments into one large list
      local parts = {}
      while i <= l do
        local sub = splitPath(inputs[i])
        for j = 1, #sub do
          parts[#parts + 1] = sub[j]
        end
        i = i + 1
      end

      -- Evaluate special segments in reverse order.
      local skip = 0
      local reversed = {}
      for idx = #parts, 1, -1 do
        local part = parts[idx]
        if part == '.' then
          -- Ignore
        elseif part == '..' then
          skip = skip + 1
        elseif skip > 0 then
          skip = skip - 1
        else
          reversed[#reversed + 1] = part
        end
      end

      -- Reverse the list again to get the correct order
      parts = reversed
      for idx = 1, #parts / 2 do
        local j = #parts - idx + 1
        parts[idx], parts[j] = parts[j], parts[idx]
      end

      local path = joinParts(prefix, parts)
      return path
    end

    -- Bundle from folder on disk
    local function folderBundle(base)
      local bundle = { base = base }

      function bundle.stat(path)
        path = pathJoin(base, "./" .. path)
        local raw, err = uv.fs_stat(path)
        if not raw then return nil, err end
        return {
          type = string.lower(raw.type),
          size = raw.size,
          mtime = raw.mtime,
        }
      end

      function bundle.readdir(path)
        path = pathJoin(base, "./" .. path)
        local req, err = uv.fs_scandir(path)
        if not req then
          return nil, err
        end

        local files = {}
        repeat
          local ent = uv.fs_scandir_next(req)
          if ent then
            files[#files + 1] = ent.name
          end
        until not ent
        return files
      end

      function bundle.readfile(path)
        path = pathJoin(base, "./" .. path)
        local fd, stat, data, err
        stat, err = uv.fs_stat(path)
        if not stat then return nil, err end
        if stat.type ~= "file" then return end
        fd, err = uv.fs_open(path, "r", 0644)
        if not fd then return nil, err end
        if stat then
          data, err = uv.fs_read(fd, stat.size, 0)
        end
        uv.fs_close(fd)
        return data, err
      end

      return bundle
    end

    -- Insert a prefix into all bundle calls
    local function chrootBundle(bundle, prefix)
      local bundleStat = bundle.stat
      function bundle.stat(path)
        return bundleStat(prefix .. path)
      end
      local bundleReaddir = bundle.readdir
      function bundle.readdir(path)
        return bundleReaddir(prefix .. path)
      end
      local bundleReadfile = bundle.readfile
      function bundle.readfile(path)
        return bundleReadfile(prefix .. path)
      end
    end

    -- Use a zip file as a bundle
    local function zipBundle(base, zip)
      local bundle = { base = base }

      function bundle.stat(path)
        path = pathJoin("./" .. path)
        if path == "" then
          return {
            type = "directory",
            size = 0,
            mtime = 0
          }
        end
        local err
        local index = zip:locate_file(path)
        if not index then
          index, err = zip:locate_file(path .. "/")
          if not index then return nil, err end
        end
        local raw = zip:stat(index)

        return {
          type = raw.filename:sub(-1) == "/" and "directory" or "file",
          size = raw.uncomp_size,
          mtime = raw.time,
        }
      end

      function bundle.readdir(path)
        path = pathJoin("./" .. path)
        local index, err
        if path == "" then
          index = 0
        else
          path = path .. "/"
          index, err = zip:locate_file(path )
          if not index then return nil, err end
          if not zip:is_directory(index) then
            return nil, path .. " is not a directory"
          end
        end
        local files = {}
        for i = index + 1, zip:get_num_files() do
          local filename = zip:get_filename(i)
          if string.sub(filename, 1, #path) ~= path then break end
          filename = filename:sub(#path + 1)
          local n = string.find(filename, "/")
          if n == #filename then
            filename = string.sub(filename, 1, #filename - 1)
            n = nil
          end
          if not n then
            files[#files + 1] = filename
          end
        end
        return files
      end

      function bundle.readfile(path)
        path = pathJoin("./" .. path)
        local index, err = zip:locate_file(path)
        if not index then return nil, err end
        return zip:extract(index)
      end

      -- Support zips with a single folder inserted at top-level
      local entries = bundle.readdir("")
      if #entries == 1 and bundle.stat(entries[1]).type == "directory" then
        chrootBundle(bundle, entries[1] .. '/')
      end

      return bundle
    end


    -- Given a list of bundles, merge them into a single VFS.  Lower indexed items
    -- overshadow later items.
    local function combinedBundle(bundles)
      local bases = {}
      for i = 1, #bundles do
        bases[i] = bundles[i].base
      end
      local bundle = { base = table.concat(bases, ";") }

      function bundle.stat(path)
        local err
        for i = 1, #bundles do
          local stat
          stat, err = bundles[i].stat(path)
          if stat then return stat end
        end
        return nil, err
      end

      function bundle.readdir(path)
        local has = {}
        local files, err
        for i = 1, #bundles do
          local list
          list, err = bundles[i].readdir(path)
          if list then
            for j = 1, #list do
              local name = list[j]
              if has[name] then
                print("Warning multiple overlapping versions of " .. name)
              else
                has[name] = true
                if files then
                  files[#files + 1] = name
                else
                  files = { name }
                end
              end
            end
          end
        end
        if files then
          return files
        else
          return nil, err
        end
      end

      function bundle.readfile(path)
        local err
        for i = 1, #bundles do
          local data
          data, err = bundles[i].readfile(path)
          if data then return data end
        end
        return nil, err
      end

      return bundle
    end

    local function makeBundle(bundlePaths)
      local parts = {}
      for n = 1, #bundlePaths do
        local path = pathJoin(uv.cwd(), bundlePaths[n])
        bundlePaths[n] = path
        local bundle
        local zip = miniz.new_reader(path)
        if zip then
          bundle = zipBundle(path, zip)
        else
          local stat = uv.fs_stat(path)
          if not stat or stat.type ~= "directory" then
            error("ERROR: " .. path .. " is not a zip file or a folder")
          end
          bundle = folderBundle(path)
        end
        parts[n] = bundle
      end
      if #parts == 1 then
        return parts[1]
      end
      return combinedBundle(parts)
    end

    local function commonBundle(bundle, args, bundlePaths, mainPath)

      luvi.makeBundle = makeBundle
      luvi.bundle = bundle

      mainPath = mainPath or "main.lua"

      bundle.paths = bundlePaths
      bundle.mainPath = mainPath

      luvi.path = {
        join = pathJoin,
        getPrefix = getPrefix,
        splitPath = splitPath,
        joinparts = joinParts,
      }

      function bundle.action(path, action, ...)
        -- If it's a real path, run it directly.
        if uv.fs_access(path, "r") then return action(path) end
        -- Otherwise, copy to a temporary folder and run from there
        local data, err = bundle.readfile(path)
        if not data then return nil, err end
        local dir = assert(uv.fs_mkdtemp(pathJoin(tmpBase, "lib-XXXXXX")))
        path = pathJoin(dir, path:match("[^/\\]+$"))
        local fd = uv.fs_open(path, "w", 384) -- 0600
        uv.fs_write(fd, data, 0)
        uv.fs_close(fd)
        local success, ret = pcall(action, path, ...)
        uv.fs_unlink(path)
        uv.fs_rmdir(dir)
        assert(success, ret)
        return ret
      end

      function bundle.register(name, path)
        if not path then path = name + ".lua" end
        package.preload[name] = function (...)
          local lua = assert(bundle.readfile(path))
          return assert(loadstring(lua, "bundle:" .. path))(...)
        end
      end

      _G.args = args

      -- Auto-register the require system if present
      local mainRequire
      local stat = bundle.stat("deps/require.lua")

      if stat and stat.type == "file" then
        bundle.register('require', "deps/require.lua")
        _G.require = require('require')("bundle:main.lua")
      end

      -- Auto-setup global p and libuv version of print
      if require and bundle.stat("deps/pretty-print") or bundle.stat("deps/pretty-print.lua") then
        _G.p = require('pretty-print').prettyPrint
      end
    end

    -- First check for a bundled zip file appended to the executable
    local path = uv.exepath()
    local zip = miniz.new_reader(path)
    if zip then
      commonBundle(zipBundle(path, zip), {}, {path})
    else
      -- lanched from luvit app dir
      local bundles = { base or '.' }
      local bundle = assert(makeBundle(bundles))
      -- Run the luvi app with the extra args
      commonBundle(bundle, {}, bundles)
    end

    loadstring(dumped)(...)

    uv.run()
  end

  return uv.new_thread(thread_entry,dumped,base, ...)
end

exports.join = function(thread)
    getfenv(fn).require = mainRequire
    fn(...)

    -- Start new event loop for thread.
    require('uv').run()
  end
  return uv.new_thread(thread_entry, dumped, table.concat(bundlePaths, ";"), ...)
end

local function join(thread)
    return uv.thread_join(thread)
end

local function equals(thread1,thread2)
    return uv.thread_equal(thread1,thread2)
end

local function self()
    return uv.thread_self()
end

--- luvit threadpool
local Worker = Object:extend()

function Worker:queue(...)
    uv.queue_work(self.handler, self.dumped, self.bundlePaths, ...)
end

local function work(thread_func, notify_entry)
  local worker = Worker:new()
  worker.dumped = type(thread_func)=='function'
    and string.dump(thread_func) or thread_func
  worker.bundlePaths = table.concat(bundlePaths, ";")

  local function thread_entry(dumped, bundlePaths, ...)
    if not _G._uv_works then
      _G._uv_works = {}
    end

    --try to find cached function entry
    local fn
    if not _G._uv_works[dumped] then
      fn = loadstring(dumped)

      -- Convert paths back to table
      local paths = {}
      for path in bundlePaths:gmatch("[^;]+") do
        paths[#paths + 1] = path
      end

      -- Load luvi environment
      local _, mainRequire = require('luvibundle').commonBundle(paths)

      -- Inject the global process table
      _G.process = _G.process or mainRequire('process').globalProcess()

      -- require injected
      getfenv(fn).require = mainRequire

      -- cache it
      _G._uv_works[dumped] = fn
    else
      fn = _G._uv_works[dumped]
    end
    -- Run function

    return fn(...)
  end

  worker.handler = uv.new_work(thread_entry,notify_entry)
  return worker
end

local function queue(worker, ...)
  worker:queue(...)
end

return {
  start = start,
  join = join,
  equals = equals,
  self = self,
  work = work,
  queue = queue,
}

<MSG> Use new luvi API instead of copying lua logic in thread

<DFF> @@ -18,7 +18,7 @@ limitations under the License.
 
 --- luvit thread management
 local uv = require('uv')
-local base = require('luvi').bundle.base
+local bundlePaths = require('luvi').bundle.paths
 
 exports.name = "luvit/thread"
 exports.version = "0.1.0"
@@ -30,423 +30,26 @@ exports.tags = {"luvit", "thread"}
 exports.start = function(thread_func, ...)
   local dumped = string.dump(thread_func)
 
-  function thread_entry(dumped, base,...)
-    --- set thread luvit enviroment, mainly copy from luvi/src/init.lua
-    local os = require('ffi').os
-    local env = require('env')
-    local uv = require('uv')
-    local luvi = require('luvi')
-    local miniz = require('miniz')
+  local function thread_entry(dumped, bundlePaths, ...)
 
-    local getPrefix, splitPath, joinParts
-
-    local tmpBase = os == "Windows" and (env.get("TMP") or uv.cwd()) or
-                                        (env.get("TMPDIR") or '/tmp')
-
-    if os == "Windows" then
-      -- Windows aware path utilities
-      function getPrefix(path)
-        return path:match("^%a:\\") or
-               path:match("^/") or
-               path:match("^\\+")
-      end
-      function splitPath(path)
-        local parts = {}
-        for part in string.gmatch(path, '([^/\\]+)') do
-          table.insert(parts, part)
-        end
-        return parts
-      end
-      function joinParts(prefix, parts, i, j)
-        if not prefix then
-          return table.concat(parts, '/', i, j)
-        elseif prefix ~= '/' then
-          return prefix .. table.concat(parts, '\\', i, j)
-        else
-          return prefix .. table.concat(parts, '/', i, j)
-        end
-      end
-    else
-      -- Simple optimized versions for UNIX systems
-      function getPrefix(path)
-        return path:match("^/")
-      end
-      function splitPath(path)
-        local parts = {}
-        for part in string.gmatch(path, '([^/]+)') do
-          table.insert(parts, part)
-        end
-        return parts
-      end
-      function joinParts(prefix, parts, i, j)
-        if prefix then
-          return prefix .. table.concat(parts, '/', i, j)
-        end
-        return table.concat(parts, '/', i, j)
-      end
-    end
-
-    local function pathJoin(...)
-      local inputs = {...}
-      local l = #inputs
-
-      -- Find the last segment that is an absolute path
-      -- Or if all are relative, prefix will be nil
-      local i = l
-      local prefix
-      while true do
-        prefix = getPrefix(inputs[i])
-        if prefix or i <= 1 then break end
-        i = i - 1
-      end
-
-      -- If there was one, remove its prefix from its segment
-      if prefix then
-        inputs[i] = inputs[i]:sub(#prefix)
-      end
-
-      -- Split all the paths segments into one large list
-      local parts = {}
-      while i <= l do
-        local sub = splitPath(inputs[i])
-        for j = 1, #sub do
-          parts[#parts + 1] = sub[j]
-        end
-        i = i + 1
-      end
-
-      -- Evaluate special segments in reverse order.
-      local skip = 0
-      local reversed = {}
-      for idx = #parts, 1, -1 do
-        local part = parts[idx]
-        if part == '.' then
-          -- Ignore
-        elseif part == '..' then
-          skip = skip + 1
-        elseif skip > 0 then
-          skip = skip - 1
-        else
-          reversed[#reversed + 1] = part
-        end
-      end
-
-      -- Reverse the list again to get the correct order
-      parts = reversed
-      for idx = 1, #parts / 2 do
-        local j = #parts - idx + 1
-        parts[idx], parts[j] = parts[j], parts[idx]
-      end
-
-      local path = joinParts(prefix, parts)
-      return path
-    end
-
-    -- Bundle from folder on disk
-    local function folderBundle(base)
-      local bundle = { base = base }
-
-      function bundle.stat(path)
-        path = pathJoin(base, "./" .. path)
-        local raw, err = uv.fs_stat(path)
-        if not raw then return nil, err end
-        return {
-          type = string.lower(raw.type),
-          size = raw.size,
-          mtime = raw.mtime,
-        }
-      end
-
-      function bundle.readdir(path)
-        path = pathJoin(base, "./" .. path)
-        local req, err = uv.fs_scandir(path)
-        if not req then
-          return nil, err
-        end
-
-        local files = {}
-        repeat
-          local ent = uv.fs_scandir_next(req)
-          if ent then
-            files[#files + 1] = ent.name
-          end
-        until not ent
-        return files
-      end
-
-      function bundle.readfile(path)
-        path = pathJoin(base, "./" .. path)
-        local fd, stat, data, err
-        stat, err = uv.fs_stat(path)
-        if not stat then return nil, err end
-        if stat.type ~= "file" then return end
-        fd, err = uv.fs_open(path, "r", 0644)
-        if not fd then return nil, err end
-        if stat then
-          data, err = uv.fs_read(fd, stat.size, 0)
-        end
-        uv.fs_close(fd)
-        return data, err
-      end
-
-      return bundle
-    end
-
-    -- Insert a prefix into all bundle calls
-    local function chrootBundle(bundle, prefix)
-      local bundleStat = bundle.stat
-      function bundle.stat(path)
-        return bundleStat(prefix .. path)
-      end
-      local bundleReaddir = bundle.readdir
-      function bundle.readdir(path)
-        return bundleReaddir(prefix .. path)
-      end
-      local bundleReadfile = bundle.readfile
-      function bundle.readfile(path)
-        return bundleReadfile(prefix .. path)
-      end
-    end
-
-    -- Use a zip file as a bundle
-    local function zipBundle(base, zip)
-      local bundle = { base = base }
-
-      function bundle.stat(path)
-        path = pathJoin("./" .. path)
-        if path == "" then
-          return {
-            type = "directory",
-            size = 0,
-            mtime = 0
-          }
-        end
-        local err
-        local index = zip:locate_file(path)
-        if not index then
-          index, err = zip:locate_file(path .. "/")
-          if not index then return nil, err end
-        end
-        local raw = zip:stat(index)
-
-        return {
-          type = raw.filename:sub(-1) == "/" and "directory" or "file",
-          size = raw.uncomp_size,
-          mtime = raw.time,
-        }
-      end
-
-      function bundle.readdir(path)
-        path = pathJoin("./" .. path)
-        local index, err
-        if path == "" then
-          index = 0
-        else
-          path = path .. "/"
-          index, err = zip:locate_file(path )
-          if not index then return nil, err end
-          if not zip:is_directory(index) then
-            return nil, path .. " is not a directory"
-          end
-        end
-        local files = {}
-        for i = index + 1, zip:get_num_files() do
-          local filename = zip:get_filename(i)
-          if string.sub(filename, 1, #path) ~= path then break end
-          filename = filename:sub(#path + 1)
-          local n = string.find(filename, "/")
-          if n == #filename then
-            filename = string.sub(filename, 1, #filename - 1)
-            n = nil
-          end
-          if not n then
-            files[#files + 1] = filename
-          end
-        end
-        return files
-      end
-
-      function bundle.readfile(path)
-        path = pathJoin("./" .. path)
-        local index, err = zip:locate_file(path)
-        if not index then return nil, err end
-        return zip:extract(index)
-      end
-
-      -- Support zips with a single folder inserted at top-level
-      local entries = bundle.readdir("")
-      if #entries == 1 and bundle.stat(entries[1]).type == "directory" then
-        chrootBundle(bundle, entries[1] .. '/')
-      end
-
-      return bundle
+    -- Convert paths back to table
+    local paths = {}
+    for path in bundlePaths:gmatch("[^;]+") do
+      paths[#paths + 1] = path
     end
 
+    -- Load luvi environment
+    local _, mainRequire = require('luvibundle').commonBundle(paths)
 
-    -- Given a list of bundles, merge them into a single VFS.  Lower indexed items
-    -- overshadow later items.
-    local function combinedBundle(bundles)
-      local bases = {}
-      for i = 1, #bundles do
-        bases[i] = bundles[i].base
-      end
-      local bundle = { base = table.concat(bases, ";") }
-
-      function bundle.stat(path)
-        local err
-        for i = 1, #bundles do
-          local stat
-          stat, err = bundles[i].stat(path)
-          if stat then return stat end
-        end
-        return nil, err
-      end
-
-      function bundle.readdir(path)
-        local has = {}
-        local files, err
-        for i = 1, #bundles do
-          local list
-          list, err = bundles[i].readdir(path)
-          if list then
-            for j = 1, #list do
-              local name = list[j]
-              if has[name] then
-                print("Warning multiple overlapping versions of " .. name)
-              else
-                has[name] = true
-                if files then
-                  files[#files + 1] = name
-                else
-                  files = { name }
-                end
-              end
-            end
-          end
-        end
-        if files then
-          return files
-        else
-          return nil, err
-        end
-      end
-
-      function bundle.readfile(path)
-        local err
-        for i = 1, #bundles do
-          local data
-          data, err = bundles[i].readfile(path)
-          if data then return data end
-        end
-        return nil, err
-      end
-
-      return bundle
-    end
-
-    local function makeBundle(bundlePaths)
-      local parts = {}
-      for n = 1, #bundlePaths do
-        local path = pathJoin(uv.cwd(), bundlePaths[n])
-        bundlePaths[n] = path
-        local bundle
-        local zip = miniz.new_reader(path)
-        if zip then
-          bundle = zipBundle(path, zip)
-        else
-          local stat = uv.fs_stat(path)
-          if not stat or stat.type ~= "directory" then
-            error("ERROR: " .. path .. " is not a zip file or a folder")
-          end
-          bundle = folderBundle(path)
-        end
-        parts[n] = bundle
-      end
-      if #parts == 1 then
-        return parts[1]
-      end
-      return combinedBundle(parts)
-    end
-
-    local function commonBundle(bundle, args, bundlePaths, mainPath)
-
-      luvi.makeBundle = makeBundle
-      luvi.bundle = bundle
-
-      mainPath = mainPath or "main.lua"
-
-      bundle.paths = bundlePaths
-      bundle.mainPath = mainPath
+    -- Run function with require injected
+    local fn = loadstring(dumped)
+    getfenv(fn).require = mainRequire
+    fn(...)
 
-      luvi.path = {
-        join = pathJoin,
-        getPrefix = getPrefix,
-        splitPath = splitPath,
-        joinparts = joinParts,
-      }
-
-      function bundle.action(path, action, ...)
-        -- If it's a real path, run it directly.
-        if uv.fs_access(path, "r") then return action(path) end
-        -- Otherwise, copy to a temporary folder and run from there
-        local data, err = bundle.readfile(path)
-        if not data then return nil, err end
-        local dir = assert(uv.fs_mkdtemp(pathJoin(tmpBase, "lib-XXXXXX")))
-        path = pathJoin(dir, path:match("[^/\\]+$"))
-        local fd = uv.fs_open(path, "w", 384) -- 0600
-        uv.fs_write(fd, data, 0)
-        uv.fs_close(fd)
-        local success, ret = pcall(action, path, ...)
-        uv.fs_unlink(path)
-        uv.fs_rmdir(dir)
-        assert(success, ret)
-        return ret
-      end
-
-      function bundle.register(name, path)
-        if not path then path = name + ".lua" end
-        package.preload[name] = function (...)
-          local lua = assert(bundle.readfile(path))
-          return assert(loadstring(lua, "bundle:" .. path))(...)
-        end
-      end
-
-      _G.args = args
-
-      -- Auto-register the require system if present
-      local mainRequire
-      local stat = bundle.stat("deps/require.lua")
-
-      if stat and stat.type == "file" then
-        bundle.register('require', "deps/require.lua")
-        _G.require = require('require')("bundle:main.lua")
-      end
-
-      -- Auto-setup global p and libuv version of print
-      if require and bundle.stat("deps/pretty-print") or bundle.stat("deps/pretty-print.lua") then
-        _G.p = require('pretty-print').prettyPrint
-      end
-    end
-
-    -- First check for a bundled zip file appended to the executable
-    local path = uv.exepath()
-    local zip = miniz.new_reader(path)
-    if zip then
-      commonBundle(zipBundle(path, zip), {}, {path})
-    else
-      -- lanched from luvit app dir
-      local bundles = { base or '.' }
-      local bundle = assert(makeBundle(bundles))
-      -- Run the luvi app with the extra args
-      commonBundle(bundle, {}, bundles)
-    end
-
-    loadstring(dumped)(...)
-
-    uv.run()
+    -- Start new event loop for thread.
+    require('uv').run()
   end
-
-  return uv.new_thread(thread_entry,dumped,base, ...)
+  return uv.new_thread(thread_entry, dumped, table.concat(bundlePaths, ";"), ...)
 end
 
 exports.join = function(thread)

{'commit': 'diff --git a/deps/thread.lua b/deps/thread.lua\nindex e4fcb70..fb7e1b1 100644\n--- a/deps/thread.lua\n+++ b/deps/thread.lua\n@@ -18,7 +18,7 @@ limitations under the License.\n \r\n --- luvit thread management\r\n local uv = require(\'uv\')\r\n-local base = require(\'luvi\').bundle.base\r\n+local bundlePaths = require(\'luvi\').bundle.paths\r\n \r\n exports.name = "luvit/thread"\r\n exports.version = "0.1.0"\r\n@@ -30,423 +30,26 @@ exports.tags = {"luvit", "thread"}\n exports.start = function(thread_func, ...)\r\n   local dumped = string.dump(thread_func)\r\n \r\n-  function thread_entry(dumped, base,...)\r\n-    --- set thread luvit enviroment, mainly copy from luvi/src/init.lua\r\n-    local os = require(\'ffi\').os\r\n-    local env = require(\'env\')\r\n-    local uv = require(\'uv\')\r\n-    local luvi = require(\'luvi\')\r\n-    local miniz = require(\'miniz\')\r\n+  local function thread_entry(dumped, bundlePaths, ...)\r\n \r\n-    local getPrefix, splitPath, joinParts\r\n-\r\n-    local tmpBase = os == "Windows" and (env.get("TMP") or uv.cwd()) or\r\n-                                        (env.get("TMPDIR") or \'/tmp\')\r\n-\r\n-    if os == "Windows" then\r\n-      -- Windows aware path utilities\r\n-      function getPrefix(path)\r\n-        return path:match("^%a:\\\\") or\r\n-               path:match("^/") or\r\n-               path:match("^\\\\+")\r\n-      end\r\n-      function splitPath(path)\r\n-        local parts = {}\r\n-        for part in string.gmatch(path, \'([^/\\\\]+)\') do\r\n-          table.insert(parts, part)\r\n-        end\r\n-        return parts\r\n-      end\r\n-      function joinParts(prefix, parts, i, j)\r\n-        if not prefix then\r\n-          return table.concat(parts, \'/\', i, j)\r\n-        elseif prefix ~= \'/\' then\r\n-          return prefix .. table.concat(parts, \'\\\\\', i, j)\r\n-        else\r\n-          return prefix .. table.concat(parts, \'/\', i, j)\r\n-        end\r\n-      end\r\n-    else\r\n-      -- Simple optimized versions for UNIX systems\r\n-      function getPrefix(path)\r\n-        return path:match("^/")\r\n-      end\r\n-      function splitPath(path)\r\n-        local parts = {}\r\n-        for part in string.gmatch(path, \'([^/]+)\') do\r\n-          table.insert(parts, part)\r\n-        end\r\n-        return parts\r\n-      end\r\n-      function joinParts(prefix, parts, i, j)\r\n-        if prefix then\r\n-          return prefix .. table.concat(parts, \'/\', i, j)\r\n-        end\r\n-        return table.concat(parts, \'/\', i, j)\r\n-      end\r\n-    end\r\n-\r\n-    local function pathJoin(...)\r\n-      local inputs = {...}\r\n-      local l = #inputs\r\n-\r\n-      -- Find the last segment that is an absolute path\r\n-      -- Or if all are relative, prefix will be nil\r\n-      local i = l\r\n-      local prefix\r\n-      while true do\r\n-        prefix = getPrefix(inputs[i])\r\n-        if prefix or i <= 1 then break end\r\n-        i = i - 1\r\n-      end\r\n-\r\n-      -- If there was one, remove its prefix from its segment\r\n-      if prefix then\r\n-        inputs[i] = inputs[i]:sub(#prefix)\r\n-      end\r\n-\r\n-      -- Split all the paths segments into one large list\r\n-      local parts = {}\r\n-      while i <= l do\r\n-        local sub = splitPath(inputs[i])\r\n-        for j = 1, #sub do\r\n-          parts[#parts + 1] = sub[j]\r\n-        end\r\n-        i = i + 1\r\n-      end\r\n-\r\n-      -- Evaluate special segments in reverse order.\r\n-      local skip = 0\r\n-      local reversed = {}\r\n-      for idx = #parts, 1, -1 do\r\n-        local part = parts[idx]\r\n-        if part == \'.\' then\r\n-          -- Ignore\r\n-        elseif part == \'..\' then\r\n-          skip = skip + 1\r\n-        elseif skip > 0 then\r\n-          skip = skip - 1\r\n-        else\r\n-          reversed[#reversed + 1] = part\r\n-        end\r\n-      end\r\n-\r\n-      -- Reverse the list again to get the correct order\r\n-      parts = reversed\r\n-      for idx = 1, #parts / 2 do\r\n-        local j = #parts - idx + 1\r\n-        parts[idx], parts[j] = parts[j], parts[idx]\r\n-      end\r\n-\r\n-      local path = joinParts(prefix, parts)\r\n-      return path\r\n-    end\r\n-\r\n-    -- Bundle from folder on disk\r\n-    local function folderBundle(base)\r\n-      local bundle = { base = base }\r\n-\r\n-      function bundle.stat(path)\r\n-        path = pathJoin(base, "./" .. path)\r\n-        local raw, err = uv.fs_stat(path)\r\n-        if not raw then return nil, err end\r\n-        return {\r\n-          type = string.lower(raw.type),\r\n-          size = raw.size,\r\n-          mtime = raw.mtime,\r\n-        }\r\n-      end\r\n-\r\n-      function bundle.readdir(path)\r\n-        path = pathJoin(base, "./" .. path)\r\n-        local req, err = uv.fs_scandir(path)\r\n-        if not req then\r\n-          return nil, err\r\n-        end\r\n-\r\n-        local files = {}\r\n-        repeat\r\n-          local ent = uv.fs_scandir_next(req)\r\n-          if ent then\r\n-            files[#files + 1] = ent.name\r\n-          end\r\n-        until not ent\r\n-        return files\r\n-      end\r\n-\r\n-      function bundle.readfile(path)\r\n-        path = pathJoin(base, "./" .. path)\r\n-        local fd, stat, data, err\r\n-        stat, err = uv.fs_stat(path)\r\n-        if not stat then return nil, err end\r\n-        if stat.type ~= "file" then return end\r\n-        fd, err = uv.fs_open(path, "r", 0644)\r\n-        if not fd then return nil, err end\r\n-        if stat then\r\n-          data, err = uv.fs_read(fd, stat.size, 0)\r\n-        end\r\n-        uv.fs_close(fd)\r\n-        return data, err\r\n-      end\r\n-\r\n-      return bundle\r\n-    end\r\n-\r\n-    -- Insert a prefix into all bundle calls\r\n-    local function chrootBundle(bundle, prefix)\r\n-      local bundleStat = bundle.stat\r\n-      function bundle.stat(path)\r\n-        return bundleStat(prefix .. path)\r\n-      end\r\n-      local bundleReaddir = bundle.readdir\r\n-      function bundle.readdir(path)\r\n-        return bundleReaddir(prefix .. path)\r\n-      end\r\n-      local bundleReadfile = bundle.readfile\r\n-      function bundle.readfile(path)\r\n-        return bundleReadfile(prefix .. path)\r\n-      end\r\n-    end\r\n-\r\n-    -- Use a zip file as a bundle\r\n-    local function zipBundle(base, zip)\r\n-      local bundle = { base = base }\r\n-\r\n-      function bundle.stat(path)\r\n-        path = pathJoin("./" .. path)\r\n-        if path == "" then\r\n-          return {\r\n-            type = "directory",\r\n-            size = 0,\r\n-            mtime = 0\r\n-          }\r\n-        end\r\n-        local err\r\n-        local index = zip:locate_file(path)\r\n-        if not index then\r\n-          index, err = zip:locate_file(path .. "/")\r\n-          if not index then return nil, err end\r\n-        end\r\n-        local raw = zip:stat(index)\r\n-\r\n-        return {\r\n-          type = raw.filename:sub(-1) == "/" and "directory" or "file",\r\n-          size = raw.uncomp_size,\r\n-          mtime = raw.time,\r\n-        }\r\n-      end\r\n-\r\n-      function bundle.readdir(path)\r\n-        path = pathJoin("./" .. path)\r\n-        local index, err\r\n-        if path == "" then\r\n-          index = 0\r\n-        else\r\n-          path = path .. "/"\r\n-          index, err = zip:locate_file(path )\r\n-          if not index then return nil, err end\r\n-          if not zip:is_directory(index) then\r\n-            return nil, path .. " is not a directory"\r\n-          end\r\n-        end\r\n-        local files = {}\r\n-        for i = index + 1, zip:get_num_files() do\r\n-          local filename = zip:get_filename(i)\r\n-          if string.sub(filename, 1, #path) ~= path then break end\r\n-          filename = filename:sub(#path + 1)\r\n-          local n = string.find(filename, "/")\r\n-          if n == #filename then\r\n-            filename = string.sub(filename, 1, #filename - 1)\r\n-            n = nil\r\n-          end\r\n-          if not n then\r\n-            files[#files + 1] = filename\r\n-          end\r\n-        end\r\n-        return files\r\n-      end\r\n-\r\n-      function bundle.readfile(path)\r\n-        path = pathJoin("./" .. path)\r\n-        local index, err = zip:locate_file(path)\r\n-        if not index then return nil, err end\r\n-        return zip:extract(index)\r\n-      end\r\n-\r\n-      -- Support zips with a single folder inserted at top-level\r\n-      local entries = bundle.readdir("")\r\n-      if #entries == 1 and bundle.stat(entries[1]).type == "directory" then\r\n-        chrootBundle(bundle, entries[1] .. \'/\')\r\n-      end\r\n-\r\n-      return bundle\r\n+    -- Convert paths back to table\r\n+    local paths = {}\r\n+    for path in bundlePaths:gmatch("[^;]+") do\r\n+      paths[#paths + 1] = path\r\n     end\r\n \r\n+    -- Load luvi environment\r\n+    local _, mainRequire = require(\'luvibundle\').commonBundle(paths)\r\n \r\n-    -- Given a list of bundles, merge them into a single VFS.  Lower indexed items\r\n-    -- overshadow later items.\r\n-    local function combinedBundle(bundles)\r\n-      local bases = {}\r\n-      for i = 1, #bundles do\r\n-        bases[i] = bundles[i].base\r\n-      end\r\n-      local bundle = { base = table.concat(bases, ";") }\r\n-\r\n-      function bundle.stat(path)\r\n-        local err\r\n-        for i = 1, #bundles do\r\n-          local stat\r\n-          stat, err = bundles[i].stat(path)\r\n-          if stat then return stat end\r\n-        end\r\n-        return nil, err\r\n-      end\r\n-\r\n-      function bundle.readdir(path)\r\n-        local has = {}\r\n-        local files, err\r\n-        for i = 1, #bundles do\r\n-          local list\r\n-          list, err = bundles[i].readdir(path)\r\n-          if list then\r\n-            for j = 1, #list do\r\n-              local name = list[j]\r\n-              if has[name] then\r\n-                print("Warning multiple overlapping versions of " .. name)\r\n-              else\r\n-                has[name] = true\r\n-                if files then\r\n-                  files[#files + 1] = name\r\n-                else\r\n-                  files = { name }\r\n-                end\r\n-              end\r\n-            end\r\n-          end\r\n-        end\r\n-        if files then\r\n-          return files\r\n-        else\r\n-          return nil, err\r\n-        end\r\n-      end\r\n-\r\n-      function bundle.readfile(path)\r\n-        local err\r\n-        for i = 1, #bundles do\r\n-          local data\r\n-          data, err = bundles[i].readfile(path)\r\n-          if data then return data end\r\n-        end\r\n-        return nil, err\r\n-      end\r\n-\r\n-      return bundle\r\n-    end\r\n-\r\n-    local function makeBundle(bundlePaths)\r\n-      local parts = {}\r\n-      for n = 1, #bundlePaths do\r\n-        local path = pathJoin(uv.cwd(), bundlePaths[n])\r\n-        bundlePaths[n] = path\r\n-        local bundle\r\n-        local zip = miniz.new_reader(path)\r\n-        if zip then\r\n-          bundle = zipBundle(path, zip)\r\n-        else\r\n-          local stat = uv.fs_stat(path)\r\n-          if not stat or stat.type ~= "directory" then\r\n-            error("ERROR: " .. path .. " is not a zip file or a folder")\r\n-          end\r\n-          bundle = folderBundle(path)\r\n-        end\r\n-        parts[n] = bundle\r\n-      end\r\n-      if #parts == 1 then\r\n-        return parts[1]\r\n-      end\r\n-      return combinedBundle(parts)\r\n-    end\r\n-\r\n-    local function commonBundle(bundle, args, bundlePaths, mainPath)\r\n-\r\n-      luvi.makeBundle = makeBundle\r\n-      luvi.bundle = bundle\r\n-\r\n-      mainPath = mainPath or "main.lua"\r\n-\r\n-      bundle.paths = bundlePaths\r\n-      bundle.mainPath = mainPath\r\n+    -- Run function with require injected\r\n+    local fn = loadstring(dumped)\r\n+    getfenv(fn).require = mainRequire\r\n+    fn(...)\r\n \r\n-      luvi.path = {\r\n-        join = pathJoin,\r\n-        getPrefix = getPrefix,\r\n-        splitPath = splitPath,\r\n-        joinparts = joinParts,\r\n-      }\r\n-\r\n-      function bundle.action(path, action, ...)\r\n-        -- If it\'s a real path, run it directly.\r\n-        if uv.fs_access(path, "r") then return action(path) end\r\n-        -- Otherwise, copy to a temporary folder and run from there\r\n-        local data, err = bundle.readfile(path)\r\n-        if not data then return nil, err end\r\n-        local dir = assert(uv.fs_mkdtemp(pathJoin(tmpBase, "lib-XXXXXX")))\r\n-        path = pathJoin(dir, path:match("[^/\\\\]+$"))\r\n-        local fd = uv.fs_open(path, "w", 384) -- 0600\r\n-        uv.fs_write(fd, data, 0)\r\n-        uv.fs_close(fd)\r\n-        local success, ret = pcall(action, path, ...)\r\n-        uv.fs_unlink(path)\r\n-        uv.fs_rmdir(dir)\r\n-        assert(success, ret)\r\n-        return ret\r\n-      end\r\n-\r\n-      function bundle.register(name, path)\r\n-        if not path then path = name + ".lua" end\r\n-        package.preload[name] = function (...)\r\n-          local lua = assert(bundle.readfile(path))\r\n-          return assert(loadstring(lua, "bundle:" .. path))(...)\r\n-        end\r\n-      end\r\n-\r\n-      _G.args = args\r\n-\r\n-      -- Auto-register the require system if present\r\n-      local mainRequire\r\n-      local stat = bundle.stat("deps/require.lua")\r\n-\r\n-      if stat and stat.type == "file" then\r\n-        bundle.register(\'require\', "deps/require.lua")\r\n-        _G.require = require(\'require\')("bundle:main.lua")\r\n-      end\r\n-\r\n-      -- Auto-setup global p and libuv version of print\r\n-      if require and bundle.stat("deps/pretty-print") or bundle.stat("deps/pretty-print.lua") then\r\n-        _G.p = require(\'pretty-print\').prettyPrint\r\n-      end\r\n-    end\r\n-\r\n-    -- First check for a bundled zip file appended to the executable\r\n-    local path = uv.exepath()\r\n-    local zip = miniz.new_reader(path)\r\n-    if zip then\r\n-      commonBundle(zipBundle(path, zip), {}, {path})\r\n-    else\r\n-      -- lanched from luvit app dir\r\n-      local bundles = { base or \'.\' }\r\n-      local bundle = assert(makeBundle(bundles))\r\n-      -- Run the luvi app with the extra args\r\n-      commonBundle(bundle, {}, bundles)\r\n-    end\r\n-\r\n-    loadstring(dumped)(...)\r\n-\r\n-    uv.run()\r\n+    -- Start new event loop for thread.\r\n+    require(\'uv\').run()\r\n   end\r\n-\r\n-  return uv.new_thread(thread_entry,dumped,base, ...)\r\n+  return uv.new_thread(thread_entry, dumped, table.concat(bundlePaths, ";"), ...)\r\n end\r\n \r\n exports.join = function(thread)\r\n', 'commit_subject': 'Use new luvi API instead of copying lua logic in thread', 'repo_name': 'luvit/luvit', 'committer': {'name': 'Tim Caswell', 'email': '5ee0edb9e2229c0838f1959779f1949031de0123@creationix.com', 'time_sec': '1440104978', 'tz_offset': '-300', 'date': {'seconds': '1440104978'}}, 'commit_tree': '15f98ba05643d68bafa8f66ea31d851c5be14c92', 'commit_message': 'Use new luvi API instead of copying lua logic in thread\n', 'language_name': 'Go', 'license': 'apache-2.0', 'hunks': '@@ -18,7 +18,7 @@ limitations under the License.\n \r\n --- luvit thread management\r\n local uv = require(\'uv\')\r\n-local base = require(\'luvi\').bundle.base\r\n+local bundlePaths = require(\'luvi\').bundle.paths\r\n \r\n exports.name = "luvit/thread"\r\n exports.version = "0.1.0"\r\n@@ -30,423 +30,26 @@ exports.tags = {"luvit", "thread"}\n exports.start = function(thread_func, ...)\r\n   local dumped = string.dump(thread_func)\r\n \r\n-  function thread_entry(dumped, base,...)\r\n-    --- set thread luvit enviroment, mainly copy from luvi/src/init.lua\r\n-    local os = require(\'ffi\').os\r\n-    local env = require(\'env\')\r\n-    local uv = require(\'uv\')\r\n-    local luvi = require(\'luvi\')\r\n-    local miniz = require(\'miniz\')\r\n+  local function thread_entry(dumped, bundlePaths, ...)\r\n \r\n-    local getPrefix, splitPath, joinParts\r\n-\r\n-    local tmpBase = os == "Windows" and (env.get("TMP") or uv.cwd()) or\r\n-                                        (env.get("TMPDIR") or \'/tmp\')\r\n-\r\n-    if os == "Windows" then\r\n-      -- Windows aware path utilities\r\n-      function getPrefix(path)\r\n-        return path:match("^%a:\\\\") or\r\n-               path:match("^/") or\r\n-               path:match("^\\\\+")\r\n-      end\r\n-      function splitPath(path)\r\n-        local parts = {}\r\n-        for part in string.gmatch(path, \'([^/\\\\]+)\') do\r\n-          table.insert(parts, part)\r\n-        end\r\n-        return parts\r\n-      end\r\n-      function joinParts(prefix, parts, i, j)\r\n-        if not prefix then\r\n-          return table.concat(parts, \'/\', i, j)\r\n-        elseif prefix ~= \'/\' then\r\n-          return prefix .. table.concat(parts, \'\\\\\', i, j)\r\n-        else\r\n-          return prefix .. table.concat(parts, \'/\', i, j)\r\n-        end\r\n-      end\r\n-    else\r\n-      -- Simple optimized versions for UNIX systems\r\n-      function getPrefix(path)\r\n-        return path:match("^/")\r\n-      end\r\n-      function splitPath(path)\r\n-        local parts = {}\r\n-        for part in string.gmatch(path, \'([^/]+)\') do\r\n-          table.insert(parts, part)\r\n-        end\r\n-        return parts\r\n-      end\r\n-      function joinParts(prefix, parts, i, j)\r\n-        if prefix then\r\n-          return prefix .. table.concat(parts, \'/\', i, j)\r\n-        end\r\n-        return table.concat(parts, \'/\', i, j)\r\n-      end\r\n-    end\r\n-\r\n-    local function pathJoin(...)\r\n-      local inputs = {...}\r\n-      local l = #inputs\r\n-\r\n-      -- Find the last segment that is an absolute path\r\n-      -- Or if all are relative, prefix will be nil\r\n-      local i = l\r\n-      local prefix\r\n-      while true do\r\n-        prefix = getPrefix(inputs[i])\r\n-        if prefix or i <= 1 then break end\r\n-        i = i - 1\r\n-      end\r\n-\r\n-      -- If there was one, remove its prefix from its segment\r\n-      if prefix then\r\n-        inputs[i] = inputs[i]:sub(#prefix)\r\n-      end\r\n-\r\n-      -- Split all the paths segments into one large list\r\n-      local parts = {}\r\n-      while i <= l do\r\n-        local sub = splitPath(inputs[i])\r\n-        for j = 1, #sub do\r\n-          parts[#parts + 1] = sub[j]\r\n-        end\r\n-        i = i + 1\r\n-      end\r\n-\r\n-      -- Evaluate special segments in reverse order.\r\n-      local skip = 0\r\n-      local reversed = {}\r\n-      for idx = #parts, 1, -1 do\r\n-        local part = parts[idx]\r\n-        if part == \'.\' then\r\n-          -- Ignore\r\n-        elseif part == \'..\' then\r\n-          skip = skip + 1\r\n-        elseif skip > 0 then\r\n-          skip = skip - 1\r\n-        else\r\n-          reversed[#reversed + 1] = part\r\n-        end\r\n-      end\r\n-\r\n-      -- Reverse the list again to get the correct order\r\n-      parts = reversed\r\n-      for idx = 1, #parts / 2 do\r\n-        local j = #parts - idx + 1\r\n-        parts[idx], parts[j] = parts[j], parts[idx]\r\n-      end\r\n-\r\n-      local path = joinParts(prefix, parts)\r\n-      return path\r\n-    end\r\n-\r\n-    -- Bundle from folder on disk\r\n-    local function folderBundle(base)\r\n-      local bundle = { base = base }\r\n-\r\n-      function bundle.stat(path)\r\n-        path = pathJoin(base, "./" .. path)\r\n-        local raw, err = uv.fs_stat(path)\r\n-        if not raw then return nil, err end\r\n-        return {\r\n-          type = string.lower(raw.type),\r\n-          size = raw.size,\r\n-          mtime = raw.mtime,\r\n-        }\r\n-      end\r\n-\r\n-      function bundle.readdir(path)\r\n-        path = pathJoin(base, "./" .. path)\r\n-        local req, err = uv.fs_scandir(path)\r\n-        if not req then\r\n-          return nil, err\r\n-        end\r\n-\r\n-        local files = {}\r\n-        repeat\r\n-          local ent = uv.fs_scandir_next(req)\r\n-          if ent then\r\n-            files[#files + 1] = ent.name\r\n-          end\r\n-        until not ent\r\n-        return files\r\n-      end\r\n-\r\n-      function bundle.readfile(path)\r\n-        path = pathJoin(base, "./" .. path)\r\n-        local fd, stat, data, err\r\n-        stat, err = uv.fs_stat(path)\r\n-        if not stat then return nil, err end\r\n-        if stat.type ~= "file" then return end\r\n-        fd, err = uv.fs_open(path, "r", 0644)\r\n-        if not fd then return nil, err end\r\n-        if stat then\r\n-          data, err = uv.fs_read(fd, stat.size, 0)\r\n-        end\r\n-        uv.fs_close(fd)\r\n-        return data, err\r\n-      end\r\n-\r\n-      return bundle\r\n-    end\r\n-\r\n-    -- Insert a prefix into all bundle calls\r\n-    local function chrootBundle(bundle, prefix)\r\n-      local bundleStat = bundle.stat\r\n-      function bundle.stat(path)\r\n-        return bundleStat(prefix .. path)\r\n-      end\r\n-      local bundleReaddir = bundle.readdir\r\n-      function bundle.readdir(path)\r\n-        return bundleReaddir(prefix .. path)\r\n-      end\r\n-      local bundleReadfile = bundle.readfile\r\n-      function bundle.readfile(path)\r\n-        return bundleReadfile(prefix .. path)\r\n-      end\r\n-    end\r\n-\r\n-    -- Use a zip file as a bundle\r\n-    local function zipBundle(base, zip)\r\n-      local bundle = { base = base }\r\n-\r\n-      function bundle.stat(path)\r\n-        path = pathJoin("./" .. path)\r\n-        if path == "" then\r\n-          return {\r\n-            type = "directory",\r\n-            size = 0,\r\n-            mtime = 0\r\n-          }\r\n-        end\r\n-        local err\r\n-        local index = zip:locate_file(path)\r\n-        if not index then\r\n-          index, err = zip:locate_file(path .. "/")\r\n-          if not index then return nil, err end\r\n-        end\r\n-        local raw = zip:stat(index)\r\n-\r\n-        return {\r\n-          type = raw.filename:sub(-1) == "/" and "directory" or "file",\r\n-          size = raw.uncomp_size,\r\n-          mtime = raw.time,\r\n-        }\r\n-      end\r\n-\r\n-      function bundle.readdir(path)\r\n-        path = pathJoin("./" .. path)\r\n-        local index, err\r\n-        if path == "" then\r\n-          index = 0\r\n-        else\r\n-          path = path .. "/"\r\n-          index, err = zip:locate_file(path )\r\n-          if not index then return nil, err end\r\n-          if not zip:is_directory(index) then\r\n-            return nil, path .. " is not a directory"\r\n-          end\r\n-        end\r\n-        local files = {}\r\n-        for i = index + 1, zip:get_num_files() do\r\n-          local filename = zip:get_filename(i)\r\n-          if string.sub(filename, 1, #path) ~= path then break end\r\n-          filename = filename:sub(#path + 1)\r\n-          local n = string.find(filename, "/")\r\n-          if n == #filename then\r\n-            filename = string.sub(filename, 1, #filename - 1)\r\n-            n = nil\r\n-          end\r\n-          if not n then\r\n-            files[#files + 1] = filename\r\n-          end\r\n-        end\r\n-        return files\r\n-      end\r\n-\r\n-      function bundle.readfile(path)\r\n-        path = pathJoin("./" .. path)\r\n-        local index, err = zip:locate_file(path)\r\n-        if not index then return nil, err end\r\n-        return zip:extract(index)\r\n-      end\r\n-\r\n-      -- Support zips with a single folder inserted at top-level\r\n-      local entries = bundle.readdir("")\r\n-      if #entries == 1 and bundle.stat(entries[1]).type == "directory" then\r\n-        chrootBundle(bundle, entries[1] .. \'/\')\r\n-      end\r\n-\r\n-      return bundle\r\n+    -- Convert paths back to table\r\n+    local paths = {}\r\n+    for path in bundlePaths:gmatch("[^;]+") do\r\n+      paths[#paths + 1] = path\r\n     end\r\n \r\n+    -- Load luvi environment\r\n+    local _, mainRequire = require(\'luvibundle\').commonBundle(paths)\r\n \r\n-    -- Given a list of bundles, merge them into a single VFS.  Lower indexed items\r\n-    -- overshadow later items.\r\n-    local function combinedBundle(bundles)\r\n-      local bases = {}\r\n-      for i = 1, #bundles do\r\n-        bases[i] = bundles[i].base\r\n-      end\r\n-      local bundle = { base = table.concat(bases, ";") }\r\n-\r\n-      function bundle.stat(path)\r\n-        local err\r\n-        for i = 1, #bundles do\r\n-          local stat\r\n-          stat, err = bundles[i].stat(path)\r\n-          if stat then return stat end\r\n-        end\r\n-        return nil, err\r\n-      end\r\n-\r\n-      function bundle.readdir(path)\r\n-        local has = {}\r\n-        local files, err\r\n-        for i = 1, #bundles do\r\n-          local list\r\n-          list, err = bundles[i].readdir(path)\r\n-          if list then\r\n-            for j = 1, #list do\r\n-              local name = list[j]\r\n-              if has[name] then\r\n-                print("Warning multiple overlapping versions of " .. name)\r\n-              else\r\n-                has[name] = true\r\n-                if files then\r\n-                  files[#files + 1] = name\r\n-                else\r\n-                  files = { name }\r\n-                end\r\n-              end\r\n-            end\r\n-          end\r\n-        end\r\n-        if files then\r\n-          return files\r\n-        else\r\n-          return nil, err\r\n-        end\r\n-      end\r\n-\r\n-      function bundle.readfile(path)\r\n-        local err\r\n-        for i = 1, #bundles do\r\n-          local data\r\n-          data, err = bundles[i].readfile(path)\r\n-          if data then return data end\r\n-        end\r\n-        return nil, err\r\n-      end\r\n-\r\n-      return bundle\r\n-    end\r\n-\r\n-    local function makeBundle(bundlePaths)\r\n-      local parts = {}\r\n-      for n = 1, #bundlePaths do\r\n-        local path = pathJoin(uv.cwd(), bundlePaths[n])\r\n-        bundlePaths[n] = path\r\n-        local bundle\r\n-        local zip = miniz.new_reader(path)\r\n-        if zip then\r\n-          bundle = zipBundle(path, zip)\r\n-        else\r\n-          local stat = uv.fs_stat(path)\r\n-          if not stat or stat.type ~= "directory" then\r\n-            error("ERROR: " .. path .. " is not a zip file or a folder")\r\n-          end\r\n-          bundle = folderBundle(path)\r\n-        end\r\n-        parts[n] = bundle\r\n-      end\r\n-      if #parts == 1 then\r\n-        return parts[1]\r\n-      end\r\n-      return combinedBundle(parts)\r\n-    end\r\n-\r\n-    local function commonBundle(bundle, args, bundlePaths, mainPath)\r\n-\r\n-      luvi.makeBundle = makeBundle\r\n-      luvi.bundle = bundle\r\n-\r\n-      mainPath = mainPath or "main.lua"\r\n-\r\n-      bundle.paths = bundlePaths\r\n-      bundle.mainPath = mainPath\r\n+    -- Run function with require injected\r\n+    local fn = loadstring(dumped)\r\n+    getfenv(fn).require = mainRequire\r\n+    fn(...)\r\n \r\n-      luvi.path = {\r\n-        join = pathJoin,\r\n-        getPrefix = getPrefix,\r\n-        splitPath = splitPath,\r\n-        joinparts = joinParts,\r\n-      }\r\n-\r\n-      function bundle.action(path, action, ...)\r\n-        -- If it\'s a real path, run it directly.\r\n-        if uv.fs_access(path, "r") then return action(path) end\r\n-        -- Otherwise, copy to a temporary folder and run from there\r\n-        local data, err = bundle.readfile(path)\r\n-        if not data then return nil, err end\r\n-        local dir = assert(uv.fs_mkdtemp(pathJoin(tmpBase, "lib-XXXXXX")))\r\n-        path = pathJoin(dir, path:match("[^/\\\\]+$"))\r\n-        local fd = uv.fs_open(path, "w", 384) -- 0600\r\n-        uv.fs_write(fd, data, 0)\r\n-        uv.fs_close(fd)\r\n-        local success, ret = pcall(action, path, ...)\r\n-        uv.fs_unlink(path)\r\n-        uv.fs_rmdir(dir)\r\n-        assert(success, ret)\r\n-        return ret\r\n-      end\r\n-\r\n-      function bundle.register(name, path)\r\n-        if not path then path = name + ".lua" end\r\n-        package.preload[name] = function (...)\r\n-          local lua = assert(bundle.readfile(path))\r\n-          return assert(loadstring(lua, "bundle:" .. path))(...)\r\n-        end\r\n-      end\r\n-\r\n-      _G.args = args\r\n-\r\n-      -- Auto-register the require system if present\r\n-      local mainRequire\r\n-      local stat = bundle.stat("deps/require.lua")\r\n-\r\n-      if stat and stat.type == "file" then\r\n-        bundle.register(\'require\', "deps/require.lua")\r\n-        _G.require = require(\'require\')("bundle:main.lua")\r\n-      end\r\n-\r\n-      -- Auto-setup global p and libuv version of print\r\n-      if require and bundle.stat("deps/pretty-print") or bundle.stat("deps/pretty-print.lua") then\r\n-        _G.p = require(\'pretty-print\').prettyPrint\r\n-      end\r\n-    end\r\n-\r\n-    -- First check for a bundled zip file appended to the executable\r\n-    local path = uv.exepath()\r\n-    local zip = miniz.new_reader(path)\r\n-    if zip then\r\n-      commonBundle(zipBundle(path, zip), {}, {path})\r\n-    else\r\n-      -- lanched from luvit app dir\r\n-      local bundles = { base or \'.\' }\r\n-      local bundle = assert(makeBundle(bundles))\r\n-      -- Run the luvi app with the extra args\r\n-      commonBundle(bundle, {}, bundles)\r\n-    end\r\n-\r\n-    loadstring(dumped)(...)\r\n-\r\n-    uv.run()\r\n+    -- Start new event loop for thread.\r\n+    require(\'uv\').run()\r\n   end\r\n-\r\n-  return uv.new_thread(thread_entry,dumped,base, ...)\r\n+  return uv.new_thread(thread_entry, dumped, table.concat(bundlePaths, ";"), ...)\r\n end\r\n \r\n exports.join = function(thread)\r\n', 'addition_count': 15, 'deletion_count': 412, 'src_file': 'a/deps/thread.lua', 'tgt_file': 'b/deps/thread.lua', 'file_extension': '.lua', 'before_file': '--[[\n\nCopyright 2014 The Luvit Authors. All Rights Reserved.\n\nLicensed under the Apache License, Version 2.0 (the "License");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an "AS-IS" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n--]]\n\r\n--- luvit thread management\r\nlocal uv = require(\'uv\')\r\nlocal base = require(\'luvi\').bundle.base\r\n\r\nexports.name = "luvit/thread"\r\nexports.version = "0.1.0"\r\n  description = "thread module for luvit"\n  tags = {"luvit", "thread","threadpool","work"}\n  dependencies = {\n    "luvit/core@1.0.5",\n  }\nexports.start = function(thread_func, ...)\r\n  local dumped = string.dump(thread_func)\r\n\r\n  function thread_entry(dumped, base,...)\r\n    --- set thread luvit enviroment, mainly copy from luvi/src/init.lua\r\n    local os = require(\'ffi\').os\r\n    local env = require(\'env\')\r\n    local uv = require(\'uv\')\r\n    local luvi = require(\'luvi\')\r\n    local miniz = require(\'miniz\')\r\n\r\n    local getPrefix, splitPath, joinParts\r\n\r\n    local tmpBase = os == "Windows" and (env.get("TMP") or uv.cwd()) or\r\n                                        (env.get("TMPDIR") or \'/tmp\')\r\n\r\n    if os == "Windows" then\r\n      -- Windows aware path utilities\r\n      function getPrefix(path)\r\n        return path:match("^%a:\\\\") or\r\n               path:match("^/") or\r\n               path:match("^\\\\+")\r\n      end\r\n      function splitPath(path)\r\n        local parts = {}\r\n        for part in string.gmatch(path, \'([^/\\\\]+)\') do\r\n          table.insert(parts, part)\r\n        end\r\n        return parts\r\n      end\r\n      function joinParts(prefix, parts, i, j)\r\n        if not prefix then\r\n          return table.concat(parts, \'/\', i, j)\r\n        elseif prefix ~= \'/\' then\r\n          return prefix .. table.concat(parts, \'\\\\\', i, j)\r\n        else\r\n          return prefix .. table.concat(parts, \'/\', i, j)\r\n        end\r\n      end\r\n    else\r\n      -- Simple optimized versions for UNIX systems\r\n      function getPrefix(path)\r\n        return path:match("^/")\r\n      end\r\n      function splitPath(path)\r\n        local parts = {}\r\n        for part in string.gmatch(path, \'([^/]+)\') do\r\n          table.insert(parts, part)\r\n        end\r\n        return parts\r\n      end\r\n      function joinParts(prefix, parts, i, j)\r\n        if prefix then\r\n          return prefix .. table.concat(parts, \'/\', i, j)\r\n        end\r\n        return table.concat(parts, \'/\', i, j)\r\n      end\r\n    end\r\n\r\n    local function pathJoin(...)\r\n      local inputs = {...}\r\n      local l = #inputs\r\n\r\n      -- Find the last segment that is an absolute path\r\n      -- Or if all are relative, prefix will be nil\r\n      local i = l\r\n      local prefix\r\n      while true do\r\n        prefix = getPrefix(inputs[i])\r\n        if prefix or i <= 1 then break end\r\n        i = i - 1\r\n      end\r\n\r\n      -- If there was one, remove its prefix from its segment\r\n      if prefix then\r\n        inputs[i] = inputs[i]:sub(#prefix)\r\n      end\r\n\r\n      -- Split all the paths segments into one large list\r\n      local parts = {}\r\n      while i <= l do\r\n        local sub = splitPath(inputs[i])\r\n        for j = 1, #sub do\r\n          parts[#parts + 1] = sub[j]\r\n        end\r\n        i = i + 1\r\n      end\r\n\r\n      -- Evaluate special segments in reverse order.\r\n      local skip = 0\r\n      local reversed = {}\r\n      for idx = #parts, 1, -1 do\r\n        local part = parts[idx]\r\n        if part == \'.\' then\r\n          -- Ignore\r\n        elseif part == \'..\' then\r\n          skip = skip + 1\r\n        elseif skip > 0 then\r\n          skip = skip - 1\r\n        else\r\n          reversed[#reversed + 1] = part\r\n        end\r\n      end\r\n\r\n      -- Reverse the list again to get the correct order\r\n      parts = reversed\r\n      for idx = 1, #parts / 2 do\r\n        local j = #parts - idx + 1\r\n        parts[idx], parts[j] = parts[j], parts[idx]\r\n      end\r\n\r\n      local path = joinParts(prefix, parts)\r\n      return path\r\n    end\r\n\r\n    -- Bundle from folder on disk\r\n    local function folderBundle(base)\r\n      local bundle = { base = base }\r\n\r\n      function bundle.stat(path)\r\n        path = pathJoin(base, "./" .. path)\r\n        local raw, err = uv.fs_stat(path)\r\n        if not raw then return nil, err end\r\n        return {\r\n          type = string.lower(raw.type),\r\n          size = raw.size,\r\n          mtime = raw.mtime,\r\n        }\r\n      end\r\n\r\n      function bundle.readdir(path)\r\n        path = pathJoin(base, "./" .. path)\r\n        local req, err = uv.fs_scandir(path)\r\n        if not req then\r\n          return nil, err\r\n        end\r\n\r\n        local files = {}\r\n        repeat\r\n          local ent = uv.fs_scandir_next(req)\r\n          if ent then\r\n            files[#files + 1] = ent.name\r\n          end\r\n        until not ent\r\n        return files\r\n      end\r\n\r\n      function bundle.readfile(path)\r\n        path = pathJoin(base, "./" .. path)\r\n        local fd, stat, data, err\r\n        stat, err = uv.fs_stat(path)\r\n        if not stat then return nil, err end\r\n        if stat.type ~= "file" then return end\r\n        fd, err = uv.fs_open(path, "r", 0644)\r\n        if not fd then return nil, err end\r\n        if stat then\r\n          data, err = uv.fs_read(fd, stat.size, 0)\r\n        end\r\n        uv.fs_close(fd)\r\n        return data, err\r\n      end\r\n\r\n      return bundle\r\n    end\r\n\r\n    -- Insert a prefix into all bundle calls\r\n    local function chrootBundle(bundle, prefix)\r\n      local bundleStat = bundle.stat\r\n      function bundle.stat(path)\r\n        return bundleStat(prefix .. path)\r\n      end\r\n      local bundleReaddir = bundle.readdir\r\n      function bundle.readdir(path)\r\n        return bundleReaddir(prefix .. path)\r\n      end\r\n      local bundleReadfile = bundle.readfile\r\n      function bundle.readfile(path)\r\n        return bundleReadfile(prefix .. path)\r\n      end\r\n    end\r\n\r\n    -- Use a zip file as a bundle\r\n    local function zipBundle(base, zip)\r\n      local bundle = { base = base }\r\n\r\n      function bundle.stat(path)\r\n        path = pathJoin("./" .. path)\r\n        if path == "" then\r\n          return {\r\n            type = "directory",\r\n            size = 0,\r\n            mtime = 0\r\n          }\r\n        end\r\n        local err\r\n        local index = zip:locate_file(path)\r\n        if not index then\r\n          index, err = zip:locate_file(path .. "/")\r\n          if not index then return nil, err end\r\n        end\r\n        local raw = zip:stat(index)\r\n\r\n        return {\r\n          type = raw.filename:sub(-1) == "/" and "directory" or "file",\r\n          size = raw.uncomp_size,\r\n          mtime = raw.time,\r\n        }\r\n      end\r\n\r\n      function bundle.readdir(path)\r\n        path = pathJoin("./" .. path)\r\n        local index, err\r\n        if path == "" then\r\n          index = 0\r\n        else\r\n          path = path .. "/"\r\n          index, err = zip:locate_file(path )\r\n          if not index then return nil, err end\r\n          if not zip:is_directory(index) then\r\n            return nil, path .. " is not a directory"\r\n          end\r\n        end\r\n        local files = {}\r\n        for i = index + 1, zip:get_num_files() do\r\n          local filename = zip:get_filename(i)\r\n          if string.sub(filename, 1, #path) ~= path then break end\r\n          filename = filename:sub(#path + 1)\r\n          local n = string.find(filename, "/")\r\n          if n == #filename then\r\n            filename = string.sub(filename, 1, #filename - 1)\r\n            n = nil\r\n          end\r\n          if not n then\r\n            files[#files + 1] = filename\r\n          end\r\n        end\r\n        return files\r\n      end\r\n\r\n      function bundle.readfile(path)\r\n        path = pathJoin("./" .. path)\r\n        local index, err = zip:locate_file(path)\r\n        if not index then return nil, err end\r\n        return zip:extract(index)\r\n      end\r\n\r\n      -- Support zips with a single folder inserted at top-level\r\n      local entries = bundle.readdir("")\r\n      if #entries == 1 and bundle.stat(entries[1]).type == "directory" then\r\n        chrootBundle(bundle, entries[1] .. \'/\')\r\n      end\r\n\r\n      return bundle\r\n    end\r\n\r\n\r\n    -- Given a list of bundles, merge them into a single VFS.  Lower indexed items\r\n    -- overshadow later items.\r\n    local function combinedBundle(bundles)\r\n      local bases = {}\r\n      for i = 1, #bundles do\r\n        bases[i] = bundles[i].base\r\n      end\r\n      local bundle = { base = table.concat(bases, ";") }\r\n\r\n      function bundle.stat(path)\r\n        local err\r\n        for i = 1, #bundles do\r\n          local stat\r\n          stat, err = bundles[i].stat(path)\r\n          if stat then return stat end\r\n        end\r\n        return nil, err\r\n      end\r\n\r\n      function bundle.readdir(path)\r\n        local has = {}\r\n        local files, err\r\n        for i = 1, #bundles do\r\n          local list\r\n          list, err = bundles[i].readdir(path)\r\n          if list then\r\n            for j = 1, #list do\r\n              local name = list[j]\r\n              if has[name] then\r\n                print("Warning multiple overlapping versions of " .. name)\r\n              else\r\n                has[name] = true\r\n                if files then\r\n                  files[#files + 1] = name\r\n                else\r\n                  files = { name }\r\n                end\r\n              end\r\n            end\r\n          end\r\n        end\r\n        if files then\r\n          return files\r\n        else\r\n          return nil, err\r\n        end\r\n      end\r\n\r\n      function bundle.readfile(path)\r\n        local err\r\n        for i = 1, #bundles do\r\n          local data\r\n          data, err = bundles[i].readfile(path)\r\n          if data then return data end\r\n        end\r\n        return nil, err\r\n      end\r\n\r\n      return bundle\r\n    end\r\n\r\n    local function makeBundle(bundlePaths)\r\n      local parts = {}\r\n      for n = 1, #bundlePaths do\r\n        local path = pathJoin(uv.cwd(), bundlePaths[n])\r\n        bundlePaths[n] = path\r\n        local bundle\r\n        local zip = miniz.new_reader(path)\r\n        if zip then\r\n          bundle = zipBundle(path, zip)\r\n        else\r\n          local stat = uv.fs_stat(path)\r\n          if not stat or stat.type ~= "directory" then\r\n            error("ERROR: " .. path .. " is not a zip file or a folder")\r\n          end\r\n          bundle = folderBundle(path)\r\n        end\r\n        parts[n] = bundle\r\n      end\r\n      if #parts == 1 then\r\n        return parts[1]\r\n      end\r\n      return combinedBundle(parts)\r\n    end\r\n\r\n    local function commonBundle(bundle, args, bundlePaths, mainPath)\r\n\r\n      luvi.makeBundle = makeBundle\r\n      luvi.bundle = bundle\r\n\r\n      mainPath = mainPath or "main.lua"\r\n\r\n      bundle.paths = bundlePaths\r\n      bundle.mainPath = mainPath\r\n\r\n      luvi.path = {\r\n        join = pathJoin,\r\n        getPrefix = getPrefix,\r\n        splitPath = splitPath,\r\n        joinparts = joinParts,\r\n      }\r\n\r\n      function bundle.action(path, action, ...)\r\n        -- If it\'s a real path, run it directly.\r\n        if uv.fs_access(path, "r") then return action(path) end\r\n        -- Otherwise, copy to a temporary folder and run from there\r\n        local data, err = bundle.readfile(path)\r\n        if not data then return nil, err end\r\n        local dir = assert(uv.fs_mkdtemp(pathJoin(tmpBase, "lib-XXXXXX")))\r\n        path = pathJoin(dir, path:match("[^/\\\\]+$"))\r\n        local fd = uv.fs_open(path, "w", 384) -- 0600\r\n        uv.fs_write(fd, data, 0)\r\n        uv.fs_close(fd)\r\n        local success, ret = pcall(action, path, ...)\r\n        uv.fs_unlink(path)\r\n        uv.fs_rmdir(dir)\r\n        assert(success, ret)\r\n        return ret\r\n      end\r\n\r\n      function bundle.register(name, path)\r\n        if not path then path = name + ".lua" end\r\n        package.preload[name] = function (...)\r\n          local lua = assert(bundle.readfile(path))\r\n          return assert(loadstring(lua, "bundle:" .. path))(...)\r\n        end\r\n      end\r\n\r\n      _G.args = args\r\n\r\n      -- Auto-register the require system if present\r\n      local mainRequire\r\n      local stat = bundle.stat("deps/require.lua")\r\n\r\n      if stat and stat.type == "file" then\r\n        bundle.register(\'require\', "deps/require.lua")\r\n        _G.require = require(\'require\')("bundle:main.lua")\r\n      end\r\n\r\n      -- Auto-setup global p and libuv version of print\r\n      if require and bundle.stat("deps/pretty-print") or bundle.stat("deps/pretty-print.lua") then\r\n        _G.p = require(\'pretty-print\').prettyPrint\r\n      end\r\n    end\r\n\r\n    -- First check for a bundled zip file appended to the executable\r\n    local path = uv.exepath()\r\n    local zip = miniz.new_reader(path)\r\n    if zip then\r\n      commonBundle(zipBundle(path, zip), {}, {path})\r\n    else\r\n      -- lanched from luvit app dir\r\n      local bundles = { base or \'.\' }\r\n      local bundle = assert(makeBundle(bundles))\r\n      -- Run the luvi app with the extra args\r\n      commonBundle(bundle, {}, bundles)\r\n    end\r\n\r\n    loadstring(dumped)(...)\r\n\r\n    uv.run()\r\n  end\r\n\r\n  return uv.new_thread(thread_entry,dumped,base, ...)\r\nend\r\n\r\nexports.join = function(thread)\r\n    getfenv(fn).require = mainRequire\n    fn(...)\n\n    -- Start new event loop for thread.\n    require(\'uv\').run()\n  end\n  return uv.new_thread(thread_entry, dumped, table.concat(bundlePaths, ";"), ...)\nend\n\nlocal function join(thread)\n    return uv.thread_join(thread)\nend\n\nlocal function equals(thread1,thread2)\n    return uv.thread_equal(thread1,thread2)\nend\n\nlocal function self()\n    return uv.thread_self()\nend\n\n--- luvit threadpool\nlocal Worker = Object:extend()\n\nfunction Worker:queue(...)\n    uv.queue_work(self.handler, self.dumped, self.bundlePaths, ...)\nend\n\nlocal function work(thread_func, notify_entry)\n  local worker = Worker:new()\n  worker.dumped = type(thread_func)==\'function\'\n    and string.dump(thread_func) or thread_func\n  worker.bundlePaths = table.concat(bundlePaths, ";")\n\n  local function thread_entry(dumped, bundlePaths, ...)\n    if not _G._uv_works then\n      _G._uv_works = {}\n    end\n\n    --try to find cached function entry\n    local fn\n    if not _G._uv_works[dumped] then\n      fn = loadstring(dumped)\n\n      -- Convert paths back to table\n      local paths = {}\n      for path in bundlePaths:gmatch("[^;]+") do\n        paths[#paths + 1] = path\n      end\n\n      -- Load luvi environment\n      local _, mainRequire = require(\'luvibundle\').commonBundle(paths)\n\n      -- Inject the global process table\n      _G.process = _G.process or mainRequire(\'process\').globalProcess()\n\n      -- require injected\n      getfenv(fn).require = mainRequire\n\n      -- cache it\n      _G._uv_works[dumped] = fn\n    else\n      fn = _G._uv_works[dumped]\n    end\n    -- Run function\n\n    return fn(...)\n  end\n\n  worker.handler = uv.new_work(thread_entry,notify_entry)\n  return worker\nend\n\nlocal function queue(worker, ...)\n  worker:queue(...)\nend\n\nreturn {\n  start = start,\n  join = join,\n  equals = equals,\n  self = self,\n  work = work,\n  queue = queue,\n}\n', 'message': 'Use new luvi API instead of copying lua logic in thread\n', 'author_name': 'Tim Caswell', 'lang': 'lua'}