text:
--
-- Test faerryn's config.
--

vim.o.rtp = ".,"..vim.o.rtp
vim.o.pp = ".,"..vim.o.pp

local user = require("user")
user.setup({ path = "./pack/user" })
local use = user.use

use {
  "antoinemadec/FixCursorHold.nvim",
  init = function() vim.g.cursorhold_updatetime = 1000 end,
}

use "ryvnf/readline.vim"

use "tpope/vim-repeat"

use {
  "norcalli/nvim-colorizer.lua",
  config = function() vim.api.nvim_command([[autocmd BufEnter * lua require("colorizer").attach_to_buffer()]]) end,
}

use "nvim-lua/plenary.nvim"
use "nvim-lua/popup.nvim"
use "nvim-telescope/telescope-fzy-native.nvim"
use {
  "nvim-telescope/telescope.nvim",
  config = function()
    local telescope = require("telescope")
    local actions = require("telescope.actions")

    telescope.setup { defaults = {
      mappings = { i = { ["<esc>"] = actions.close } },
      file_previewer = require("telescope.previewers").vim_buffer_cat.new,
    } }

    telescope.load_extension("fzy_native")

    vim.api.nvim_set_keymap("n", "<Leader>f", [[<Cmd>lua require("telescope.builtin").find_files{ hidden = true }<CR>]], { noremap = true })
    vim.api.nvim_set_keymap("n", "<Leader>b", [[<Cmd>lua require("telescope.builtin").buffers()<CR>]], { noremap = true })
  end,
}

use "nvim-lua/plenary.nvim"
use {
  "lewis6991/gitsigns.nvim",
  config = function()
    require("gitsigns").setup {
      signs = {
        add          = { hl = "GitGutterAdd",    text = "+" },
        change       = { hl = "GitGutterChange", text = "~" },
        delete       = { hl = "GitGutterDelete", text = "_" },
        topdelete    = { hl = "GitGutterDelete", text = "‾" },
        changedelete = { hl = "GitGutterChange", text = "~" },
      },
      keymaps = {},
    }
  end,
}

use "tomtom/tcomment_vim"

use {
  "nvim-treesitter/nvim-treesitter",
  config = function()
    require("nvim-treesitter.configs").setup({ highlight = { enable = true } })
  end,
}

use {
  "gruvbox-community/gruvbox",
  init = function()
    vim.g.gruvbox_bold                 = 1
    vim.g.gruvbox_italic               = 1
    vim.g.gruvbox_transparent_bg       = 1
    vim.g.gruvbox_underline            = 1
    vim.g.gruvbox_undercurl            = 1
    vim.g.gruvbox_termcolors           = 256
    vim.g.gruvbox_contrast_dark        = "medium"
    vim.g.gruvbox_contrast_light       = "medium"
    vim.g.gruvbox_italicize_comments   = 1
    vim.g.gruvbox_italicize_strings    = 1
    vim.g.gruvbox_invert_selection     = 0
    vim.g.gruvbox_invert_signs         = 0
    vim.g.gruvbox_invert_indent_guides = 0
    vim.g.gruvbox_invert_tabline       = 0
    vim.g.gruvbox_improved_strings     = 1
    vim.g.gruvbox_improved_warnings    = 1
    vim.g.gruvbox_guisp_fallback       = 1
  end,
  config = function() vim.api.nvim_command("colorscheme gruvbox") end,
}

use {
  "ziglang/zig.vim",
  init = function() vim.g.zig_fmt_autosave = false end,
}

user.flush()


text:
AddCSLuaFile()
AddCSLuaFile("sh_sounds.lua")
include("sh_sounds.lua")

	CustomizableWeaponry:registerAmmo(".410 Bore", ".410 Bore Shells", 4, 10)
	CustomizableWeaponry:registerAmmo(".45 Long Colt", ".45LC Rounds", 11.48, 33)
	SWEP.PrintName = "Taurus Public Defender"

if CLIENT then
	SWEP.DrawCrosshair = false
	SWEP.CSMuzzleFlashes = true

	SWEP.IconLetter = "y"
	killicon.Add( "khr_rgnbull", "icons/killicons/khr_rgnbull", Color(255, 80, 0, 150))
	SWEP.SelectIcon = surface.GetTextureID("icons/killicons/khr_rgnbull")

	SWEP.MuzzleEffect = "muzzleflash_g3"
	SWEP.PosBasedMuz = true
	SWEP.NoShells = true

	SWEP.EffectiveRange_Orig = 18 * 39.37
	SWEP.DamageFallOff_Orig = .5

	SWEP.IronsightPos = Vector(-1.844, 1, 0.897)
	SWEP.IronsightAng = Vector(-1.4, 0.03, 0)

	SWEP.JudgeLongPos = Vector(-1.844, 1, 0.818)
	SWEP.JudgeLongAng = Vector(-.95, 0.03, 0)

	SWEP.JudgeLongerPos = Vector(-1.844, 1, 0.785)
	SWEP.JudgeLongerAng = Vector(-0.7, 0.03, 0)

	SWEP.CustomizePos = Vector(3.488, -2.627, -0.821)
	SWEP.CustomizeAng = Vector(17.009, 29.971, 16.669)

	SWEP.SprintPos = Vector(0, 0, -1)
	SWEP.SprintAng = Vector(-15.478, 11.96, 0)

	SWEP.AlternativePos = Vector(-0.4, 1, -0.5)
	SWEP.AlternativeAng = Vector(0, 0, 0)

	SWEP.ViewModelMovementScale = 1
	SWEP.BoltBone = "hammer"
	SWEP.BoltShootOffset = Vector(0, -.25, 0)
	SWEP.BoltBonePositionRecoverySpeed = 3
	SWEP.FullAimViewmodelRecoil = true
	SWEP.HUD_MagText = "CYLINDER: "

	SWEP.LuaVMRecoilAxisMod = {vert = .5, hor = 1, roll = 1, forward = .5, pitch = 2}
	SWEP.CustomizationMenuScale = 0.012
	SWEP.DisableSprintViewSimulation = true

	SWEP.AttachmentModelsVM = {
	["md_uecw_csgo_acog"] = { type = "Model", model = "models/gmod4phun/csgo/eq_optic_acog.mdl", bone = "weapon", rel = "", pos = Vector(0, 0.949, -3.636), angle = Angle(90, -90, 0), size = Vector(0.6, 0.6, 0.6), color = Color(255, 255, 255, 255), surpresslightning = false, material = "", skin = 0, bodygroup = {} }
}
SWEP.ACOGAxisAlign = {right = 0, up = 0, forward = 0}
end

SWEP.MuzzleVelocity = 259 -- in meter/s

SWEP.MagBGs = {main = 2, shell2 = 1, shell = 0}
SWEP.BarrelBGs = {main = 1, one = 0, two = 1, three = 2}

SWEP.LuaViewmodelRecoil = true
SWEP.LuaViewmodelRecoilOverride = true
SWEP.CanRestOnObjects = false

SWEP.Attachments = {[1] = {header = "Barrel", offset = {-650, -300}, atts = {"bg_judgelong","bg_judgelonger"}},
["+reload"] = {header = "Ammo", offset = {350, -150}, atts = {"am_flechette410","am_45lc"}}}

SWEP.Animations = {fire = {"shoot1", "shoot2"},
	reload = "reload",
	idle = "idle",
	draw = "draw"}

SWEP.Sounds = {draw = {{time = 0, sound = "RB_DRAW"}},

	reload = {[1] = {time = 0.25, sound = "RB_OUT"},
	[2] = {time = .8, sound = "RB_EJECT"},
	[3] = {time = 2.5, sound = "RB_INSERT"},
	[4] = {time = 3.25, sound = "RB_IN"}}}

SWEP.SpeedDec = 15

SWEP.Slot = 1
SWEP.SlotPos = 0
SWEP.NormalHoldType = "revolver"
SWEP.RunHoldType = "normal"
SWEP.FireModes = {"double"}
SWEP.Base = "cw_base"
SWEP.Category = "CW 2.0 - Revolvers"

SWEP.Author			= "Spy"
SWEP.Contact		= ""
SWEP.Purpose		= ""
SWEP.Instructions	= ""

SWEP.ViewModelFOV	= 80
SWEP.AimViewModelFOV = 80
SWEP.ViewModelFlip	= false
SWEP.OverallMouseSens = 1
SWEP.ViewModel		= "models/khrcw2/v_khri_410jury.mdl"
SWEP.WorldModel		= "models/weapons/w_357.mdl"

SWEP.Spawnable			= true
SWEP.AdminSpawnable		= true

SWEP.Primary.ClipSize		= 5
SWEP.Primary.DefaultClip	= 5
SWEP.Primary.Automatic		= false
SWEP.Primary.Ammo			= ".410 Bore"

SWEP.FireDelay = 0.2
SWEP.FireSound = "410_FIRE"
SWEP.Recoil = 2

SWEP.HipSpread = 0.035
SWEP.AimSpread = 0.02
SWEP.VelocitySensitivity = 1.1
SWEP.MaxSpreadInc = 0.08
SWEP.MaxSpreadInc = 0.075
SWEP.SpreadPerShot = 0.02
SWEP.ClumpSpread = .019
SWEP.SpreadCooldown = 0.33
SWEP.Shots = 4
SWEP.Damage = 30
SWEP.DeployTime = 0.6
SWEP.Chamberable = false
SWEP.ADSFireAnim = false

SWEP.ReloadSpeed = 1
SWEP.ReloadTime = 4
SWEP.ReloadHalt = 4

SWEP.ReloadTime_Empty = 4
SWEP.ReloadHalt_Empty = 4

function SWEP:IndividualThink()
	self.EffectiveRange = 18 * 39.37
	self.DamageFallOff = .5
	self.ClumpSpread = .019

	if self.ActiveAttachments.bg_judgelong then
	self.EffectiveRange = ((self.EffectiveRange + 2 * 39.37))
	self.DamageFallOff = ((self.DamageFallOff - .05))
	self.ClumpSpread = ((self.ClumpSpread - .002))
	end
	if self.ActiveAttachments.bg_judgelonger then
	self.EffectiveRange = ((self.EffectiveRange + 3.96 * 39.37))
	self.DamageFallOff = ((self.DamageFallOff - .09))
	self.ClumpSpread = ((self.ClumpSpread - .004))
	end
	if self.ActiveAttachments.am_45lc then
	self.EffectiveRange = ((self.EffectiveRange + 35 * 39.37))
	self.DamageFallOff = ((self.DamageFallOff - .1))
	self.ClumpSpread = nil
	end
end

domain: lua


text:
local void = require('plenary.async.async').void
local scheduler = require('plenary.async.util').scheduler

local Status = require("gitsigns.status")
local config = require('gitsigns.config').config
local mk_repeatable = require('gitsigns.repeat').mk_repeatable
local popup = require('gitsigns.popup')
local signs = require('gitsigns.signs')
local util = require('gitsigns.util')
local manager = require('gitsigns.manager')

local gs_cache = require('gitsigns.cache')
local cache = gs_cache.cache
local CacheEntry = gs_cache.CacheEntry

local gs_hunks = require('gitsigns.hunks')
local Hunk = gs_hunks.Hunk

local api = vim.api
local current_buf = api.nvim_get_current_buf

local NavHunkOpts = {}

local M = {}

local function get_cursor_hunk(bufnr, hunks)
   bufnr = bufnr or current_buf()
   hunks = hunks or cache[bufnr].hunks

   local lnum = api.nvim_win_get_cursor(0)[1]
   return gs_hunks.find_hunk(lnum, hunks)
end

