function table.clone(org)
  return {unpack(org)}
end

function Event ()
  local state = {
    listeners = {}
  }

  local api = {
    debug = false
  }

  local function listen (fn)
    if api.debug then
      DebugPrint('Adding listener')
    end
    local handler = {
      fn = fn,
      removed = false
    }
    table.insert(state.listeners, handler)

    local function unlisten ()
      for index = 1,#state.listeners do
        if state.listeners[index] == handler then
          table.remove(state.listeners, index)
          handler.removed = true
          return
        end
      end
    end

    return unlisten
  end

  local function broadcast ( ... )
    if api.debug then
      DebugPrint('Triggering ' .. #state.listeners .. ' listener')
    end
    if #state.listeners == 0 then
      return
    end
    local handlers = table.clone(state.listeners)
    local data = {...}
    local errors = {}

    for index = 1,#handlers do
      local handler = handlers[index]
      if handler and not handler.removed then
        local status, err = pcall(function () --luacheck: ignore status
          handler.fn(unpack(data))
        end)
        if err then
          print(err)
          table.insert(errors, err)
        end
      end
    end

    for index = 1,#errors do
      -- this will throw and not print any of the others, but whatever
      error(errors[index])
    end
  end

  api.broadcast = broadcast
  api.listen = listen

  return api
end
