<commit_before>local utilities = {}

local bit32 = require("bit32-compat")

math.epsilon = 1E-12

utilities.required = function (options, name, context)
  if not options[name] then utilities.error(context.." needs a "..name.." parameter") end
  return options[name]
end

utilities.boolean = function (value, default)
  if value == "false" then return false end
  if value == false then return false end
  if value == "true" then return true end
  if value == true then return true end
  return default
end

if not table.maxn then
  table.maxn = function(tbl)
    local max = 0
    for i,_ in pairs(tbl) do if i > max then max = i end end
    return max
  end
end

utilities.error = function(message, bug)
  utilities.warn(message, bug)
  io.stderr:flush()
  SILE.outputter:finish()
  os.exit(1)
end

utilities.warn = function(message, bug)
  io.stderr:write("\n! " .. message)
  if SILE.traceback or bug then
    io.stderr:write(" at:\n" .. SILE.traceStack:locationTrace())
    io.stderr:write(debug.traceback(nil, 2))
  else
    io.stderr:write(" at " .. SILE.traceStack:locationHead())
  end
  io.stderr:write("\n")
end

utilities.debugging = function (category)
  return SILE.debugFlags.all or SILE.debugFlags[category]
end

utilities.feq = function (lhs, rhs) -- Float point equal
  local abs = math.abs
  return abs(lhs - rhs) <= math.epsilon * (abs(lhs) + abs(rhs))
end

utilities.gtoke = function (string, pattern)
  string = string and tostring(string) or ''
  pattern = pattern and tostring(pattern) or "%s+"
  local length = #string
  return coroutine.wrap(function()
    local index = 1
    repeat
      local first, last = string:find(pattern, index)
      if last then
        if index < first then coroutine.yield({ string = string:sub(index, first - 1) }) end
        coroutine.yield({ separator = string:sub(first, last) })
        index = last + 1
      else
        if index <= length then
          coroutine.yield({ string = string:sub(index) })
        end
        break
      end
    until index > length
  end)
end

utilities.debug = function (category, ...)
  if utilities.debugging(category) then
    io.stderr:write("\n["..category.."] ", table.concat({ ... }, " "))
  end
end

utilities.dump = function (...)
  local arg = { ... } -- Avoid things that Lua stuffs in arg like args to self()
  require("pl.pretty").dump(#arg == 1 and arg[1] or arg, "/dev/stderr")
end

utilities.concat = function (array, separator)
  return table.concat(utilities.map(tostring, array), separator)
end

utilities.inherit = function (orig, spec)
  local new = std.tree.clone(orig)
  if spec then
    for k,v in pairs(spec) do new[k] = v end
  end
  if new.init then new:init() end
  return new
end

utilities.map = function (func, array)
  local new_array = {}
  local last = #array
  for i = 1, last do<commit_msg>refactor(core): Use Penlight's autoloader now that it's always present<commit_after>local utilities = {}

local bit32 = require("bit32-compat")

math.epsilon = 1E-12

utilities.required = function (options, name, context)
  if not options[name] then utilities.error(context.." needs a "..name.." parameter") end
  return options[name]
end

utilities.boolean = function (value, default)
  if value == "false" then return false end
  if value == false then return false end
  if value == "true" then return true end
  if value == true then return true end
  return default
end

if not table.maxn then
  table.maxn = function(tbl)
    local max = 0
    for i,_ in pairs(tbl) do if i > max then max = i end end
    return max
  end
end

utilities.error = function(message, bug)
  utilities.warn(message, bug)
  io.stderr:flush()
  SILE.outputter:finish()
  os.exit(1)
end

utilities.warn = function(message, bug)
  io.stderr:write("\n! " .. message)
  if SILE.traceback or bug then
    io.stderr:write(" at:\n" .. SILE.traceStack:locationTrace())
    io.stderr:write(debug.traceback(nil, 2))
  else
    io.stderr:write(" at " .. SILE.traceStack:locationHead())
  end
  io.stderr:write("\n")
end

utilities.debugging = function (category)
  return SILE.debugFlags.all or SILE.debugFlags[category]
end

utilities.feq = function (lhs, rhs) -- Float point equal
  local abs = math.abs
  return abs(lhs - rhs) <= math.epsilon * (abs(lhs) + abs(rhs))
end

utilities.gtoke = function (string, pattern)
  string = string and tostring(string) or ''
  pattern = pattern and tostring(pattern) or "%s+"
  local length = #string
  return coroutine.wrap(function()
    local index = 1
    repeat
      local first, last = string:find(pattern, index)
      if last then
        if index < first then coroutine.yield({ string = string:sub(index, first - 1) }) end
        coroutine.yield({ separator = string:sub(first, last) })
        index = last + 1
      else
        if index <= length then
          coroutine.yield({ string = string:sub(index) })
        end
        break
      end
    until index > length
  end)
end

utilities.debug = function (category, ...)
  if utilities.debugging(category) then
    io.stderr:write("\n["..category.."] ", table.concat({ ... }, " "))
  end
end

utilities.dump = function (...)
  local arg = { ... } -- Avoid things that Lua stuffs in arg like args to self()
  pretty.dump(#arg == 1 and arg[1] or arg, "/dev/stderr")
end

utilities.concat = function (array, separator)
  return table.concat(utilities.map(tostring, array), separator)
end

utilities.inherit = function (orig, spec)
  local new = std.tree.clone(orig)
  if spec then
    for k,v in pairs(spec) do new[k] = v end
  end
  if new.init then new:init() end
  return new
end

utilities.map = function (func, array)
  local new_array = {}
  local last = #array
  for i = 1, last do
{'fraction_non_alphanumeric': 0.12660453666256374, 'fraction_numerical': 0.005626868296113944, 'mean_word_length': 3.2195845697329375, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '187177', 'n_tokens_mistral': 1866, 'n_tokens_neox': 1824, 'n_words': 587}