text:
----------------------------------------------------------------------------
-- Lua script to generate a customized, minified version of Lua.
-- The resulting 'minilua' is used for the build process of uJIT.
----------------------------------------------------------------------------
-- Copyright (C) 2020-2021 LuaVela Authors. See Copyright Notice in COPYRIGHT
-- Copyright (C) 2015-2020 IPONWEB Ltd. See Copyright Notice in COPYRIGHT
-- Portions taken verbatim or adapted from LuaJIT.
-- Copyright (C) 2005-2017 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
----------------------------------------------------------------------------

local sub, match, gsub = string.sub, string.match, string.gsub

local LUA_VERSION = "5.1.5"
local LUA_SOURCE

local function usage()
  io.stderr:write("Usage: ", arg and arg[0] or "genminilua",
                  " lua-", LUA_VERSION, "-source-dir\n")
  os.exit(1)
end

local function find_sources()
  LUA_SOURCE = arg and arg[1]
  if not LUA_SOURCE then usage() end
  if sub(LUA_SOURCE, -1) ~= "/" then LUA_SOURCE = LUA_SOURCE.."/" end
  local fp = io.open(LUA_SOURCE .. "lua.h")
  if not fp then
    LUA_SOURCE = LUA_SOURCE.."src/"
    fp = io.open(LUA_SOURCE .. "lua.h")
    if not fp then usage() end
  end
  local all = fp:read("*a")
  fp:close()
  if not match(all, 'LUA_RELEASE%s*"Lua '..LUA_VERSION..'"') then
    io.stderr:write("Error: version mismatch\n")
    usage()
  end
end

local LUA_FILES = {
"lmem.c", "lobject.c", "ltm.c", "lfunc.c", "ldo.c", "lstring.c", "ltable.c",
"lgc.c", "lstate.c", "ldebug.c", "lzio.c", "lopcodes.c",
"llex.c", "lcode.c", "lparser.c", "lvm.c", "lapi.c", "lauxlib.c",
"lbaselib.c", "ltablib.c", "liolib.c", "loslib.c", "lstrlib.c", "linit.c",
}

local REMOVE_LIB = {}
gsub([[
collectgarbage dofile gcinfo getfenv getmetatable load print rawequal rawset
select tostring xpcall
foreach foreachi getn maxn setn
popen tmpfile seek setvbuf __tostring
clock date difftime execute getenv rename setlocale time tmpname
dump gfind len reverse
LUA_LOADLIBNAME LUA_MATHLIBNAME LUA_DBLIBNAME
]], "%S+", function(name)
  REMOVE_LIB[name] = true
end)

local REMOVE_EXTINC = { ["<assert.h>"] = true, ["<locale.h>"] = true, }

local CUSTOM_MAIN = [[
typedef unsigned int UB;
static UB barg(lua_State *L,int idx){
union{lua_Number n;U64 b;}bn;
bn.n=lua_tonumber(L,idx)+6755399441055744.0;
if (bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number");
return(UB)bn.b;
}
#define BRET(b) lua_pushnumber(L,(lua_Number)(int)(b));return 1;
static int tobit(lua_State *L){
BRET(barg(L,1))}
static int bnot(lua_State *L){
BRET(~barg(L,1))}
static int band(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)}
static int bor(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)}
static int bxor(lua_State *L){
int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)}
static int lshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET(b<<n)}
static int rshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET(b>>n)}
static int arshift(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)}
static int rol(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((b<<n)|(b>>(32-n)))}
static int ror(lua_State *L){
UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))}
static int bswap(lua_State *L){
UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)}
static int tohex(lua_State *L){
UB b=barg(L,1);
int n=lua_isnone(L,2)?8:(int)barg(L,2);
const char *hexdigits="0123456789abcdef";
char buf[8];
int i;
if(n<0){n=-n;hexdigits="0123456789ABCDEF";}
if(n>8)n=8;
for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;}
lua_pushlstring(L,buf,(size_t)n);
return 1;
}
static const struct luaL_Reg bitlib[] = {
{"tobit",tobit},
{"bnot",bnot},
{"band",band},
{"bor",bor},
{"bxor",bxor},
{"lshift",lshift},
{"rshift",rshift},
{"arshift",arshift},
{"rol",rol},
{"ror",ror},
{"bswap",bswap},
{"tohex",tohex},
{NULL,NULL}
};
int main(int argc, char **argv){
  lua_State *L = luaL_newstate();
  int i;
  luaL_openlibs(L);
  luaL_register(L, "bit", bitlib);
  if (argc < 2) return sizeof(void *);
  lua_createtable(L, 0, 1);
  lua_pushstring(L, argv[1]);
  lua_rawseti(L, -2, 0);
  lua_setglobal(L, "arg");
  if (luaL_loadfile(L, argv[1]))
    goto err;
  for (i = 2; i < argc; i++)
    lua_pushstring(L, argv[i]);
  if (lua_pcall(L, argc - 2, 0, 0)) {
  err:
    fprintf(stderr, "Error: %s\n", lua_tostring(L, -1));
    return 1;
  }
  lua_close(L);
  return 0;
}
]]