local function get_range_hunks(bufnr, hunks, range, strict)
   bufnr = bufnr or current_buf()
   hunks = hunks or cache[bufnr].hunks

   local ret = {}
   for _, hunk in ipairs(hunks) do
      if range[1] == 1 and hunk.start == 0 and hunk.vend == 0 then
         return { hunk }
      end

      if strict then
         if (range[1] <= hunk.start and range[2] >= hunk.vend) then
            ret[#ret + 1] = hunk
         end
      else
         if (range[2] >= hunk.start and range[1] <= hunk.vend) then
            ret[#ret + 1] = hunk
         end
      end
   end

   return ret
end

M.stage_hunk = mk_repeatable(void(function(range)
   range = range or M.user_range
   local valid_range = false
   local bufnr = current_buf()
   local bcache = cache[bufnr]
   if not bcache then
      return
   end

   if not util.path_exists(bcache.file) then
      print("Error: Cannot stage lines. Please add the file to the working tree.")
      return
   end

   local hunks = {}

   if range and range[1] ~= range[2] then
      valid_range = true
      table.sort(range)
      hunks = get_range_hunks(bufnr, bcache.hunks, range)
   else
      hunks[1] = get_cursor_hunk(bufnr, bcache.hunks)
   end

   if #hunks == 0 then
      return
   end

   bcache.git_obj:stage_hunks(hunks)

   for _, hunk in ipairs(hunks) do
      table.insert(bcache.staged_diffs, hunk)
   end

   bcache.compare_text = nil

   local hunk_signs = gs_hunks.process_hunks(hunks)

   scheduler()

   for lnum, _ in pairs(hunk_signs) do
      signs.remove(bufnr, lnum)
   end
   void(manager.update)(bufnr)
end))

M.reset_hunk = mk_repeatable(function(range)
   range = range or M.user_range
   local bufnr = current_buf()
   local hunks = {}

   if range and range[1] ~= range[2] then
      table.sort(range)
      hunks = get_range_hunks(bufnr, nil, range)
   else
      hunks[1] = get_cursor_hunk(bufnr)
   end

   if #hunks == 0 then
      return
   end

   local offset = 0

   for _, hunk in ipairs(hunks) do
      local lstart, lend
      if hunk.type == 'delete' then
         lstart = hunk.start
         lend = hunk.start
      else
         local length = vim.tbl_count(vim.tbl_filter(function(l)
            return vim.startswith(l, '+')
         end, hunk.lines))

         lstart = hunk.start - 1
         lend = hunk.start - 1 + length
      end
      local lines = gs_hunks.extract_removed(hunk)
      api.nvim_buf_set_lines(bufnr, lstart + offset, lend + offset, false, lines)
      offset = offset + (#lines - (lend - lstart))
   end
end)

M.reset_buffer = function()
   local bufnr = current_buf()
   local bcache = cache[bufnr]
   if not bcache then
      return
   end

   api.nvim_buf_set_lines(bufnr, 0, -1, false, bcache:get_compare_text())
end

M.undo_stage_hunk = mk_repeatable(void(function()
   local bufnr = current_buf()
   local bcache = cache[bufnr]
   if not bcache then
      return
   end

   local hunk = table.remove(bcache.staged_diffs)
   if not hunk then
      print("No hunks to undo")
      return
   end

   bcache.git_obj:stage_hunks({ hunk }, true)
   bcache.compare_text = nil
   scheduler()
   signs.add(config, bufnr, gs_hunks.process_hunks({ hunk }))
   manager.update(bufnr)
end))

M.stage_buffer = void(function()
   local bufnr = current_buf()

   local bcache = cache[bufnr]
   if not bcache then
      return
   end

   local hunks = bcache.hunks
   if #hunks == 0 then
      print("No unstaged changes in file to stage")
      return
   end

   if not util.path_exists(bcache.git_obj.file) then
      print("Error: Cannot stage file. Please add it to the working tree.")
      return
   end

   bcache.git_obj:stage_hunks(hunks)

   for _, hunk in ipairs(hunks) do
      table.insert(bcache.staged_diffs, hunk)
   end
   bcache.compare_text = nil

   scheduler()
   signs.remove(bufnr)
   Status:clear_diff(bufnr)
end)

M.reset_buffer_index = void(function()
   local bufnr = current_buf()
   local bcache = cache[bufnr]
   if not bcache then
      return
   end

   local hunks = bcache.staged_diffs
   bcache.staged_diffs = {}

   bcache.git_obj:unstage_file()
   bcache.compare_text = nil

   scheduler()
   signs.add(config, bufnr, gs_hunks.process_hunks(hunks))
   void(manager.update)(bufnr)
end)

local function nav_hunk(options)
   local bcache = cache[current_buf()]
   if not bcache then
      return
   end

   local show_navigation_msg = not string.find(vim.o.shortmess, 'S')
   if options.navigation_message ~= nil then
      show_navigation_msg = options.navigation_message
   end

   local hunks = bcache.hunks
   if not hunks or vim.tbl_isempty(hunks) then
      if show_navigation_msg then
         vim.api.nvim_echo({ { 'No hunks', 'WarningMsg' } }, false, {})
      end
      return
   end
   local line = api.nvim_win_get_cursor(0)[1]

   local wrap = vim.o.wrapscan
   if options.wrap ~= nil then
      wrap = options.wrap
   end

   local hunk, index = gs_hunks.find_nearest_hunk(line, hunks, options.forwards, wrap)

   if hunk == nil then
      if show_navigation_msg then
         vim.api.nvim_echo({ { 'No more hunks', 'WarningMsg' } }, false, {})
      end
      return
   end

   local row = options.forwards and hunk.start or hunk.vend
   if row then

      if row == 0 then
         row = 1
      end
      api.nvim_win_set_cursor(0, { row, 0 })
      if pcall(api.nvim_buf_get_var, 0, '_gitsigns_preview_open') then
         vim.schedule(M.preview_hunk)
      end

      if index ~= nil and show_navigation_msg then
         vim.api.nvim_echo({ { string.format('Hunk %d of %d', index, #hunks), 'None' } }, false, {})
      end

   end
end

M.next_hunk = function(options)
   options = options or {}
   options.forwards = true
   nav_hunk(options)
end

M.prev_hunk = function(options)
   options = options or {}
   options.forwards = false
   nav_hunk(options)
end

local ns = api.nvim_create_namespace('gitsigns')

M.preview_hunk = function()
   local cbuf = current_buf()
   local bcache = cache[cbuf]
   local hunk, index = get_cursor_hunk(cbuf, bcache.hunks)

   if not hunk then return end

   local lines = {
      ('Hunk %d of %d'):format(index, #bcache.hunks),
      unpack(hunk.lines),
   }

   local _, bufnr = popup.create(lines, config.preview_config)
   api.nvim_buf_set_option(bufnr, 'filetype', 'diff')

   api.nvim_buf_add_highlight(bufnr, -1, 'Title', 0, 0, -1)

   api.nvim_buf_set_var(cbuf, '_gitsigns_preview_open', true)
   vim.cmd([[autocmd CursorMoved,CursorMovedI <buffer> ++once silent! unlet b:_gitsigns_preview_open]])

   if config.use_internal_diff then
      local regions = require('gitsigns.diff_ffi').run_word_diff(hunk.lines)
      local offset = #lines - #hunk.lines
      for _, region in ipairs(regions) do
         local line, scol, ecol = region[1], region[3], region[4]
         api.nvim_buf_set_extmark(bufnr, ns, line + offset - 1, scol, {
            end_col = ecol,
            hl_group = 'TermCursor',
         })
      end
   end
end

M.select_hunk = function()
   local hunk = get_cursor_hunk()
   if not hunk then return end

   vim.cmd('normal! ' .. hunk.start .. 'GV' .. hunk.vend .. 'G')
end

M.get_hunks = function(bufnr)
   bufnr = current_buf()
   if not cache[bufnr] then return end
   local ret = {}
   for _, h in ipairs(cache[bufnr].hunks) do
      ret[#ret + 1] = {
         head = h.head,
         lines = h.lines,
         type = h.type,
         added = h.added,
         removed = h.removed,
      }
   end
   return ret
end

local function defer(duration, callback)
   local timer = vim.loop.new_timer()
   timer:start(duration, 0, function()
      timer:stop()
      timer:close()
      vim.schedule_wrap(callback)()
   end)
   return timer
end

M.blame_line = void(function(full)
   local bufnr = current_buf()
   local bcache = cache[bufnr]
   if not bcache then return end

   local loading = defer(1000, function()
      popup.create({ 'Loading...' }, config.preview_config)
   end)

   scheduler()
   local buftext = api.nvim_buf_get_lines(bufnr, 0, -1, false)
   local lnum = api.nvim_win_get_cursor(0)[1]
   local result = bcache.git_obj:run_blame(buftext, lnum)
   pcall(function()
      loading:close()
   end)

   local is_committed = bcache.git_obj.object_name and tonumber('0x' .. result.sha) ~= 0
   if is_committed then
      local commit_message = {}
      if full then
         commit_message = bcache.git_obj:command({ 'show', '-s', '--format=%B', result.sha })
         while commit_message[#commit_message] == '' do
            commit_message[#commit_message] = nil
         end
      else
         commit_message = { result.summary }
      end

      local date = os.date('%Y-%m-%d %H:%M', tonumber(result['author_time']))

      local lines = {
         ('%s %s (%s):'):format(result.abbrev_sha, result.author, date),
         unpack(commit_message),
      }

      scheduler()
      local _, pbufnr = popup.create(lines, config.preview_config)

      local p1 = #result.abbrev_sha
      local p2 = #result.author
      local p3 = #date

      local function add_highlight(hlgroup, line, start, length)
         api.nvim_buf_add_highlight(pbufnr, -1, hlgroup, line, start, start + length)
      end

      add_highlight('Directory', 0, 0, p1)
      add_highlight('MoreMsg', 0, p1 + 1, p2)
      add_highlight('Label', 0, p1 + p2 + 2, p3 + 2)
   else
      local lines = { result.author }
      scheduler()
      local _, pbufnr = popup.create(lines, config.preview_config)
      api.nvim_buf_add_highlight(pbufnr, -1, 'MoreMsg', 0, 0, #result.author)
   end
end)

local function calc_base(base)
   if base and base:sub(1, 1):match('[~\\^]') then
      base = 'HEAD' .. base
   end
   return base
end

M.change_base = function(base)
   local buf = current_buf()
   local bcache = cache[buf]
   if bcache == nil then return end
   base = calc_base(base)
   bcache.base = base
   bcache.compare_text = nil
   void(manager.update)(buf, bcache)
end

M.diffthis = void(function(base)
   local bufnr = current_buf()
   local bcache = cache[bufnr]
   if not bcache then return end

   if api.nvim_win_get_option(0, 'diff') then return end

   local text
   local err
   local comp_obj = bcache:get_compare_obj(calc_base(base))
   if base then
      text, err = bcache.git_obj:get_show_text(comp_obj)
      if err then
         print(err)
         return
      end
      scheduler()
   else
      text = bcache:get_compare_text()
   end

   local ft = api.nvim_buf_get_option(bufnr, 'filetype')

   local bufname = string.format('gitsigns://%s/%s', bcache.git_obj.gitdir, comp_obj)

   vim.cmd("keepalt aboveleft vertical split " .. bufname)

   local dbuf = current_buf()

   api.nvim_buf_set_option(dbuf, 'modifiable', true)
   api.nvim_buf_set_lines(dbuf, 0, -1, false, text)
   api.nvim_buf_set_option(dbuf, 'modifiable', false)

   api.nvim_buf_set_option(dbuf, 'filetype', ft)
   api.nvim_buf_set_option(dbuf, 'buftype', 'nowrite')

   vim.cmd(string.format('autocmd! WinClosed <buffer=%d> ++once call nvim_buf_delete(%d, {})', dbuf, dbuf))

   vim.cmd([[windo diffthis]])
end)

local function hunks_to_qflist(buf_or_filename, hunks, qflist)
   for i, hunk in ipairs(hunks) do
      qflist[#qflist + 1] = {
         bufnr = type(buf_or_filename) == "number" and (buf_or_filename) or nil,
         filename = type(buf_or_filename) == "string" and buf_or_filename or nil,
         lnum = hunk.start,
         text = string.format('Lines %d-%d (%d/%d)',
         hunk.start, hunk.vend, i, #hunks),
      }
   end
end

local function run_diff(a, b)
   if config.use_internal_diff then
      return require('gitsigns.diff_ffi').run_diff(a, b, config.diff_algorithm)
   else
      return require('gitsigns.diff_ext').run_diff(a, b, config.diff_algorithm)
   end
end

local function buildqflist(target)
   target = target or current_buf()
   if target == 0 then target = current_buf() end
   local qflist = {}

   if type(target) == 'number' then
      local bufnr = target
      if not cache[bufnr] then return end
      hunks_to_qflist(bufnr, cache[bufnr].hunks, qflist)
   elseif target == 'attached' or target == 'all' then
      local gitdirs_done = {}
      for bufnr, bcache in pairs(cache) do
         hunks_to_qflist(bufnr, bcache.hunks, qflist)

         if target == 'all' then
            local git_obj = bcache.git_obj
            if not gitdirs_done[git_obj.gitdir] then
               for _, f in ipairs(git_obj:files_changed()) do
                  local f_abs = git_obj.toplevel .. '/' .. f
                  local hunks = run_diff(
                  git_obj:get_show_text(':0:' .. f),
                  util.file_lines(f_abs))

                  hunks_to_qflist(f_abs, hunks, qflist)
               end
            end
            gitdirs_done[git_obj.gitdir] = true
         end
      end
   end
   return qflist
end

M.setqflist = void(function(target)
   local qflist = buildqflist(target)
   scheduler()
   vim.fn.setqflist({}, ' ', {
      items = qflist,
      title = 'Hunks',
   })
end)

M.setloclist = void(function(nr, target)
   nr = nr or 0
   local qflist = buildqflist(target)
   scheduler()
   vim.fn.setloclist(nr, {}, ' ', {
      items = qflist,
      title = 'Hunks',
   })
end)

M.get_actions = function()
   local hunk = get_cursor_hunk()

   local actions_l = {}
   if hunk then
      actions_l = {
         'stage_hunk',
         'undo_stage_hunk',
         'reset_hunk',
         'preview_hunk',
         'select_hunk',
      }
   else
      actions_l = {
         'blame_line',
      }
   end

   local actions = {}
   for _, a in ipairs(actions_l) do
      actions[a] = (M)[a]
   end

   return actions
end

M.refresh = void(function()
   manager.setup_signs_and_highlights(true)
   require('gitsigns.current_line_blame').setup()
   for k, v in pairs(cache) do
      v.compare_text = nil
      manager.update(k, v)
   end
end)

M.toggle_signs = function()
   config.signcolumn = not config.signcolumn
   M.refresh()
end

M.toggle_numhl = function()
   config.numhl = not config.numhl
   M.refresh()
end

M.toggle_linehl = function()
   config.linehl = not config.linehl
   M.refresh()
end

M.toggle_word_diff = function()
   config.word_diff = not config.word_diff
   M.refresh()
end

M.toggle_current_line_blame = function()
   config.current_line_blame = not config.current_line_blame
   M.refresh()
end

return M


text:
local syntax = require "core.syntax"

syntax.add {
  files = { "%.md$", "%.markdown$" },
  patterns = {
    { pattern = "\\.",                    type = "normal"   },
    { pattern = { "<!%-%-", "%-%->" },    type = "comment"  },
    { pattern = { "```", "```" },         type = "string"   },
    { pattern = { "``", "``", "\\" },     type = "string"   },
    { pattern = { "`", "`", "\\" },       type = "string"   },
    { pattern = { "~~", "~~", "\\" },     type = "keyword2" },
    { pattern = "%-%-%-+",                type = "comment" },
    { pattern = "%*%s+",                  type = "operator" },
    { pattern = { "%*", "[%*\n]", "\\" }, type = "operator" },
    { pattern = { "%_", "[%_\n]", "\\" }, type = "keyword2" },
    { pattern = "#.-\n",                  type = "keyword"  },
    { pattern = "!?%[.-%]%(.-%)",         type = "function" },
    { pattern = "https?://%S+",           type = "function" },
  },
  symbols = { },
}


text:
require("util")
require("tiled/tilesets")
-- slugdefs tells us information about slug types
-- such as where the head/body images are stored
Slug = {defs = dofile("slug/slugdefs.lua")}

Slug.__index = metareplacer(Slug)
require("slug/segment")

--[[--
   creates a new slug
   @param self now owned by slug, passed in unlike usual
   @return new slug
]]
function Slug.new (self)
   local sprites = Slug.defs[self.sprites].tiles
   self.stats = Slug.defs[self.sprites].stats
   self.sprites = {}
   for i, spr in ipairs(sprites) do
      self.sprites[i] = sprites[i]--Sprite.new(spr.tex, 0, 0, tilew, tileh, spr.x, spr.y)
   end
   self.size = #self.segs
   self.maxsize = self.stats.maxsize
   self.action = self.stats.skills[1]
   local prev = nil
   for i = 1,self.size do
      local sprite = self.sprites[2]
      if i == 1 then
	 sprite = self.sprites[1]
      end
      self.segs[i] = Segment.new(prev, nil, sprite, self.segs[i], self, {0,0,0,0})
      prev = self.segs[i]
   end
   self.head = self.segs[1]
   self.tail = self.segs[self.size]
   self.segs = nil
   setmetatable(self, Slug)
   self:addToMap()
   return self
end

--[[--
   creates the overlay for movement

   this overlay displays the maximum movement a slug can make with
   the `range` of moves it has left

   @param range number of moves slug has left
]]
function Slug:movementOverlay(range)
   local diamond = self:listDiamond(range)
   local arrs = {overlay.named.up, overlay.named.right, overlay.named.down, overlay.named.left}
   local x, y
   if #diamond < 4 then
      return
   end
   for i = 1, 4 do
      if diamond[i] then
	 x,y = Map.basePosition(diamond[i][1], diamond[i][2])
	 diamond[i] = Sprite.new(arrs[i].tex, x, y, tilew, tileh, arrs[i].x, arrs[i].y)
      end
   end
   local move = overlay.named.move
   for i = 5, #diamond do
      if diamond[i] then
	 x,y = Map.basePosition(diamond[i][1], diamond[i][2])
	 diamond[i] = Sprite.new(move.tex, x, y, tilew, tileh, move.x, move.y)
      end
   end
   self.overlay = diamond
end

--[[--
   creates a basic overlay

   calls the overlayFn to determine what of the diamond of squares in range
   should be displayed

   @param range how may tiles away does this overlay go
   @param overlayFn determines visible squares
]]
function Slug:basicOverlay(range, overlayFn)
   if not overlayFn then
      overlayFn = Slug.attackOverlayFn
   end
   local diamond = self:listDiamond2(range, overlayFn)
   local x, y
   local atk = overlay.named.attack
   for i = 1, #diamond do
      if diamond[i] then
	 x,y = Map.basePosition(diamond[i][1], diamond[i][2])
	 diamond[i] = Sprite.new(atk.tex, x, y, tilew, tileh, atk.x, atk.y)
      end
   end
   self.overlay = diamond
end

--[[--
   destroys current overlay
]]
function Slug:destroyOverlay()
   if self.overlay then
      for i,v in ipairs(self.overlay) do
	 if v then
	    v:destroy()
	 end
      end
   end
   self.overlay = nil
end

--[[--
   draws overlay
]]
function Slug:drawOverlay()
   if self.overlay then
      local x, y = Map.position(self.head.pos[1] + 1, self.head.pos[2] + 1)
      for i,v in ipairs(self.overlay) do
	 if v then
	    v:draw(x,y)
	 end
      end
   end
end

--[[--
   how to determine whether a square should have the attack overlay

   @param x coord
   @param y coord

   @return should show for coord
]]
function Slug.attackOverlayFn(x,y)
   return map:valid(x, y) and map.map[map:indexOf(x, y)]
end

--[[--
   creates a list of the coords that make up an overlay of a certain size

   @param size
   @param overlayFn

   @return list of coords (false replaces unwanted tiles)
]]
function Slug:listDiamond2(size, overlayFn)
   -- >v, <v,<^,>^
   local deltas = {{1,1},{-1,1},{-1,-1},{1,-1}}
   local j = 1
   local hpos = self.head.pos
   local pos = {0,0}--
   local lst = {}
   local x, y
   for ring = 1,size do
      pos[2] = pos[2] - 1
      for t,d in ipairs(deltas) do
	 for i=1,ring do
	    x, y = pos[1]+hpos[1], pos[2]+hpos[2]
	    if overlayFn(x, y) then
	       lst[j] = {pos[1], pos[2]}
	    else
	       lst[j] = false
	    end
	    pos[1] = pos[1] + d[1]
	    pos[2] = pos[2] + d[2]
	    j = j + 1
	 end
      end
   end
   return lst
end

--[[--
   same as `listDiamond2` above but using a breadth first search

   @param size

   @return list of coords (false replaces unwanted tiles)
]]
function Slug:listDiamond(size)
   -- >v, <v,<^,>^
   local q = {s=0,e=1,n=1}
   local low = {0 - size, 0 - size}
   local visited = {}
   local tmp,cur,ind,mind,s
   local hpos = self.head.pos
   local x,y
   q[q.s] = {0,0,size}
   local deltas = {{0,-1},{1,0},{0,1},{-1,0}}
   local swidth = size*2 + 1
   while q.n >= 1 do
      cur = q[q.s]
      q.s = q.s + 1
      q.n = q.n - 1
      s = cur[3]
      for t,d in ipairs(deltas) do
	 tmp = {cur[1] + d[1], cur[2] + d[2],s-1}
	 --print(tmp[1],tmp[2],tmp[3])
	 if tmp[3] >= 0 and tmp[1] >= low[1] and tmp[1] < low[1] + swidth and tmp[2] >= low[2] and tmp[2] < low[2] + swidth then
	    ind = (tmp[1] - low[1]) + (tmp[2] - low[2])*swidth
	    x,y=tmp[1]+hpos[1], tmp[2]+hpos[2]
	    mind = map:indexOf(x, y)
	    if map:valid(x, y) and not visited[ind] and map.map[mind] then
	       --print("yes", ind)--), tmp[1]+hpos[1], tmp[2]+hpos[2], tmp[1], tmp[2], map.map[mind])
	       visited[ind] = true
	       q[q.e] = tmp
	       q.e = q.e + 1
	       q.n = q.n + 1
	    end
	 end
      end
   end
   deltas = {{1,1},{-1,1},{-1,-1},{1,-1}}
   local j = 1
   hpos = self.head.pos
   local pos = {0,0}--
   local lst = {}
   for ring = 1,size do
      pos[2] = pos[2] - 1
      for t,d in ipairs(deltas) do
	 for i=1,ring do
	    ind = (pos[1] - low[1]) + (pos[2] - low[2])*swidth
	    --print(ind)
	    if visited[ind] then
	       lst[j] = {pos[1], pos[2]}
	    else
	       lst[j] = false
	    end
	    pos[1] = pos[1] + d[1]
	    pos[2] = pos[2] + d[2]
	    j = j + 1
	 end
      end
   end
   return lst
end

--[[--
   spawn slugs from Tiled lua file
]]
function Slug.spawn(data)
   slugs = {}
   for i, v in ipairs(data) do
      if not slugs[v.name] then
	 slugs[v.name] = {}
      end
      --print(v.y, v.x, map.tilesize, map.width, (v.y // map.tilesize))
      slugs[v.name][v.properties.index] = {
	 (v.x // map.tilesize) + 1,
	 (v.y // map.tilesize) + 1
      }
      slugs[v.name].type = v.type
      if v.properties.team then
	 slugs[v.name].team = v.properties.team
      end
      if v.properties.spawner then
	 slugs[v.name].spawner = true
      end
   end
   for name, v in pairs(slugs) do
      slugs[name] = Slug.new({sprites = v.type, segs = v, name=name, team=v.team, spawner = v.spawner})
   end
end

--[[--
   despawn slugs from Tiled lua file
]]
function Slug.despawn()
   for name, v in pairs(slugs) do
      if v then
	 v:destroy()
      end
   end
   slugs = nil
end

--[[--
   load all slug data
   names -> textures
]]
function Slug.load ()
   local data = Slug.defs
   local tilesets = data.tilesets
   local slugdefs = data.slugs
   Tileset.loadSurfaces(tilesets)
   tilesets:colorBridge()
   tilesets:asTextures()
   tilesets:loadTilesets()
   for name, v in pairs(slugdefs) do
      for i, tile in ipairs(v.tiles) do
	 local j, dat = tilesets:tilefinder(tile)
	 if j then
	    local t = tilesets:initTile(tilesets[j],dat)
	    v.tiles[i] = t
	 end
      end
   end
   Slug.defs = slugdefs
   Slug.tilesets = tilesets
end

--[[--
   deallocate global slug textures
]]
function Slug.unload()
   Tileset.destroyTilesets(Slug.tilesets)
end

--[[--
   Remove Slug from Map
]]
function Slug:removeFromMap()
   local seg = self.head
   while seg do
      seg:unsetMapConnections()
      seg = seg.n
   end
   seg = self.head
   while seg do
      seg:removeFromMap()
      seg = seg.n
   end
end

--[[--
   Add Slug to Map
]]
function Slug:addToMap()
   local seg = self.head
   while seg do
      seg:addToMap()
      seg = seg.n
   end
   seg = self.head
   while seg do
      seg:setMapConnections()
      seg = seg.n
   end
end

--[[--
   move slug's head to (x,y)

   Edge cases:
   - case off map
   - case encounter other
   - diagonal or on head
   - case encounter consumable
   - case encounter self tail
   - case encounter self (max len)
   - case encounter self default

   @param x
   @param y
]]
function Slug:move(x, y)
   local head = self.head
   local dx = math.abs(x - head.pos[1])
   local dy = math.abs(y - head.pos[2])
   local ind = map:indexOf(x,y)
   if not map:valid(x, y) or not map.map[ind] then
      return false
   end
   local mid = map.objects[ind]
   local item = nil
   if mid then
      if mid.item then
	 item = mid
	 mid = nil
      elseif mid.slug ~= self then
	 return false
      end
   end

   if dx > 1 or dy > 1 or dy == dx then
      return false
   end

   local tail = self.tail
   local ntail = nil
   local tx = tail.pos[1]
   local ty = tail.pos[2]
   head:unsetMapConnections()
   tail:unsetMapConnections()
   if mid and mid ~= tail then
      mid:unsetMapConnections()
   end
   head:removeFromMap()
   tail:removeFromMap()
   if mid and mid ~= tail then
      mid:removeFromMap()
      local t = mid.pos
      mid.pos = tail.pos
      tail.pos = t
      mid:addToMap()
      mid:unlink()
      mid:insert(tail.p, tail)
   end

   if tail ~= head then
      local prev = tail.p
      tail:unlink()
      tail:insert(head, head.n)
      tail.pos[1] = head.pos[1]
      tail.pos[2] = head.pos[2]
      tail:addToMap()
      if prev ~= head then
	 self.tail = prev
      end
   end
   head.pos[1] = x
   head.pos[2] = y
   head:addToMap()
   if not mid and self.size < self.maxsize then
      self.size = self.size + 1
      ntail = Segment.new(self.tail, nil, self.sprites[2], {tx,ty}, self, {0,0,0,0})
      self.tail = ntail
      ntail:addToMap()
      ntail:setMapConnections()
   end
   if mid and mid ~= tail then
      mid:setMapConnections()
   end
   head:setMapConnections()
   tail:setMapConnections()

   if item then
      item:take()
   end
   return true
end

--[[--
   remove `amount` segments from
   slug, possibly destroying it

   probably needs to be moved into Skills.lua now
   @param amount How many tiles to remove
]]
function Slug:damage(amount)
   for i = 1,amount do
      if self.size > 0 then
	 self.size = self.size - 1
	 local t = self.tail
	 t:unsetMapConnections()
	 t:removeFromMap()
	 self.tail = t.p
	 t:unlink()
	 if self.size <= 0 then
	    self:destroy()
	 end
      end
   end
end

--[[--
   deallocate slug
]]
function Slug:destroy ()
   self:destroyOverlay()
   if self.name and slugs[self.name] then
      slugs[self.name] = nil
   end
end


text:
--[[

  Client animation library by arc_
               Version 1.0.0

  Licence
  ----------------

  You are free to modify this file and redistribute it with your changes.
  However, always mention that you changed it (and eventually what changes
  you made) and keep the original author, version number and licence intact.

  Selling this script or a derivative of it is not allowed.

  Documentation
  ----------------

  Terminology

    - Animation: a sequence of phases that act on one or more elements
	  and follow each other sequentially in time.

	  Multiple animations can be running at the same time. All defined
	  animations run in parallel.

	  An animation is in fact one phase with several subphases (see below),
	  with animation specific functions available.

	- Phase: a part of an animation sequence. A phase consists of a
	  paramater that linearly goes from a given starting value to a
	  given ending value, over the specified amount of time, and is
	  applied to one certain element. While a phase is running, its
	  callback function will be called onClientRender with the following
	  arguments:

	    phase.fn(element elem, float param, table phase)

	  Specifying time and callback function is optional. If no time is
	  specified but a function is, phase.fn(elem) will be called once.
	  If no function is specified but a time is, the phase consists
	  of simply waiting during that time, doing nothing.

	  A phase can be run once, repeated multiple times or loop infinitely.

	  Phases can also contain phases. In that case the parent phase consists
	  of completing all child phases, in order. This allows you to f.e.
	  make an element move left and right continuously: define a phase for
	  moving it to the left, followed by a phase for moving it back to the
	  right, and encapsulate these two phases in a parent phase that loops
	  forever.

	  Phases can be nested to arbitrary depth. The element a subphase works on
	  is inherited from its parent phase (or, if the parent phase doesn't
	  specify an element, from the grandparent, etc).

  Definition of a phase

    A phase is simply a table containing properties and (optionally) subphases.
	Available phase properties are: (the values for the properties are examples,
	not default values)

	phase = {
		from = 0,           -- the starting value of the parameter
		to = 1,             -- the ending value of the parameter
		[time = 1000,]      -- the time (in ms) in which to go from start to end
		[fn = callback,]    -- the function to call on each frame update
		[repeats = 5,]      -- how many times to run this phase before going on to
		                    --   the next. defaults to 1

		[subphase1,]        -- optional subphases. if one or more of these are included,
		[subphase2,]        --   only the "repeats" property is valid for this parent phase
		...
	}

  Available functions

    anim = Animation.create(elem, phase1, phase2, ...)
	  Creates and returns a new animation. This means nothing more than
	  creating a new phase, putting the specified phases in it as subphases,
	  and making the functions of the Animation class available to it.

	  Once an animation is created, it is not yet running.

	anim = Animation.createAndPlay(elem, phase1, phase2, ...)
	  Creates a new animation and immediately starts playing it.

	anim = Animation.createNamed(name, elem, ...)
	  If an animation with the specified name exists, returns that animation.
	  Otherwise creates a new named animation. You can look the animation up
	  again later with Animation.getNamed(name).

	anim = Animation.createNamedAndPlay(name, elem, ...)
	  Self explanatory.

	anim = Animation.getNamed(name)
	  Returns the animation with the specified name if it exists,
	  false otherwise.

	anim:play()
	  Start playing a newly created animation or resume a paused animation.

	anim:pause()
	  Pauses the animation. Resume it later with anim:play() or delete it
	  with anim:remove().

	anim:remove()
	  Deletes the animation completely. It can not be resumed anymore.

	anim:isPlaying()
	  Returns true if the animation is currently playing, false if not.

	Animation.playingAnimationsExist()
	  Returns true if there is any animation that is currently playing.

	anim:addPhase(phase3), phase2:addPhase(phase3)
	  Appends a new subphase to the animation or phase. Can be done while
	  the animation is playing. Note that to be able to use phase2:addPhase(),
	  phase2 first has to be processed (default values filled in, made part of
	  the Phase class) by being passed as an argument to
	  Animation.create[AndPlay] or addPhase.

  Examples

    Fade in a picture:

	  local pict = guiCreateStaticImage(...)
	  Animation.createAndPlay(pict, { from = 0, to = 1, time = 2000, fn = guiSetAlpha })

	Fade in a picture using a preset (for more presets, see the end of this file):

	  local pict = guiCreateStaticImage(...)
	  Animation.createAndPlay(pict, Animation.presets.guiFadeIn(2000))

	Move a label to the right while fading it in:

	  local label = guiCreateLabel(10, 100, 150, 20, 'Test', false)
	  Animation.createAndPlay(label, Animation.presets.guiMove(200, 100, 2000))
	  Animation.createAndPlay(label, Animation.presets.guiFadeIn(2000))

	Move a label left and right forever, without presets:

	  function guiSetX(elem, x)
	      local curX, curY = guiGetPosition(elem, false)
		  guiSetPosition(elem, x, curY, false)
	  end
	  local label = guiCreateLabel(10, 100, 150, 20, 'Test', false)
	  Animation.createAndPlay(
	      label,
		  {
		      repeats = 0,
			  { from = 10, to = 200, time = 2000, fn = guiSetX },
			  { from = 200, to = 10, time = 2000, fn = guiSetX }
		  }
	  )

                                                 ]]--

Phase = {}
Phase.__index = Phase

Animation = setmetatable({}, { __index = Phase })
Animation.__index = Animation

Animation.collection = {}

function Animation.create(elem, ...)
	local anim = setmetatable({ elem = elem, ... }, Animation)
	anim:_setup()
	return anim
end

function Animation.createAndPlay(elem, ...)
	local anim = Animation.create(elem, ...)
	anim:play()
	return anim
end

function Animation.createNamed(name, elem, ...)
	local anim = Animation.getNamed(name) or Animation.create(elem, ...)
	anim.name = name
	return anim
end

function Animation.createNamedAndPlay(name, elem, ...)
	local anim = Animation.createNamed(name, elem, ...)
	anim:play()
	return anim
end

function Animation.getNamed(name)
	local i, anim = table.find(Animation.collection, 'name', name)
	return i and anim
end

function Animation:isPlaying()
	return self.playing or false
end

function Animation.playingAnimationsExist()
	return table.find(Animation.collection, 'playing', true) and true
end

function Animation:play()
	if self.playing then
		return
	end
	if not table.find(Animation.collection, self) then
		table.insert(Animation.collection, self)
	end
	if not Animation.playingAnimationsExist() then
		addEventHandler('onClientRender', root, updateAnim)
	end
	self.playing = true
end

function Animation:pause()
	self.playing = false
	if not Animation.playingAnimationsExist() then
		removeEventHandler('onClientRender', root, updateAnim)
	end
end

function Animation:remove()
	table.removevalue(Animation.collection, self)
	if not Animation.playingAnimationsExist() then
		removeEventHandler('onClientRender', root, updateAnim)
	end
	self.playing = false
end

function Phase:_setup(parent)
	self.parent = parent
	if self[1] then
		for i,phase in ipairs(self) do
			if type(phase) == 'function' then
				phase = { fn = phase }
				self[i] = phase
			end
			setmetatable(phase, Phase)
			phase:_setup(self)
		end
		self.curphase = 1
	elseif self.time then
		self.from = self.from or 0
		self.to = self.to or 1
		self.speed = (self.to - self.from) / self.time
	end
	self.repeats = self.repeats or 1
	self.currepeat = 1
end

function Phase:addPhase(phase)
	setmetatable(phase, Phase)
	self[#self+1] = phase
	if #self == 1 then
		self.curphase = 1
	end
	phase:_setup(self)
end

function Phase:addPhases(...)
	for i,phase in ipairs({ ... }) do
		self:addPhase(phase)
	end
end

function updateAnim()
	local elem
	local phase
	local curTick = getTickCount()
	local phaseEnded

	for i,anim in ipairs(Animation.collection) do
		if anim.playing then
			phase = anim
			while phase.curphase do
				if phase.elem then
					elem = phase.elem
				end
				phase = phase[phase.curphase]
			end
			phaseEnded = false
			if type(elem) == 'userdata' and not isElement(elem) then
				anim:remove()
				phaseEnded = true
			elseif not phase.time then
				phase.fn(elem, phase)
				phaseEnded = true
			else
				if not phase.starttick then
					phase.starttick = curTick
				end
				phase.prevpassed = phase.passed
				phase.passed = (curTick - phase.starttick) % phase.time
				if phase.prevpassed and phase.passed < phase.prevpassed then
					phase.currepeat = phase.currepeat + 1
					phaseEnded = phase.repeats > 0 and phase.currepeat > phase.repeats
				end
			end
			if phaseEnded then
				repeat
					phase.currepeat = 1
					phase.starttick = nil
					phase.passed = nil
					phase = phase.parent
					phase.curphase = phase.curphase + 1
					if phase.curphase > #phase then
						phase.curphase = 1
						phase.currepeat = phase.currepeat + 1
						if phase.repeats == 0 or phase.currepeat <= phase.repeats then
							break
						end
					else
						break
					end
				until phase == anim
				if phase == anim and phase.currepeat > phase.repeats then
					anim:remove()
					anim = false
				else
					phase = phase[phase.curphase]
					if not phase.time then
						anim = false
					elseif not phase.passed then
						phase.passed = 0
					end
				end
			end
			if anim and phase.fn then
				phase.value = phase.from + phase.speed*phase.passed
				if elem then
					phase.fn(elem, phase.transform and phase.transform(phase.value) or phase.value, phase)
				else
					phase.fn(phase.transform and phase.transform(phase.value) or phase.value, phase)
				end
			end
		end
	end
end

function table.find(t, ...)
	local args = { ... }
	if #args == 0 then
		for k,v in pairs(t) do
			if v then
				return k, v
			end
		end
		return false
	end

	local value = table.remove(args)
	if value == '[nil]' then
		value = nil
	end
	for k,v in pairs(t) do
		for i,index in ipairs(args) do
			if type(index) == 'function' then
				v = index(v)
			else
				if index == '[last]' then
					index = #v
				end
				v = v[index]
			end
		end
		if v == value then
			return k, t[k]
		end
	end
	return false
end

function table.removevalue(t, val)
	for i,v in ipairs(t) do
		if v == val then
			table.remove(t, i)
			return i
		end
	end
	return false
end

--[[

  The preset functions return phases for commonly used animation effects.

                                                                           ]]--
Animation.presets = {}

function Animation.presets.guiPulse(time, value, phase)
	-- guiPulse(time)
	-- Pulses an image (scale down/up). time = ms for a complete pulsation cycle
	if type(time) ~= 'userdata' then
		return { from = 0, to = 2*math.pi, transform = math.sin, time = time, repeats = 0, fn = Animation.presets.guiPulse }
	else
		local elem = time
		if not phase.width then
			phase.width, phase.height = guiGetSize(elem, false)
			phase.centerX, phase.centerY = guiGetPosition(elem, false)
			phase.centerX = phase.centerX + math.floor(phase.width/2)
			phase.centerY = phase.centerY + math.floor(phase.height/2)
		end
		local pct = 1 - (value+1)*0.1
		local width = pct*phase.width
		local height = pct*phase.height
		local x = phase.centerX - math.floor(width/2)
		local y = phase.centerY - math.floor(height/2)
		guiSetPosition(elem, x, y, false)
		guiSetSize(elem, width, height, false)
	end
end

function Animation.presets.guiFadeIn(time)
	return { from = 0, to = 1, time = time or 1000, fn = guiSetAlpha }
end

function Animation.presets.guiFadeOut(time)
	return { from = 1, to = 0, time = time or 1000, fn = guiSetAlpha }
end

function Animation.presets.guiMove(endX, endY, time, loop, startX, startY, speedUpSlowDown)
	-- guiMove(endX, endY, [ time = 1000, loop = false, startX = current X, startY = current Y, speedUpSlowDown = false ])
	if type(endX) ~= 'userdata' then
		return { from = speedUpSlowDown and -math.pi/2 or 0, to = speedUpSlowDown and math.pi/2 or 1,
		         time = time or 1000, repeats = loop and 0 or 1, fn = Animation.presets.guiMove,
		         startX = startX, startY = startY, endX = endX, endY = endY, speedUpSlowDown = speedUpSlowDown }
	else
		local elem, value, phase = endX, endY, time
		if phase.speedUpSlowDown then
			value = (value + 1)/2
		end
		if not phase.startX then
			phase.startX, phase.startY = guiGetPosition(elem, false)
		end
		guiSetPosition(elem, phase.startX + (phase.endX - phase.startX)*value, phase.startY + (phase.endY - phase.startY)*value, false)
	end
end

function Animation.presets.guiMoveResize(endX, endY, endWidth, endHeight, time, loop, startX, startY, startWidth, startHeight, speedUpSlowDown)
	-- guiMoveResize(endX, endY, endWidth, endHeight, [ time = 1000, loop = false, startX = current X, startY = current Y,
	--   startWidth = current width, startHeight = current height, speedUpSlowDown = false ])
	if type(endX) ~= 'userdata' then
		return { from = speedUpSlowDown and -math.pi/2 or 0, to = speedUpSlowDown and math.pi/2 or 1,
		         time = time or 1000, repeats = loop and 0 or 1, transform = math.sin, fn = Animation.presets.guiMoveResize,
		         startX = startX, startY = startY, startWidth = startWidth, startHeight = startHeight,
		         endX = endX, endY = endY, endWidth = endWidth, endHeight = endHeight, speedUpSlowDown = speedUpSlowDown }
	else
		local elem, value, phase = endX, endY, endWidth
		if phase.speedUpSlowDown then
			value = (value + 1)/2
		end
		if not phase.startX then
			phase.startX, phase.startY = guiGetPosition(elem, false)
			phase.startWidth, phase.startHeight = guiGetSize(elem, false)
		end
		guiSetPosition(elem, math.floor(phase.startX + value*(phase.endX - phase.startX)), math.floor(phase.startY + value*(phase.endY - phase.startY)), false)
		guiSetSize(elem, math.floor(phase.startWidth + value*(phase.endWidth - phase.startWidth)), math.floor(phase.startHeight + value*(phase.endHeight - phase.startHeight)), false)
	end
end


text:
description 'A simple loading screen!'

files {
    'index.html',

    'css/index.css',
    'css/colors.css',
    'css/icomoon.css',

    'fonts/gravity.otf',
    'fonts/icomoon.ttf',

    'img/cursor.png',
    'img/logo.png',
    'img/bg1.png',
    'img/bg2.png',
    'img/bg3.png',

    'js/synn.js',
    'js/config.js',
    'js/logger.js',
    'js/progressbar-handler.js',
    'js/progressbar-main.js',
    'js/progressbar-renderer.js',
    'js/music-handler.js',
    'js/music-controls.js',
    'js/background-handler.js',
}

loadscreen 'index.html'


text:
--[[
	Licensed according to the included 'LICENSE' document
	Author: Thomas Harning Jr <harningt@gmail.com>
]]
local lpeg = require("lpeg")
local jsonutil = require("json.util")
local merge = jsonutil.merge
local util = require("json.decode.util")

-- Container module for other JavaScript types (bool, null, undefined)

local _ENV = nil

-- For null and undefined, use the util.null value to preserve null-ness
local booleanCapture =
	lpeg.P("true") * lpeg.Cc(true)
	+ lpeg.P("false") * lpeg.Cc(false)

local nullCapture = lpeg.P("null")
local undefinedCapture = lpeg.P("undefined")

local defaultOptions = {
	allowUndefined = true,
	null = jsonutil.null,
	undefined = jsonutil.undefined
}

local modeOptions = {}

modeOptions.simple = {
	null = false,     -- Mapped to nil
	undefined = false -- Mapped to nil
}
modeOptions.strict = {
	allowUndefined = false
}

local function mergeOptions(options, mode)
	jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode])
end

local function generateLexer(options)
	-- The 'or nil' clause allows false to map to a nil value since 'nil' cannot be merged
	options = options.others
	local valueCapture = (
		booleanCapture
		+ nullCapture * lpeg.Cc(options.null or nil)
	)
	if options.allowUndefined then
		valueCapture = valueCapture + undefinedCapture * lpeg.Cc(options.undefined or nil)
	else
		valueCapture = valueCapture + #undefinedCapture * util.denied("undefined", "others.allowUndefined")
	end
	return valueCapture
end

local others = {
	mergeOptions = mergeOptions,
	generateLexer = generateLexer
}

return others


text:
local mod	= DBM:NewMod("ArtifactXylem", "DBM-Challenges", 2)
local L		= mod:GetLocalizedStrings()

mod:SetRevision(("$Revision: 84 $"):sub(12, -3))
mod:SetCreatureID(115244)
mod:SetZone()--Healer (1710), Tank (1698), DPS (1703-The God-Queen's Fury), DPS (Fel Totem Fall)
mod.soloChallenge = true
mod.onlyNormal = true

mod:RegisterCombat("combat")

mod:RegisterEventsInCombat(
	"SPELL_CAST_START 234728",
	"SPELL_AURA_APPLIED 231443",
--	"SPELL_AURA_APPLIED_DOSE",
--	"SPELL_AURA_REMOVED",
	"SPELL_CAST_SUCCESS 232661 231522",
--	"UNIT_DIED",
	"UNIT_SPELLCAST_SUCCEEDED boss1"
)
--Notes:
--TODO, all. mapids, mob iDs, win event to stop timers (currently only death event stops them)
--TODO, more timer work/data.
--TODO, phase 2
--Frost Phase
local warnFrostPhase				= mod:NewSpellAnnounce(242394, 2)
--Arcane Phase
local warnArcanePhase				= mod:NewSpellAnnounce(242386, 2)

--Frost Phase
local specWarnRazorIce				= mod:NewSpecialWarningDodge(232661, nil, nil, nil, 1, 2)
--Transition
local specWarnArcaneAnnihilation	= mod:NewSpecialWarningInterrupt(234728, nil, nil, nil, 1, 2)
--Arcane Phase
local specWarnShadowBarrage			= mod:NewSpecialWarningDodge(231443, nil, nil, nil, 2, 2)
local specWarnDrawPower				= mod:NewSpecialWarningInterrupt(231522, nil, nil, nil, 1, 2)

--Frost Phase
local timerRazorIceCD				= mod:NewCDTimer(25.5, 232661, nil, nil, nil, 3)--25.5-38.9 (other casts can delay it a lot)
--Transition
local timerArcaneAnnihilationCD		= mod:NewNextTimer(5, 234728, nil, nil, nil, 4, nil, DBM_CORE_INTERRUPT_ICON)
local timerShadowBarrageCD			= mod:NewCDTimer(40.0, 231443, nil, nil, nil, 3)--Actually used both phases
--Arcane Phase
local timerDrawPowerCD				= mod:NewCDTimer(18.2, 231522, nil, nil, nil, 4, nil, DBM_CORE_INTERRUPT_ICON)

--local countdownTimer				= mod:NewCountdownFades(10, 141582)

--Frost Phase
local voiceRazorIce					= mod:NewVoice(232661)--watchstep
--Transition
local voiceArcaneAnnihilation		= mod:NewVoice(234728)--kickcast
--Arcane Phase
local voiceShadowBarrage			= mod:NewVoice(231443)--watchorb
local voiceDrawPower				= mod:NewVoice(231522)--kickcast

local activeBossGUIDS = {}

function mod:OnCombatStart(delay)
	timerRazorIceCD:Start(12-delay)
end

function mod:SPELL_CAST_START(args)
	local spellId = args.spellId
	if spellId == 234423 then
		specWarnArcaneAnnihilation:Show(args.sourceName)
		voiceArcaneAnnihilation:Play("kickcast")
	end
end

function mod:SPELL_CAST_SUCCESS(args)
	local spellId = args.spellId
	if spellId == 232661 then
		specWarnRazorIce:Show()
		voiceRazorIce:Play("watchstep")
		timerRazorIceCD:Start()
	elseif spellId == 231522 then
		specWarnDrawPower:Show(args.sourceName)
		voiceDrawPower:Play("kickcast")
		timerDrawPowerCD:Start()
	end
end

function mod:SPELL_AURA_APPLIED(args)
	local spellId = args.spellId
	if spellId == 231443 then
		specWarnShadowBarrage:Show()
		voiceShadowBarrage:Play("watchorb")
		timerShadowBarrageCD:Start()
	end
end
--mod.SPELL_AURA_APPLIED_DOSE = mod.SPELL_AURA_APPLIED

--[[
function mod:SPELL_AURA_REMOVED(args)
	local spellId = args.spellId
	if spellId == 238471 then
		local amount = args.amount or 1
		warnScale:Show(args.destName, amount)
	end
end
mod.SPELL_AURA_REMOVED_DOSE = mod.SPELL_AURA_REMOVED
--]]

function mod:UNIT_DIED(args)
	if args.destGUID == UnitGUID("player") then--Solo scenario, a player death is a wipe
		DBM:EndCombat(self, true)
	end
	--local cid = self:GetCIDFromGUID(args.destGUID)
--	if cid == 177933 then--Variss

--	end
end

function mod:UNIT_SPELLCAST_SUCCEEDED(uId, _, _, spellGUID)
	local spellId = tonumber(select(5, strsplit("-", spellGUID)), 10)
	if spellId == 242394 then--Frost Phase
		timerDrawPowerCD:Stop()
		warnFrostPhase:Show()
		timerArcaneAnnihilationCD:Start()
		timerRazorIceCD:Start(20)--20-33
	elseif spellId == 242386 then--Arcane Phase
		warnArcanePhase:Show()
		timerRazorIceCD:Stop()
		timerArcaneAnnihilationCD:Start()
		--timerShadowBarrageCD:Start(11)
		timerDrawPowerCD:Start(27)--27-42
	elseif spellId == 164393 then--Cancel Channeling (Successfully interrupted Arcane Annihilation)

	end
end

--[[
function mod:INSTANCE_ENCOUNTER_ENGAGE_UNIT()
	for i = 1, 5 do
		local unitID = "boss"..i
		local unitGUID = UnitGUID(unitID)
		if UnitExists(unitID) and not activeBossGUIDS[unitGUID] then
			local bossName = UnitName(unitID)
			local cid = self:GetUnitCreatureId(unitID)
			--Tank
			if cid == 115244 then--Archmage Xylem

			end
		end
	end
end

--"<53.75 21:03:46> [CHAT_MSG_MONSTER_EMOTE] |TInterface\\Icons\\spell_shaman_earthquake:20|t%s readies itself to charge!#Jormog the Behemoth###Kylistà##0#0##0#12#nil#0#false#false#false#false", -- [133]
function mod:CHAT_MSG_MONSTER_EMOTE(msg)
	if msg:find("Interface\\Icons\\spell_shaman_earthquake") then
		specWarnCharge:Show()
		voiceCharge:Play("charge")
	end
end
--]]


text:
local _M = require 'apicast.policy_loader'

describe('APIcast Policy Loader', function()

  describe(':load_path', function()
    it('finds builtin policies', function()
      local path = _M:load_path('apicast', 'builtin')

      assert.match([[%g+/gateway/src/apicast/policy/apicast/%?.lua]], path)
    end)
  end)

  describe(':call', function()
    it('finds apicast builtin policy', function()
      local root = require('apicast.policy.apicast')
      local sandbox = _M:call('apicast')

      assert.is_table(sandbox)
      assert.are_not.same(root, sandbox)
      assert.equal(root._NAME, sandbox._NAME)
      assert.equal(root._VERSION, sandbox._VERSION)
    end)

    it('uses sandboxed load paths', function()
      local ok, ret = pcall(_M.call, _M, 'unknown', '0.1')

      assert.falsy(ok)
      assert.match([[module 'init' not found:
%s+no file '%g+/gateway/policies/unknown/0.1/init.lua']], ret)
    end)

    it('loads two instances of the same policy', function()
      local test = _M:call('test', '1.0.0-0', { 'spec/fixtures/policies' })
      local test2 = _M:call('test', '1.0.0-0', { 'spec/fixtures/policies' })

      test.one = 1
      assert.falsy(test2.one)
      assert.are_not.same(test, test2)

      assert.are.same(test.dependency, test2.dependency)
      assert.are_not.equal(test.dependency, test2.dependency)
    end)

    it('loads two versions of the same policy', function()
      local test = _M:call('test', '1.0.0-0', { 'spec/fixtures/policies' })
      local test2 = _M:call('test', '2.0.0-0', { 'spec/fixtures/policies' })

      assert.are.same({ '1.0 dependency' }, test.dependency)
      assert.are.same({ '2.0 dependency' }, test2.dependency)
    end)
  end)

  describe(':pcall', function()
    it('returns the existing module', function()
      assert(_M:call('apicast'))
    end)

    it('returns nil and error for invalid module', function()
      local ok, err = _M:pcall('invalid', '0.1')

      assert.is_nil(ok)
      assert.is_string(err)
      assert.match([[module 'init' not found:
%s+no file '%g+/gateway/policies/invalid/0.1/init.lua']], err)
    end)
  end)
end)


text:
--[[
Módulo responsável por serializar um artigo (converter um artigo em "dto" de artigo e vice-versa)
]]
local utils = require "utils"
local ConferenceSerializer = require "models/conference_serializer"

--[[
Responsabilidade: Monta um objeto com dados de artigo e demais dados para serem usados no html
Pré-Condição: * Banco de dados deve estar online
              * Deve receber um artigo com suas propriedades preenchidas
Pós-Condição: * Caminho do download é fornecido
              * Autores são convertidos em uma string onde são separados por vírgula
              * caminho do html é formado usando o id do artigo
              * Conferencia é adicionada ao objeto
              * Retorna o objeto
]]
local function data_for(article)
  local data = utils.merge(article:data(), {
    download_path = article:document_path(),
    scholar_download_url = article:scholar_link(),
    authors = table.concat(article.authors, ", "),
    view_path = "/articles/" .. article.id .. ".html",
  })
  if article.conference then
    data.conference = ConferenceSerializer:serialize_one(article.conference)
  else
    data.conference = {}
  end
  return data
end

return {
  serialize_one = function(self, article)
    return data_for(article)
  end,

  serialize_many = function(self, articles)
    return utils.map(articles, function(article) return data_for(article) end)
  end,
}


text:
return {
  ["server"] = "irc.esper.net",
  ["port"] = "6667"
  ["ssl"] = false
  ["nickname"] = "Ratbeef"
  ["username"] = "Ratbeef"
  ["connect_commands"] = {
    "PRIVMSG NickServ :identify ".."passwordhere"..""
    "PRIVMSG bauen1 :I'm here!"
  }
  ["admins"] = {
    "bauen1"
  },
  ["trusted"] = {
    "MrRatermat",
    "vifino",
    "ds84182",
    "bauen1"
  },
  ["channels"] = {"#V"},
  ["blacklistChannels"] = {"#oc"}, -- Dont spam #oc
  ["blacklistAcc"] = {"ping"}
  ["prefix"] = "Ratbeef:",
  ["output_prefix"] = "Ratbot: "
}


text:
local _, WagoAnything = ...

--[[
  Author: Julio Manuel Fernandez-Diaz
  Date:   January 12, 2007
  (For Lua 5.1)

  Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount()

  Formats tables with cycles recursively to any depth.
  The output is returned as a string.
  References to other tables are shown as values.
  Self references are indicated.

  The string returned is "Lua code", which can be procesed
  (in the case in which indent is composed by spaces or "--").
  Userdata and function keys and values are shown as strings,
  which logically are exactly not equivalent to the original code.

  This routine can serve for pretty formating tables with
  proper indentations, apart from printing them:

      print(table.show(t, "t"))   -- a typical use

  Heavily based on "Saving tables with cycles", PIL2, p. 113.

  Arguments:
      t is the table.
      name is the name of the table (optional)
      indent is a first indentation (optional).
--]]
function WagoAnything.PrettyTable(t, name, indent)
  local cart     -- a container
  local autoref  -- for self references

  --[[ counts the number of elements in a table
  local function tablecount(t)
    local n = 0
    for _, _ in pairs(t) do n = n+1 end
    return n
  end
  ]]
  -- (RiciLake) returns true if the table is empty
  local function isemptytable(t) return next(t) == nil end

  local function basicSerialize (o)
    local so = tostring(o)
    if type(o) == "function" then
      local info = debug.getinfo(o, "S")
      -- info.name is nil because o is not a calling level
      if info.what == "C" then
        return string.format("%q", so .. ", C function")
      else
        -- the information is defined through lines
        return string.format("%q", so .. ", defined in (" ..
            info.linedefined .. "-" .. info.lastlinedefined ..
            ")" .. info.source)
      end
    elseif type(o) == "number" or type(o) == "boolean" then
      return so
    else
      return string.format("%q", so)
    end
  end

  local function addtocart (value, name, indent, saved, field)
    indent = indent or ""
    saved = saved or {}
    field = field or name

    if #cart > 20000 then
      return
    end

    cart = cart .. indent .. field

    if type(value) ~= "table" then
      cart = cart .. " = " .. basicSerialize(value) .. ",\n"
    else
      if saved[value] then
          cart = cart .. " = {}, -- " .. saved[value]
                      .. " (self reference)\n"
          autoref = autoref ..  name .. " = " .. saved[value] .. ",\n"
      else
          saved[value] = name
          --if tablecount(value) == 0 then
          if isemptytable(value) then
            cart = cart .. " = {},\n"
          else
            cart = cart .. " = {\n"
            for k, v in pairs(value) do
                k = basicSerialize(k)
                local fname = string.format("%s[%s]", name, k)
                field = string.format("[%s]", k)
                -- three spaces between levels
                addtocart(v, fname, indent .. "   ", saved, field)
            end
            cart = cart .. indent .. "},\n"
          end
      end
    end
  end

  if type(t) ~= "table" then
    if name then
      return name .. " = " .. basicSerialize(t)
    else
      return basicSerialize(t)
    end
  end
  name = name or "__unnamed__"
  cart, autoref = "", ""
  addtocart(t, name, indent)
  if #cart > 20000 then
    cart = cart .. '\n... |cFFD6373DTable is too large to display in full. Data shown has been truncated.|r'
  end
  return cart .. autoref
end


text:
---------------------------------------------------------------------------------------------------
-- Common module
---------------------------------------------------------------------------------------------------
--[[ Required Shared libraries ]]
local actions = require("user_modules/sequences/actions")
local security = require("user_modules/sequences/security")
local utils = require("user_modules/utils")
local test = require("user_modules/dummy_connecttest")
local commonFunctions = require("user_modules/shared_testcases/commonFunctions")
local commonPreconditions = require('user_modules/shared_testcases/commonPreconditions')
local constants = require("protocol_handler/ford_protocol_constants")
local events = require("events")
local json = require("modules/json")

--[[ General configuration parameters ]]
config.SecurityProtocol = "DTLS"
config.application1.registerAppInterfaceParams.appName = "server"
config.application1.registerAppInterfaceParams.fullAppID = "SPT"

--[[ Module ]]
local m = actions

m.frameInfo = security.frameInfo
m.readFile = utils.readFile

--[[ Variables ]]
local preloadedPT = commonFunctions:read_parameter_from_smart_device_link_ini("PreloadedPT")

--[[ Functions ]]
local function getSystemTimeValue()
  local dd = os.date("*t")
  return {
    millisecond = 0,
    second = dd.sec,
    minute = dd.min,
    hour = dd.hour,
    day = dd.day,
    month = dd.month,
    year = dd.year,
    tz_hour = 2,
    tz_minute = 0
  }
end

local function registerGetSystemTimeResponse()
  actions.getHMIConnection():ExpectRequest("BasicCommunication.GetSystemTime")
  :Do(function(_, data)
      actions.getHMIConnection():SendResponse(data.id, data.method, "SUCCESS", { systemTime = getSystemTimeValue() })
    end)
  :Pin()
  :Times(AnyNumber())
end

function m.allowSDL()
  local event = events.Event()
  event.matches = function(e1, e2) return e1 == e2 end
  m.getHMIConnection():SendNotification("SDL.OnAllowSDLFunctionality", {
    allowed = true,
    source = "GUI",
    device = {
      id = utils.getDeviceMAC(),
      name = utils.getDeviceName()
    }
  })
  RUN_AFTER(function() m.getHMIConnection():RaiseEvent(event, "Allow SDL event") end, 500)
  return m.getHMIConnection():ExpectEvent(event, "Allow SDL event")
end

function m.start()
  test:runSDL()
  commonFunctions:waitForSDLStart(test)
  :Do(function()
      test:initHMI()
      :Do(function()
          local rid = actions.getHMIConnection():SendRequest("MB.subscribeTo", {
            propertyName = "BasicCommunication.OnSystemTimeReady" })
          actions.getHMIConnection():ExpectResponse(rid)
          :Do(function()
              utils.cprint(35, "HMI initialized")
              test:initHMI_onReady()
              :Do(function()
                  utils.cprint(35, "HMI is ready")
                  actions.getHMIConnection():SendNotification("BasicCommunication.OnSystemTimeReady")
                  registerGetSystemTimeResponse()
                  test:connectMobile()
                  :Do(function()
                      utils.cprint(35, "Mobile connected")
                      m.allowSDL()
                    end)
                end)
            end)
        end)
    end)
end

function m.sendAddCommandProtected()
  local params = {
    cmdID = 1,
    menuParams = {
      position = 1,
      menuName = "Command_1"
    }
  }
  local cid = m.getMobileSession():SendEncryptedRPC("AddCommand", params)
  m.getHMIConnection():ExpectRequest("UI.AddCommand", params)
  :Do(function(_, data)
      m.getHMIConnection():SendResponse(data.id, data.method, "SUCCESS", { })
    end)
  m.getMobileSession():ExpectEncryptedResponse(cid, { success = true, resultCode = "SUCCESS" })
  m.getMobileSession():ExpectEncryptedNotification("OnHashChange")
end

function m.activateAppProtected()
  local rid = m.getHMIConnection():SendRequest("SDL.ActivateApp", { appID = m.getHMIAppId() })
  m.getHMIConnection():ExpectResponse(rid)
  m.getMobileSession():ExpectEncryptedNotification("OnHMIStatus", {
    hmiLevel = "FULL", audioStreamingState = "AUDIBLE", systemContext = "MAIN" })
end

local function saveFile(pContent, pFileName)
  local f = io.open(pFileName, "w")
  f:write(pContent)
  f:close()
end

local function getAllCrtsFromPEM(pCrtsFileName)
  local crts = utils.readFile(pCrtsFileName)
  local o = {}
  local i = 1
  local s = crts:find("-----BEGIN RSA PRIVATE KEY-----", i, true)
  local _, e = crts:find("-----END RSA PRIVATE KEY-----", i, true)
  o.key = crts:sub(s, e) .. "\n"
  for _, v in pairs({ "crt", "rootCA", "issuingCA" }) do
    i = e
    s = crts:find("-----BEGIN CERTIFICATE-----", i, true)
    _, e = crts:find("-----END CERTIFICATE-----", i, true)
    o[v] = crts:sub(s, e) .. "\n"
  end
  return o
end

local function createCrtHashes()
  local sdlBin = commonPreconditions:GetPathToSDL()
  os.execute("cd " .. sdlBin .. " && c_rehash .")
end

local function updateSDLIniFile()
  m.setSDLIniParameter("KeyPath", "module_key.pem")
  m.setSDLIniParameter("CertificatePath", "module_crt.pem")
end

function m.initSDLCertificates(pCrtsFileName, pIsModuleCrtDefined)
  if pIsModuleCrtDefined == nil then pIsModuleCrtDefined = true end
  local allCrts = getAllCrtsFromPEM(pCrtsFileName)
  local sdlBin = commonPreconditions:GetPathToSDL()
  saveFile(allCrts.rootCA, sdlBin .. "rootCA.pem")
  saveFile(allCrts.issuingCA, sdlBin .. "issuingCA.pem")
  createCrtHashes()
  if pIsModuleCrtDefined then
    saveFile(allCrts.key, sdlBin .. "module_key.pem")
    saveFile(allCrts.crt, sdlBin .. "module_crt.pem")
  end
  updateSDLIniFile()
end

function m.cleanUpCertificates()
  local sdlBin = commonPreconditions:GetPathToSDL()
  os.execute("cd " .. sdlBin .. " && find . -type l -not -name 'lib*' -exec rm -f {} \\;")
  os.execute("cd " .. sdlBin .. " && rm -rf *.pem")
end

local preconditionsOrig = m.preconditions
local postconditionsOrig = m.postconditions

function m.preloadedPTUpdate(pPTUpdateFunc)
  local preloadedFile = commonPreconditions:GetPathToSDL() .. preloadedPT
  local pt = utils.jsonFileToTable(preloadedFile)
  pt.policy_table.functional_groupings["DataConsent-2"].rpcs = json.null
  if pPTUpdateFunc then pPTUpdateFunc(pt) end
  utils.tableToJsonFile(pt, preloadedFile)
end

function m.preconditions(pPTUpdateFunc)
  preconditionsOrig()
  m.cleanUpCertificates()
  commonPreconditions:BackupFile(preloadedPT)
  if pPTUpdateFunc == nil then
    pPTUpdateFunc = function(pPT)
      pPT.policy_table.app_policies["default"].encryption_required = true
      pPT.policy_table.functional_groupings["Base-4"].encryption_required = true
    end
  end
  m.preloadedPTUpdate(pPTUpdateFunc)
end

function m.postconditions()
  postconditionsOrig()
  m.cleanUpCertificates()
  commonPreconditions:RestoreFile(preloadedPT)
end

function m.defaultExpNotificationFunc()
  m.getHMIConnection():ExpectRequest("BasicCommunication.DecryptCertificate")
  :Do(function(_, d)
      m.getHMIConnection():SendResponse(d.id, d.method, "SUCCESS", { })
    utils.wait(1000) -- time for SDL to save certificates
    end)
  :Times(AnyNumber())
  m.getHMIConnection():ExpectRequest("VehicleInfo.GetVehicleData", { odometer = true })
end

local policyTableUpdateOrig = m.policyTableUpdate
function m.policyTableUpdate(pPTUpdateFunc, pExpNotificationFunc)
  local func = m.defaultExpNotificationFunc
  if pExpNotificationFunc then func = pExpNotificationFunc end
  policyTableUpdateOrig(pPTUpdateFunc, func)
end

function m.policyTableUpdateSuccess(pPTUpdateFunc)
  m.isPTUStarted()
  :Do(function()
      m.policyTableUpdate(pPTUpdateFunc)
    end)
end

local function registerStartSecureServiceFunc(pMobSession)
  function pMobSession.mobile_session_impl.control_services:StartSecureService(pServiceId, pPayload)
    local msg = {
      serviceType = pServiceId,
      frameInfo = constants.FRAME_INFO.START_SERVICE,
      sessionId = self.session.sessionId.get(),
      encryption = true,
      binaryData = pPayload
    }
    self:Send(msg)
  end
  function pMobSession.mobile_session_impl:StartSecureService(pServiceId, pPayload)
    if not self.isSecuredSession then
      self.security:registerSessionSecurity()
      self.security:prepareToHandshake()
    end
    return self.control_services:StartSecureService(pServiceId, pPayload)
  end
  function pMobSession:StartSecureService(pServiceId, pPayload)
    return self.mobile_session_impl:StartSecureService(pServiceId, pPayload)
  end
end

local origGetMobileSession = actions.getMobileSession
function actions.getMobileSession(pAppId)
  if not pAppId then pAppId = 1 end
  if not test.mobileSession[pAppId] then
    local session = origGetMobileSession(pAppId)
    registerStartSecureServiceFunc(session)
  end
  return origGetMobileSession(pAppId)
end

return m


text:
-- INCLUDE ZONE

-- custom error handler
require("crash")

local json = require("com/json")
local strmethods = require("src/strmethods")

local Vec2 = require("src/Essentials/Vector2")
local Color = require("src/Essentials/Color")

local Debug = require("src/Kernel/Debug")

local BootScreen = require("src/Kernel/BootScreen")
local Game = require("src/Game")

local Settings = require("src/Kernel/Settings")

local DiscordRichPresence = require("src/DiscordRichPresence")

-- CONSTANT ZONE
VERSION = "v0.40.0"
VERSION_NAME = "Beta 4.0.0"
DISCORD_APPLICATION_ID = "797956172539887657"

-- TODO: at some point, get rid of this and make it configurable
NATIVE_RESOLUTION = Vec2(800, 600)

-- GLOBAL ZONE
displaySize = Vec2(800, 600)
displayFullscreen = false
mousePos = Vec2(0, 0)
keyModifiers = {lshift = false, lctrl = false, lalt = false, rshift = false, rctrl = false, ralt = false}

game = nil
dbg = nil

variableSet = {}

totalTime = 0
timeScale = 1

-- CALLBACK ZONE
function love.load()
	--local s = loadFile("test.txt")
	--print(s)
	--print(jsonBeautify(s))
	dbg = Debug()
	engineSettings = Settings("engine/settings.json")
	discordRPC = DiscordRichPresence()
	-- Init boot screen
	loadBootScreen()
end

function love.update(dt)
	dbg:profUpdateStart()

	mousePos = posFromScreen(Vec2(love.mouse.getPosition()))
	if game then game:update(dt * timeScale) end

	dbg:update(dt)
	discordRPC:update(dt)

	-- rainbow effect for the shooter and console cursor blink; to be phased out soon
	totalTime = totalTime + dt

	dbg:profUpdateStop()
end

function love.draw()
	--dbg:profDrawStart()

	-- Main
	if game then game:draw() end

	-- Tests
	dbg:draw()

	--dbg:profDrawStop()
end

function love.mousepressed(x, y, button)
	if game then game:mousepressed(x, y, button) end
end

function love.mousereleased(x, y, button)
	if game then game:mousereleased(x, y, button) end
end

function love.keypressed(key)
	for k, v in pairs(keyModifiers) do if key == k then keyModifiers[k] = true end end
	-- Backspace is treated exclusively and will trigger repeatedly when held.
	love.keyboard.setKeyRepeat(key == "backspace")

	if not dbg.console.active then
		if game then game:keypressed(key) end
	end

	dbg:keypressed(key)
end

function love.keyreleased(key)
	for k, v in pairs(keyModifiers) do if key == k then keyModifiers[k] = false end end

	if not dbg.console.active then
		if game then game:keyreleased(key) end
	end

	dbg:keyreleased(key)
end

function love.textinput(t)
	if not dbg.console.active then
		if game then game:textinput(t) end
	end

	dbg:textinput(t)
end

function love.resize(w, h)
	displaySize = Vec2(w, h)
end

function love.quit()
	print("[] User-caused Exit... []")
	if game and game.quit then game:quit(true) end
	discordRPC:disconnect()
end

-- FUNCTION ZONE
function loadGame(gameName)
	game = Game(gameName)
	game:init()
end

function loadBootScreen()
	game = BootScreen()
	game:init()
end

function getDisplayOffsetX()
	return (displaySize.x - NATIVE_RESOLUTION.x * getResolutionScale()) / 2
end

function getResolutionScale()
	return displaySize.y / NATIVE_RESOLUTION.y
end

function posOnScreen(pos)
	return pos * getResolutionScale() + Vec2(getDisplayOffsetX(), 0)
end

function posFromScreen(pos)
	return (pos - Vec2(getDisplayOffsetX(), 0)) / getResolutionScale()
end

function getRainbowColor(t)
	t = t * 3
	local r = math.min(math.max(2 * (1 - math.abs(t % 3)), 0), 1) + math.min(math.max(2 * (1 - math.abs((t % 3) - 3)), 0), 1)
	local g = math.min(math.max(2 * (1 - math.abs((t % 3) - 1)), 0), 1)
	local b = math.min(math.max(2 * (1 - math.abs((t % 3) - 2)), 0), 1)
	return Color(r, g, b)
end

function loadFile(path)
	local file = io.open(path, "r")
	if not file then
		print("WARNING: File \"" .. path .. "\" does not exist. Expect errors!")
		return
	end
	io.input(file)
	local contents = io.read("*a")
	io.close(file)
	return contents
end

function loadJson(path)
	return json.decode(loadFile(path))
end

-- This function allows to load images from external sources.
-- This is an altered code from https://love2d.org/forums/viewtopic.php?t=85350#p221460
function loadImageData(path)
	local f = io.open(path, "rb")
	if f then
		local data = f:read("*all")
		f:close()
		if data then
			data = love.filesystem.newFileData(data, "tempname")
			data = love.image.newImageData(data)
			return data
		end
	end
end

function loadImage(path)
	local imageData = loadImageData(path)
	if not imageData then error("LOAD IMAGE FAIL: " .. path) end
	local image = love.graphics.newImage(imageData)
	return image
end

-- This function allows to load sounds from external sources.
-- This is an altered code from the above function.
function loadSound(path, type)
	local f = io.open(path, "rb")
	if f then
		local data = f:read("*all")
		f:close()
		if data then
			-- to make everything work properly, we need to get the extension from the path, because it is used
			-- source: https://love2d.org/wiki/love.filesystem.newFileData
			local t = strSplit(path, ".")
			local extension = t[#t]
			data = love.filesystem.newFileData(data, "tempname." .. extension)
			data = love.sound.newSoundData(data)
			local sound = love.audio.newSource(data, type)
			return sound
		end
	end
end

function saveFile(path, data)
	local file = io.open(path, "w")
	io.output(file)
	io.write(data)
	io.close(file)
end

function saveJson(path, data)
	print("Saving JSON data to " .. path .. "...")
	saveFile(path, jsonBeautify(json.encode(data)))
end

function getDirListing(path, filter, extFilter, recursive, pathRec)
	-- Returns a list of directories and/or files in a given path.
	-- filter can be "all", "dir" for directories only or "file" for files only.
	filter = filter or "all"
	pathRec = pathRec or ""

	local result = {}
	-- If it's compiled /fused/, this piece of code is needed to be able to read the external files
	if love.filesystem.isFused() then
		local success = love.filesystem.mount(love.filesystem.getSourceBaseDirectory(), "")
		if not success then
			local msg = string.format("Failed to read contents of folder: \"%s\". Report this error to a developer.", path)
			error(msg)
		end
	end
	-- Now we can access the directory regardless of whether it's fused or not.
	local items = love.filesystem.getDirectoryItems(path .. "/" .. pathRec)
	-- Each folder will get a / character on the end BUT ONLY IN "ALL" FILTER so it's easier to tell whether this is a file or a directory.
	for i, item in ipairs(items) do
		local p = path .. "/" .. pathRec .. item
		if love.filesystem.getInfo(p).type == "directory" then
			if filter == "all" then
				table.insert(result, pathRec .. item .. "/")
			elseif filter == "dir" then
				table.insert(result, pathRec .. item)
			end
			if recursive then
				for j, file in ipairs(getDirListing(path, filter, extFilter, true, pathRec .. item .. "/")) do
					table.insert(result, file)
				end
			end
		else
			if filter == "all" or filter == "file" and (not extFilter or item:sub(item:len() - extFilter:len(), item:len()) == extFilter) then
				table.insert(result, pathRec .. item)
			end
		end
	end
	-- Unmount it so we don't get into safety problems.
	if pathRec == "" then
		love.filesystem.unmount(love.filesystem.getSourceBaseDirectory())
	end
	return result
end

function parseString(data, variables)
	if not data then return nil end
	if type(data) == "string" then return data end
	str = ""
	for i, compound in ipairs(data) do
		if type(compound) == "string" then
			str = str .. compound
		else
			if compound.type == "scoreFormat" then
				str = str .. numStr(parseNumber(compound.value, variables))
			elseif compound.type == "variable" then
				if not variables[compound.name] then
					-- print("FATAL: Invalid variable: " .. compound.name)
					-- print("Variables:")
					-- for k, v in pairs(variables) do print(k, v) end
					-- print("The game will crash now...")
				end
				str = str .. tostring(variables[compound.name])
			end
		end
	end
	return str
end

function parsePath(data, variables)
	if not data then return nil end
	return "games/" .. game.name .. "/" .. parseString(data, variables)
end

function parseNumber(data, variables, properties)
	if not data then return nil end
	if type(data) == "number" then return data end
	if type(data) == "string" then return tonumber(data) end
	if data.type == "variable" then return variables[data.name] end
	if data.type == "property" then return properties[data.name] end
	if data.type == "randomSign" then
		local value = parseNumber(data.value, variables, properties)
		return math.random() < 0.5 and -value or value
	end
	if data.type == "randomInt" then
		local min = parseNumber(data.min, variables, properties)
		local max = parseNumber(data.max, variables, properties)
		return math.random(min, max)
	end
	if data.type == "randomFloat" then
		local min = parseNumber(data.min, variables, properties)
		local max = parseNumber(data.max, variables, properties)
		return min + math.random() * (max - min)
	end
	if data.type == "expr_graph" then
		local value = parseNumber(data.value, variables, properties)
		local points = {}
		for i, point in ipairs(data.points) do
			points[i] = parseVec2(point, variables, properties)
		end
		for i, point in ipairs(points) do
			if value < point.x then
				local prevPoint = points[i - 1]
				if prevPoint and point.x - prevPoint.x > 0 then
					local t = (point.x - value) / (point.x - prevPoint.x)
					return prevPoint.y * t + point.y * (1 - t)
				end
				return point.y
			end
		end
		return points[#points].y
	end
	if data.type == "fromString" then
		return tonumber(parseString(data.value, variables))
	end
end

function parseVec2(data, variables, properties)
	if not data then return nil end
	if data.type == "variable" then return variables[data.name] end
	return Vec2(parseNumber(data.x, variables, properties), parseNumber(data.y, variables, properties))
end

function parseColor(data, variables, properties)
	if not data then return nil end
	if data.type == "variable" then return variables[data.name] end
	return Color(parseNumber(data.r, variables, properties), parseNumber(data.g, variables, properties), parseNumber(data.b, variables, properties))
end

function numStr(n)
	local text = ""
	local s = tostring(n)
	local l = s:len()
	for i = 1, l do
		text = text .. s:sub(i, i)
		if l - i > 0 and (l - i) % 3 == 0 then text = text .. "," end
	end
	return text
end

-- One-dimensional cubic Beazier curve.
-- More info: http://www.demofox.org/bezcubic1d.html
-- The given expression can be simplified, because we are defining A = 0 and D = 1.
-- The shortened expression: y = B * 3x(1-x)^2 + C * 3x^2(1-x) + x^3
-- x is t, B is p1 and C is p2.
function bzLerp(t, p1, p2)
	local b = p1 * (3 * t * math.pow(1 - t, 2))
	local c = p2 * (math.pow(3 * t, 2) * (1 - t))
	local d = math.pow(x, 3)
	return b + c + d
end


text:
local original_electric_furnace = data.raw["furnace"]["electric-furnace"]
local beaconed_data = {
  machine_energy_usage              = original_electric_furnace.energy_usage,
  machine_emissions                 = original_electric_furnace.energy_source.emissions_per_minute,
  machine_crafting_speed            = original_electric_furnace.crafting_speed,
  machine_module_slots              = original_electric_furnace.module_specification.module_slots,
  beacon_count                      = global_electric_furnace_beacon_count,
  average_beacon_count              = global_electric_furnace_average_beacon_count,
  beacon_effect                     = global_beacon_transmission_effect,
  beacon_module_slots               = global_beacon_module_slots,
  beacon_module_speed_bonus         = global_speed_module_1_speed_bonus,
  beacon_module_energy_usage_bonus  = global_speed_module_1_energy_usage_bonus,
  machine_module_speed_bonus        = global_productivity_module_1_speed_bonus,
  machine_module_energy_usage_bonus = global_productivity_module_1_energy_usage_bonus,
  machine_module_productivity_bonus = global_productivity_module_1_productivity_bonus,
  machine_module_pollution_bonus    = global_productivity_module_1_pollution_bonus,
  original_animation_speed          = 0.5,
  tier_animation_speed_multiplier   = global_tier_1_furnace_animation_speed_multiplier,
  custom_animation_speed_multiplier = 1,
  emission_hack                     = 1.01981
}
local beaconed_electric_furnace_1_animation_speed = beaconed_stats(beaconed_data).beaconed_animation_speed

beaconed_electric_furnace = util.table.deepcopy(data.raw["furnace"]["electric-furnace"])
beaconed_electric_furnace.name = "beaconed-electric-furnace"
beaconed_electric_furnace.icon = "__Built-in-Beacons__/graphics/icons/beaconed-electric-furnace.png"
beaconed_electric_furnace.minable.result = "beaconed-electric-furnace"
beaconed_electric_furnace.next_upgrade = "beaconed-electric-furnace-2"
beaconed_electric_furnace.crafting_speed = beaconed_stats(beaconed_data).beaconed_crafting_speed--6.2
beaconed_electric_furnace.energy_source.emissions_per_minute = beaconed_stats(beaconed_data).beaconed_emissions_per_minute
beaconed_electric_furnace.energy_source.drain = beaconed_stats(beaconed_data).beaconed_drain_string
beaconed_electric_furnace.energy_usage = beaconed_stats(beaconed_data).beaconed_energy_usage_string
beaconed_electric_furnace.allowed_effects = {"productivity", "pollution"}

if settings.startup["productivity-mode"].value == 'Modded Modules' then
  beaconed_electric_furnace.module_specification.module_slots = data.raw["furnace"]["electric-furnace"].module_specification.module_slots * 2
  if settings.startup["show-module-slot-row-length"].value > 0 then
    beaconed_electric_furnace.module_specification.module_info_max_icons_per_row = settings.startup["show-module-slot-row-length"].value
  end
  if settings.startup["show-module-slot-rows"].value > 0 then
    beaconed_electric_furnace.module_specification.module_info_max_icon_rows = settings.startup["show-module-slot-rows"].value
  end
else
  beaconed_electric_furnace.module_specification.module_slots = 0
  beaconed_electric_furnace.base_productivity = beaconed_stats(beaconed_data).beaconed_base_productivity
end

if settings.startup["modded-entity-graphics"].value == "ON" then
beaconed_electric_furnace.animation =
{
  layers =
  {
    {
      filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/beaconed-electric-furnace-base.png",
      priority = "high",
      width = 129,
      height = 100,
      frame_count = 1,
      shift = {0.421875, 0},
      hr_version =
      {
        filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/hr-beaconed-electric-furnace-base.png",
        priority = "high",
        width = 239,
        height = 219,
        frame_count = 1,
        shift = util.by_pixel(0.75, 5.75),
        scale = 0.5
      }
    },
    {
      filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/beaconed-electric-furnace-overlay.png",
      priority = "high",
      width = 101,
      height = 101,
      frame_count = 1,
      shift = util.by_pixel(1, 0),
      tint = beaconed_electric_furnace_1_tint,
      hr_version =
      {
        filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/hr-beaconed-electric-furnace-overlay.png",
        priority = "high",
        width = 201,
        height = 200,
        frame_count = 1,
        shift = util.by_pixel(0.75, 0),
        tint = beaconed_electric_furnace_1_tint,
        scale = 0.5
      }
    },
    {
      filename = "__base__/graphics/entity/electric-furnace/electric-furnace-shadow.png",
      priority = "high",
      width = 129,
      height = 100,
      frame_count = 1,
      shift = {0.421875, 0},
      draw_as_shadow = true,
      hr_version =
      {
        filename = "__base__/graphics/entity/electric-furnace/hr-electric-furnace-shadow.png",
        priority = "high",
        width = 227,
        height = 171,
        frame_count = 1,
        draw_as_shadow = true,
        shift = util.by_pixel(11.25, 7.75),
        scale = 0.5
      }
    }
  }
}

beaconed_electric_furnace.working_visualisations[2].animation =
{
  layers =
  {
    {
      filename = "__base__/graphics/entity/electric-furnace/electric-furnace-propeller-1.png",
      priority = "high",
      width = 19,
      height = 13,
      frame_count = 4,
      animation_speed = beaconed_electric_furnace_1_animation_speed,
      shift = {-0.671875, -0.640625},
      hr_version =
      {
        filename = "__base__/graphics/entity/electric-furnace/hr-electric-furnace-propeller-1.png",
        priority = "high",
        width = 37,
        height = 25,
        frame_count = 4,
        animation_speed = beaconed_electric_furnace_1_animation_speed,
        shift = util.by_pixel(-20.5, -18.5),
        scale = 0.5
      }
    },
    {
      filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/beaconed-electric-furnace-propeller-1-overlay.png",
      priority = "high",
      width = 19,
      height = 13,
      frame_count = 4,
      animation_speed = beaconed_electric_furnace_1_animation_speed,
      shift = {-0.671875, -0.640625},
      tint = beaconed_electric_furnace_1_tint,
      hr_version =
      {
        filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/hr-beaconed-electric-furnace-propeller-1-overlay.png",
        priority = "high",
        width = 37,
        height = 25,
        frame_count = 4,
        animation_speed = beaconed_electric_furnace_1_animation_speed,
        shift = util.by_pixel(-20.5, -18.5),
        tint = beaconed_electric_furnace_1_tint,
        scale = 0.5
      }
    }
  }
}
beaconed_electric_furnace.working_visualisations[3].animation =
{
  layers =
  {
    {
      filename = "__base__/graphics/entity/electric-furnace/electric-furnace-propeller-2.png",
      priority = "high",
      width = 12,
      height = 9,
      frame_count = 4,
      animation_speed = beaconed_electric_furnace_1_animation_speed,
      shift = {0.0625, -1.234375},
      hr_version =
      {
        filename = "__base__/graphics/entity/electric-furnace/hr-electric-furnace-propeller-2.png",
        priority = "high",
        width = 23,
        height = 15,
        frame_count = 4,
        animation_speed = beaconed_electric_furnace_1_animation_speed,
        shift = util.by_pixel(3.5, -38),
        scale = 0.5
      }
    },
    {
      filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/beaconed-electric-furnace-propeller-2-overlay.png",
      priority = "high",
      width = 12,
      height = 8,
      frame_count = 4,
      animation_speed = beaconed_electric_furnace_1_animation_speed,
      shift = util.by_pixel(3.5, -38.5),
      tint = beaconed_electric_furnace_1_tint,
      hr_version =
      {
        filename = "__Built-in-Beacons__/graphics/entity/beaconed-electric-furnace/hr-beaconed-electric-furnace-propeller-2-overlay.png",
        priority = "high",
        width = 23,
        height = 15,
        frame_count = 4,
        animation_speed = beaconed_electric_furnace_1_animation_speed,
        shift = util.by_pixel(3.25, -38.25),
        tint = beaconed_electric_furnace_1_tint,
        scale = 0.5
      }
    }
  }
}
end

if settings.startup["modded-entity-graphics"].value ~= "OFF" then
  local set_animation_speed = function(anim)
    if anim then
      anim.animation_speed = beaconed_electric_furnace_1_animation_speed
      if (anim.hr_version) then
        anim.hr_version.animation_speed = beaconed_electric_furnace_1_animation_speed
      end
    end
  end
  for i,layer in pairs(beaconed_electric_furnace.working_visualisations) do
    set_animation_speed(layer.animation)
  end
end

data:extend({
  beaconed_electric_furnace
})
data:extend({
  {
    type = "item",
    name = "beaconed-electric-furnace",
    icon = "__Built-in-Beacons__/graphics/icons/beaconed-electric-furnace.png",
    icon_size = 64,
    icon_mipmaps = 4,
    subgroup = "smelting-machine",
    order = "b",
    place_result = "beaconed-electric-furnace",
    stack_size = 50,
    localised_description = {'item-description.beaconed-electric-furnace', global_electric_furnace_beacon_count}
  },
})
data:extend({
  {
    type = "recipe",
    name = "beaconed-electric-furnace",
    enabled = false,
    icon = "__Built-in-Beacons__/graphics/icons/beaconed-electric-furnace.png",
    icon_size = 64,
    icon_mipmaps = 4,
    subgroup = "built-in-beacons",
    order = "b",
    ingredients =
    {
      {"electric-furnace", 1},
      {"beacon", global_electric_furnace_average_beacon_count},
      {"speed-module", global_electric_furnace_average_beacon_count * global_beacon_module_slots}
    },
    results = {
      {type = "item", name = "beaconed-electric-furnace", amount = 1}
    },
    allow_as_intermediate = false,
    localised_description = {'item-description.beaconed-electric-furnace', global_electric_furnace_beacon_count}
  }
})

if global_logging == true then
  log(serpent.block( beaconed_data ))
  log(serpent.block( beaconed_stats(beaconed_data) ))
end