local function read_sources()
  local t = {}
  for i, name in ipairs(LUA_FILES) do
    local fp = assert(io.open(LUA_SOURCE..name, "r"))
    t[i] = fp:read("*a")
    assert(fp:close())
  end
  t[#t+1] = CUSTOM_MAIN
  return table.concat(t)
end

local includes = {}

local function merge_includes(src)
  return gsub(src, '#include%s*"([^"]*)"%s*\n', function(name)
    if includes[name] then return "" end
    includes[name] = true
    local fp = assert(io.open(LUA_SOURCE..name, "r"))
    local inc = fp:read("*a")
    assert(fp:close())
    inc = gsub(inc, "#ifndef%s+%w+_h\n#define%s+%w+_h\n", "")
    inc = gsub(inc, "#endif%s*$", "")
    return merge_includes(inc)
  end)
end

local function get_license(src)
  return match(src, "/%*+\n%* Copyright %(.-%*/\n")
end

local function fold_lines(src)
  return gsub(src, "\\\n", " ")
end

local strings = {}

local function save_str(str)
  local n = #strings+1
  strings[n] = str
  return "\1"..n.."\2"
end

local function save_strings(src)
  src = gsub(src, '"[^"\n]*"', save_str)
  return gsub(src, "'[^'\n]*'", save_str)
end

local function restore_strings(src)
  return gsub(src, "\1(%d+)\2", function(numstr)
    return strings[tonumber(numstr)]
  end)
end

local function def_istrue(def)
  return def == "INT_MAX > 2147483640L" or
         def == "LUAI_BITSINT >= 32" or
         def == "SIZE_Bx < LUAI_BITSINT-1" or
         def == "cast" or
         def == "defined(LUA_CORE)" or
         def == "MINSTRTABSIZE" or
         def == "LUA_MINBUFFER" or
         def == "HARDSTACKTESTS" or
         def == "UNUSED"
end

local head, defs = {[[
#ifdef _MSC_VER
typedef unsigned __int64 U64;
#else
typedef unsigned long long U64;
#endif
]]}, {}

local function preprocess(src)
  local t = { match(src, "^(.-)#") }
  local lvl, on, oldon = 0, true, {}
  for pp, def, txt in string.gmatch(src, "#(%w+) *([^\n]*)\n([^#]*)") do
    if pp == "if" or pp == "ifdef" or pp == "ifndef" then
      lvl = lvl + 1
      oldon[lvl] = on
      on = def_istrue(def)
    elseif pp == "else" then
      if oldon[lvl] then
        if on == false then on = true else on = false end
      end
    elseif pp == "elif" then
      if oldon[lvl] then
        on = def_istrue(def)
      end
    elseif pp == "endif" then
      on = oldon[lvl]
      lvl = lvl - 1
    elseif on then
      if pp == "include" then
        if not head[def] and not REMOVE_EXTINC[def] then
          head[def] = true
          head[#head+1] = "#include "..def.."\n"
        end
      elseif pp == "define" then
        local k, sp, v = match(def, "([%w_]+)(%s*)(.*)")
        if k and not (sp == "" and sub(v, 1, 1) == "(") then
          defs[k] = gsub(v, "%a[%w_]*", function(tok)
            return defs[tok] or tok
          end)
        else
          t[#t+1] = "#define "..def.."\n"
        end
      elseif pp ~= "undef" then
        error("unexpected directive: "..pp.." "..def)
      end
    end
    if on then t[#t+1] = txt end
  end
  return gsub(table.concat(t), "%a[%w_]*", function(tok)
    return defs[tok] or tok
  end)
end

local function merge_header(src, license)
  local hdr = string.format([[
/* This is a heavily customized and minimized copy of Lua %s. */
/* It's only used to build LuaJIT. It does NOT have all standard functions! */
]], LUA_VERSION)
  return hdr..license..table.concat(head)..src
end

local function strip_unused1(src)
  return gsub(src, '(  {"?([%w_]+)"?,%s+%a[%w_]*},\n)', function(line, func)
    return REMOVE_LIB[func] and "" or line
  end)
end

local function strip_unused2(src)
  return gsub(src, "Symbolic Execution.-}=", "")
end

local function strip_unused3(src)
  src = gsub(src, "extern", "static")
  src = gsub(src, "\nstatic([^\n]-)%(([^)]*)%)%(", "\nstatic%1 %2(")
  src = gsub(src, "#define lua_assert[^\n]*\n", "")
  src = gsub(src, "lua_assert%b();?", "")
  src = gsub(src, "default:\n}", "default:;\n}")
  src = gsub(src, "lua_lock%b();", "")
  src = gsub(src, "lua_unlock%b();", "")
  src = gsub(src, "luai_threadyield%b();", "")
  src = gsub(src, "luai_userstateopen%b();", "{}")
  src = gsub(src, "luai_userstate%w+%b();", "")
  src = gsub(src, "%(%(c==.*luaY_parser%)", "luaY_parser")
  src = gsub(src, "trydecpoint%(ls,seminfo%)",
                  "luaX_lexerror(ls,\"malformed number\",TK_NUMBER)")
  src = gsub(src, "int c=luaZ_lookahead%b();", "")
  src = gsub(src, "luaL_register%(L,[^,]*,co_funcs%);\nreturn 2;",
                  "return 1;")
  src = gsub(src, "getfuncname%b():", "NULL:")
  src = gsub(src, "getobjname%b():", "NULL:")
  src = gsub(src, "if%([^\n]*hookmask[^\n]*%)\n[^\n]*\n", "")
  src = gsub(src, "if%([^\n]*hookmask[^\n]*%)%b{}\n", "")
  src = gsub(src, "if%([^\n]*hookmask[^\n]*&&\n[^\n]*%b{}\n", "")
  src = gsub(src, "(twoto%b()%()", "%1(size_t)")
  src = gsub(src, "i<sizenode", "i<(int)sizenode")
  src = gsub(src, "cast%(unsigned int,key%-1%)", "cast(unsigned int,key)-1")
  return gsub(src, "\n\n+", "\n")
end

local function strip_comments(src)
  return gsub(src, "/%*.-%*/", " ")
end

local function strip_whitespace(src)
  src = gsub(src, "^%s+", "")
  src = gsub(src, "%s*\n%s*", "\n")
  src = gsub(src, "[ \t]+", " ")
  src = gsub(src, "(%W) ", "%1")
  return gsub(src, " (%W)", "%1")
end

local function rename_tokens1(src)
  src = gsub(src, "getline", "getline_")
  src = gsub(src, "struct ([%w_]+)", "ZX%1")
  return gsub(src, "union ([%w_]+)", "ZY%1")
end

local function rename_tokens2(src)
  src = gsub(src, "ZX([%w_]+)", "struct %1")
  return gsub(src, "ZY([%w_]+)", "union %1")
end

local function func_gather(src)
  local nodes, list = {}, {}
  local pos, len = 1, #src
  while pos < len do
    local d, w = match(src, "^(#define ([%w_]+)[^\n]*\n)", pos)
    if d then
      local n = #list+1
      list[n] = d
      nodes[w] = n
    else
      local s
      d, w, s = match(src, "^(([%w_]+)[^\n]*([{;])\n)", pos)
      if not d then
        d, w, s = match(src, "^(([%w_]+)[^(]*%b()([{;])\n)", pos)
        if not d then d = match(src, "^[^\n]*\n", pos) end
      end
      if s == "{" then
        d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
        if sub(d, -2) == "{\n" then
          d = d..sub(match(src, "^%b{}[^;\n]*;?\n", pos+#d-2), 3)
        end
      end
      local k, v = nil, d
      if w == "typedef" then
        if match(d, "^typedef enum") then
          head[#head+1] = d
        else
          k = match(d, "([%w_]+);\n$")
          if not k then k = match(d, "^.-%(.-([%w_]+)%)%(") end
        end
      elseif w == "enum" then
        head[#head+1] = v
      elseif w ~= nil then
        k = match(d, "^[^\n]-([%w_]+)[(%[=]")
        if k then
          if w ~= "static" and k ~= "main" then v = "static "..d end
        else
          k = w
        end
      end
      if w and k then
        local o = nodes[k]
        if o then nodes["*"..k] = o end
        local n = #list+1
        list[n] = v
        nodes[k] = n
      end
    end
    pos = pos + #d
  end
  return nodes, list
end

local function func_visit(nodes, list, used, n)
  local i = nodes[n]
  for m in string.gmatch(list[i], "[%w_]+") do
    if nodes[m] then
      local j = used[m]
      if not j then
        used[m] = i
        func_visit(nodes, list, used, m)
      elseif i < j then
        used[m] = i
      end
    end
  end
end

local function func_collect(src)
  local nodes, list = func_gather(src)
  local used = {}
  func_visit(nodes, list, used, "main")
  for n,i in pairs(nodes) do
    local j = used[n]
    if j and j < i then used["*"..n] = j end
  end
  for n,i in pairs(nodes) do
    if not used[n] then list[i] = "" end
  end
  return table.concat(list)
end

find_sources()
local src = read_sources()
src = merge_includes(src)
local license = get_license(src)
src = fold_lines(src)
src = strip_unused1(src)
src = save_strings(src)
src = strip_unused2(src)
src = strip_comments(src)
src = preprocess(src)
src = strip_whitespace(src)
src = strip_unused3(src)
src = rename_tokens1(src)
src = func_collect(src)
src = rename_tokens2(src)
src = restore_strings(src)
src = merge_header(src, license)
io.write(src)


text:
local mapping = require('cmp.config.mapping')
local cache = require('cmp.utils.cache')
local keymap = require('cmp.utils.keymap')
local misc = require('cmp.utils.misc')
local api = require('cmp.utils.api')

---@class cmp.Config
---@field public g cmp.ConfigSchema
local config = {}

---@type cmp.Cache
config.cache = cache.new()

---@type cmp.ConfigSchema
config.global = require('cmp.config.default')()

---@type table<number, cmp.ConfigSchema>
config.buffers = {}

---@type table<string, cmp.ConfigSchema>
config.cmdline = {}

---@type cmp.ConfigSchema
config.onetime = {}

---Set configuration for global.
---@param c cmp.ConfigSchema
config.set_global = function(c)
  config.global = misc.merge(config.normalize(c), config.normalize(config.global))
  config.global.revision = config.global.revision or 1
  config.global.revision = config.global.revision + 1
end

---Set configuration for buffer
---@param c cmp.ConfigSchema
---@param bufnr number|nil
config.set_buffer = function(c, bufnr)
  local revision = (config.buffers[bufnr] or {}).revision or 1
  config.buffers[bufnr] = c or {}
  config.buffers[bufnr].revision = revision + 1
end

---Set configuration for cmdline
---@param c cmp.ConfigSchema
---@param cmdtype string
config.set_cmdline = function(c, cmdtype)
  local revision = (config.cmdline[cmdtype] or {}).revision or 1
  config.cmdline[cmdtype] = c or {}
  config.cmdline[cmdtype].revision = revision + 1
end

---Set configuration as oneshot completion.
---@param c cmp.ConfigSchema
config.set_onetime = function(c)
  local revision = (config.onetime or {}).revision or 1
  config.onetime = c or {}
  config.onetime.revision = revision + 1
end

---@return cmp.ConfigSchema
config.get = function()
  local global = config.global
  if config.onetime.sources then
    local onetime = config.onetime
    return config.cache:ensure({ 'get_onetime', global.revision or 0, onetime.revision or 0 }, function()
      return misc.merge(config.normalize(onetime), config.normalize(global))
    end)
  elseif api.is_cmdline_mode() then
    local cmdtype = vim.fn.getcmdtype()
    local cmdline = config.cmdline[cmdtype] or { revision = 1, sources = {} }
    return config.cache:ensure({ 'get_cmdline', cmdtype, global.revision or 0, cmdline.revision or 0 }, function()
      return misc.merge(config.normalize(cmdline), config.normalize(global))
    end)
  else
    local bufnr = vim.api.nvim_get_current_buf()
    local buffer = config.buffers[bufnr] or { revision = 1 }
    return config.cache:ensure({ 'get_buffer', bufnr, global.revision or 0, buffer.revision or 0 }, function()
      return misc.merge(config.normalize(buffer), config.normalize(global))
    end)
  end
end

---Return cmp is enabled or not.
config.enabled = function()
  local enabled = config.get().enabled
  if type(enabled) == 'function' then
    enabled = enabled()
  end
  return enabled and api.is_suitable_mode()
end

---Return source config
---@param name string
---@return cmp.SourceConfig
config.get_source_config = function(name)
  local c = config.get()
  for _, s in ipairs(c.sources) do
    if s.name == name then
      return s
    end
  end
  return nil
end

---Normalize mapping key
---@param c cmp.ConfigSchema
---@return cmp.ConfigSchema
config.normalize = function(c)
  if c.mapping then
    local normalized = {}
    for k, v in pairs(c.mapping) do
      normalized[keymap.normalize(k)] = mapping(v, { 'i' })
    end
    c.mapping = normalized
  end

  if c.sources then
    for _, s in ipairs(c.sources) do
      if s.opts and not s.option then
        s.option = s.opts
        s.opts = nil
        vim.api.nvim_echo({
          { '[nvim-cmp] ', 'Normal' },
          { 'sources[number].opts', 'WarningMsg' },
          { ' is deprecated.\n', 'Normal' },
          { '[nvim-cmp] Please use ', 'Normal' },
          { 'sources[number].option', 'WarningMsg' },
          { ' instead.', 'Normal' },
        }, true, {})
      end
      s.option = s.option or {}
    end
  end

  return c
end

return config

domain: lua


text:
--[[
Sample plugin file for highlight

Adds modern monospace fonts
]]

Description="Adds modern monospace fonts"

-- function to update theme definition
-- optional parameter: theme description
function themeUpdate()

  if (HL_OUTPUT == HL_FORMAT_HTML or HL_OUTPUT == HL_FORMAT_XHTML) then
    Injections[#Injections+1]="pre.hl, ol.hl { font-family: Consolas,Monaco,\"Andale Mono\",\"Ubuntu Mono\",monospace;}"
  end

end

--The Plugins array assigns code chunks to themes or language definitions.
--The chunks are interpreted after the theme or lang file were parsed,
--so you can refer to elements of these files

Plugins={

  { Type="theme", Chunk=themeUpdate }

}


text:
---@gendoc

local ObjectStateBackupUtils = Ballance2.Utils.ObjectStateBackupUtils

---带物理的机关基类，你可用于只有一个物体的简单物理机关
---@class ModulPhysics : ModulBase
---@field _PhysicsObject PhysicsObject 物理物体，请在编辑器中设置此字段
---@field _PhysicsObjectCollIDName string 设置物理物体球碰撞声音组，可以在编辑器中设置此字段
ModulPhysics = ModulBase:extend()

function ModulPhysics:new()
  ModulBase.super.new(self)
  self._PhysicsObject = nil
  self._PhysicsObjectCollIDName = nil
  self.EnableBallRangeChecker = true
  self.BallCheckeRange = 50
end
function ModulPhysics:Start()
  if not self.IsPreviewMode then
    if self._PhysicsObject == nil then
      self._PhysicsObject = self.gameObject:GetComponent(BallancePhysics.Wapper.PhysicsObject) ---@type PhysicsObject
    end
    if not IsNilOrEmpty(self._PhysicsObjectCollIDName) then
      self._PhysicsObject.CollisionID = GamePlay.BallSoundManager:GetSoundCollIDByName(self._PhysicsObjectCollIDName)
    end
  end
end
function ModulPhysics:BallEnterRange()
  if not self.IsPreviewMode then
    if self._PhysicsObject == nil and self._PhysicsObject.IsPhysicalized then
      self._PhysicsObject:WakeUp()
    end
  end
end
function ModulPhysics:Active()
  self.gameObject:SetActive(true)
  self._PhysicsObject:Physicalize()
end
function ModulPhysics:Deactive()
  self.gameObject:SetActive(false)
  self._PhysicsObject:UnPhysicalize(true)
end
function ModulPhysics:Reset()
  ObjectStateBackupUtils.RestoreObject(self._PhysicsObject.gameObject)
end
function ModulPhysics:Backup()
  ObjectStateBackupUtils.BackUpObject(self._PhysicsObject.gameObject)
end

function ModulPhysics:ActiveForPreview()
  self.gameObject:SetActive(true)
end
function ModulPhysics:DeactiveForPreview()
  self.gameObject:SetActive(false)
end

function CreateClass:ModulPhysics()
  return ModulPhysics()
end


text:
local screen = require("Screen")
local GUI = require("GUI")
local color = require("Color")
local filesystem = require("Filesystem")
local system = require("System")
local paths = require("Paths")
local system = require("System")
local text = require("Text")
local event = require("Event")
local number = require("Number")

-------------------------------------------------------------------------------

local socketHandle
local socketConnectDelay = 1
local socketReadDelay = 1
local oldUptime = 0

local channelUsersList = {operators = {}, voiced = {}, default = {}}
local channelUsersListUpdatingFinished = true

local userZoneMaxWidth = 26
local chatTimeWidth = 5

local selectedItem

local socketUsername = "Socket "

local systemNames = {
	["NickServ"] = true,
	["ChanServ"] = true,
	["DerpServ"] = true,
	[socketUsername] = true,
}

local colorScheme = {
	noticeMessageSender = 0x0049BF,
	noticeMessageText = 0x0092FF,
	actionMessageSender = 0xCC9200,
	actionMessageText = 0xFFB600,
	myMessageSender = 0x2D2D2D,
	myMessageText = 0x969696,
	otherMessageSender = 0x2D2D2D,
	otherMessageText = 0x696969,
	channelDataMessageSender = 0x696969,
	channelDataMessageText = 0xB4B4B4,
}

local applicationPath = paths.user.applicationData .. "IRC/"
local configPath = applicationPath .. "Config.cfg"
local historyPath = applicationPath .. "History.cfg"

local config = {
	server = "irc.esper.net",
	port = 6667,
	username = "",
	password = "",
	historyLimit = 50,
}

local history = {
	["#cc.ru"] = {},
	["#oc"] = {},
	[socketUsername] = {},
	["NickServ"] = {},
	["ECS"] = {},
}

if filesystem.exists(configPath) then
	config = filesystem.readTable(configPath)
end

if filesystem.exists(historyPath) then
	history = filesystem.readTable(historyPath)
end

-------------------------------------------------------------------------------

local workspace, window = system.addWindow(GUI.filledWindow(1, 1, 110, 27, 0xE1E1E1))

local leftPanel = window:addChild(GUI.panel(1, 1, 21, 1, 0x2D2D2D))
local leftLayout = window:addChild(GUI.layout(1, 4, leftPanel.width, 1, 1, 1))
leftLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
leftLayout:setMargin(1, 1, 0, 0)

local channelsText = leftLayout:addChild(GUI.text(1, 1, 0xE1E1E1, "  Channels"))
local channelsList = leftLayout:addChild(GUI.list(1, 1, leftPanel.width, 1, 1, 0, 0x2D2D2D, 0x696969, 0x2D2D2D, 0x696969, 0x3366CC, 0xE1E1E1, false))

local usersText = leftLayout:addChild(GUI.text(1, 1, 0xE1E1E1, "  Users"))
local usersList = leftLayout:addChild(GUI.list(1, 1, leftPanel.width, 1, 1, 0, 0x2D2D2D, 0x696969, 0x2D2D2D, 0x696969, 0x3366CC, 0xE1E1E1, false))

local systemText = leftLayout:addChild(GUI.text(1, 1, 0xE1E1E1, "  System"))
local systemList = leftLayout:addChild(GUI.list(1, 1, leftPanel.width, 1, 1, 0, 0x2D2D2D, 0x696969, 0x2D2D2D, 0x696969, 0x3366CC, 0xE1E1E1, false))

local contactLayout = window:addChild(GUI.layout(1, 1, leftPanel.width, 3, 1, 1))
contactLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_CENTER, GUI.ALIGNMENT_VERTICAL_TOP)
contactLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
contactLayout:setSpacing(1, 1, 0)

local contactButtonWidth = 7
local contactAddButton = contactLayout:addChild(GUI.button(1, 1, contactButtonWidth, contactLayout.height, 0x3C3C3C, 0xA5A5A5, 0x878787, 0xB4B4B4, "+"))
local contactRemoveButton = contactLayout:addChild(GUI.button(1, 1, contactButtonWidth, contactLayout.height, 0x4B4B4B, 0xA5A5A5, 0x878787, 0xB4B4B4, "-"))
contactRemoveButton.colors.disabled.background = 0x4B4B4B
contactRemoveButton.colors.disabled.text = 0x696969
local settingsButton = contactLayout:addChild(GUI.button(1, 1, contactButtonWidth, contactLayout.height, 0x3C3C3C, 0xA5A5A5, 0x878787, 0xB4B4B4, "*"))

window.backgroundPanel.width = 18
local rightLayout = window:addChild(GUI.layout(1, 1, window.backgroundPanel.width - 2, 1, 1, 1))
rightLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
rightLayout:setMargin(1, 1, 0, 0)
rightLayout:setSpacing(1, 1, 0)

local chat = window:addChild(GUI.object(1, 1, 1, 1))
chat.passScreenEvents = true

local scrollBar = window:addChild(GUI.scrollBar(1, 1, 1, 1, 0xD2D2D2, 0x878787, 1, 1, 1, 1, 1, true))

local chatInputLayout = window:addChild(GUI.layout(1, 1, 1, 3, 1, 1))
chatInputLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
chatInputLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)
chatInputLayout:setSpacing(1, 1, 0)

local chatInput = chatInputLayout:addChild(GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x696969, 0xA5A5A5, 0xE1E1E1, 0x2D2D2D, "", "Type message here"))
chatInput.historyEnabled = true

local chatComboBox = chatInputLayout:addChild(GUI.comboBox(1, 1, 14, 3, 0xD2D2D2, 0x4B4B4B, 0xD2D2D2, 0x969696))
chatComboBox.dropDownMenu.itemHeight = 1
chatComboBox:addItem("/msg")
chatComboBox:addItem("/me")
chatComboBox:addItem("/notice")
chatComboBox:addItem("/ctcp")
chatComboBox:addItem("/raw")

local backgroundContainer = window:addChild(GUI.container(1, 1, 1, 1))
local backgroundPanel = backgroundContainer:addChild(GUI.panel(1, 1, 1, 1, 0xF0F0F0))
local backgroundLayout = backgroundContainer:addChild(GUI.layout(1, 1, 1, 1, 1, 1))
backgroundLayout.hidden = true

local loginServerLayout = GUI.layout(1, 1, 36, 3, 1, 1)
loginServerLayout:setAlignment(1, 1, GUI.ALIGNMENT_HORIZONTAL_LEFT, GUI.ALIGNMENT_VERTICAL_TOP)
loginServerLayout:setDirection(1, 1, GUI.DIRECTION_HORIZONTAL)

local loginServerInput = loginServerLayout:addChild(GUI.input(1, 1, 27, 3, 0xE1E1E1, 0x787878, 0xB4B4B4, 0xE1E1E1, 0x2D2D2D, config.server or "", "Server"))
local loginPortInput = loginServerLayout:addChild(GUI.input(1, 1, loginServerLayout.width - loginServerInput.width - 1, 3, 0xE1E1E1, 0x787878, 0xB4B4B4, 0xE1E1E1, 0x2D2D2D, config.port and tostring(config.port) or "", "Port"))

local loginUsernameInput = GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x787878, 0xB4B4B4, 0xE1E1E1, 0x2D2D2D, config.username or "", "Username")
local loginPasswordInput = GUI.input(1, 1, 36, 3, 0xE1E1E1, 0x787878, 0xB4B4B4, 0xE1E1E1, 0x2D2D2D, config.password or "", "Password")
local loginPasswordSwitchAndLabel = GUI.switchAndLabel(1, 1, 36, 8, 0x66DB80, 0xE1E1E1, 0xFFFFFF, 0xB4B4B4, "Log into NickServ:", true)
local loginSubmitButton = GUI.button(1, 1, 36, 3, 0xC3C3C3, 0xFFFFFF, 0x969696, 0xFFFFFF, "Connect")
local loginStatusText = GUI.text(1, 1, 0xA5A5A5, "")

window.actionButtons.localX = 3
window.actionButtons:moveToFront()

local function getProperList(name)
	return systemNames[name] and systemList or name:sub(1, 1) == "#" and channelsList or usersList
end

local function getItemByText(name)
	return getProperList(name):getItem(name)
end

local function saveConfig()
	filesystem.writeTable(configPath, config)
end

local function socketWrite(data)
	local success, result = pcall(socketHandle.write, data .. "\r\n")
	if success then
		return true, result
	else
		return false, result
	end
end

local function sendMessage(target, text, notice, ctcp)
	socketWrite((notice and "NOTICE " or "PRIVMSG ") .. target .. (ctcp and " :\x01" or " :") .. text .. (ctcp and "\x01" or ""))
end

local function status(text)
	local state = text ~= nil
	if text then
		loginStatusText.text = text
		loginStatusText:update()
	end

	loginStatusText.hidden, loginServerLayout.hidden, loginUsernameInput.hidden, loginPasswordSwitchAndLabel.hidden, loginSubmitButton.hidden = not state, state, state, state, state
	loginPasswordInput.hidden = state and true or not loginPasswordSwitchAndLabel.switch.state

	workspace:draw()
end

local function updateLeftLayout()
	local function checkTextAndList(text, list)
		text.hidden = #list.children == 0
		list.hidden = text.hidden
		list.height = #list.children
	end

	checkTextAndList(channelsText, channelsList)
	checkTextAndList(usersText, usersList)
	checkTextAndList(systemText, systemList)
end

local function contactItemDraw(item)
	local background = item.pressed and item.colors.pressed.background or item.colors.default.background
	local foreground = item.pressed and item.colors.pressed.text or item.colors.default.text

	screen.drawRectangle(item.x, item.y, item.width, item.height, background, foreground, " ")

	local y, textLimit = math.floor(item.y + item.height / 2)
	if not item.pressed and item.unreadCount > 0 then
		local tipString = tostring(item.unreadCount)
		local tipWidth = #tipString + 2

		screen.drawRectangle(item.x + item.width - tipWidth - 1, y, tipWidth, 1, 0x3C3C3C, 0xE1E1E1, " ")
		screen.drawText(item.x + item.width - tipWidth, y, 0xE1E1E1, tipString)

		textLimit = item.width - 4 - tipWidth
	else
		textLimit = item.width - 4
	end

	screen.drawText(item.x + 2, y, foreground, text.limit(item.text, textLimit, "right"))
end

local function addContactItemToList(name)
	if not history[name] then
		history[name] = {}
	end

	local list = getProperList(name)
	local item = list:addItem(name)

	item.unreadCount = 0
	item.draw = contactItemDraw

	item.onTouch = function()
		if list == channelsList then
			usersList.selectedItem = nil
			systemList.selectedItem = nil
		elseif list == usersList then
			channelsList.selectedItem = nil
			systemList.selectedItem = nil
		else
			channelsList.selectedItem = nil
			usersList.selectedItem = nil
		end

		selectedItem = item
		item.unreadCount = 0
		contactRemoveButton.disabled = systemNames[item.text]
		rightLayout.cells[1][1].verticalMargin = 0

		scrollBar.maximumValue = #history[name]
		scrollBar.value = scrollBar.maximumValue

		rightLayout:removeChildren()
		workspace:draw()

		if socketHandle then
			if list == channelsList then
				if item.joined then
					socketWrite("NAMES " .. name)
				else
					item.joined = true
					socketWrite("JOIN " .. name)
				end
			end
		end
	end

	table.sort(list.children, function(a, b) return a.text:lower() < b.text:lower() end)
	updateLeftLayout()

	return item
end

local function addChatMessage(conversationName, text, sender)
	if not history[conversationName] then
		addContactItemToList(conversationName)
	end

	text = text:gsub("[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F]+", "")

	local chars = {}
	for i = 1, unicode.len(text) do
		chars[i] = unicode.sub(text, i, i)
		if unicode.isWide(chars[i]) then
			chars[i] = "?"
		end
	end
	text = table.concat(chars)

	local message = {
		text = text,
		time = os.date("%H:%M", system.getTime()),
		sender = sender
	}

	table.insert(history[conversationName], message)
	if #history[conversationName] > config.historyLimit then
		table.remove(history[conversationName], 1)
	end

	local item = getItemByText(conversationName)
	if item == selectedItem then
		scrollBar.maximumValue = #history[conversationName]

		if scrollBar.value == scrollBar.maximumValue - 1 then
			scrollBar.value = scrollBar.maximumValue
		end
	elseif item.unreadCount < config.historyLimit then
		item.unreadCount = item.unreadCount + 1
	end

	return message
end

chat.draw = function()
	screen.drawRectangle(chat.x, chat.y, chat.width, chat.height, 0xF0F0F0, colorScheme.otherMessageText, " ")

	if history[selectedItem.text] and #history[selectedItem.text] > 0 then
		local y, userZoneWidth, messages = chat.y + chat.height - 2, 0, history[selectedItem.text]

		for i = scrollBar.value, 1, -1 do
			userZoneWidth = math.max(userZoneWidth, unicode.len(messages[i].sender or selectedItem.text))
		end
		userZoneWidth = math.min(userZoneWidth + chatTimeWidth + 4, userZoneMaxWidth)

		for i = chat.y, chat.y + chat.height - 1 do
			local index = screen.getIndex(chat.x + userZoneWidth - 1, i)
			local background, foreground, symbol = screen.rawGet(index)

			screen.rawSet(index, background, 0xE1E1E1, "│")
		end

		for i = scrollBar.value, 1, -1 do
			if messages[i].newMessages then
				local elda = " New messages "
				local pizda = chat.width - userZoneWidth - 3 - unicode.len(elda)
				local klitor = math.floor(pizda / 2)
				local vagina = pizda - klitor

				screen.drawText(chat.x + userZoneWidth + 1, y, 0xFF9280, string.rep("─", klitor) .. elda .. string.rep("─", vagina))
				y = y - 1
			else
				local wrappedLines = text.wrap(messages[i].text, chat.width - userZoneWidth - 3)

				local senderColor, textColor
				if messages[i].notice then
					senderColor, textColor = colorScheme.noticeMessageSender, colorScheme.noticeMessageText
				elseif messages[i].action then
					senderColor, textColor = colorScheme.actionMessageSender, colorScheme.actionMessageText
				elseif messages[i].channelAction then
					senderColor, textColor = colorScheme.channelDataMessageSender, colorScheme.channelDataMessageText
				elseif messages[i].sender == config.username then
					senderColor, textColor = colorScheme.myMessageSender, colorScheme.myMessageText
				else
					senderColor, textColor = colorScheme.otherMessageSender, colorScheme.otherMessageText
				end

				for j = #wrappedLines, 1, -1 do
					screen.drawText(chat.x + userZoneWidth + 1, y, textColor, wrappedLines[j])

					y = y - 1
					if y < chat.y then
						return
					end
				end

				local sender = messages[i].sender or selectedItem.text
				local limited = text.limit(sender, userZoneWidth - chatTimeWidth - 4, "center")
				screen.drawText(chat.x + userZoneWidth - unicode.len(limited) - 2, y + 1, senderColor, limited)
				screen.drawText(chat.x + 1, y + 1, 0xC3C3C3, messages[i].time)
			end

			y = y - 1
		end
	end
end

local function checkLoginInputs()
	loginSubmitButton.disabled = #loginUsernameInput.text == 0 or #loginServerInput.text == 0 or not loginPortInput.text:match("^%d+$")
end

loginUsernameInput.onInputFinished = function()
	checkLoginInputs()
	workspace:draw()
end

loginPasswordInput.onInputFinished = loginUsernameInput.onInputFinished
loginServerInput.onInputFinished = loginUsernameInput.onInputFinished
loginPortInput.onInputFinished = loginUsernameInput.onInputFinished

local function login()
	backgroundLayout.hidden = false

	backgroundLayout:removeChildren()
	backgroundLayout:addChild(loginServerLayout)
	backgroundLayout:addChild(loginUsernameInput)
	backgroundLayout:addChild(loginPasswordInput)
	backgroundLayout:addChild(loginPasswordSwitchAndLabel)
	backgroundLayout:addChild(loginSubmitButton)
	backgroundLayout:addChild(loginStatusText)

	checkLoginInputs()
	status()
end

chatInput.onInputFinished = function()
	if #chatInput.text > 0 then
		if chatComboBox.selectedItem == 1 then
			sendMessage(selectedItem.text, chatInput.text)
			addChatMessage(selectedItem.text, chatInput.text, config.username)
		elseif chatComboBox.selectedItem == 2 then
			sendMessage(selectedItem.text, "ACTION " .. chatInput.text, false, true)
			addChatMessage(selectedItem.text, chatInput.text, config.username, "!").action = true
		elseif chatComboBox.selectedItem == 3 then
			sendMessage(selectedItem.text, chatInput.text, true)
			addChatMessage(selectedItem.text, chatInput.text, config.username, "!").notice = true
		elseif chatComboBox.selectedItem == 3 then
			sendMessage(selectedItem.text, chatInput.text, false, true)
			addChatMessage(selectedItem.text, chatInput.text, config.username, "!").action = true
		else
			socketWrite(chatInput.text)
			addChatMessage(selectedItem.text, chatInput.text, config.username)
		end

		chatInput.text = ""

		workspace:draw()
	end
end

local function addScrollEventHandler(layout)
	local function getTotalHeight(layout)
		local height = 0

		for i = 1, #layout.children do
			height = height + layout.children[i].height + (i < #layout.children and layout.cells[1][1].spacing or 0)
		end

		return height
	end

	layout.eventHandler = function(workspace, layout, e1, e2, e3, e4, e5)
		if e1 == "scroll" then
			if e5 > 0 then
				if layout.cells[1][1].verticalMargin < 0 then
					layout.cells[1][1].verticalMargin = layout.cells[1][1].verticalMargin + 1
					workspace:draw()
				end
			else
				if layout.cells[1][1].verticalMargin > -getTotalHeight(layout) + 1 then
					layout.cells[1][1].verticalMargin = layout.cells[1][1].verticalMargin - 1
					workspace:draw()
				end
			end
		end
	end
end

addScrollEventHandler(leftLayout)
addScrollEventHandler(rightLayout)

local function selectItem(item)
	selectedItem = item
	item.parent.selectedItem = item:indexOf()
	item.onTouch()
end

local function userButtonOnTouch(workspace, object)
	local text = object.text:gsub("^[@+]", "")
	if history[text] then
		selectItem(getItemByText(text))
	else
		selectItem(addContactItemToList(text))
	end
end

local function updateUsersLayoutFromList()
	local function addCategory(field, name)
		if #channelUsersList[field] > 0 then
			rightLayout:addChild(GUI.object(1, 1, 1, 1))
			rightLayout:addChild(GUI.text(1, 1, 0x5A5A5A, name)).height = 2

			table.sort(channelUsersList[field], function(a, b) return unicode.lower(a) < unicode.lower(b) end)

			for i = 1, #channelUsersList[field] do
				rightLayout:addChild(GUI.adaptiveButton(1, 1, 0, 0, nil, 0x969696, nil, 0x2D2D2D, channelUsersList[field][i])).onTouch = userButtonOnTouch
			end
		end
	end

	rightLayout:removeChildren()
	addCategory("operators", "Operators")
	addCategory("voiced", "Voiced")
	addCategory("default", "Users")
end

local function addUserToList(name)
	local firstSymbol = name:sub(1, 1)
	local field = firstSymbol == "@" and "operators" or firstSymbol == "+" and "voiced" or "default"

	for i = 1, #channelUsersList[field] do
		if channelUsersList[field][i] == name then
			return true
		end
	end

	table.insert(channelUsersList[field], name)
end

local function removeUserFromList(name)
	for field in pairs(channelUsersList) do
		for i = 1, #channelUsersList[field] do
			if channelUsersList[field][i] == name then
				table.remove(channelUsersList[field], i)
				updateUsersLayoutFromList()
				return true
			end
		end
	end
end

chat.eventHandler = function(workspace, chat, e1, e2, e3, e4, e5)
	if e1 == "scroll" then
		if e5 > 0 then
			if scrollBar.value > 1 then
				scrollBar.value = scrollBar.value - 1
				workspace:draw()
			end
		else
			if scrollBar.value < scrollBar.maximumValue then
				scrollBar.value = scrollBar.value + 1
				workspace:draw()
			end
		end
	elseif not e1 and socketHandle and computer.uptime() - oldUptime > socketReadDelay then
		local data = ""
		while true do
			local success, result = pcall(socketHandle.read, math.huge)
			if success then
				if result and #result > 0 then
					data = data .. result
				elseif #data > 0 then
					for line in data:gmatch("[^\r\n]+") do
						addChatMessage(socketUsername, line)

						local lineWithoutDots = line:match("^:(.+)")
						if lineWithoutDots then
							local words = {}
							for word in lineWithoutDots:gmatch("[^%s]+") do
								table.insert(words, word)
							end

							if #words >= 2 then
								local beforeDots, afterDots = lineWithoutDots:match("^([^:]+):(.+)")
								local username, address = words[1]:match("([^!]+)!([^!]+)")

								if words[2] == "NOTICE" then
									if username then
										if username == "NickServ" and afterDots then
											if afterDots:match("You are now identified") then
												backgroundContainer.hidden = true
											elseif afterDots:match("Invalid password for") then
												GUI.alert("Invalid password")
											end
										end

										addChatMessage(selectedItem.text, afterDots, username).notice = true
									else
										if afterDots and afterDots:match("Looking up your hostname...") then
											socketWrite("USER " .. config.username .. " 0 * :" .. config.username .. "\r\nNICK " .. config.username)
										end
									end
								elseif words[2] == "PRIVMSG" and username then
									local conversationName = words[3]:sub(1, 1) == "#" and words[3] or username

									local ctcp = afterDots:match("^\1(.+)\1$")
									if ctcp then
										local command, data = ctcp:match("^([^%s]+)%s(.+)")
										if ctcp == "VERSION" then
											sendMessage(username, "VERSION Hexagon-OS IRC Client / OpenComputers (Lua 5.3)", true, true)
										elseif ctcp == "TIME" then
											sendMessage(username, "TIME " .. os.date(system.getTime()), true, true)


text:
local Debris = game:GetService("Debris")
local RunService = game:GetService("RunService")
local SoundService = game:GetService("SoundService")

local Boop = SoundService.Boop

local ACCESSOR_LABEL_FORMAT = "Indexes: %d, Swaps: %d"
local COLOR_DEFAULT = Color3.new(0.8, 0.8, 0.8)
local COLOR_INDEX = Color3.new(1, 0, 0)
local COLOR_SWAP = Color3.new(0, 0, 1)
local INTERVAL_STEPS = 1
local TRANSACTION_INDEX = "INDEX"
local TRANSACTION_SET = "SET"
local TRANSACTION_SWAP = "SWAP"

local Accessor = {}
Accessor.__index = Accessor

local function lerp(a, b, t)
	return a + (b - a) * t
end

local function playSound(value, size)
	local boop = Boop:Clone()
	boop.PitchShift.Octave = lerp(0.5, 2, value / size)
	boop.Parent = workspace
	boop:Play()
	Debris:AddItem(boop, 0.5)
end

function Accessor:CreateIndex(index)
	return {
		transaction = TRANSACTION_INDEX,
		index = index
	}
end

function Accessor:Index(index)
	return self:Transaction({
		self:CreateIndex(index)
	})
end

function Accessor:CreateSwap(index1, index2)
	return {
		transaction = TRANSACTION_SWAP,
		index1 = index1,
		index2 = index2
	}
end

function Accessor:Swap(index1, index2)
	return self:Transaction({
		self:CreateSwap(index1, index2)
	})
end

function Accessor:CreateSet(index, value)
	return {
		transaction = TRANSACTION_SET,
		index = index,
		value = value
	}
end

function Accessor:Set(index, value)
	return self:Transaction({
		self:CreateSet(index, value)
	})
end

function Accessor:SetMark(key, index, color)
	if self.marks[key] then
		self.marks[key].BackgroundColor3 = COLOR_DEFAULT
		self.marked[self.marks[key]] = nil
	end

	if index then
		local entry = self.entries[index]
		entry.BackgroundColor3 = color
		self.marked[entry] = true
		self.marks[key] = entry
	end
end

function Accessor:Destroy()
	self.destroyed = true
end

function Accessor:Transaction(transaction)
	if self.destroyed then
		-- Easiest way to make the function uses the Accessor stop working...error!
		error("Transaction after destruction (this is normal).")
	end

	for _, reset in pairs(self.resetColor) do
		if not self.marked[reset] then
			reset.BackgroundColor3 = COLOR_DEFAULT
		end
	end

	self.resetColor = {}

	local values = {}

	for _, action in pairs(transaction) do
		local value

		if action.transaction == TRANSACTION_INDEX then
			local entry = self.entries[action.index]
			value = tonumber(entry.Name)
			entry.BackgroundColor3 = COLOR_INDEX
			self.resetColor[#self.resetColor + 1] = entry
			playSound(value, self.length)
			self.indexes = self.indexes + 1
		elseif action.transaction == TRANSACTION_SWAP then
			local entry1, entry2 = self.entries[action.index1], self.entries[action.index2]
			entry1.LayoutOrder, entry2.LayoutOrder = entry2.LayoutOrder, entry1.LayoutOrder
			self.entries[entry1.LayoutOrder], self.entries[entry2.LayoutOrder] = entry1, entry2
			self.swaps = self.swaps + 1
			playSound(entry1.LayoutOrder, self.length)
			playSound(entry2.LayoutOrder, self.length)
			entry1.BackgroundColor3 = COLOR_SWAP
			entry2.BackgroundColor3 = COLOR_SWAP
			self.resetColor[#self.resetColor + 1] = entry1
			self.resetColor[#self.resetColor + 1] = entry2
		elseif action.transaction == TRANSACTION_SET then
			local entry = self.entries[action.index]
			entry.LayoutOrder = action.value
			self.entries[action.value] = entry
		end

		values[#values + 1] = value
	end

	self.label.Text = ACCESSOR_LABEL_FORMAT:format(self.indexes, self.swaps)

	for _ = 1, INTERVAL_STEPS do
		RunService.Stepped:wait()
	end

	return unpack(values)
end

function Accessor.new(entries, label)
	label.Text = ACCESSOR_LABEL_FORMAT:format(0, 0)

	return setmetatable({
		indexes = 0,
		entries = entries,
		label = label,
		length = #entries,
		marked = {},
		marks = {},
		resetColor = {},
		swaps = 0,
	}, Accessor)
end

return Accessor


text:
function loadstring_executes_lua_code_inside_a_string_by_creating_a_function()
  local f = loadstring("return 1 + 1")
  assert_equal(2, f())
end

function loadstring_does_not_have_access_to_the_scope_where_it_is_invoked()
  local value = 10
  local f = loadstring("return value")
  assert_equal(nil, f())
  -- loadstring always uses the global scope.
end

function loadstring_can_use_local_variables_declared_inside_the_string()
  local f = loadstring("local x = 10; return x + 1")
  assert_equal(11, f())
end

function loadstring_returns_nil_plus_an_error_message_if_there_is_a_syntax_error()
  local value = 10
  local status, message = loadstring("if true return 'hello' end")
  assert_equal(nil, status)
  assert_equal([[[string "if true return 'hello' end"]:1: 'then' expected near 'return']], message)
end

function loadstring_never_raises_errors_when_called_but_its_generated_function_can_raise_them()
  local f = loadstring("error('hello', 0)")

  assert_equal("function", type(f))

  local status, message = pcall(f)

  assert_equal(false, status)
  assert_equal("hello", message)
end

function loadfile_works_like_loadstring_but_it_uses_a_path_and_reads_from_a_file()
  local f = loadfile("test_file.lua")
  assert_equal("function", type(f))

  local person = f()
  assert_equal("kikito", person.id)
  assert_equal("hello there!", person.speak())
end

function dofile_loads_the_file_and_executes_the_function_directly()
  local person = dofile("test_file.lua")
  assert_equal("kikito", person.id)
  assert_equal("hello there!", person.speak())
  -- it also raises errors if the file isn't found, the path doesn't exist, etc
end

function package_path_is_a_string_containing_question_mark_dot_lua()
  assert_equal("string", type(package.path))
  assert_equal(true, package.path:find('?.lua') ~= nil)
end

function require_is_like_do_file_but_it_uses_package_path_so_it_doesnt_need_dot_lua_at_the_end_of_path()
  local person = require("test_file")
  assert_equal("kikito", person.id)
  assert_equal("hello there!", person.speak())
  --.note that you can modify package.path so that the files are correctly loaded
end

function require_loads_the_file_only_once_caching_the_results()
  local person1 = dofile("test_file.lua")
  local person2 = require("test_file")
  local person3 = require("test_file")

  assert_equal(false, person1 == person2)
  assert_equal(true,  person2 == person3)
end

-- for all this, require is the Prefered Lua Way for requiring files


text:
local floor = math.floor
local random = math.random
local pLightGray = 163

local GRandomLines = {}
GRandomLines.__index = GRandomLines

function GRandomLines.new(self, obj)
	obj = obj or {}

	if not obj.frame then return nil end

    setmetatable(obj, GRandomLines)

    return obj;
end

function GRandomLines.draw(self, ctx)

	for i = 1, 300 do

		local x1 = random((self.frame.width - 1));
		local y1 = random((self.frame.height - 1));
		local x2 = random((self.frame.width - 1));
		local y2 = random((self.frame.height - 1));

		local r = floor(random(0,255));
		local g = floor(random(0,255));
		local b = floor(random(0,255));

		ctx:stroke(r, g, b, 255);
		ctx:fill(r, g, b, 255);

		ctx:strokeWidth(1.0);
		ctx:line(x1, y1, x2, y2);

		--ctx:strokeWidth(8.0);
		ctx:circle(x1, y1, 4);
		ctx:circle(x2, y2, 4);
    end
end

return GRandomLines


text:
-- Relative require in same directory
-- Global, because I don't want to declare it in every. single. file.
function _Require_relative(PATH, file, up)
    up = up or 0
    local path, match
    path, _     = ( (PATH):gsub("\\",".") ):gsub("/",".")
    path, match = path:gsub("(.*)%..*$", "%1" )
    for i = 1, up do
        path, match = path:gsub("%.(%w+)$", '')
    end
	return require(table.concat({path, file}, "."))
end

local scandir = require( table.concat({..., 'scandir'},".") )

Libs = scandir('lib')
for _, filename in ipairs(Libs) do
    local ext = filename:match("^.+(%..+)$")
    local name = ext == '.lua' and filename:gsub('.lua', '') or filename
    print('lib name: '..name)
    Libs[name] = require( table.concat({..., 'lib',name},".") )
end

local Strike = require( table.concat({..., 'Strike'},".") )

return Strike


text:
return
{
	HOOK_PLAYER_RIGHT_CLICKING_ENTITY =
	{
		CalledWhen = "A player has right-clicked an entity. Plugins may override / refuse.",
		DefaultFnName = "OnPlayerRightClickingEntity",  -- also used as pagename
		Desc = [[
			This hook is called when the {{cPlayer|player}} right-clicks an {{cEntity|entity}}. Plugins may
			override the default behavior or even cancel the default processing.
		]],
		Params =
		{
			{ Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has right-clicked the entity" },
			{ Name = "Entity", Type = "{{cEntity}} descendant", Notes = "The entity that has been right-clicked" },
		},
		Returns = [[
			If the functino returns false or no value, MCServer calls other plugins' callbacks and finally does
			the default processing for the right-click. If the function returns true, no other callbacks are
			called and the default processing is skipped.
		]],
	},  -- HOOK_PLAYER_RIGHT_CLICKING_ENTITY
}


text:
return {
	init_effect = "",
	name = "第2章重巡使用盾buff",
	time = 99999,
	picture = "",
	desc = "第2章重巡使用盾buff",
	stack = 1,
	id = 8019,
	icon = 8019,
	last_effect = "",
	effect_list = {
		{
			type = "BattleBuffCount",
			trigger = {
				"onShieldBroken"
			},
			arg_list = {
				shieldBuffID = 8018,
				countTarget = 3,
				countType = 8020
			}
		},
		{
			type = "BattleBuffAddBuff",
			trigger = {
				"onBattleBuffCount"
			},
			arg_list = {
				buff_id = 8020,
				rant = 10000,
				target = "TargetSelf",
				countType = 8020
			}
		}
	}
}


text:
require("rrpg.lua");
local __o_rrpgObjs = require("rrpgObjs.lua");
require("rrpgGUI.lua");
require("rrpgDialogs.lua");
require("rrpgLFM.lua");
require("ndb.lua");

function newfrmGuild()
    __o_rrpgObjs.beginObjectsLoading();

    local obj = gui.fromHandle(_obj_newObject("form"));
    local self = obj;
    local sheet = nil;

    rawset(obj, "_oldSetNodeObjectFunction", rawget(obj, "setNodeObject"));

    function obj:setNodeObject(nodeObject)
        sheet = nodeObject;
        self.sheet = nodeObject;
        self:_oldSetNodeObjectFunction(nodeObject);
    end;

    function obj:setNodeDatabase(nodeObject)
        self:setNodeObject(nodeObject);
    end;

    _gui_assignInitialParentForForm(obj.handle);
    obj:beginUpdate();
    obj:setName("frmGuild");
    obj:setAlign("client");

    obj.scrollBox1 = gui.fromHandle(_obj_newObject("scrollBox"));
    obj.scrollBox1:setParent(obj);
    obj.scrollBox1:setAlign("client");
    obj.scrollBox1:setName("scrollBox1");

    obj.richEdit1 = gui.fromHandle(_obj_newObject("richEdit"));
    obj.richEdit1:setParent(obj.scrollBox1);
    obj.richEdit1:setAlign("client");
    obj.richEdit1:setField("cla_desc");
    lfm_setPropAsString(obj.richEdit1, "backgroundColor",  "#333333");
    lfm_setPropAsString(obj.richEdit1, "defaultFontSize",  "12");
    lfm_setPropAsString(obj.richEdit1, "defaultFontColor",  "white");
    obj.richEdit1:setName("richEdit1");

    function obj:_releaseEvents()
    end;

    obj._oldLFMDestroy = obj.destroy;

    function obj:destroy()
        self:_releaseEvents();

        if (self.handle ~= 0) and (self.setNodeDatabase ~= nil) then
          self:setNodeDatabase(nil);
        end;

        if self.scrollBox1 ~= nil then self.scrollBox1:destroy(); self.scrollBox1 = nil; end;
        if self.richEdit1 ~= nil then self.richEdit1:destroy(); self.richEdit1 = nil; end;
        self:_oldLFMDestroy();
    end;

    obj:endUpdate();

     __o_rrpgObjs.endObjectsLoading();

    return obj;
end;

local _frmGuild = {
    newEditor = newfrmGuild,
    new = newfrmGuild,
    name = "frmGuild",
    dataType = "",
    formType = "undefined",
    formComponentName = "form",
    title = "",
    description=""};

frmGuild = _frmGuild;
rrpg.registrarForm(_frmGuild);

return _frmGuild;


text:
local LightFuelDimmer = Class(function(self, inst)
    self.inst = inst

    --The list of lights to dim with this component
    self.lightlist = {}

    --Parameters for controlling how fuel consumption and effects thereof
    self.fuelburnrate = TUNING.MAX_FUEL_LEVEL
    self.fuellevel = TUNING.STARTING_FUEL_LEVEL

    --Parameters that control the burn rate
    self.modburntimeremaining = 0
    self.modburnmultiplier = 1
    self.timedmodification = false

    --Parameters that determine the colour based on fuel burn rate
    self.maxcolour = {255/255,255/255,255/255}
    self.currentcolour = {self.maxcolour[1], self.maxcolour[2], self.maxcolour[3]}
	self.intensity = 1 -- a final multiplier on the colour
    self.prevpct = TUNING.STARTING_FUEL_LEVEL / TUNING.MAX_FUEL_LEVEL

    self.ison = true

    self.inst:ListenForEvent("flashlighton", function()
        self.ison = true
    end)

    self.inst:ListenForEvent("flashlightoff", function()
        self.ison = false
    end)

    self.inst:StartUpdatingComponent(self)
end)

function LightFuelDimmer:SetIntensity(intensity)
	self.intensity = intensity
	self:UpdateLights()
end

--Add a light to flicker
function LightFuelDimmer:AddLight(light)
    table.insert(self.lightlist, light)
end

--Remove a light to flicker
function LightFuelDimmer:RemoveLight(light)
    table.remove(self.lightlist, light)
end

function LightFuelDimmer:UpdateLights()
	local pct = self.ison and self.fuellevel / TUNING.MAX_FUEL_LEVEL or 0
    if pct > TUNING.MIN_REASONABLE_FUEL then
        pct = Remap(pct, TUNING.MIN_REASONABLE_FUEL, 1, TUNING.MIN_REASONABLE_BRIGHTNESS, 1)
    else
        pct = Remap(pct, 0, TUNING.MIN_REASONABLE_FUEL, 0, TUNING.MIN_REASONABLE_BRIGHTNESS)
    end
	self.currentcolour = {self.maxcolour[1] * pct * self.intensity, self.maxcolour[2] * pct * self.intensity, self.maxcolour[3] * pct * self.intensity}
	for i, l in ipairs(self.lightlist) do
		l.Light:SetColour(self.currentcolour[1], self.currentcolour[2], self.currentcolour[3])
	end
end

--Set the normal colour for the lights
function LightFuelDimmer:SetMaxColour(colour)
    if colour and #colour == 3 then
        self.maxcolour = {colour[1], colour[2], colour[3]}

		self:UpdateLights()
    end
end

--Got some fuel, need to update the colour and fuel level
function LightFuelDimmer:AddFuel(amount)
    if amount and amount >= 0 then
        if self.fuellevel <= 0 then
            self.inst:PushEvent("fuelrefilled")
        end
        self.fuellevel = self.fuellevel + amount
        if self.fuellevel > TUNING.MAX_FUEL_LEVEL then self.fuellevel = TUNING.MAX_FUEL_LEVEL end

		self:UpdateLights()

        if self.fuellevel >= TUNING.LOW_FUEL_LEVEL then
            self.inst:PushEvent("fuelnotlow")
        end
    end
end

--Remove some amount of fuel, update colour and fuel level
function LightFuelDimmer:RemoveFuel(amount)
    if amount and amount >= 0 then
        self.fuellevel = self.fuellevel - amount
        if self.fuellevel < 0 then self.fuellevel = 0 end

		self:UpdateLights()
    end
end

--Modify the fuel use rate
function LightFuelDimmer:ModifyFuelConsumptionRate(multiplier, duration)
    if multiplier and multiplier > 0 then
        self.modburnmultiplier = multiplier
        if duration and duration > 0 then
            self.modburntimeremaining = duration
            self.timedmodification = true
        else
            self.timedmodification = false
        end
    end
end

function LightFuelDimmer:OnUpdate(dt)
    if self.ison then
        if self.timedmodification then
            self.modburntimeremaining = self.modburntimeremaining - dt
            if self.modburntimeremaining <= 0 then
                self.modburnmultiplier = 1
            end
        end

        self.fuellevel = self.fuellevel - (1 * self.modburnmultiplier)

        if self.fuellevel <= TUNING.LOW_FUEL_LEVEL then
            if self.fuellevel <= 0 then
                self.fuellevel = 0
                self.ison = false
                self.inst:PushEvent("fuelempty")
            end
            self.inst:PushEvent("fuellow")
        end

        if self.fuellevel <= 0 then
            --lose game stuff
        end
    else
        if self.timedmodification then
            self.modburntimeremaining = self.modburntimeremaining - dt
            if self.modburntimeremaining <= 0 then
                self.modburnmultiplier = 1
            end
        end
    end

	if self.currentcolour  and #self.currentcolour == 3 then
		self:UpdateLights()
	end
end

function LightFuelDimmer:GetDebugString()
	return string.format("on: %s", tostring(self.ison))
end

return LightFuelDimmer


text:
modifier_sven_great_cleave_lua = class({})

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:IsHidden()
	return true
end

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:OnCreated( kv )
	self.great_cleave_damage = self:GetAbility():GetSpecialValueFor( "great_cleave_damage" )
	self.great_cleave_radius = self:GetAbility():GetSpecialValueFor( "great_cleave_radius" )
end

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:OnRefresh( kv )
	self.great_cleave_damage = self:GetAbility():GetSpecialValueFor( "great_cleave_damage" )
	self.great_cleave_radius = self:GetAbility():GetSpecialValueFor( "great_cleave_radius" )
end

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:DeclareFunctions()
	local funcs = {
		MODIFIER_EVENT_ON_ATTACK_LANDED,
	}

	return funcs
end

--------------------------------------------------------------------------------

function modifier_sven_great_cleave_lua:OnAttackLanded( params )
	if IsServer() then
		if params.attacker == self:GetParent() and ( not self:GetParent():IsIllusion() ) then
			if self:GetParent():PassivesDisabled() then
				return 0
			end

			local target = params.target
			if target ~= nil and target:GetTeamNumber() ~= self:GetParent():GetTeamNumber() then
				local cleaveDamage = ( self.great_cleave_damage * params.damage ) / 100.0
				DoCleaveAttack( self:GetParent(), target, self:GetAbility(), cleaveDamage, self.great_cleave_radius, "particles/units/heroes/hero_sven/sven_spell_great_cleave.vpcf" )
			end
		end
	end

	return 0
end


text:
local export = {}

local tab = {
	["А"]="A", ["Б"]="B", ["В"]="V", ["Г"]="G", ["Д"]="D", ["Е"]="E", ["Ё"]="Yo", ["Ж"]="Ž", ["З"]="Z", ["И"]="I", ["Й"]="Y", ["Ј"]="J̌", ["J"]="J̌[[Category:Altai text with misused characters|J]]",
	["К"]="K", ["Л"]="L", ["М"]="M", ["Н"]="N", ["Ҥ"]="Ŋ", ["О"]="O", ["Ӧ"]="Ö", ["Ö"]="Ö[[Category:Altai text with misused characters|Ö]]", ["П"]="P", ["Р"]="R", ["С"]="S", ["Т"]="T",
	["У"]="U", ["Ӱ"]="Ü", ["Ф"]="F", ["Х"]="H", ["Ц"]="C", ["Ч"]="Č", ["Ш"]="Š", ["Щ"]="Šč", ["Ъ"]="ʺ", ["Ы"]="Ï", ["Ь"]="ʹ",
	["Э"]="E", ["Ю"]="Yu", ["Я"]="Ya",
	['а']='a', ['б']='b', ['в']='v', ['г']='g', ['д']='d', ['е']='e', ['ё']='yo', ['ж']='ž', ['з']='z', ['и']='i', ['й']='y', ["ј"]="ǰ", ["j"]="ǰ[[Category:Altai text with misused characters|j]]",
	['к']='k', ['л']='l', ['м']='m', ['н']='n', ['ҥ']='ŋ', ['о']='o', ['ӧ']='ö', ['ö']='ö[[Category:Altai text with misused characters|ö]]', ['п']='p', ['р']='r', ['с']='s', ['т']='t',
	['у']='u', ['ӱ']='ü', ['ф']='f',
	['х']='h', ['ц']='c', ['ч']='č', ['ш']='š', ['щ']='šč', ['ъ']='ʺ', ['ы']='ï', ['ь']='ʹ', ['э']='e', ['ю']='yu', ['я']='ya',
}

local iotated = {
	["Е"] = "Ye",
	["е"] = "ye",
}

function export.tr(text, lang, sc)
	local ugsub = mw.ustring.gsub

	-- Ё needs to be composed if is decomposed (e + combining diaeresis).
	-- However, this cannot happen in wikitext, only in Lua modules.
	text = mw.ustring.toNFC(text)

	-- е after a vowel or at the beginning of a word becomes ye
	-- Note that according to modern Altai orthography ее (instead of ээ) is occationally used for long r
	text = ugsub(text, "([АОӨУҮЫЯЁЮИЪЬаоөуүыяёюиъь%A][́̀]?)е", "%1ye")
	--text = mw.ustring.gsub(text, "([АОӨУҮЫЕЯЁЮИЕЪЬаоөуүыэяёюиеъь%A][́̀]?)е", "%1ye")
	text = ugsub(text, "^[Ее]", iotated)
	text = ugsub(text, "([^Ѐ-ӿ])([Ее])", function(a, b)
			return a .. iotated[b]
		end)

	return (ugsub(text, '.', tab))
end

return export


text:
--[=[
@c GuildTextChannel x GuildChannel x TextChannel
@d Represents a text channel in a Discord guild, where guild members and webhooks
can send and receive messages.
]=]

local json = require('json')

local GuildChannel = require('containers/abstract/GuildChannel')
local TextChannel = require('containers/abstract/TextChannel')
local FilteredIterable = require('iterables/FilteredIterable')
local Webhook = require('containers/Webhook')
local Cache = require('iterables/Cache')
local Resolver = require('client/Resolver')

local GuildTextChannel, get = require('class')('GuildTextChannel', GuildChannel, TextChannel)

function GuildTextChannel:__init(data, parent)
	GuildChannel.__init(self, data, parent)
	TextChannel.__init(self, data, parent)
end

function GuildTextChannel:_load(data)
	GuildChannel._load(self, data)
	TextChannel._load(self, data)
end

--[=[
@m createWebhook
@p name string
@r Webhook
@d Creates a webhook for this channel. The name must be between 2 and 32 characters
in length.
]=]
function GuildTextChannel:createWebhook(name)
	local data, err = self.client._api:createWebhook(self._id, {name = name})
	if data then
		return Webhook(data, self.client)
	else
		return nil, err
	end
end

--[=[
@m getWebhooks
@r Cache
@d Returns a newly constructed cache of all webhook objects for the channel. The
cache and its objects are not automatically updated via gateway events. You must
call this method again to get the updated objects.
]=]
function GuildTextChannel:getWebhooks()
	local data, err = self.client._api:getChannelWebhooks(self._id)
	if data then
		return Cache(data, Webhook, self.client)
	else
		return nil, err
	end
end

--[=[
@m bulkDelete
@p messages Message-ID-Resolvables
@r boolean
@d Bulk deletes multiple messages, from 2 to 100, from the channel. Messages over 2 weeks old cannot be deleted and will discord will return an error.
]=]
function GuildTextChannel:bulkDelete(messages)
	messages = Resolver.messageIds(messages)
	local data, err
	if #messages == 1 then
		data, err = self.client._api:deleteMessage(self._id, messages[1])
	else
		data, err = self.client._api:bulkDeleteMessages(self._id, {messages = messages})
	end
	if data then
		return true
	else
		return false, err
	end
end

--[=[
@m setTopic
@p topic string
@r boolean
@d Sets the channel's topic. This must be between 1 and 1024 characters. Pass `nil`
to remove the topic.
]=]
function GuildTextChannel:setTopic(topic)
	return self:_modify({topic = topic or json.null})
end

--[=[
@m setRateLimit
@p limit number
@r boolean
@d Sets the channel's slowmode rate limit in seconds. This must be between 0 and 120.
Passing 0 or `nil` will clear the limit.
]=]
function GuildTextChannel:setRateLimit(limit)
	return self:_modify({rate_limit_per_user = limit or json.null})
end

--[=[
@m enableNSFW
@r boolean
@d Enables the NSFW setting for the channel. NSFW channels are hidden from users
until the user explicitly requests to view them.
]=]
function GuildTextChannel:enableNSFW()
	return self:_modify({nsfw = true})
end

--[=[
@m disableNSFW
@r boolean
@d Disables the NSFW setting for the channel. NSFW channels are hidden from users
until the user explicitly requests to view them.
]=]
function GuildTextChannel:disableNSFW()
	return self:_modify({nsfw = false})
end

--[=[@p topic string/nil The channel's topic. This should be between 1 and 1024 characters.]=]
function get.topic(self)
	return self._topic
end

--[=[@p nsfw boolean Whether this channel is marked as NSFW (not safe for work).]=]
function get.nsfw(self)
	return self._nsfw or false
end

--[=[@p rateLimit number Slowmode rate limit per guild member.]=]
function get.rateLimit(self)
	return self._rate_limit_per_user or 0
end

--[=[@p members FilteredIterable A filtered iterable of guild members that have
permission to read this channel. If you want to check whether a specific member
has permission to read this channel, it would be better to get the member object
elsewhere and use `Member:hasPermission` rather than check whether the member
exists here.]=]
function get.members(self)
	if not self._members then
		self._members = FilteredIterable(self._parent._members, function(m)
			return m:hasPermission(self, 'readMessages')
		end)
	end
	return self._members
end

return GuildTextChannel


text:
return {
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65181
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65182
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65183
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65184
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65185
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65186
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65187
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65188
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65189
				}
			}
		}
	},
	{
		effect_list = {
			{
				type = "BattleSkillFire",
				casterAniEffect = "",
				target_choise = "TargetNil",
				targetAniEffect = "",
				arg_list = {
					weapon_id = 65190
				}
			}
		}
	},
	uiEffect = "",
	name = "",
	cd = 0,
	painting = 1,
	id = 13751,
	picture = "1",
	castCV = "skill",
	desc = "鱼雷",
	aniEffect = {
		effect = "jineng",
		offset = {
			0,
			-2,
			0
		}
	},
	effect_list = {
		{
			type = "BattleSkillFire",
			casterAniEffect = "",
			target_choise = "TargetNil",
			targetAniEffect = "",
			arg_list = {
				weapon_id = 65181
			}
		}
	}
}


text:
data:extend({
    {
        type = "font",
        name = "fp-font-14p",
        from = "default",
        size = 14
    },
    {
        type = "font",
        name = "fp-font-14p-semi",
        from = "default-semibold",
        size = 14
    },
    {
        type = "font",
        name = "fp-font-15p",
        from = "default-semibold",
        size = 15
    },
    {
        type = "font",
        name = "fp-font-mono-15p",
        from = "default-mono",
        size = 15
    },
    {
        type = "font",
        name = "fp-font-bold-15p",
        from = "default-bold",
        size = 15
    },
    {
        type = "font",
        name = "fp-font-16p",
        from = "default",
        size = 16
    },
    {
        type = "font",
        name = "fp-font-semibold-16p",
        from = "default-semibold",
        size = 16
    },
    {
        type = "font",
        name = "fp-font-bold-16p",
        from = "default-bold",
        size = 16
    },
    {
        type = "font",
        name = "fp-font-18p",
        from = "default",
        size = 18
    },
    {
        type = "font",
        name = "fp-font-20p",
        from = "default",
        size = 20
    },
    {
        type = "font",
        name = "fp-font-bold-20p",
        from = "default-bold",
        size = 20
    },
    {
        type = "font",
        name = "fp-font-bold-26p",
        from = "default-bold",
        size = 26
    }
})


text:
-->>Services and modules
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local config = require(script.Configuration)
local utils = require(script.Utilities)

-->>Initial setup tasks
local heartbeatWait = utils.heartbeatWait
local holder = utils.constructFromProperties("Folder", config.holder)

local module = {}

-->>(Function) [Yields] [Returns Nametag] addTag(player: Player)
--Creates a new default nametag for a specfied player and returns it.
module.addTag = function(player)
	-->>Creates the components separately using util and config.
	local billboard = utils.constructFromProperties("BillboardGui", config.billboard)
	local frame = utils.constructFromProperties("Frame", config.frame)
	local name = utils.constructFromProperties("TextLabel", config.name)
	local mainStat = utils.constructFromProperties("TextLabel", config.mainStat)
	local extraStat = utils.constructFromProperties("TextLabel", config.extraStat)
	local healthBar = utils.constructFromProperties("Frame", config.healthBar)
	local healthBackground = healthBar:Clone()

	-->>Sets up the individual components
	billboard.Enabled = false
	healthBackground.BackgroundTransparency = .5
	healthBackground.Name = "HealthBackground"
	healthBackground.ZIndex = 1
	if player ~= nil then
		local finalName = utils.waitForProperty(player, "Name")
		billboard.Name = finalName..config.billboard["Name"]
		if config.options["useDisplayName"] == true then
			if player.DisplayName ~= nil then --Deals with the gradual rollout of display names; some players don't have access yet.
				name.Text = player.DisplayName
			else
				name.Text = finalName
			end
			mainStat.Text = "@"..finalName
		else
			name.Text = finalName
		end
	else--Deals with blank tags. Warning prevents accidental use.
		billboard.Name = "BLANK_TAG--"..tostring(os.time())
		warn("Creating an empty tag is not recommended, aside from use with NPCs. Do not forget to delete unused tags.")
	end

	-->>Assembles the components into a nametag and puts it into the holder.
	name.Parent = frame
	mainStat.Parent = frame
	extraStat.Parent = frame
	healthBar.Parent = frame
	healthBackground.Parent = frame
	frame.Parent = billboard
	billboard.Parent = holder

	return billboard--Sends the tag back to the requester for use with linkTag.
end

-->>(Function) getTag(player: Player) [Yields] [Returns Nametag]
--Gets a player's nametag using configuration data.
module.getTag = function(player)
	-->>Finds the info from config about the naming scheme
	local location = config.holder["Parent"]
	local holder = location:FindFirstChild(config.holder["Name"])
	local suffix = config.billboard["Name"]

	-->>Looks for the tag, then if it is not found waits to see if a tag is being renamed while the player loads.
	if player.Name ~= nil then
		if holder:FindFirstChild(player.Name..suffix) ~= nil then
			return holder:FindFirstChild(player.Name..suffix)
		elseif holder:FindFirstChild(suffix) ~= nil then
			repeat
				heartbeatWait(.01)
			until holder:FindFirstChild(player.Name..suffix) ~= nil or holder:FindFirstChild(suffix) == nil
			if holder:FindFirstChild(player.Name..suffix) ~= nil then
				return holder:FindFirstChild(player.Name..suffix)
			end
		else
			error(player.Name.."'s tag could not be found in "..location.Name..". Please create a new tag first.")
		end
	else--As with before, when the player's name does not load, the module will wait for it to catch up before proceeding.
		local finalName = utils.waitForProperty(player, "Name")
		if holder:FindFirstChild(finalName..suffix) ~= nil then
			return holder:FindFirstChild(finalName..suffix)
		else
			error(player.Name.."'s tag was not found when performing getTag.")
		end
	end
end

-->>(Function) linkTag(player: Player, tag: Nametag, groupId: Integer)
--Links a specific tag to a player. Including a group id will make it so the group role replaces MainStat.
module.linkTag = function(player, tag, groupId)
	-->>Deals with updating the name's text border color with the team color.
	if config.options["nameOutlinedWithTeamColor"] == true then
		local updateTeamColor = function()
			local nameLabel = tag:FindFirstChild(config.frame["Name"]):FindFirstChild(config.name["Name"])
			if player.Neutral ~= true then
				nameLabel.TextStrokeColor3 = player.TeamColor.Color
				nameLabel.TextStrokeTransparency = 0
			else
				nameLabel.TextStrokeTransparency = 1
				nameLabel.TextStrokeColor3 = config.presets["colors"]["secondary"]
			end
		end
		updateTeamColor()--Updates the team color preemptively just in case.
		player:GetPropertyChangedSignal("Team"):Connect(updateTeamColor)
	end

	-->> Manages spawn based changes.
	player.CharacterAppearanceLoaded:Connect(function(character)
		-->>Updates the health bar size.
		local healthBar = tag.Frame.HealthBar
		healthBar.Size = config.healthBar["Size"]
		character.Humanoid:GetPropertyChangedSignal("Health"):Connect(function()
			tag.Frame.HealthBar.Size = UDim2.new((character.Humanoid.Health/character.Humanoid.MaxHealth) * config.options["healthBarScale"], healthBar.Size.X.Offset, healthBar.Size.Y.Scale, healthBar.Size.Y.Offset)
		end)
		-->>Updates the MainStat with the role.
		if groupId ~= nil then
			if config.options["useDisplayName"] == true then
				tag.Frame.ExtraStat.Text = player:GetRoleInGroup(groupId)
			else
				tag.Frame.MainStat.Text = player:GetRoleInGroup(groupId)
			end
		end
		-->>Changes the humanoid to display the tag.
		character.Humanoid.DisplayDistanceType = "None"
		tag.Adornee = character.Head
	end)
	tag.Enabled = true--Enables the tag to make it visible after the chanes are complete.
end

-->>(Function) changeTag(tag: Nametag, objectName: String [Specific], properties: Dictionary [Specific])
--Changes the properties of the specified object in a given player's nametag.
--Strings are names of objects, as specified in config.
--Dictionaries are in the format {Property = Value; Property = Value; etc.}. Example: {Text = "Spam"; ZIndex = 5}.
module.changeTag = function(tag, objectName, properties)
	--Uses util functions to modify the selected
	if tag ~= nil then
		if objectName ~= "Frame" then
			utils.modifyFromProperties(tag.Frame:FindFirstChild(objectName), properties)
		else
			utils.modifyFromProperties(tag:FindFirstChild(objectName), properties)
		end
	else
		error("The function changeTag experienced an error: the tag passed to the function no longer exists. No changes have been made.")
	end
end

return module


text:
local helpers = require "spec.helpers"
local cache = require "kong.tools.database_cache"
local cjson = require "cjson"

describe("Plugin: basic-auth (hooks)", function()
  local admin_client, proxy_client

  before_each(function()
    helpers.dao:truncate_tables()
    local api = assert(helpers.dao.apis:insert {
      name = "api-1",
      hosts = { "basic-auth.com" },
      upstream_url = "http://mockbin.com"
    })
    assert(helpers.dao.plugins:insert {
      name = "basic-auth",
      api_id = api.id
    })

    local consumer = assert(helpers.dao.consumers:insert {
      username = "bob"
    })
    assert(helpers.dao.basicauth_credentials:insert {
      username = "bob",
      password = "kong",
      consumer_id = consumer.id
    })

    assert(helpers.start_kong())
    proxy_client = helpers.proxy_client()
    admin_client = helpers.admin_client()
  end)

  after_each(function()
    if admin_client and proxy_client then
      admin_client:close()
      proxy_client:close()
    end
    helpers.stop_kong()
  end)

  it("invalidates credentials when the Consumer is deleted", function()
    -- populate cache
    local res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmc=",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(200, res)

    -- ensure cache is populated
    local cache_key = cache.basicauth_credential_key("bob")
    res = assert(admin_client:send {
      method = "GET",
      path = "/cache/"..cache_key
    })
    assert.res_status(200, res)

    -- delete Consumer entity
    res = assert(admin_client:send {
      method = "DELETE",
      path = "/consumers/bob"
    })
    assert.res_status(204, res)

    -- ensure cache is invalidated
    helpers.wait_until(function()
      local res = assert(admin_client:send {
        method = "GET",
        path = "/cache/"..cache_key
      })
      res:read_body()
      return res.status == 404
    end)

    res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmc=",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(403, res)
  end)

  it("invalidates credentials from cache when deleted", function()
    -- populate cache
    local res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmc=",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(200, res)

    -- ensure cache is populated
    local cache_key = cache.basicauth_credential_key("bob")
    res = assert(admin_client:send {
      method = "GET",
      path = "/cache/"..cache_key
    })
    local body = assert.res_status(200, res)
    local credential = cjson.decode(body)

    -- delete credential entity
    res = assert(admin_client:send {
      method = "DELETE",
      path = "/consumers/bob/basic-auth/"..credential.id
    })
    assert.res_status(204, res)

    -- ensure cache is invalidated
    helpers.wait_until(function()
      local res = assert(admin_client:send {
        method = "GET",
        path = "/cache/"..cache_key
      })
      res:read_body()
      return res.status == 404
    end)

    res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmc=",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(403, res)
  end)

  it("invalidated credentials from cache when updated", function()
    -- populate cache
    local res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmc=",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(200, res)

    -- ensure cache is populated
    local cache_key = cache.basicauth_credential_key("bob")
    res = assert(admin_client:send {
      method = "GET",
      path = "/cache/"..cache_key
    })
    local body = assert.res_status(200, res)
    local credential = cjson.decode(body)

    -- delete credential entity
    res = assert(admin_client:send {
      method = "PATCH",
      path = "/consumers/bob/basic-auth/"..credential.id,
      body = {
        username = "bob",
        password = "kong-updated"
      },
      headers = {
        ["Content-Type"] = "application/json"
      }
    })
    assert.res_status(200, res)

    -- ensure cache is invalidated
    helpers.wait_until(function()
      local res = assert(admin_client:send {
        method = "GET",
        path = "/cache/"..cache_key
      })
      res:read_body()
      return res.status == 404
    end)

    res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmc=",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(403, res)

    res = assert(proxy_client:send {
      method = "GET",
      path = "/",
      headers = {
        ["Authorization"] = "Basic Ym9iOmtvbmctdXBkYXRlZA==",
        ["Host"] = "basic-auth.com"
      }
    })
    assert.res_status(200, res)
  end)
end)


text:
--!A cross-platform build utility based on Lua
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- Copyright (C) 2015-present, TBOOX Open Source Group.
--
-- @author      ruki
-- @file        dlist.lua
--

-- load modules
local object = require("base/object")

-- define module
local dlist = dlist or object { _init = {"_length"} } {0}

-- clear list
function dlist:clear()
    self._length = 0
    self._first  = nil
    self._last   = nil
end

-- push item to tail
function dlist:push(t)
    assert(t)
    if self._last then
        self._last._next = t
        t._prev = self._last
        self._last = t
    else
        self._first = t
        self._last = t
    end
    self._length = self._length + 1
end

-- insert item after the given item
function dlist:insert(t, after)
    assert(t)
    if not after then
        return self:push(t)
    end
    assert(t ~= after)
    if after._next then
        after._next._prev = t
        t._next = after._next
    else
        self._last = t
    end
    t._prev = after
    after._next = t
    self._length = self._length + 1
end

-- pop item from tail
function dlist:pop()
    if not self._last then return end
    local t = self._last
    if t._prev then
        t._prev._next = nil
        self._last = t._prev
        t._prev = nil
    else
        self._first = nil
        self._last = nil
    end
    self._length = self._length - 1
    return t
end

-- shift item: 1 2 3 <- 2 3
function dlist:shift()
    if not self._first then return end
    local t = self._first
    if t._next then
        t._next._prev = nil
        self._first = t._next
        t._next = nil
    else
        self._first = nil
        self._last = nil
    end
    self._length = self._length - 1
    return t
end

-- unshift item: 1 2 -> t 1 2
function dlist:unshift(t)
    assert(t)
    if self._first then
        self._first._prev = t
        t._next = self._first
        self._first = t
    else
        self._first = t
        self._last = t
    end
    self._length = self._length + 1
end

-- remove item
function dlist:remove(t)
    assert(t)
    if t._next then
        if t._prev then
            t._next._prev = t._prev
            t._prev._next = t._next
        else
            assert(t == self._first)
            t._next._prev = nil
            self._first = t._next
        end
    elseif t._prev then
        assert(t == self._last)
        t._prev._next = nil
        self._last = t._prev
    else
        assert(t == self._first and t == self._last)
        self._first = nil
        self._last = nil
    end
    t._next = nil
    t._prev = nil
    self._length = self._length - 1
    return t
end

-- get first item
function dlist:first()
    return self._first
end

-- get last item
function dlist:last()
    return self._last
end

-- get next item
function dlist:next(last)
    if last then
        return last._next
    else
        return self._first
    end
end

-- get the previous item
function dlist:prev(last)
    if last then
        return last._prev
    else
        return self._last
    end
end

-- get list size
function dlist:size()
    return self._length
end

-- is empty?
function dlist:empty()
    return self:size() == 0
end

-- get items
--
-- e.g.
--
-- for item in dlist:items() do
--     print(item)
-- end
--
function dlist:items()

    -- init iterator
    local iter = function (list, item)
        return list:next(item)
    end

    -- return iterator and initialized state
    return iter, self, nil
end

-- get reverse items
function dlist:ritems()

    -- init iterator
    local iter = function (list, item)
        return list:prev(item)
    end

    -- return iterator and initialized state
    return iter, self, nil
end

-- new dlist
function dlist.new()
    return dlist()
end

-- return module: dlist
return dlist


text:
local popup = require("neogit.lib.popup")
local Buffer = require("neogit.lib.buffer")
local git = require("neogit.lib.git")
local a = require 'plenary.async_lib'
local async, await, void, scheduler = a.async, a.await, a.void, a.scheduler

local function commits_to_string(commits)
  local result = {}
  local previous_level = 0

  for _, commit in pairs(commits) do
    local branch = "*"
    if previous_level > commit.level then
      table.insert(result, string.rep(" ", 7) .. string.rep(" |", commit.level + 1) .. "/")
    elseif previous_level < commit.level then
      table.insert(result, string.rep(" ", 7) .. string.rep(" |", previous_level + 1) .. "\\")
    end
    for _=1,commit.level do
      branch = "| " .. branch
    end
    if commit.remote == "" then
      table.insert(result, string.format("%s %s %s", commit.hash, branch, commit.message))
    else
      table.insert(result, string.format("%s %s %s %s", commit.hash, branch, commit.remote, commit.message))
    end
    previous_level = commit.level
  end

  return result
end

local show_in_buffer = async(function (commits)
  await(scheduler())
  Buffer.create({
    name = "NeogitLog",
    filetype = "NeogitLog",
    initialize = function(buffer)
      local result = commits_to_string(commits)
      buffer:set_lines(0, -1, false, result)
    end
  })
end)

local function create()
  popup.create(
    "NeogitLogPopup",
    {
      {
        key = "g",
        description = "Show graph",
        cli = "graph",
        enabled = true
      },
      {
        key = "c",
        description = "Show graph in color",
        cli = "color",
        enabled = true,
        parse = false
      },
      {
        key = "d",
        description = "Show refnames",
        cli = "decorate",
        enabled = true
      },
      {
        key = "S",
        description = "Show signatures",
        cli = "show-signature",
        enabled = false
      },
      {
        key = "u",
        description = "Show diffs",
        cli = "patch",
        enabled = false
      },
      {
        key = "s",
        description = "Show diffstats",
        cli = "stat",
        enabled = false
      },
      {
        key = "D",
        description = "Simplify by decoration",
        cli = "simplify-by-decoration",
        enabled = false
      },
      {
        key = "f",
        description = "Follow renames when showing single-file log",
        cli = "follow",
        enabled = false
      },
    },
    {
      {
        key = "n",
        description = "Limit number of commits",
        cli = "max-count",
        value = "256"
      },
      {
        key = "f",
        description = "Limit to files",
        cli = "-count",
        value = ""
      },
      {
        key = "a",
        description = "Limit to author",
        cli = "author",
        value = ""
      },
      {
        key = "g",
        description = "Search messages",
        cli = "grep",
        value = ""
      },
      {
        key = "G",
        description = "Search changes",
        cli = "",
        value = ""
      },
      {
        key = "S",
        description = "Search occurences",
        cli = "",
        value = ""
      },
      {
        key = "L",
        description = "Trace line evolution",
        cli = "",
        value = ""
      },
    },
    {
      {
        {
          key = "l",
          description = "Log current",
          callback = void(async(function(popup)
            local commits = await(git.log.list(popup.to_cli()))
            await(show_in_buffer(commits))
          end))
        },
        {
          key = "o",
          description = "Log other",
          callback = function() end
        },
        {
          key = "h",
          description = "Log HEAD",
          callback = void(async(function(popup)
            local output = await(
              git.cli.log
                .oneline
                .args(unpack(popup.get_arguments()))
                .for_range('HEAD')
                .call())
            local commits = git.log.parse_log(output)
            await(show_in_buffer(commits))
          end))
        },
      },
      {
        {
          key = "L",
          description = "Log local branches",
          callback = void(async(function(popup)
            local output = await(
              git.cli.log
                .oneline
                .args(unpack(popup.get_arguments()))
                .branches
                .call())
            local commits = git.log.parse_log(output)
            await(show_in_buffer(commits))
          end))
        },
        {
          key = "b",
          description = "Log all branches",
          callback = void(async(function(popup)
            local output = await(
              git.cli.log
                .oneline
                .args(unpack(popup.get_arguments()))
                .branches
                .remotes
                .call())
            local commits = git.log.parse_log(output)
            await(show_in_buffer(commits))
          end))
        },
        {
          key = "a",
          description = "Log all references",
          callback = void(async(function(popup)
            local output = await(
              git.cli.log
                .oneline
                .args(unpack(popup.get_arguments()))
                .all
                .call())
            local commits = git.log.parse_log(output)
            await(show_in_buffer(commits))
          end))
        },
      },
      {
        {
          key = "r",
          description = "Reflog current",
          callback = function() end
        },
        {
          key = "O",
          description = "Reflog other",
          callback = function() end
        },
        {
          key = "H",
          description = "Reflog HEAD",
          callback = function() end
        },
      }
    })
end

return {
  create = create
}